summaryrefslogtreecommitdiff
path: root/libusb/os/linux_usbfs.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-06-13 21:49:01 +0200
committerHans de Goede <hdegoede@redhat.com>2013-06-19 11:04:15 +0200
commitd4e993192aa81a1867bddf90d53cf750ec21e7b1 (patch)
tree1ba35c380272b8f492629c2a9614a602573018b9 /libusb/os/linux_usbfs.c
parentfc51f19341af70508b94c06ff763842b396ea72e (diff)
downloadlibusb-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.c26
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;