summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandru Csete <oz9aec@gmail.com>2016-09-23 13:53:25 +0200
committerAlexandru Csete <oz9aec@gmail.com>2016-09-23 13:54:51 +0200
commit67baea5e32de0daef510dfebfa67bf94c0b88f68 (patch)
treef2cacd82d1ec07057a7404e3f239204e2692baf5
parent7566a55d929eab238c9066572b865164042b2aa0 (diff)
fcd: Update hidapi to latest HEAD.
This contains necessary fixes for Mac OS X.
-rw-r--r--gr-fcd/lib/hid/hid-libusb.c117
-rw-r--r--gr-fcd/lib/hid/hidapi.h32
-rw-r--r--gr-fcd/lib/hid/hidmac.c406
-rw-r--r--gr-fcd/lib/hid/hidwin.c355
4 files changed, 532 insertions, 378 deletions
diff --git a/gr-fcd/lib/hid/hid-libusb.c b/gr-fcd/lib/hid/hid-libusb.c
index 097f87215d..3c6d877f88 100644
--- a/gr-fcd/lib/hid/hid-libusb.c
+++ b/gr-fcd/lib/hid/hid-libusb.c
@@ -14,7 +14,7 @@
At the discretion of the user of this library,
this software may be licensed under the terms of the
- GNU Public License v3, a BSD-Style license, or the
+ GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
@@ -44,11 +44,74 @@
#include <wchar.h>
/* GNU / LibUSB */
-#include "libusb.h"
-#include "iconv.h"
+#include <libusb.h>
+#ifndef __ANDROID__
+#include <iconv.h>
+#endif
#include "hidapi.h"
+#ifdef __ANDROID__
+
+/* Barrier implementation because Android/Bionic don't have pthread_barrier.
+ This implementation came from Brent Priddy and was posted on
+ StackOverflow. It is used with his permission. */
+typedef int pthread_barrierattr_t;
+typedef struct pthread_barrier {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int count;
+ int trip_count;
+} pthread_barrier_t;
+
+static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
+{
+ if(count == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
+ return -1;
+ }
+ if(pthread_cond_init(&barrier->cond, 0) < 0) {
+ pthread_mutex_destroy(&barrier->mutex);
+ return -1;
+ }
+ barrier->trip_count = count;
+ barrier->count = 0;
+
+ return 0;
+}
+
+static int pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_cond_destroy(&barrier->cond);
+ pthread_mutex_destroy(&barrier->mutex);
+ return 0;
+}
+
+static int pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ pthread_mutex_lock(&barrier->mutex);
+ ++(barrier->count);
+ if(barrier->count >= barrier->trip_count)
+ {
+ barrier->count = 0;
+ pthread_cond_broadcast(&barrier->cond);
+ pthread_mutex_unlock(&barrier->mutex);
+ return 1;
+ }
+ else
+ {
+ pthread_cond_wait(&barrier->cond, &(barrier->mutex));
+ pthread_mutex_unlock(&barrier->mutex);
+ return 0;
+ }
+}
+
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -250,10 +313,10 @@ static int get_usage(uint8_t *report_descriptor, size_t size,
}
#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.
+#if defined(__FreeBSD__) && __FreeBSD__ < 10
+/* The libusb version included in FreeBSD < 10 doesn't have this function. In
+ mainline libusb, it's inlined in libusb.h. This function will bear a striking
+ resemblance 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_*.
@@ -326,8 +389,9 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
char buf[512];
int len;
wchar_t *str = NULL;
- wchar_t wbuf[256];
+#ifndef __ANDROID__ /* we don't use iconv on Android */
+ wchar_t wbuf[256];
/* iconv variables */
iconv_t ic;
size_t inbytes;
@@ -339,6 +403,7 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
char *inptr;
#endif
char *outptr;
+#endif
/* Determine which language to use. */
uint16_t lang;
@@ -355,6 +420,25 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
if (len < 0)
return NULL;
+#ifdef __ANDROID__
+
+ /* Bionic does not have iconv support nor wcsdup() function, so it
+ has to be done manually. The following code will only work for
+ code points that can be represented as a single UTF-16 character,
+ and will incorrectly convert any code points which require more
+ than one UTF-16 character.
+
+ Skip over the first character (2-bytes). */
+ len -= 2;
+ str = malloc((len / 2 + 1) * sizeof(wchar_t));
+ int i;
+ for (i = 0; i < len / 2; i++) {
+ str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8);
+ }
+ str[len / 2] = 0x00000000;
+
+#else
+
/* buf does not need to be explicitly NULL-terminated because
it is only passed into iconv() which does not need it. */
@@ -388,6 +472,8 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
err:
iconv_close(ic);
+#endif
+
return str;
}
@@ -607,7 +693,7 @@ void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
}
}
-hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number)
+hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
{
struct hid_device_info *devs, *cur_dev;
const char *path_to_open = NULL;
@@ -619,7 +705,8 @@ hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, wchar
if (cur_dev->vendor_id == vendor_id &&
cur_dev->product_id == product_id) {
if (serial_number) {
- if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+ if (cur_dev->serial_number &&
+ wcscmp(serial_number, cur_dev->serial_number) == 0) {
path_to_open = cur_dev->path;
break;
}
@@ -762,7 +849,7 @@ static void *read_thread(void *param)
/* 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
make sure that a thread which is about to go to sleep waiting on
- the condition acutally will go to sleep before the condition is
+ the condition actually will go to sleep before the condition is
signaled. */
pthread_mutex_lock(&dev->mutex);
pthread_cond_broadcast(&dev->condition);
@@ -790,11 +877,11 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
int d = 0;
int good_open = 0;
- dev = new_hid_device();
-
if(hid_init() < 0)
return NULL;
+ dev = new_hid_device();
+
libusb_get_device_list(usb_context, &devs);
while ((usb_dev = devs[d++]) != NULL) {
struct libusb_device_descriptor desc;
@@ -871,7 +958,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
== LIBUSB_ENDPOINT_IN;
- /* Decide whether to use it for intput or output. */
+ /* Decide whether to use it for input or output. */
if (dev->input_endpoint == 0 &&
is_interrupt && is_input) {
/* Use this endpoint for INPUT */
@@ -927,7 +1014,7 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t
if (dev->output_endpoint <= 0) {
- /* No interrput out endpoint. Use the Control Endpoint */
+ /* No interrupt out endpoint. Use the Control Endpoint */
res = libusb_control_transfer(dev->device_handle,
LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
0x09/*HID Set_Report*/,
diff --git a/gr-fcd/lib/hid/hidapi.h b/gr-fcd/lib/hid/hidapi.h
index 8e55c84742..e5bc2dc40a 100644
--- a/gr-fcd/lib/hid/hidapi.h
+++ b/gr-fcd/lib/hid/hidapi.h
@@ -11,7 +11,7 @@
At the discretion of the user of this library,
this software may be licensed under the terms of the
- GNU Public License v3, a BSD-Style license, or the
+ GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
@@ -87,7 +87,7 @@ extern "C" {
needed. This function should be called at the beginning of
execution however, if there is a chance of HIDAPI handles
being opened by different threads simultaneously.
-
+
@ingroup API
@returns
@@ -112,6 +112,8 @@ extern "C" {
This function returns a linked list of all the HID devices
attached to the system which match vendor_id and product_id.
+ If @p vendor_id is set to 0 then any vendor matches.
+ If @p product_id is set to 0 then any product matches.
If @p vendor_id and @p product_id are both set to 0, then
all HID devices will be returned.
@@ -155,7 +157,7 @@ extern "C" {
This function returns a pointer to a #hid_device object on
success or NULL on failure.
*/
- HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number);
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
/** @brief Open a HID device by its path name.
@@ -207,7 +209,7 @@ extern "C" {
contain the Report number if the device uses numbered reports.
@ingroup API
- @param dev A device handle returned from hid_open().
+ @param device A device handle returned from hid_open().
@param data A buffer to put the read data into.
@param length The number of bytes to read. For devices with
multiple reports, make sure to read an extra byte for
@@ -216,7 +218,8 @@ extern "C" {
@returns
This function returns the actual number of bytes read and
- -1 on error.
+ -1 on error. If no packet was available to be read within
+ the timeout period, this function returns 0.
*/
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
@@ -235,7 +238,8 @@ extern "C" {
@returns
This function returns the actual number of bytes read and
- -1 on error.
+ -1 on error. If no packet was available to be read and
+ the handle is in non-blocking mode, this function returns 0.
*/
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
@@ -289,22 +293,26 @@ extern "C" {
/** @brief Get a feature report from a HID device.
- Make sure to set the first byte of @p data[] to the Report
- ID of the report to be read. Make sure to allow space for
- this extra byte in @p data[].
+ Set the first byte of @p data[] to the Report ID of the
+ report to be read. Make sure to allow space for this
+ extra byte in @p data[]. Upon return, the first byte will
+ still contain the Report ID, and the report data will
+ start in data[1].
@ingroup API
@param device A device handle returned from hid_open().
@param data A buffer to put the read data into, including
the Report ID. Set the first byte of @p data[] to the
- Report ID of the report to be read.
+ Report ID of the report to be read, or set it to zero
+ if your device does not use numbered reports.
@param length The number of bytes to read, including an
extra byte for the report ID. The buffer can be longer
than the actual report.
@returns
- This function returns the number of bytes read and
- -1 on error.
+ This function returns the number of bytes read plus
+ one for the report ID (which is still in the first
+ byte), or -1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
diff --git a/gr-fcd/lib/hid/hidmac.c b/gr-fcd/lib/hid/hidmac.c
index d8c69a8e52..e0756a1588 100644
--- a/gr-fcd/lib/hid/hidmac.c
+++ b/gr-fcd/lib/hid/hidmac.c
@@ -11,7 +11,7 @@
At the discretion of the user of this library,
this software may be licensed under the terms of the
- GNU Public License v3, a BSD-Style license, or the
+ GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
@@ -24,12 +24,14 @@
#include <IOKit/hid/IOHIDManager.h>
#include <IOKit/hid/IOHIDKeys.h>
+#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>
#include <wchar.h>
#include <locale.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
+#include <dlfcn.h>
#include "hidapi.h"
@@ -118,16 +120,8 @@ struct hid_device_ {
pthread_barrier_t barrier; /* Ensures correct startup sequence */
pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */
int shutdown_thread;
-
- hid_device *next;
};
-/* Static list of all the devices open. This way when a device gets
- disconnected, its hid_device structure can be marked as disconnected
- from hid_device_removal_callback(). */
-static hid_device *device_list = NULL;
-static pthread_mutex_t device_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-
static hid_device *new_hid_device(void)
{
hid_device *dev = calloc(1, sizeof(hid_device));
@@ -141,7 +135,6 @@ static hid_device *new_hid_device(void)
dev->input_report_buf = NULL;
dev->input_reports = NULL;
dev->shutdown_thread = 0;
- dev->next = NULL;
/* Thread objects */
pthread_mutex_init(&dev->mutex, NULL);
@@ -149,22 +142,6 @@ static hid_device *new_hid_device(void)
pthread_barrier_init(&dev->barrier, NULL, 2);
pthread_barrier_init(&dev->shutdown_barrier, NULL, 2);
- /* Add the new record to the device_list. */
- pthread_mutex_lock(&device_list_mutex);
- if (!device_list)
- device_list = dev;
- else {
- hid_device *d = device_list;
- while (d) {
- if (!d->next) {
- d->next = dev;
- break;
- }
- d = d->next;
- }
- }
- pthread_mutex_unlock(&device_list_mutex);
-
return dev;
}
@@ -197,29 +174,11 @@ static void free_hid_device(hid_device *dev)
pthread_cond_destroy(&dev->condition);
pthread_mutex_destroy(&dev->mutex);
- /* Remove it from the device list. */
- pthread_mutex_lock(&device_list_mutex);
- hid_device *d = device_list;
- if (d == dev) {
- device_list = d->next;
- }
- else {
- while (d) {
- if (d->next == dev) {
- d->next = d->next->next;
- break;
- }
-
- d = d->next;
- }
- }
- pthread_mutex_unlock(&device_list_mutex);
-
/* Free the structure itself. */
free(dev);
}
-static IOHIDManagerRef hid_mgr = 0x0;
+static IOHIDManagerRef hid_mgr = 0x0;
#if 0
@@ -255,7 +214,6 @@ static unsigned short get_product_id(IOHIDDeviceRef device)
return get_int_property(device, CFSTR(kIOHIDProductIDKey));
}
-
static int32_t get_max_report_length(IOHIDDeviceRef device)
{
return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));
@@ -263,59 +221,46 @@ static int32_t get_max_report_length(IOHIDDeviceRef device)
static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len)
{
- CFStringRef str = IOHIDDeviceGetProperty(device, prop);
+ CFStringRef str;
- buf[0] = 0x0000;
-
- if (str) {
- CFRange range;
- range.location = 0;
- range.length = len;
- CFIndex used_buf_len;
- CFStringGetBytes(str,
- range,
- kCFStringEncodingUTF32LE,
- (char)'?',
- FALSE,
- (UInt8*)buf,
- len,
- &used_buf_len);
- buf[len-1] = 0x00000000;
- return used_buf_len;
- }
- else
+ if (!len)
return 0;
-}
-
-static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len)
-{
- CFStringRef str = IOHIDDeviceGetProperty(device, prop);
+ str = IOHIDDeviceGetProperty(device, prop);
- buf[0] = 0x0000;
+ buf[0] = 0;
if (str) {
+ CFIndex str_len = CFStringGetLength(str);
CFRange range;
- range.location = 0;
- range.length = len;
CFIndex used_buf_len;
- CFStringGetBytes(str,
+ CFIndex chars_copied;
+
+ len --;
+
+ range.location = 0;
+ range.length = ((size_t)str_len > len)? len: (size_t)str_len;
+ chars_copied = CFStringGetBytes(str,
range,
- kCFStringEncodingUTF8,
+ kCFStringEncodingUTF32LE,
(char)'?',
FALSE,
(UInt8*)buf,
- len,
+ len * sizeof(wchar_t),
&used_buf_len);
- buf[len-1] = 0x00000000;
- return used_buf_len;
+
+ if (chars_copied == len)
+ buf[len] = 0; /* len is decremented above */
+ else
+ buf[chars_copied] = 0;
+
+ return 0;
}
else
- return 0;
+ return -1;
}
-
static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)
{
return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);
@@ -342,53 +287,87 @@ static wchar_t *dup_wcs(const wchar_t *s)
return ret;
}
-
-static int make_path(IOHIDDeviceRef device, char *buf, size_t len)
+/* hidapi_IOHIDDeviceGetService()
+ *
+ * Return the io_service_t corresponding to a given IOHIDDeviceRef, either by:
+ * - on OS X 10.6 and above, calling IOHIDDeviceGetService()
+ * - on OS X 10.5, extract it from the IOHIDDevice struct
+ */
+static io_service_t hidapi_IOHIDDeviceGetService(IOHIDDeviceRef device)
{
- int res;
- unsigned short vid, pid;
- char transport[32];
-
- buf[0] = '\0';
-
- res = get_string_property_utf8(
- device, CFSTR(kIOHIDTransportKey),
- transport, sizeof(transport));
-
- if (!res)
- return -1;
-
- vid = get_vendor_id(device);
- pid = get_product_id(device);
-
- res = snprintf(buf, len, "%s_%04hx_%04hx_%p",
- transport, vid, pid, device);
+ static void *iokit_framework = NULL;
+ static io_service_t (*dynamic_IOHIDDeviceGetService)(IOHIDDeviceRef device) = NULL;
+
+ /* Use dlopen()/dlsym() to get a pointer to IOHIDDeviceGetService() if it exists.
+ * If any of these steps fail, dynamic_IOHIDDeviceGetService will be left NULL
+ * and the fallback method will be used.
+ */
+ if (iokit_framework == NULL) {
+ iokit_framework = dlopen("/System/Library/IOKit.framework/IOKit", RTLD_LAZY);
+
+ if (iokit_framework != NULL)
+ dynamic_IOHIDDeviceGetService = dlsym(iokit_framework, "IOHIDDeviceGetService");
+ }
+ if (dynamic_IOHIDDeviceGetService != NULL) {
+ /* Running on OS X 10.6 and above: IOHIDDeviceGetService() exists */
+ return dynamic_IOHIDDeviceGetService(device);
+ }
+ else
+ {
+ /* Running on OS X 10.5: IOHIDDeviceGetService() doesn't exist.
+ *
+ * Be naughty and pull the service out of the IOHIDDevice.
+ * IOHIDDevice is an opaque struct not exposed to applications, but its
+ * layout is stable through all available versions of OS X.
+ * Tested and working on OS X 10.5.8 i386, x86_64, and ppc.
+ */
+ struct IOHIDDevice_internal {
+ /* The first field of the IOHIDDevice struct is a
+ * CFRuntimeBase (which is a private CF struct).
+ *
+ * a, b, and c are the 3 fields that make up a CFRuntimeBase.
+ * See http://opensource.apple.com/source/CF/CF-476.18/CFRuntime.h
+ *
+ * The second field of the IOHIDDevice is the io_service_t we're looking for.
+ */
+ uintptr_t a;
+ uint8_t b[4];
+#if __LP64__
+ uint32_t c;
+#endif
+ io_service_t service;
+ };
+ struct IOHIDDevice_internal *tmp = (struct IOHIDDevice_internal *)device;
- buf[len-1] = '\0';
- return res+1;
+ return tmp->service;
+ }
}
+/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */
static int init_hid_manager(void)
{
- IOReturn res;
-
/* Initialize all the HID Manager Objects */
hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
- IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
- IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- res = IOHIDManagerOpen(hid_mgr, kIOHIDOptionsTypeNone);
- return (res == kIOReturnSuccess)? 0: -1;
+ if (hid_mgr) {
+ IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
+ IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ return 0;
+ }
+
+ return -1;
}
+/* Initialize the IOHIDManager if necessary. This is the public function, and
+ it is safe to call this function repeatedly. Return 0 for success and -1
+ for failure. */
int HID_API_EXPORT hid_init(void)
{
if (!hid_mgr) {
- if (init_hid_manager() < 0) {
- hid_exit();
- return -1;
- }
+ return init_hid_manager();
}
+
+ /* Already initialized. */
return 0;
}
@@ -404,19 +383,29 @@ int HID_API_EXPORT hid_exit(void)
return 0;
}
+static void process_pending_events(void) {
+ SInt32 res;
+ do {
+ res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE);
+ } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
+}
+
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
{
- struct hid_device_info *root = NULL; // return object
+ struct hid_device_info *root = NULL; /* return object */
struct hid_device_info *cur_dev = NULL;
CFIndex num_devices;
int i;
- setlocale(LC_ALL,"");
-
/* Set up the HID Manager if it hasn't been done */
- hid_init();
+ if (hid_init() < 0)
+ return NULL;
+
+ /* give the IOHIDManager a chance to update itself */
+ process_pending_events();
/* Get a list of the Devices */
+ IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
/* Convert the list into a C array so we can iterate easily. */
@@ -430,7 +419,6 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
unsigned short dev_pid;
#define BUF_LEN 256
wchar_t buf[BUF_LEN];
- char cbuf[BUF_LEN];
IOHIDDeviceRef dev = device_array[i];
@@ -441,12 +429,14 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
dev_pid = get_product_id(dev);
/* 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;
- size_t len;
+ io_object_t iokit_dev;
+ kern_return_t res;
+ io_string_t path;
- /* VID/PID match. Create the record. */
+ /* VID/PID match. Create the record. */
tmp = malloc(sizeof(struct hid_device_info));
if (cur_dev) {
cur_dev->next = tmp;
@@ -456,14 +446,20 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
}
cur_dev = tmp;
- // Get the Usage Page and Usage for this device.
+ /* Get the Usage Page and Usage for this device. */
cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
/* Fill out the record */
cur_dev->next = NULL;
- len = make_path(dev, cbuf, sizeof(cbuf));
- cur_dev->path = strdup(cbuf);
+
+ /* Fill in the path (IOService plane) */
+ iokit_dev = hidapi_IOHIDDeviceGetService(dev);
+ res = IORegistryEntryGetPath(iokit_dev, kIOServicePlane, path);
+ if (res == KERN_SUCCESS)
+ cur_dev->path = strdup(path);
+ else
+ cur_dev->path = strdup("");
/* Serial Number */
get_serial_number(dev, buf, BUF_LEN);
@@ -508,7 +504,7 @@ void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
}
}
-hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number)
+hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
{
/* This function is identical to the Linux version. Platform independent. */
struct hid_device_info *devs, *cur_dev;
@@ -545,20 +541,13 @@ hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short pr
}
static void hid_device_removal_callback(void *context, IOReturn result,
- void *sender, IOHIDDeviceRef dev_ref)
+ void *sender)
{
/* Stop the Run Loop for this device. */
- pthread_mutex_lock(&device_list_mutex);
- hid_device *d = device_list;
- while (d) {
- if (d->device_handle == dev_ref) {
- d->disconnected = 1;
- CFRunLoopStop(d->run_loop);
- }
+ hid_device *d = context;
- d = d->next;
- }
- pthread_mutex_unlock(&device_list_mutex);
+ d->disconnected = 1;
+ CFRunLoopStop(d->run_loop);
}
/* The Run Loop calls this function for each input report received.
@@ -612,17 +601,18 @@ static void hid_report_callback(void *context, IOReturn result, void *sender,
}
-/* This gets called when the read_thred's run loop gets signaled by
+/* This gets called when the read_thread's run loop gets signaled by
hid_close(), and serves to stop the read_thread's run loop. */
static void perform_signal_callback(void *context)
{
hid_device *dev = context;
- CFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent()
+ CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/
}
static void *read_thread(void *param)
{
hid_device *dev = param;
+ SInt32 code;
/* Move the device's run loop to this thread. */
IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
@@ -646,7 +636,6 @@ static void *read_thread(void *param)
/* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
reports into the hid_report_callback(). */
- SInt32 code;
while (!dev->shutdown_thread && !dev->disconnected) {
code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);
/* Return if the device has been disconnected */
@@ -670,19 +659,12 @@ static void *read_thread(void *param)
/* 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
make sure that a thread which is about to go to sleep waiting on
- the condition acutally will go to sleep before the condition is
+ the condition actually will go to sleep before the condition is
signaled. */
pthread_mutex_lock(&dev->mutex);
pthread_cond_broadcast(&dev->condition);
pthread_mutex_unlock(&dev->mutex);
- /* Close the OS handle to the device, but only if it's not
- been unplugged. If it's been unplugged, then calling
- IOHIDDeviceClose() will crash. */
- if (!dev->disconnected) {
- IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
- }
-
/* Wait here until hid_close() is called and makes it past
the call to CFRunLoopWakeUp(). This thread still needs to
be valid when that function is called on the other thread. */
@@ -691,71 +673,77 @@ static void *read_thread(void *param)
return NULL;
}
+/* hid_open_path()
+ *
+ * path must be a valid path to an IOHIDDevice in the IOService plane
+ * Example: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver"
+ */
hid_device * HID_API_EXPORT hid_open_path(const char *path)
{
- int i;
hid_device *dev = NULL;
- CFIndex num_devices;
+ io_registry_entry_t entry = MACH_PORT_NULL;
dev = new_hid_device();
/* Set up the HID Manager if it hasn't been done */
- hid_init();
+ if (hid_init() < 0)
+ return NULL;
+
+ /* Get the IORegistry entry for the given path */
+ entry = IORegistryEntryFromPath(kIOMasterPortDefault, path);
+ if (entry == MACH_PORT_NULL) {
+ /* Path wasn't valid (maybe device was removed?) */
+ goto return_error;
+ }
- CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
+ /* Create an IOHIDDevice for the entry */
+ dev->device_handle = IOHIDDeviceCreate(kCFAllocatorDefault, entry);
+ if (dev->device_handle == NULL) {
+ /* Error creating the HID device */
+ goto return_error;
+ }
- num_devices = CFSetGetCount(device_set);
- IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
- CFSetGetValues(device_set, (const void **) device_array);
- for (i = 0; i < num_devices; i++) {
- char cbuf[BUF_LEN];
- size_t len;
- IOHIDDeviceRef os_dev = device_array[i];
-
- len = make_path(os_dev, cbuf, sizeof(cbuf));
- if (!strcmp(cbuf, path)) {
- // Matched Paths. Open this Device.
- IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
- if (ret == kIOReturnSuccess) {
- char str[32];
-
- free(device_array);
- CFRelease(device_set);
- dev->device_handle = os_dev;
-
- /* Create the buffers for receiving data */
- dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);
- dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));
-
- /* Create the Run Loop Mode for this device.
- printing the reference seems to work. */
- sprintf(str, "HIDAPI_%p", os_dev);
- dev->run_loop_mode =
- CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
-
- /* Attach the device to a Run Loop */
- IOHIDDeviceRegisterInputReportCallback(
- os_dev, dev->input_report_buf, dev->max_input_report_len,
- &hid_report_callback, dev);
- IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback, NULL);
-
- /* Start the read thread */
- pthread_create(&dev->thread, NULL, read_thread, dev);
-
- /* Wait here for the read thread to be initialized. */
- pthread_barrier_wait(&dev->barrier);
-
- return dev;
- }
- else {
- goto return_error;
- }
- }
+ /* Open the IOHIDDevice */
+ IOReturn ret = IOHIDDeviceOpen(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);
+ if (ret == kIOReturnSuccess) {
+ char str[32];
+
+ /* Create the buffers for receiving data */
+ dev->max_input_report_len = (CFIndex) get_max_report_length(dev->device_handle);
+ dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));
+
+ /* Create the Run Loop Mode for this device.
+ printing the reference seems to work. */
+ sprintf(str, "HIDAPI_%p", dev->device_handle);
+ dev->run_loop_mode =
+ CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
+
+ /* Attach the device to a Run Loop */
+ IOHIDDeviceRegisterInputReportCallback(
+ dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
+ &hid_report_callback, dev);
+ IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev);
+
+ /* Start the read thread */
+ pthread_create(&dev->thread, NULL, read_thread, dev);
+
+ /* Wait here for the read thread to be initialized. */
+ pthread_barrier_wait(&dev->barrier);
+
+ IOObjectRelease(entry);
+ return dev;
+ }
+ else {
+ goto return_error;
}
return_error:
- free(device_array);
- CFRelease(device_set);
+ if (dev->device_handle != NULL)
+ CFRelease(dev->device_handle);
+
+ if (entry != MACH_PORT_NULL)
+ IOObjectRelease(entry);
+
free_hid_device(dev);
return NULL;
}
@@ -767,8 +755,8 @@ static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char
IOReturn res;
/* Return if the device has been disconnected. */
- if (dev->disconnected)
- return -1;
+ if (dev->disconnected)
+ return -1;
if (data[0] == 0x0) {
/* Not using numbered Reports.
@@ -981,7 +969,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
IOHIDDeviceRegisterInputReportCallback(
dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
NULL, dev);
- IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev);
+ IOHIDDeviceRegisterRemovalCallback(dev->device_handle, NULL, dev);
IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
}
@@ -1003,7 +991,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
been unplugged. If it's been unplugged, then calling
IOHIDDeviceClose() will crash. */
if (!dev->disconnected) {
- IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
+ IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);
}
/* Clear out the queue of received reports. */
@@ -1012,6 +1000,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
return_data(dev, NULL, 0);
}
pthread_mutex_unlock(&dev->mutex);
+ CFRelease(dev->device_handle);
free_hid_device(dev);
}
@@ -1033,7 +1022,7 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
{
- // TODO:
+ /* TODO: */
return 0;
}
@@ -1041,7 +1030,7 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index
HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
{
- // TODO:
+ /* TODO: */
return NULL;
}
@@ -1051,6 +1040,7 @@ HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
+
#if 0
static int32_t get_location_id(IOHIDDeviceRef device)
{
@@ -1096,8 +1086,6 @@ int main(void)
IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
CFSetGetValues(device_set, (const void **) device_array);
- setlocale(LC_ALL, "");
-
for (i = 0; i < num_devices; i++) {
IOHIDDeviceRef dev = device_array[i];
printf("Device: %p\n", dev);
diff --git a/gr-fcd/lib/hid/hidwin.c b/gr-fcd/lib/hid/hidwin.c
index 5d34aadf48..86810d7e56 100644
--- a/gr-fcd/lib/hid/hidwin.c
+++ b/gr-fcd/lib/hid/hidwin.c
@@ -8,10 +8,10 @@
8/22/2009
Copyright 2009, All Rights Reserved.
-
+
At the discretion of the user of this library,
this software may be licensed under the terms of the
- GNU Public License v3, a BSD-Style license, or the
+ GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
@@ -36,7 +36,11 @@ typedef LONG NTSTATUS;
#define _wcsdup wcsdup
#endif
-//#define HIDAPI_USE_DDK
+/* The maximum number of characters that can be passed into the
+ HidD_Get*String() functions without it failing.*/
+#define MAX_STRING_WCHARS 0xFFF
+
+/*#define HIDAPI_USE_DDK*/
#ifdef __cplusplus
extern "C" {
@@ -47,13 +51,13 @@ extern "C" {
#include <hidsdi.h>
#endif
- // Copied from inc/ddk/hidclass.h, part of the Windows DDK.
+ /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
#define HID_OUT_CTL_CODE(id) \
CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
#ifdef __cplusplus
-} // extern "C"
+} /* extern "C" */
#endif
#include <stdio.h>
@@ -62,8 +66,11 @@ extern "C" {
#include "hidapi.h"
+#undef MIN
+#define MIN(x,y) ((x) < (y)? (x): (y))
+
#ifdef _MSC_VER
- // Thanks Microsoft, but I know how to use strncpy().
+ /* Thanks Microsoft, but I know how to use strncpy(). */
#pragma warning(disable:4996)
#endif
@@ -72,10 +79,10 @@ extern "C" {
#endif
#ifndef HIDAPI_USE_DDK
- // Since we're not building with the DDK, and the HID header
- // files aren't part of the SDK, we have to define all this
- // stuff here. In lookup_functions(), the function pointers
- // defined below are set.
+ /* Since we're not building with the DDK, and the HID header
+ files aren't part of the SDK, we have to define all this
+ stuff here. In lookup_functions(), the function pointers
+ defined below are set. */
typedef struct _HIDD_ATTRIBUTES{
ULONG Size;
USHORT VendorID;
@@ -93,8 +100,8 @@ extern "C" {
USHORT Reserved[17];
USHORT fields_not_used_by_hidapi[10];
} HIDP_CAPS, *PHIDP_CAPS;
- typedef char* HIDP_PREPARSED_DATA;
- #define HIDP_STATUS_SUCCESS 0x0
+ typedef void* PHIDP_PREPARSED_DATA;
+ #define HIDP_STATUS_SUCCESS 0x110000
typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
@@ -103,9 +110,10 @@ extern "C" {
typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
- typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, HIDP_PREPARSED_DATA **preparsed_data);
- typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(HIDP_PREPARSED_DATA *preparsed_data);
- typedef BOOLEAN (__stdcall *HidP_GetCaps_)(HIDP_PREPARSED_DATA *preparsed_data, HIDP_CAPS *caps);
+ typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
+ typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
+ typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
+ typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
static HidD_GetAttributes_ HidD_GetAttributes;
static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
@@ -117,14 +125,16 @@ extern "C" {
static HidD_GetPreparsedData_ HidD_GetPreparsedData;
static HidD_FreePreparsedData_ HidD_FreePreparsedData;
static HidP_GetCaps_ HidP_GetCaps;
+ static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
static HMODULE lib_handle = NULL;
static BOOLEAN initialized = FALSE;
-#endif // HIDAPI_USE_DDK
+#endif /* HIDAPI_USE_DDK */
struct hid_device_ {
HANDLE device_handle;
BOOL blocking;
+ USHORT output_report_length;
size_t input_report_length;
void *last_error_str;
DWORD last_error_num;
@@ -138,17 +148,26 @@ static hid_device *new_hid_device()
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
dev->device_handle = INVALID_HANDLE_VALUE;
dev->blocking = TRUE;
+ dev->output_report_length = 0;
dev->input_report_length = 0;
dev->last_error_str = NULL;
dev->last_error_num = 0;
dev->read_pending = FALSE;
dev->read_buf = NULL;
memset(&dev->ol, 0, sizeof(dev->ol));
- dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);
+ dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
return dev;
}
+static void free_hid_device(hid_device *dev)
+{
+ CloseHandle(dev->ol.hEvent);
+ CloseHandle(dev->device_handle);
+ LocalFree(dev->last_error_str);
+ free(dev->read_buf);
+ free(dev);
+}
static void register_error(hid_device *device, const char *op)
{
@@ -160,11 +179,11 @@ static void register_error(hid_device *device, const char *op)
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPWSTR)&msg, 0/*sz*/,
+ (LPVOID)&msg, 0/*sz*/,
NULL);
-
- // Get rid of the CR and LF that FormatMessage() sticks at the
- // end of the message. Thanks Microsoft!
+
+ /* Get rid of the CR and LF that FormatMessage() sticks at the
+ end of the message. Thanks Microsoft! */
ptr = msg;
while (*ptr) {
if (*ptr == '\r') {
@@ -174,8 +193,8 @@ static void register_error(hid_device *device, const char *op)
ptr++;
}
- // Store the message off in the Device entry so that
- // the hid_error() function can pick it up.
+ /* Store the message off in the Device entry so that
+ the hid_error() function can pick it up. */
LocalFree(device->last_error_str);
device->last_error_str = msg;
}
@@ -196,6 +215,7 @@ static int lookup_functions()
RESOLVE(HidD_GetPreparsedData);
RESOLVE(HidD_FreePreparsedData);
RESOLVE(HidP_GetCaps);
+ RESOLVE(HidD_SetNumInputBuffers);
#undef RESOLVE
}
else
@@ -205,34 +225,20 @@ static int lookup_functions()
}
#endif
-static HANDLE open_device(const char *path)
+static HANDLE open_device(const char *path, BOOL enumerate)
{
HANDLE handle;
+ DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
+ DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
- /* First, try to open with sharing mode turned off. This will make it so
- that a HID device can only be opened once. This is to be consistent
- with the behavior on the other platforms. */
handle = CreateFileA(path,
- GENERIC_WRITE |GENERIC_READ,
- 0, /*share mode*/
+ desired_access,
+ share_mode,
NULL,
OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL,
+ FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
0);
- if (handle == INVALID_HANDLE_VALUE) {
- /* Couldn't open the device. Some devices must be opened
- with sharing enabled (even though they are only opened once),
- so try it here. */
- handle = CreateFileA(path,
- GENERIC_WRITE |GENERIC_READ,
- FILE_SHARE_READ|FILE_SHARE_WRITE, /*share mode*/
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL,
- 0);
- }
-
return handle;
}
@@ -264,29 +270,31 @@ int HID_API_EXPORT hid_exit(void)
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
{
BOOL res;
- struct hid_device_info *root = NULL; // return object
+ struct hid_device_info *root = NULL; /* return object */
struct hid_device_info *cur_dev = NULL;
- // Windows objects for interacting with the driver.
+ /* Windows objects for interacting with the driver. */
GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
SP_DEVINFO_DATA devinfo_data;
SP_DEVICE_INTERFACE_DATA device_interface_data;
SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
int device_index = 0;
+ int i;
if (hid_init() < 0)
return NULL;
- // Initialize the Windows objects.
+ /* Initialize the Windows objects. */
+ memset(&devinfo_data, 0x0, sizeof(devinfo_data));
devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- // Get information for all the devices belonging to the HID class.
+ /* Get information for all the devices belonging to the HID class. */
device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
-
- // Iterate over each device in the HID class, looking for the right one.
-
+
+ /* Iterate over each device in the HID class, looking for the right one. */
+
for (;;) {
HANDLE write_handle = INVALID_HANDLE_VALUE;
DWORD required_size = 0;
@@ -297,16 +305,16 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
&InterfaceClassGuid,
device_index,
&device_interface_data);
-
+
if (!res) {
- // A return of FALSE from this function means that
- // there are no more devices.
+ /* A return of FALSE from this function means that
+ there are no more devices. */
break;
}
- // Call with 0-sized detail size, and let the function
- // tell us how long the detail struct needs to be. The
- // size is put in &required_size.
+ /* Call with 0-sized detail size, and let the function
+ tell us how long the detail struct needs to be. The
+ size is put in &required_size. */
res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
&device_interface_data,
NULL,
@@ -314,13 +322,13 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
&required_size,
NULL);
- // Allocate a long enough structure for device_interface_detail_data.
+ /* Allocate a long enough structure for device_interface_detail_data. */
device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
- // Get the detailed data for this device. The detail data gives us
- // the device path for this device, which is then passed into
- // CreateFile() to get a handle to the device.
+ /* Get the detailed data for this device. The detail data gives us
+ the device path for this device, which is then passed into
+ CreateFile() to get a handle to the device. */
res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
&device_interface_data,
device_interface_detail_data,
@@ -329,42 +337,67 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
NULL);
if (!res) {
- //register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
- // Continue to the next device.
+ /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
+ Continue to the next device. */
goto cont;
}
+ /* Make sure this device is of Setup Class "HIDClass" and has a
+ driver bound to it. */
+ for (i = 0; ; i++) {
+ char driver_name[256];
+
+ /* Populate devinfo_data. This function will return failure
+ when there are no more interfaces left. */
+ res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
+ if (!res)
+ goto cont;
+
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (!res)
+ goto cont;
+
+ if (strcmp(driver_name, "HIDClass") == 0) {
+ /* See if there's a driver bound. */
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (res)
+ break;
+ }
+ }
+
//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
- // Open a handle to the device
- write_handle = open_device(device_interface_detail_data->DevicePath);
+ /* Open a handle to the device */
+ write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);
- // Check validity of write_handle.
+ /* Check validity of write_handle. */
if (write_handle == INVALID_HANDLE_VALUE) {
- // Unable to open the device.
+ /* Unable to open the device. */
//register_error(dev, "CreateFile");
goto cont_close;
- }
+ }
- // Get the Vendor ID and Product ID for this device.
+ /* Get the Vendor ID and Product ID for this device. */
attrib.Size = sizeof(HIDD_ATTRIBUTES);
HidD_GetAttributes(write_handle, &attrib);
//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
- // Check the VID/PID to see if we should add this
- // device to the enumeration list.
- if ((vendor_id == 0x0 && product_id == 0x0) ||
- (attrib.VendorID == vendor_id && attrib.ProductID == product_id)) {
+ /* Check the VID/PID to see if we should add this
+ device to the enumeration list. */
+ if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
+ (product_id == 0x0 || attrib.ProductID == product_id)) {
#define WSTR_LEN 512
const char *str;
struct hid_device_info *tmp;
- HIDP_PREPARSED_DATA *pp_data = NULL;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
HIDP_CAPS caps;
BOOLEAN res;
NTSTATUS nt_res;
- wchar_t wstr[WSTR_LEN]; // TODO: Determine Size
+ wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
size_t len;
/* VID/PID match. Create the record. */
@@ -377,7 +410,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
}
cur_dev = tmp;
- // Get the Usage Page and Usage for this device.
+ /* Get the Usage Page and Usage for this device. */
res = HidD_GetPreparsedData(write_handle, &pp_data);
if (res) {
nt_res = HidP_GetCaps(pp_data, &caps);
@@ -388,7 +421,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
HidD_FreePreparsedData(pp_data);
}
-
+
/* Fill out the record */
cur_dev->next = NULL;
str = device_interface_detail_data->DevicePath;
@@ -452,14 +485,14 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
cont_close:
CloseHandle(write_handle);
cont:
- // We no longer need the detail data. It can be freed
+ /* We no longer need the detail data. It can be freed */
free(device_interface_detail_data);
device_index++;
}
- // Close the device information handle.
+ /* Close the device information handle. */
SetupDiDestroyDeviceInfoList(device_info_set);
return root;
@@ -468,7 +501,7 @@ cont:
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
{
- // TODO: Merge this with the Linux version. This function is platform-independent.
+ /* TODO: Merge this with the Linux version. This function is platform-independent. */
struct hid_device_info *d = devs;
while (d) {
struct hid_device_info *next = d->next;
@@ -482,13 +515,13 @@ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *d
}
-HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number)
+HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
{
- // TODO: Merge this functions with the Linux version. This function should be platform independent.
+ /* TODO: Merge this functions with the Linux version. This function should be platform independent. */
struct hid_device_info *devs, *cur_dev;
const char *path_to_open = NULL;
hid_device *handle = NULL;
-
+
devs = hid_enumerate(vendor_id, product_id);
cur_dev = devs;
while (cur_dev) {
@@ -514,7 +547,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi
}
hid_free_enumeration(devs);
-
+
return handle;
}
@@ -522,7 +555,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
{
hid_device *dev;
HIDP_CAPS caps;
- HIDP_PREPARSED_DATA *pp_data = NULL;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
BOOLEAN res;
NTSTATUS nt_res;
@@ -532,17 +565,24 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
dev = new_hid_device();
- // Open a handle to the device
- dev->device_handle = open_device(path);
+ /* Open a handle to the device */
+ dev->device_handle = open_device(path, FALSE);
- // Check validity of write_handle.
+ /* Check validity of write_handle. */
if (dev->device_handle == INVALID_HANDLE_VALUE) {
- // Unable to open the device.
+ /* Unable to open the device. */
register_error(dev, "CreateFile");
goto err;
}
- // Get the Input Report length for the device.
+ /* Set the Input Report buffer size to 64 reports. */
+ res = HidD_SetNumInputBuffers(dev->device_handle, 64);
+ if (!res) {
+ register_error(dev, "HidD_SetNumInputBuffers");
+ goto err;
+ }
+
+ /* Get the Input Report length for the device. */
res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
if (!res) {
register_error(dev, "HidD_GetPreparsedData");
@@ -550,9 +590,10 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
}
nt_res = HidP_GetCaps(pp_data, &caps);
if (nt_res != HIDP_STATUS_SUCCESS) {
- register_error(dev, "HidP_GetCaps");
+ register_error(dev, "HidP_GetCaps");
goto err_pp_data;
}
+ dev->output_report_length = caps.OutputReportByteLength;
dev->input_report_length = caps.InputReportByteLength;
HidD_FreePreparsedData(pp_data);
@@ -562,9 +603,8 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
err_pp_data:
HidD_FreePreparsedData(pp_data);
-err:
- CloseHandle(dev->device_handle);
- free(dev);
+err:
+ free_hid_device(dev);
return NULL;
}
@@ -574,27 +614,52 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
BOOL res;
OVERLAPPED ol;
+ unsigned char *buf;
memset(&ol, 0, sizeof(ol));
- res = WriteFile(dev->device_handle, data, length, NULL, &ol);
+ /* Make sure the right number of bytes are passed to WriteFile. Windows
+ expects the number of bytes which are in the _longest_ report (plus
+ one for the report number) bytes even if the data is a report
+ which is shorter than that. Windows gives us this value in
+ caps.OutputReportByteLength. If a user passes in fewer bytes than this,
+ create a temporary buffer which is the proper size. */
+ if (length >= dev->output_report_length) {
+ /* The user passed the right number of bytes. Use the buffer as-is. */
+ buf = (unsigned char *) data;
+ } else {
+ /* Create a temporary buffer and copy the user's data
+ into it, padding the rest with zeros. */
+ buf = (unsigned char *) malloc(dev->output_report_length);
+ memcpy(buf, data, length);
+ memset(buf + length, 0, dev->output_report_length - length);
+ length = dev->output_report_length;
+ }
+ res = WriteFile(dev->device_handle, buf, length, NULL, &ol);
+
if (!res) {
if (GetLastError() != ERROR_IO_PENDING) {
- // WriteFile() failed. Return error.
+ /* WriteFile() failed. Return error. */
register_error(dev, "WriteFile");
- return -1;
+ bytes_written = -1;
+ goto end_of_function;
}
}
- // Wait here until the write is done. This makes
- // hid_write() synchronous.
+ /* Wait here until the write is done. This makes
+ hid_write() synchronous. */
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
if (!res) {
- // The Write operation failed.
+ /* The Write operation failed. */
register_error(dev, "WriteFile");
- return -1;
+ bytes_written = -1;
+ goto end_of_function;
}
+end_of_function:
+ if (buf != data)
+ free(buf);
+
return bytes_written;
}
@@ -602,21 +667,23 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
{
DWORD bytes_read = 0;
+ size_t copy_len = 0;
BOOL res;
- // Copy the handle for convenience.
+ /* Copy the handle for convenience. */
HANDLE ev = dev->ol.hEvent;
if (!dev->read_pending) {
- // Start an Overlapped I/O read.
+ /* Start an Overlapped I/O read. */
dev->read_pending = TRUE;
+ memset(dev->read_buf, 0, dev->input_report_length);
ResetEvent(ev);
res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol);
-
+
if (!res) {
if (GetLastError() != ERROR_IO_PENDING) {
- // ReadFile() has failed.
- // Clean up and return error.
+ /* ReadFile() has failed.
+ Clean up and return error. */
CancelIo(dev->device_handle);
dev->read_pending = FALSE;
goto end_of_function;
@@ -625,21 +692,21 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
}
if (milliseconds >= 0) {
- // See if there is any data yet.
+ /* See if there is any data yet. */
res = WaitForSingleObject(ev, milliseconds);
if (res != WAIT_OBJECT_0) {
- // There was no data this time. Return zero bytes available,
- // but leave the Overlapped I/O running.
+ /* There was no data this time. Return zero bytes available,
+ but leave the Overlapped I/O running. */
return 0;
}
}
- // Either WaitForSingleObject() told us that ReadFile has completed, or
- // we are in non-blocking mode. Get the number of bytes read. The actual
- // data has been copied to the data[] array which was passed to ReadFile().
+ /* Either WaitForSingleObject() told us that ReadFile has completed, or
+ we are in non-blocking mode. Get the number of bytes read. The actual
+ data has been copied to the data[] array which was passed to ReadFile(). */
res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
-
- // Set pending back to false, even if GetOverlappedResult() returned error.
+
+ /* Set pending back to false, even if GetOverlappedResult() returned error. */
dev->read_pending = FALSE;
if (res && bytes_read > 0) {
@@ -649,21 +716,23 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
work like the other platforms, and to make it work more like the
HID spec, we'll skip over this byte. */
bytes_read--;
- memcpy(data, dev->read_buf+1, length);
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf+1, copy_len);
}
else {
/* Copy the whole buffer, report number and all. */
- memcpy(data, dev->read_buf, length);
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf, copy_len);
}
}
-
+
end_of_function:
if (!res) {
register_error(dev, "GetOverlappedResult");
return -1;
}
-
- return bytes_read;
+
+ return copy_len;
}
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
@@ -713,20 +782,26 @@ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned
if (!res) {
if (GetLastError() != ERROR_IO_PENDING) {
- // DeviceIoControl() failed. Return error.
+ /* DeviceIoControl() failed. Return error. */
register_error(dev, "Send Feature Report DeviceIoControl");
return -1;
}
}
- // Wait here until the write is done. This makes
- // hid_get_feature_report() synchronous.
+ /* Wait here until the write is done. This makes
+ hid_get_feature_report() synchronous. */
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
if (!res) {
- // The operation failed.
+ /* The operation failed. */
register_error(dev, "Send Feature Report GetOverLappedResult");
return -1;
}
+
+ /* bytes_returned does not include the first byte which contains the
+ report ID. The data buffer actually contains one more byte than
+ bytes_returned. */
+ bytes_returned++;
+
return bytes_returned;
#endif
}
@@ -736,18 +811,14 @@ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
if (!dev)
return;
CancelIo(dev->device_handle);
- CloseHandle(dev->ol.hEvent);
- CloseHandle(dev->device_handle);
- LocalFree(dev->last_error_str);
- free(dev->read_buf);
- free(dev);
+ free_hid_device(dev);
}
int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
{
BOOL res;
- res = HidD_GetManufacturerString(dev->device_handle, string, 2 * maxlen);
+ res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
if (!res) {
register_error(dev, "HidD_GetManufacturerString");
return -1;
@@ -760,7 +831,7 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wch
{
BOOL res;
- res = HidD_GetProductString(dev->device_handle, string, 2 * maxlen);
+ res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
if (!res) {
register_error(dev, "HidD_GetProductString");
return -1;
@@ -773,7 +844,7 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *de
{
BOOL res;
- res = HidD_GetSerialNumberString(dev->device_handle, string, 2 * maxlen);
+ res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
if (!res) {
register_error(dev, "HidD_GetSerialNumberString");
return -1;
@@ -786,7 +857,7 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int
{
BOOL res;
- res = HidD_GetIndexedString(dev->device_handle, string_index, string, 2 * maxlen);
+ res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
if (!res) {
register_error(dev, "HidD_GetIndexedString");
return -1;
@@ -802,10 +873,10 @@ HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
}
-//#define PICPGM
-//#define S11
+/*#define PICPGM*/
+/*#define S11*/
#define P32
-#ifdef S11
+#ifdef S11
unsigned short VendorID = 0xa0a0;
unsigned short ProductID = 0x0001;
#endif
@@ -831,36 +902,36 @@ int __cdecl main(int argc, char* argv[])
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
- // Set up the command buffer.
+ /* Set up the command buffer. */
memset(buf,0x00,sizeof(buf));
buf[0] = 0;
buf[1] = 0x81;
+
-
- // Open the device.
+ /* Open the device. */
int handle = open(VendorID, ProductID, L"12345");
if (handle < 0)
printf("unable to open device\n");
- // Toggle LED (cmd 0x80)
+ /* Toggle LED (cmd 0x80) */
buf[1] = 0x80;
res = write(handle, buf, 65);
if (res < 0)
printf("Unable to write()\n");
- // Request state (cmd 0x81)
+ /* Request state (cmd 0x81) */
buf[1] = 0x81;
write(handle, buf, 65);
if (res < 0)
printf("Unable to write() (2)\n");
- // Read requested state
+ /* Read requested state */
read(handle, buf, 65);
if (res < 0)
printf("Unable to read()\n");
- // Print out the returned buffer.
+ /* Print out the returned buffer. */
for (int i = 0; i < 4; i++)
printf("buf[%d]: %d\n", i, buf[i]);
@@ -869,5 +940,5 @@ int __cdecl main(int argc, char* argv[])
#endif
#ifdef __cplusplus
-} // extern "C"
+} /* extern "C" */
#endif