diff options
-rw-r--r-- | libusb/core.c | 25 | ||||
-rw-r--r-- | libusb/libusb.h | 1 | ||||
-rw-r--r-- | libusb/libusbi.h | 17 | ||||
-rw-r--r-- | libusb/os/linux_usbfs.c | 33 |
4 files changed, 76 insertions, 0 deletions
diff --git a/libusb/core.c b/libusb/core.c index 4fffc84..baf9afb 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -1179,6 +1179,31 @@ API_EXPORTED int libusb_detach_kernel_driver(libusb_device_handle *dev, return LIBUSB_ERROR_NOT_SUPPORTED; } +/** \ingroup dev + * Re-attach an interface's kernel driver, which was previously detached + * using libusb_detach_kernel_driver(). + * + * \param dev a device handle + * \param interface the interface to attach the driver from + * \returns 0 on success + * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active + * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist + * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns LIBUSB_ERROR_BUSY if the driver cannot be attached because the + * interface is claimed by a program or driver + * \returns another LIBUSB_ERROR code on other failure + * \see libusb_kernel_driver_active() + */ +API_EXPORTED int libusb_attach_kernel_driver(libusb_device_handle *dev, + int interface) +{ + usbi_dbg("interface %d", interface); + if (usbi_backend->attach_kernel_driver) + return usbi_backend->attach_kernel_driver(dev, interface); + else + return LIBUSB_ERROR_NOT_SUPPORTED; +} + /** \ingroup lib * Set message verbosity. * - Level 0: no messages ever printed by the library (default) diff --git a/libusb/libusb.h b/libusb/libusb.h index fedd624..db022c2 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -792,6 +792,7 @@ int libusb_reset_device(libusb_device_handle *dev); int libusb_kernel_driver_active(libusb_device_handle *dev, int interface); int libusb_detach_kernel_driver(libusb_device_handle *dev, int interface); +int libusb_attach_kernel_driver(libusb_device_handle *dev, int interface); /* async I/O */ diff --git a/libusb/libusbi.h b/libusb/libusbi.h index ec79a20..43dd109 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -640,6 +640,23 @@ struct usbi_os_backend { int (*detach_kernel_driver)(struct libusb_device_handle *handle, int interface); + /* Attach a kernel driver to an interface. Optional. + * + * Reattach a kernel driver to the device. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active + * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface, + * preventing reattachment + * - another LIBUSB_ERROR code on other failure + */ + int (*attach_kernel_driver)(struct libusb_device_handle *handle, + int interface); + /* Destroy a device. Optional. * * This function is called when the last reference to a device is diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index d690511..e2c4234 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -1190,6 +1190,38 @@ static int op_detach_kernel_driver(struct libusb_device_handle *handle, return 0; } +static int op_attach_kernel_driver(struct libusb_device_handle *handle, + int interface) +{ + int fd = __device_handle_priv(handle)->fd; + struct usbfs_ioctl command; + int r; + + command.ifno = interface; + command.ioctl_code = IOCTL_USBFS_CONNECT; + command.data = NULL; + + r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); + if (r < 0) { + if (errno == ENODATA) + return LIBUSB_ERROR_NOT_FOUND; + else if (errno == EINVAL) + return LIBUSB_ERROR_INVALID_PARAM; + else if (errno == ENODEV) + return LIBUSB_ERROR_NO_DEVICE; + else if (errno == EBUSY) + return LIBUSB_ERROR_BUSY; + + usbi_err(HANDLE_CTX(handle), + "attach failed error %d errno %d", r, errno); + return LIBUSB_ERROR_OTHER; + } else if (r == 0) { + return LIBUSB_ERROR_NOT_FOUND; + } + + return 0; +} + static void op_destroy_device(struct libusb_device *dev) { struct linux_device_priv *priv = __device_priv(dev); @@ -2023,6 +2055,7 @@ const struct usbi_os_backend linux_usbfs_backend = { .kernel_driver_active = op_kernel_driver_active, .detach_kernel_driver = op_detach_kernel_driver, + .attach_kernel_driver = op_attach_kernel_driver, .destroy_device = op_destroy_device, |