Core: Add HID and kernel detach capability detection for all backends
authorPete Batard <pete@akeo.ie>
Sun, 17 Mar 2013 22:13:53 +0000 (22:13 +0000)
committerPete Batard <pete@akeo.ie>
Tue, 2 Apr 2013 18:13:47 +0000 (19:13 +0100)
* Also remove Linux special case from xusb sample.
* Note that LIBUSBX_API_VERSION is incremented as a result of
  libusb_has_capability() returning nonzero rather than 1 when
  a capability is supported.
* A LIBUSB_CAP_HAS_HOTPLUG is also added, though it is currently
  not implemented on any platform
* Closes #102

examples/xusb.c
libusb/core.c
libusb/libusb.h
libusb/libusbi.h
libusb/os/darwin_usb.c
libusb/os/linux_usbfs.c
libusb/os/openbsd_usb.c
libusb/os/wince_usb.c
libusb/os/windows_usb.c
libusb/version_nano.h

index 463cc2f..856f723 100644 (file)
@@ -735,10 +735,8 @@ static int test_device(uint16_t vid, uint16_t pid)
        const struct libusb_endpoint_descriptor *endpoint;
        int i, j, k, r;
        int iface, nb_ifaces, first_iface = -1;
-#if defined(__linux__)
-       // Attaching/detaching the kernel driver is only relevant for Linux
+       // For attaching/detaching the kernel driver, if needed
        int iface_detached = -1;
-#endif
        struct libusb_device_descriptor dev_desc;
        const char* speed_name[5] = { "Unknown", "1.5 Mbit/s (USB LowSpeed)", "12 Mbit/s (USB FullSpeed)",
                "480 Mbit/s (USB HighSpeed)", "5000 Mbit/s (USB SuperSpeed)"};
@@ -833,16 +831,17 @@ static int test_device(uint16_t vid, uint16_t pid)
        {
                printf("\nClaiming interface %d...\n", iface);
                r = libusb_claim_interface(handle, iface);
-#if defined(__linux__)
-               if ((r != LIBUSB_SUCCESS) && (iface == 0)) {
-                       // Maybe we need to detach the driver
-                       perr("   Failed. Trying to detach driver...\n");
-                       libusb_detach_kernel_driver(handle, iface);
-                       iface_detached = iface;
-                       printf("   Claiming interface again...\n");
-                       r = libusb_claim_interface(handle, iface);
+               if ((r != LIBUSB_SUCCESS) && libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)
+                       && (libusb_kernel_driver_active(handle, iface) > 0)) {
+                       // Try to detach the kernel driver
+                       perr("   A kernel driver is active, trying to detach it...\n");
+                       r = libusb_detach_kernel_driver(handle, iface);
+                       if (r == LIBUSB_SUCCESS) {
+                               iface_detached = iface;
+                               printf("   Claiming interface again...\n");
+                               r = libusb_claim_interface(handle, iface);
+                       }
                }
-#endif
                if (r != LIBUSB_SUCCESS) {
                        perr("   Failed.\n");
                }
@@ -891,12 +890,10 @@ static int test_device(uint16_t vid, uint16_t pid)
                libusb_release_interface(handle, iface);
        }
 
-#if defined(__linux__)
        if (iface_detached >= 0) {
                printf("Re-attaching kernel driver...\n");
                libusb_attach_kernel_driver(handle, iface_detached);
        }
-#endif
 
        printf("Closing device...\n");
        libusb_close(handle);
index b3df73a..e2da1ea 100644 (file)
@@ -1740,15 +1740,21 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx)
 
 /** \ingroup misc
  * Check at runtime if the loaded library has a given capability.
+ * This call should be performed after \ref libusb_init(), to ensure the
+ * backend has updated its capability set.
  *
  * \param capability the \ref libusb_capability to check for
- * \returns 1 if the running library has the capability, 0 otherwise
+ * \returns nonzero if the running library has the capability, 0 otherwise
  */
 int API_EXPORTED libusb_has_capability(uint32_t capability)
 {
        switch (capability) {
        case LIBUSB_CAP_HAS_CAPABILITY:
                return 1;
+       case LIBUSB_CAP_HAS_HID_ACCESS:
+               return (usbi_backend->caps && USBI_CAP_HAS_HID_ACCESS);
+       case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER:
+               return (usbi_backend->caps && USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
        }
        return 0;
 }
index d7e84c0..3613864 100644 (file)
@@ -136,7 +136,7 @@ typedef unsigned __int32  uint32_t;
  * Internally, LIBUSBX_API_VERSION is defined as follows:
  * (libusbx major << 24) | (libusbx minor << 16) | (16 bit incremental)
  */
-#define LIBUSBX_API_VERSION 0x010000FF
+#define LIBUSBX_API_VERSION 0x01000101
 
 #ifdef __cplusplus
 extern "C" {
@@ -994,7 +994,17 @@ struct libusb_transfer {
  */
 enum libusb_capability {
        /** The libusb_has_capability() API is available. */
-       LIBUSB_CAP_HAS_CAPABILITY = 0,
+       LIBUSB_CAP_HAS_CAPABILITY = 0x0000,
+       /** Hotplug support is available. */
+       LIBUSB_CAP_HAS_HOTPLUG = 0x0001,
+       /** The library can access HID devices without requiring user intervention.
+        * Note that before being able to actually access an HID device, you may
+        * still have to call additional libusbx functions such as
+        * \ref libusb_detach_kernel_driver(). */
+       LIBUSB_CAP_HAS_HID_ACCESS = 0x0100,
+       /** The library supports detaching of the default USB driver, using 
+        * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */
+       LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101
 };
 
 /** \ingroup lib
index eed549e..ed95d43 100644 (file)
 #define USB_MAXINTERFACES      32
 #define USB_MAXCONFIG          8
 
+/* Backend specific capabilities */
+#define USBI_CAP_HAS_HID_ACCESS                                        0x00010000
+#define USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER 0x00020000
+
 /* The following is used to silence warnings for unused variables */
-#define UNUSED(var)                    (void)(var)
+#define UNUSED(var)                    do { (void)(var); } while(0)
 
 struct list_head {
        struct list_head *prev, *next;
@@ -446,6 +450,9 @@ struct usbi_os_backend {
        /* A human-readable name for your backend, e.g. "Linux usbfs" */
        const char *name;
 
+       /* Binary mask for backend specific capabilities */
+       uint32_t caps;
+
        /* Perform initialization of your backend. You might use this function
         * to determine specific capabilities of the system, allocate required
         * data structures for later, etc.
index 08bd7f0..30ee3ff 100644 (file)
@@ -1782,6 +1782,7 @@ static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
 
 const struct usbi_os_backend darwin_backend = {
         .name = "Darwin",
+        .caps = 0,
         .init = darwin_init,
         .exit = darwin_exit,
         .get_device_list = darwin_get_device_list,
index 99bbd07..95e5339 100644 (file)
@@ -2527,6 +2527,7 @@ static clockid_t op_get_timerfd_clockid(void)
 
 const struct usbi_os_backend linux_usbfs_backend = {
        .name = "Linux usbfs",
+       .caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
        .init = op_init,
        .exit = NULL,
        .get_device_list = op_get_device_list,
index 88e2c7a..353385b 100644 (file)
@@ -89,6 +89,7 @@ static int _access_endpoint(struct libusb_transfer *);
 
 const struct usbi_os_backend openbsd_backend = {
        "Synchronous OpenBSD backend",
+       0,
        NULL,                           /* init() */
        NULL,                           /* exit() */
        obsd_get_device_list,
index 354c0e6..e4f7c7b 100644 (file)
@@ -973,6 +973,7 @@ static int wince_clock_gettime(int clk_id, struct timespec *tp)
 
 const struct usbi_os_backend wince_backend = {
         "Windows CE",
+        0,
         wince_init,
         wince_exit,
 
index 1eb81b4..7c2428d 100644 (file)
@@ -2262,6 +2262,7 @@ static int windows_clock_gettime(int clk_id, struct timespec *tp)
 // NB: MSVC6 does not support named initializers.
 const struct usbi_os_backend windows_backend = {
        "Windows",
+       USBI_CAP_HAS_HID_ACCESS,
        windows_init,
        windows_exit,
 
index 5a977a3..26d7735 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 10633
+#define LIBUSB_NANO 10634