Add libusb_attach_kernel_driver()
authorBastien Nocera <hadess@hadess.net>
Thu, 30 Oct 2008 14:35:23 +0000 (14:35 +0000)
committerDaniel Drake <dsd@gentoo.org>
Mon, 3 Nov 2008 23:14:42 +0000 (23:14 +0000)
Add support for re-attaching a driver to a device under Linux.

[dsd: fixed handling of return value, and added LIBUSB_ERROR_BUSY case]

libusb/core.c
libusb/libusb.h
libusb/libusbi.h
libusb/os/linux_usbfs.c

index 4fffc84..baf9afb 100644 (file)
@@ -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)
index fedd624..db022c2 100644 (file)
@@ -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 */
 
index ec79a20..43dd109 100644 (file)
@@ -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
index d690511..e2c4234 100644 (file)
@@ -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,