Add support for re-attaching a driver to a device under Linux.
[dsd: fixed handling of return value, and added LIBUSB_ERROR_BUSY case]
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)
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 */
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
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);
.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,