summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libusb/core.c50
-rw-r--r--libusb/libusb-1.0.def2
-rw-r--r--libusb/libusb.h2
-rw-r--r--libusb/libusbi.h1
-rw-r--r--libusb/os/linux_usbfs.c42
-rw-r--r--libusb/version_nano.h2
6 files changed, 93 insertions, 6 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 1c3748d..c902747 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -1361,7 +1361,14 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev,
* endpoint halts cleared, toggles reset).
*
* You cannot change/reset configuration if your application has claimed
- * interfaces - you should free them with libusb_release_interface() first.
+ * interfaces. It is advised to set the desired configuration before claiming
+ * interfaces.
+ *
+ * Alternatively you can call libusb_release_interface() first. Note if you
+ * do things this way you must ensure that auto_detach_kernel_driver for
+ * <tt>dev</tt> is 0, otherwise the kernel driver will be re-attached when you
+ * release the interface(s).
+ *
* You cannot change/reset configuration if other applications or drivers have
* claimed interfaces.
*
@@ -1383,6 +1390,7 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev,
* \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_set_auto_detach_kernel_driver()
*/
int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev,
int configuration)
@@ -1398,6 +1406,9 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev,
* It is legal to attempt to claim an already-claimed interface, in which
* case libusbx just returns 0 without doing anything.
*
+ * If auto_detach_kernel_driver is set to 1 for <tt>dev</tt>, the kernel driver
+ * will be detached if necessary, on failure the detach error is returned.
+ *
* Claiming of interfaces is a purely logical operation; it does not cause
* any requests to be sent over the bus. Interface claiming is used to
* instruct the underlying operating system that your application wishes
@@ -1414,6 +1425,7 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev,
* interface
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns a LIBUSB_ERROR code on other failure
+ * \see libusb_set_auto_detach_kernel_driver()
*/
int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev,
int interface_number)
@@ -1447,6 +1459,9 @@ out:
* This is a blocking function. A SET_INTERFACE control request will be sent
* to the device, resetting interface state to the first alternate setting.
*
+ * If auto_detach_kernel_driver is set to 1 for <tt>dev</tt>, the kernel
+ * driver will be re-attached after releasing the interface.
+ *
* \param dev a device handle
* \param interface_number the <tt>bInterfaceNumber</tt> of the
* previously-claimed interface
@@ -1454,6 +1469,7 @@ out:
* \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_set_auto_detach_kernel_driver()
*/
int API_EXPORTED libusb_release_interface(libusb_device_handle *dev,
int interface_number)
@@ -1678,6 +1694,38 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev,
return LIBUSB_ERROR_NOT_SUPPORTED;
}
+/** \ingroup dev
+ * Enable/disable libusbx's automatic kernel driver detachment. When this is
+ * enabled libusbx will automatically detach the kernel driver on an interface
+ * when claiming the interface, and attach it when releasing the interface.
+ *
+ * Automatic kernel driver detachment is disabled on newly opened device
+ * handles by default.
+ *
+ * On platforms which do not have LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER
+ * this function will return LIBUSB_ERROR_NOT_SUPPORTED, and libusbx will
+ * continue as if this function was never called.
+ *
+ * \param dev a device handle
+ * \param enable whether to enable or disable auto kernel driver detachment
+ *
+ * \returns LIBUSB_SUCCESS on success
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
+ * is not available
+ * \see libusb_claim_interface()
+ * \see libusb_release_interface()
+ * \see libusb_set_configuration()
+ */
+int API_EXPORTED libusb_set_auto_detach_kernel_driver(
+ libusb_device_handle *dev, int enable)
+{
+ if (!(usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+
+ dev->auto_detach_kernel_driver = enable;
+ return LIBUSB_SUCCESS;
+}
+
/** \ingroup lib
* Set log message verbosity.
*
diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def
index e6c46fd..cb0e32a 100644
--- a/libusb/libusb-1.0.def
+++ b/libusb/libusb-1.0.def
@@ -130,6 +130,8 @@ EXPORTS
libusb_release_interface@8 = libusb_release_interface
libusb_reset_device
libusb_reset_device@4 = libusb_reset_device
+ libusb_set_auto_detach_kernel_driver
+ libusb_set_auto_detach_kernel_driver@8 = libusb_set_auto_detach_kernel_driver
libusb_set_configuration
libusb_set_configuration@8 = libusb_set_configuration
libusb_set_debug
diff --git a/libusb/libusb.h b/libusb/libusb.h
index a56a687..d7cc40f 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -1390,6 +1390,8 @@ int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev,
int interface_number);
int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev,
int interface_number);
+int LIBUSB_CALL libusb_set_auto_detach_kernel_driver(
+ libusb_device_handle *dev, int enable);
/* async I/O */
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index d5e5c59..c9b402d 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -317,6 +317,7 @@ struct libusb_device_handle {
struct list_head list;
struct libusb_device *dev;
+ int auto_detach_kernel_driver;
unsigned char os_priv
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index a27ed44..e4ff79d 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1317,7 +1317,7 @@ static int op_set_configuration(struct libusb_device_handle *handle, int config)
return LIBUSB_SUCCESS;
}
-static int op_claim_interface(struct libusb_device_handle *handle, int iface)
+static int claim_interface(struct libusb_device_handle *handle, int iface)
{
int fd = _device_handle_priv(handle)->fd;
int r = ioctl(fd, IOCTL_USBFS_CLAIMINTF, &iface);
@@ -1336,7 +1336,7 @@ static int op_claim_interface(struct libusb_device_handle *handle, int iface)
return 0;
}
-static int op_release_interface(struct libusb_device_handle *handle, int iface)
+static int release_interface(struct libusb_device_handle *handle, int iface)
{
int fd = _device_handle_priv(handle)->fd;
int r = ioctl(fd, IOCTL_USBFS_RELEASEINTF, &iface);
@@ -1407,7 +1407,7 @@ static int op_reset_device(struct libusb_device_handle *handle)
getting bound to the in kernel driver if any). */
for (i = 0; i < USB_MAXINTERFACES; i++) {
if (handle->claimed_interfaces & (1L << i)) {
- op_release_interface(handle, i);
+ release_interface(handle, i);
}
}
@@ -1428,7 +1428,7 @@ static int op_reset_device(struct libusb_device_handle *handle)
/* And re-claim any interfaces which were claimed before the reset */
for (i = 0; i < USB_MAXINTERFACES; i++) {
if (handle->claimed_interfaces & (1L << i)) {
- r = op_claim_interface(handle, i);
+ r = claim_interface(handle, i);
if (r) {
usbi_warn(HANDLE_CTX(handle),
"failed to re-claim interface %d after reset", i);
@@ -1530,6 +1530,40 @@ static int op_attach_kernel_driver(struct libusb_device_handle *handle,
return 0;
}
+static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle,
+ int interface)
+{
+ int r;
+
+ r = op_detach_kernel_driver(handle, interface);
+ if (r != 0 && r != LIBUSB_ERROR_NOT_FOUND)
+ return r;
+
+ return claim_interface(handle, interface);
+}
+
+static int op_claim_interface(struct libusb_device_handle *handle, int iface)
+{
+ if (handle->auto_detach_kernel_driver)
+ return detach_kernel_driver_and_claim(handle, iface);
+ else
+ return claim_interface(handle, iface);
+}
+
+static int op_release_interface(struct libusb_device_handle *handle, int iface)
+{
+ int r;
+
+ r = release_interface(handle, iface);
+ if (r)
+ return r;
+
+ if (handle->auto_detach_kernel_driver)
+ op_attach_kernel_driver(handle, iface);
+
+ return 0;
+}
+
static void op_destroy_device(struct libusb_device *dev)
{
struct linux_device_priv *priv = _device_priv(dev);
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 5a98334..60306bf 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10741
+#define LIBUSB_NANO 10742