linux: Fix libusb_get_device_speed() not working on wrapped devices
We don't have a sysfs_dir for wrapped devices, so we cannot read the speed
from sysfs.
The Linux kernel has supported a new ioctl to get the speed directly from
the fd for a while now, use that when we don't have sysfs access.
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1871818
Reported-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index f5c92c2..f3c188e 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -863,6 +863,26 @@
return LIBUSB_SUCCESS;
}
+static enum libusb_speed usbfs_get_speed(struct libusb_context *ctx, int fd)
+{
+ int r;
+
+ r = ioctl(fd, IOCTL_USBFS_GET_SPEED, NULL);
+ switch (r) {
+ case USBFS_SPEED_UNKNOWN: return LIBUSB_SPEED_UNKNOWN;
+ case USBFS_SPEED_LOW: return LIBUSB_SPEED_LOW;
+ case USBFS_SPEED_FULL: return LIBUSB_SPEED_FULL;
+ case USBFS_SPEED_HIGH: return LIBUSB_SPEED_HIGH;
+ case USBFS_SPEED_WIRELESS: return LIBUSB_SPEED_HIGH;
+ case USBFS_SPEED_SUPER: return LIBUSB_SPEED_SUPER;
+ case USBFS_SPEED_SUPER_PLUS: return LIBUSB_SPEED_SUPER_PLUS;
+ default:
+ usbi_warn(ctx, "Error getting device speed: %d", r);
+ }
+
+ return LIBUSB_SPEED_UNKNOWN;
+}
+
static int initialize_device(struct libusb_device *dev, uint8_t busnum,
uint8_t devaddr, const char *sysfs_dir, int wrapped_fd)
{
@@ -893,6 +913,8 @@
usbi_warn(ctx, "unknown device speed: %d Mbps", speed);
}
}
+ } else if (wrapped_fd >= 0) {
+ dev->speed = usbfs_get_speed(ctx, wrapped_fd);
}
/* cache descriptors in memory */
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
index 060aa35..1238ffa 100644
--- a/libusb/os/linux_usbfs.h
+++ b/libusb/os/linux_usbfs.h
@@ -127,6 +127,14 @@
unsigned char eps[0];
};
+#define USBFS_SPEED_UNKNOWN 0
+#define USBFS_SPEED_LOW 1
+#define USBFS_SPEED_FULL 2
+#define USBFS_SPEED_HIGH 3
+#define USBFS_SPEED_WIRELESS 4
+#define USBFS_SPEED_SUPER 5
+#define USBFS_SPEED_SUPER_PLUS 6
+
#define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer)
#define IOCTL_USBFS_SETINTERFACE _IOR('U', 4, struct usbfs_setinterface)
#define IOCTL_USBFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
@@ -146,6 +154,8 @@
#define IOCTL_USBFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbfs_disconnect_claim)
#define IOCTL_USBFS_ALLOC_STREAMS _IOR('U', 28, struct usbfs_streams)
#define IOCTL_USBFS_FREE_STREAMS _IOR('U', 29, struct usbfs_streams)
+#define IOCTL_USBFS_DROP_PRIVILEGES _IOW('U', 30, __u32)
+#define IOCTL_USBFS_GET_SPEED _IO('U', 31)
extern usbi_mutex_static_t linux_hotplug_lock;