diff options
author | Hans de Goede <hdegoede@redhat.com> | 2013-06-13 21:49:01 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2013-06-19 11:04:15 +0200 |
commit | d4e993192aa81a1867bddf90d53cf750ec21e7b1 (patch) | |
tree | 1ba35c380272b8f492629c2a9614a602573018b9 /libusb/os/linux_usbfs.c | |
parent | fc51f19341af70508b94c06ff763842b396ea72e (diff) | |
download | libusb-d4e993192aa81a1867bddf90d53cf750ec21e7b1.tar.gz |
linux_usbfs: Add support for new disconnect-and-claim ioctl
Currently the linux_usbfs detach_kernel_driver_and_claim() helper function
makes 3 system calls:
1) IOCTL_USBFS_GETDRIVER, to check the driver is not usbfs
2) IOCTL_USBFS_DISCONNECT
3) IOCTL_USBFS_CLAIMINTF
Between each of these calls the state of the interface can change, and
things might not work as expected when it does, iow this is inherently racy.
To fix this a new IOCTL_USBFS_DISCONNECT_CLAIM ioctl has been added to the
kernel a while back, which does all 3 in one. This patch adds support for
this ioctl, with a fall back to the old method for kernels lacking this new
ioctl.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'libusb/os/linux_usbfs.c')
-rw-r--r-- | libusb/os/linux_usbfs.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index e4ff79d..6a4a3f1 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -1533,8 +1533,32 @@ static int op_attach_kernel_driver(struct libusb_device_handle *handle, static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle, int interface) { - int r; + struct usbfs_disconnect_claim dc; + int r, fd = _device_handle_priv(handle)->fd; + + dc.interface = interface; + strcpy(dc.driver, "usbfs"); + dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER; + r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc); + if (r == 0 || (r != 0 && errno != ENOTTY)) { + if (r == 0) + return 0; + + switch (errno) { + case EBUSY: + return LIBUSB_ERROR_BUSY; + case EINVAL: + return LIBUSB_ERROR_INVALID_PARAM; + case ENODEV: + return LIBUSB_ERROR_NO_DEVICE; + } + usbi_err(HANDLE_CTX(handle), + "disconnect-and-claim failed errno %d", errno); + return LIBUSB_ERROR_OTHER; + } + /* Fallback code for kernels which don't support the + disconnect-and-claim ioctl */ r = op_detach_kernel_driver(handle, interface); if (r != 0 && r != LIBUSB_ERROR_NOT_FOUND) return r; |