summaryrefslogtreecommitdiff
path: root/gr-fcd/lib
diff options
context:
space:
mode:
authordl1ksv <dl1ksv@gmx.de>2013-07-15 22:05:01 +0200
committerJohnathan Corgan <johnathan@corganlabs.com>2013-07-17 15:46:38 -0700
commitc0e969a3fb644c4919b8fe621c2ff9f7d2329fe3 (patch)
tree3982a4389214894dff685d06e0e71f500138f6df /gr-fcd/lib
parent212e41e8500348e984dd15082c3727c12d19f20f (diff)
Applying hidapi patch from Hans de Goede
Diffstat (limited to 'gr-fcd/lib')
-rw-r--r--gr-fcd/lib/hid/hid-libusb.c193
1 files changed, 117 insertions, 76 deletions
diff --git a/gr-fcd/lib/hid/hid-libusb.c b/gr-fcd/lib/hid/hid-libusb.c
index 82cbc91512..097f87215d 100644
--- a/gr-fcd/lib/hid/hid-libusb.c
+++ b/gr-fcd/lib/hid/hid-libusb.c
@@ -8,6 +8,7 @@
8/22/2009
Linux Version - 6/2/2010
Libusb Version - 8/13/2010
+ FreeBSD Version - 11/1/2011
Copyright 2009, All Rights Reserved.
@@ -22,7 +23,7 @@
http://github.com/signal11/hidapi .
********************************************************/
-#define _GNU_SOURCE // needed for wcsdup() before glibc 2.10
+#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
/* C */
#include <stdio.h>
@@ -58,11 +59,15 @@ extern "C" {
#define LOG(...) do {} while (0)
#endif
+#ifndef __FreeBSD__
+#define DETACH_KERNEL_DRIVER
+#endif
/* Uncomment to enable the retrieval of Usage and Usage Page in
-hid_enumerate(). Warning, this is very invasive as it requires the detach
+hid_enumerate(). Warning, on platforms different from FreeBSD
+this is very invasive as it requires the detach
and re-attach of the kernel driver. See comments inside hid_enumerate().
-Linux/libusb HIDAPI programs are encouraged to use the interface number
+libusb HIDAPI programs are encouraged to use the interface number
instead to differentiate between interfaces on a composite HID device. */
/*#define INVASIVE_GET_USAGE*/
@@ -100,13 +105,14 @@ struct hid_device_ {
pthread_cond_t condition;
pthread_barrier_t barrier; /* Ensures correct startup sequence */
int shutdown_thread;
+ int cancelled;
struct libusb_transfer *transfer;
/* List of received input reports. */
struct input_report *input_reports;
};
-static int initialized = 0;
+static libusb_context *usb_context = NULL;
uint16_t get_usb_code_for_current_locale(void);
static int return_data(hid_device *dev, unsigned char *data, size_t length);
@@ -114,18 +120,7 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length);
static hid_device *new_hid_device(void)
{
hid_device *dev = calloc(1, sizeof(hid_device));
- dev->device_handle = NULL;
- dev->input_endpoint = 0;
- dev->output_endpoint = 0;
- dev->input_ep_max_packet_size = 0;
- dev->interface = 0;
- dev->manufacturer_index = 0;
- dev->product_index = 0;
- dev->serial_index = 0;
dev->blocking = 1;
- dev->shutdown_thread = 0;
- dev->transfer = NULL;
- dev->input_reports = NULL;
pthread_mutex_init(&dev->mutex, NULL);
pthread_cond_init(&dev->condition, NULL);
@@ -146,7 +141,7 @@ static void free_hid_device(hid_device *dev)
}
#if 0
-//TODO: Implement this funciton on Linux.
+/*TODO: Implement this funciton on hidapi/libusb.. */
static void register_error(hid_device *device, const char *op)
{
@@ -187,7 +182,7 @@ static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur
static int get_usage(uint8_t *report_descriptor, size_t size,
unsigned short *usage_page, unsigned short *usage)
{
- int i = 0;
+ unsigned int i = 0;
int size_code;
int data_len, key_size;
int usage_found = 0, usage_page_found = 0;
@@ -253,7 +248,28 @@ static int get_usage(uint8_t *report_descriptor, size_t size,
return -1; /* failure */
}
-#endif // INVASIVE_GET_USAGE
+#endif /* INVASIVE_GET_USAGE */
+
+#ifdef __FreeBSD__
+/* The FreeBSD version of libusb doesn't have this funciton. In mainline
+ libusb, it's inlined in libusb.h. This function will bear a striking
+ resemblence to that one, because there's about one way to code it.
+
+ Note that the data parameter is Unicode in UTF-16LE encoding.
+ Return value is the number of bytes in data, or LIBUSB_ERROR_*.
+ */
+static inline int libusb_get_string_descriptor(libusb_device_handle *dev,
+ uint8_t descriptor_index, uint16_t lang_id,
+ unsigned char *data, int length)
+{
+ return libusb_control_transfer(dev,
+ LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */
+ LIBUSB_REQUEST_GET_DESCRIPTOR,
+ (LIBUSB_DT_STRING << 8) | descriptor_index,
+ lang_id, data, (uint16_t) length, 1000);
+}
+
+#endif
/* Get the first language the device says it reports. This comes from
@@ -272,7 +288,7 @@ static uint16_t get_first_language(libusb_device_handle *dev)
if (len < 4)
return 0x0;
- return buf[1]; // First two bytes are len and descriptor type.
+ return buf[1]; /* First two bytes are len and descriptor type. */
}
static int is_language_supported(libusb_device_handle *dev, uint16_t lang)
@@ -308,7 +324,7 @@ static int is_language_supported(libusb_device_handle *dev, uint16_t lang)
static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
{
char buf[512];
- unsigned int len;
+ int len;
wchar_t *str = NULL;
wchar_t wbuf[256];
@@ -317,7 +333,11 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
size_t inbytes;
size_t outbytes;
size_t res;
+#ifdef __FreeBSD__
+ const char *inptr;
+#else
char *inptr;
+#endif
char *outptr;
/* Determine which language to use. */
@@ -335,25 +355,27 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
if (len < 0)
return NULL;
- buf[sizeof(buf)-1] = '\0';
-
- if (len+1 < sizeof(buf))
- buf[len+1] = '\0';
+ /* buf does not need to be explicitly NULL-terminated because
+ it is only passed into iconv() which does not need it. */
/* Initialize iconv. */
- ic = iconv_open("UTF-32", "UTF-16");
- if (ic == (iconv_t)-1)
+ ic = iconv_open("WCHAR_T", "UTF-16LE");
+ if (ic == (iconv_t)-1) {
+ LOG("iconv_open() failed\n");
return NULL;
+ }
- /* Convert to UTF-32 (wchar_t on glibc systems).
+ /* Convert to native wchar_t (UTF-32 on glibc/BSD systems).
Skip the first character (2-bytes). */
inptr = buf+2;
inbytes = len-2;
outptr = (char*) wbuf;
outbytes = sizeof(wbuf);
res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
- if (res == (size_t)-1)
+ if (res == (size_t)-1) {
+ LOG("iconv() failed\n");
goto err;
+ }
/* Write the terminating NULL. */
wbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000;
@@ -361,7 +383,7 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
*((wchar_t*)outptr) = 0x00000000;
/* Allocate and copy the string. */
- str = wcsdup(wbuf+1);
+ str = wcsdup(wbuf);
err:
iconv_close(ic);
@@ -384,10 +406,17 @@ static char *make_path(libusb_device *dev, int interface_number)
int HID_API_EXPORT hid_init(void)
{
- if (!initialized) {
- if (libusb_init(NULL))
+ if (!usb_context) {
+ const char *locale;
+
+ /* Init Libusb */
+ if (libusb_init(&usb_context))
return -1;
- initialized = 1;
+
+ /* Set the locale if it's not set. */
+ locale = setlocale(LC_CTYPE, NULL);
+ if (!locale)
+ setlocale(LC_CTYPE, "");
}
return 0;
@@ -395,9 +424,9 @@ int HID_API_EXPORT hid_init(void)
int HID_API_EXPORT hid_exit(void)
{
- if (initialized) {
- libusb_exit(NULL);
- initialized = 0;
+ if (usb_context) {
+ libusb_exit(usb_context);
+ usb_context = NULL;
}
return 0;
@@ -411,15 +440,13 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
ssize_t num_devs;
int i = 0;
- struct hid_device_info *root = NULL; // return object
+ struct hid_device_info *root = NULL; /* return object */
struct hid_device_info *cur_dev = NULL;
- setlocale(LC_ALL,"");
-
- if (!initialized)
- hid_init();
+ if(hid_init() < 0)
+ return NULL;
- num_devs = libusb_get_device_list(NULL, &devs);
+ num_devs = libusb_get_device_list(usb_context, &devs);
if (num_devs < 0)
return NULL;
while ((dev = devs[i++]) != NULL) {
@@ -432,10 +459,6 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
unsigned short dev_vid = desc.idVendor;
unsigned short dev_pid = desc.idProduct;
- /* HID's are defined at the interface level. */
- if (desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE)
- continue;
-
res = libusb_get_active_config_descriptor(dev, &conf_desc);
if (res < 0)
libusb_get_config_descriptor(dev, 0, &conf_desc);
@@ -449,8 +472,8 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
interface_num = intf_desc->bInterfaceNumber;
/* Check the VID/PID against the arguments */
- if ((vendor_id == 0x0 && product_id == 0x0) ||
- (vendor_id == dev_vid && product_id == dev_pid)) {
+ if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
+ (product_id == 0x0 || product_id == dev_pid)) {
struct hid_device_info *tmp;
/* VID/PID match. Create the record. */
@@ -484,6 +507,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
get_usb_string(handle, desc.iProduct);
#ifdef INVASIVE_GET_USAGE
+{
/*
This section is removed because it is too
invasive on the system. Getting a Usage Page
@@ -499,9 +523,9 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
#if 0. For composite devices, use the interface
field in the hid_device_info struct to distinguish
between interfaces. */
- int detached = 0;
unsigned char data[256];
-
+#ifdef DETACH_KERNEL_DRIVER
+ int detached = 0;
/* Usage Page and Usage */
res = libusb_kernel_driver_active(handle, interface_num);
if (res == 1) {
@@ -511,6 +535,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
else
detached = 1;
}
+#endif
res = libusb_claim_interface(handle, interface_num);
if (res >= 0) {
/* Get the HID Report Descriptor. */
@@ -533,14 +558,16 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
}
else
LOG("Can't claim interface %d\n", res);
-
+#ifdef DETACH_KERNEL_DRIVER
/* Re-attach kernel driver if necessary. */
if (detached) {
res = libusb_attach_kernel_driver(handle, interface_num);
if (res < 0)
LOG("Couldn't re-attach kernel driver.\n");
}
-#endif /*******************/
+#endif
+}
+#endif /* INVASIVE_GET_USAGE */
libusb_close(handle);
}
@@ -618,6 +645,7 @@ hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, wchar
static void read_callback(struct libusb_transfer *transfer)
{
hid_device *dev = transfer->user_data;
+ int res;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
@@ -656,10 +684,12 @@ static void read_callback(struct libusb_transfer *transfer)
}
else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
dev->shutdown_thread = 1;
+ dev->cancelled = 1;
return;
}
else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
dev->shutdown_thread = 1;
+ dev->cancelled = 1;
return;
}
else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
@@ -670,7 +700,12 @@ static void read_callback(struct libusb_transfer *transfer)
}
/* Re-submit the transfer object. */
- libusb_submit_transfer(transfer);
+ res = libusb_submit_transfer(transfer);
+ if (res != 0) {
+ LOG("Unable to submit URB. libusb error code: %d\n", res);
+ dev->shutdown_thread = 1;
+ dev->cancelled = 1;
+ }
}
@@ -696,25 +731,33 @@ static void *read_thread(void *param)
from inside read_callback() */
libusb_submit_transfer(dev->transfer);
- // Notify the main thread that the read thread is up and running.
+ /* Notify the main thread that the read thread is up and running. */
pthread_barrier_wait(&dev->barrier);
/* Handle all the events. */
while (!dev->shutdown_thread) {
int res;
- res = libusb_handle_events(NULL);
+ res = libusb_handle_events(usb_context);
if (res < 0) {
- /* There was an error. Break out of this loop. */
- break;
+ /* There was an error. */
+ LOG("read_thread(): libusb reports error # %d\n", res);
+
+ /* Break out of this loop only on fatal error.*/
+ if (res != LIBUSB_ERROR_BUSY &&
+ res != LIBUSB_ERROR_TIMEOUT &&
+ res != LIBUSB_ERROR_OVERFLOW &&
+ res != LIBUSB_ERROR_INTERRUPTED) {
+ break;
+ }
}
}
/* Cancel any transfer that may be pending. This call will fail
if no transfers are pending, but that's OK. */
- if (libusb_cancel_transfer(dev->transfer) == 0) {
- /* The transfer was cancelled, so wait for its completion. */
- libusb_handle_events(NULL);
- }
+ libusb_cancel_transfer(dev->transfer);
+
+ while (!dev->cancelled)
+ libusb_handle_events_completed(usb_context, &dev->cancelled);
/* Now that the read thread is stopping, Wake any threads which are
waiting on data (in hid_read_timeout()). Do this under a mutex to
@@ -741,21 +784,18 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
{
hid_device *dev = NULL;
- dev = new_hid_device();
-
libusb_device **devs;
libusb_device *usb_dev;
- ssize_t num_devs;
int res;
int d = 0;
int good_open = 0;
- setlocale(LC_ALL,"");
+ dev = new_hid_device();
- if (!initialized)
- hid_init();
+ if(hid_init() < 0)
+ return NULL;
- num_devs = libusb_get_device_list(NULL, &devs);
+ libusb_get_device_list(usb_context, &devs);
while ((usb_dev = devs[d++]) != NULL) {
struct libusb_device_descriptor desc;
struct libusb_config_descriptor *conf_desc = NULL;
@@ -774,15 +814,15 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
if (!strcmp(dev_path, path)) {
/* Matched Paths. Open this device */
- // OPEN HERE //
+ /* OPEN HERE */
res = libusb_open(usb_dev, &dev->device_handle);
if (res < 0) {
LOG("can't open device\n");
free(dev_path);
- break;
+ break;
}
good_open = 1;
-
+#ifdef DETACH_KERNEL_DRIVER
/* Detach the kernel driver, but only if the
device is managed by the kernel */
if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
@@ -795,7 +835,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
break;
}
}
-
+#endif
res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
if (res < 0) {
LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
@@ -847,7 +887,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
pthread_create(&dev->thread, NULL, read_thread, dev);
- // Wait here for the read thread to be initialized.
+ /* Wait here for the read thread to be initialized. */
pthread_barrier_wait(&dev->barrier);
}
@@ -861,12 +901,12 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
libusb_free_device_list(devs, 1);
- // If we have a good handle, return it.
+ /* If we have a good handle, return it. */
if (good_open) {
return dev;
}
else {
- // Unable to open any devices.
+ /* Unable to open any devices. */
free_hid_device(dev);
return NULL;
}
@@ -1324,6 +1364,7 @@ uint16_t get_usb_code_for_current_locale(void)
char *locale;
char search_string[64];
char *ptr;
+ struct lang_map_entry *lang;
/* Get the current locale. */
locale = setlocale(0, NULL);
@@ -1346,7 +1387,7 @@ uint16_t get_usb_code_for_current_locale(void)
}
/* Find the entry which matches the string code of our locale. */
- struct lang_map_entry *lang = lang_map;
+ lang = lang_map;
while (lang->string_code) {
if (!strcmp(lang->string_code, search_string)) {
return lang->usb_code;
@@ -1366,7 +1407,7 @@ uint16_t get_usb_code_for_current_locale(void)
ptr++;
}
-#if 0 // TODO: Do we need this?
+#if 0 /* TODO: Do we need this? */
/* Find the entry which matches the string code of our language. */
lang = lang_map;
while (lang->string_code) {