v2 of the infamous HID capabilities patch, now with kernel detach
detection bonus!
I also carried over the libusb HP cap, in the unlikely event they
release anytime soon and users want to switch.
Unless there are any objections, I will be pushing that patch tomorrow.
Regards,
/Pete
>From 92dda3d8af2826e16699f088a03a9626ddcd8939 Mon Sep 17 00:00:00 2001
From: Pete Batard <p...@akeo.ie>
Date: Sun, 17 Mar 2013 22:13:53 +0000
Subject: [PATCH] Core: Add HID and kernel detach capability detection for all
backends
* 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
---
examples/xusb.c | 25 +++++++++++--------------
libusb/core.c | 8 +++++++-
libusb/libusb.h | 14 ++++++++++++--
libusb/libusbi.h | 9 ++++++++-
libusb/os/darwin_usb.c | 1 +
libusb/os/linux_usbfs.c | 1 +
libusb/os/openbsd_usb.c | 1 +
libusb/os/wince_usb.c | 1 +
libusb/os/windows_usb.c | 1 +
9 files changed, 44 insertions(+), 19 deletions(-)
diff --git a/examples/xusb.c b/examples/xusb.c
index 463cc2f..856f723 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -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);
diff --git a/libusb/core.c b/libusb/core.c
index b3df73a..e2da1ea 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -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;
}
diff --git a/libusb/libusb.h b/libusb/libusb.h
index d7e84c0..3613864 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -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
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index eed549e..ed95d43 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -52,8 +52,12 @@
#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.
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index 08bd7f0..30ee3ff 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -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,
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 99bbd07..95e5339 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -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,
diff --git a/libusb/os/openbsd_usb.c b/libusb/os/openbsd_usb.c
index 88e2c7a..353385b 100644
--- a/libusb/os/openbsd_usb.c
+++ b/libusb/os/openbsd_usb.c
@@ -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,
diff --git a/libusb/os/wince_usb.c b/libusb/os/wince_usb.c
index 354c0e6..e4f7c7b 100644
--- a/libusb/os/wince_usb.c
+++ b/libusb/os/wince_usb.c
@@ -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,
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index d8156b8..f59f92d 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -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,
--
1.8.0.msysgit.0
------------------------------------------------------------------------------
Own the Future-Intel® Level Up Game Demo Contest 2013
Rise to greatness in Intel's independent game demo contest.
Compete for recognition, cash, and the chance to get your game
on Steam. $5K grand prize plus 10 genre and skill prizes.
Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel