return usbi_backend->reset_device(dev);
}
+/** \ingroup dev
+ * Determine if a kernel driver is active on an interface. If a kernel driver
+ * is active, you cannot claim the interface, and libusb will be unable to
+ * perform I/O.
+ *
+ * \param dev a device handle
+ * \param interface the interface to check
+ * \returns 0 if no kernel driver is active
+ * \returns 1 if a kernel driver is active
+ * \returns LIBUSB_ERROR code on failure
+ * \see libusb_detach_kernel_driver
+ */
+API_EXPORTED int libusb_kernel_driver_active(libusb_device_handle *dev,
+ int interface)
+{
+ usbi_dbg("interface %d", interface);
+ if (usbi_backend->kernel_driver_active)
+ return usbi_backend->kernel_driver_active(dev, interface);
+ else
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup dev
+ * Detach a kernel driver from an interface. If successful, you will then be
+ * able to claim the interface and perform I/O.
+ *
+ * \param dev a device handle
+ * \param interface the interface to detach 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 another LIBUSB_ERROR code on other failure
+ * \see libusb_kernel_driver_active
+ */
+API_EXPORTED int libusb_detach_kernel_driver(libusb_device_handle *dev,
+ int interface)
+{
+ usbi_dbg("interface %d", interface);
+ if (usbi_backend->detach_kernel_driver)
+ return usbi_backend->detach_kernel_driver(dev, interface);
+ else
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
/** \ingroup lib
* Initialize libusb. This function must be called before calling any other
* libusb function.
LIBUSB_ERROR_BUSY = -5,
LIBUSB_ERROR_TIMEOUT = -6,
LIBUSB_ERROR_NO_MEM = -7,
- LIBUSB_ERROR_OTHER = -8,
+ LIBUSB_ERROR_NOT_SUPPORTED = -8,
+ LIBUSB_ERROR_OTHER = -9,
};
/** \ingroup asyncio
int libusb_clear_halt(libusb_device_handle *dev, unsigned char endpoint);
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);
+
/* async I/O */
/** \ingroup asyncio
unsigned char endpoint);
int (*reset_device)(struct libusb_device_handle *handle);
+ /* optional */
+ int (*kernel_driver_active)(struct libusb_device_handle *handle,
+ int interface);
+ int (*detach_kernel_driver)(struct libusb_device_handle *handle,
+ int interface);
+
void (*destroy_device)(struct libusb_device *dev);
int (*submit_transfer)(struct usbi_transfer *itransfer);
return 0;
}
+static int op_kernel_driver_active(struct libusb_device_handle *handle,
+ int interface)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ struct usbfs_getdriver getdrv;
+ int r;
+
+ getdrv.interface = interface;
+ r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv);
+ if (r) {
+ if (errno == ENODATA)
+ return 0;
+
+ usbi_err("get driver failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return 1;
+}
+
+static int op_detach_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_DISCONNECT;
+ command.data = NULL;
+
+ r = ioctl(fd, IOCTL_USBFS_IOCTL, &command);
+ if (r) {
+ if (errno == ENODATA)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else if (errno == EINVAL)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ usbi_err("detach failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return 0;
+}
+
static void op_destroy_device(struct libusb_device *dev)
{
unsigned char *nodepath = __device_priv(dev)->nodepath;
.clear_halt = op_clear_halt,
.reset_device = op_reset_device,
+ .kernel_driver_active = op_kernel_driver_active,
+ .detach_kernel_driver = op_detach_kernel_driver,
+
.destroy_device = op_destroy_device,
.submit_transfer = op_submit_transfer,