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;