* 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.
*
* \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)
* 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
* 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)
* 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
* \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)
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.
*
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);
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);
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);
}
}
/* 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);
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);