summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2008-10-30 14:35:23 +0000
committerDaniel Drake <dsd@gentoo.org>2008-11-03 23:14:42 +0000
commit1d7cf3d0fa8698eae25097cbda1870be90ff6f5e (patch)
treed5fe8abbaa6f3c00c52e6e1609ef360e219808d2
parent914a4e70657c86b5094770aa2d898c978b1cdf41 (diff)
downloadlibusb-1d7cf3d0fa8698eae25097cbda1870be90ff6f5e.tar.gz
Add libusb_attach_kernel_driver()
Add support for re-attaching a driver to a device under Linux. [dsd: fixed handling of return value, and added LIBUSB_ERROR_BUSY case]
-rw-r--r--libusb/core.c25
-rw-r--r--libusb/libusb.h1
-rw-r--r--libusb/libusbi.h17
-rw-r--r--libusb/os/linux_usbfs.c33
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,