Permalink
Browse files

Update to hidapi 0.7.0

  • Loading branch information...
csete committed Mar 6, 2012
1 parent 1d953e3 commit b455f59cc696d8619d67a51ce7cd66923d38aac1
Showing with 688 additions and 179 deletions.
  1. +103 −19 lib/hid-libusb.c
  2. +52 −1 lib/hidapi.h
  3. +365 −84 lib/hidmac.c
  4. +168 −75 lib/hidwin.c
View
@@ -22,6 +22,8 @@
http://github.com/signal11/hidapi .
********************************************************/
+#define _GNU_SOURCE // needed for wcsdup() before glibc 2.10
+
/* C */
#include <stdio.h>
#include <string.h>
@@ -38,6 +40,7 @@
#include <sys/utsname.h>
#include <fcntl.h>
#include <pthread.h>
+#include <wchar.h>
/* GNU / LibUSB */
#include "libusb.h"
@@ -378,6 +381,28 @@ static char *make_path(libusb_device *dev, int interface_number)
return strdup(str);
}
+
+int HID_API_EXPORT hid_init(void)
+{
+ if (!initialized) {
+ if (libusb_init(NULL))
+ return -1;
+ initialized = 1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+ if (initialized) {
+ libusb_exit(NULL);
+ initialized = 0;
+ }
+
+ return 0;
+}
+
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
{
libusb_device **devs;
@@ -391,11 +416,9 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
setlocale(LC_ALL,"");
- if (!initialized) {
- libusb_init(NULL);
- initialized = 1;
- }
-
+ if (!initialized)
+ hid_init();
+
num_devs = libusb_get_device_list(NULL, &devs);
if (num_devs < 0)
return NULL;
@@ -679,11 +702,7 @@ static void *read_thread(void *param)
/* Handle all the events. */
while (!dev->shutdown_thread) {
int res;
- struct timeval tv;
-
- tv.tv_sec = 0;
- tv.tv_usec = 100; //TODO: Fix this value.
- res = libusb_handle_events_timeout(NULL, &tv);
+ res = libusb_handle_events(NULL);
if (res < 0) {
/* There was an error. Break out of this loop. */
break;
@@ -696,6 +715,15 @@ static void *read_thread(void *param)
/* The transfer was cancelled, so wait for its completion. */
libusb_handle_events(NULL);
}
+
+ /* 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
+ signaled. */
+ pthread_mutex_lock(&dev->mutex);
+ pthread_cond_broadcast(&dev->condition);
+ pthread_mutex_unlock(&dev->mutex);
/* The dev->transfer->buffer and dev->transfer objects are cleaned up
in hid_close(). They are not cleaned up here because this thread
@@ -724,11 +752,9 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
setlocale(LC_ALL,"");
- if (!initialized) {
- libusb_init(NULL);
- initialized = 1;
- }
-
+ if (!initialized)
+ hid_init();
+
num_devs = libusb_get_device_list(NULL, &devs);
while ((usb_dev = devs[d++]) != NULL) {
struct libusb_device_descriptor desc;
@@ -752,6 +778,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
res = libusb_open(usb_dev, &dev->device_handle);
if (res < 0) {
LOG("can't open device\n");
+ free(dev_path);
break;
}
good_open = 1;
@@ -763,6 +790,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
if (res < 0) {
libusb_close(dev->device_handle);
LOG("Unable to detach Kernel Driver\n");
+ free(dev_path);
good_open = 0;
break;
}
@@ -771,6 +799,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
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);
+ free(dev_path);
libusb_close(dev->device_handle);
good_open = 0;
break;
@@ -910,8 +939,14 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length)
return len;
}
+static void cleanup_mutex(void *param)
+{
+ hid_device *dev = param;
+ pthread_mutex_unlock(&dev->mutex);
+}
-int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+
+int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
{
int bytes_read = -1;
@@ -923,6 +958,7 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
#endif
pthread_mutex_lock(&dev->mutex);
+ pthread_cleanup_push(&cleanup_mutex, dev);
/* There's an input report queued up. Return it. */
if (dev->input_reports) {
@@ -938,20 +974,68 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
goto ret;
}
- if (dev->blocking) {
- pthread_cond_wait(&dev->condition, &dev->mutex);
- bytes_read = return_data(dev, data, length);
+ if (milliseconds == -1) {
+ /* Blocking */
+ while (!dev->input_reports && !dev->shutdown_thread) {
+ pthread_cond_wait(&dev->condition, &dev->mutex);
+ }
+ if (dev->input_reports) {
+ bytes_read = return_data(dev, data, length);
+ }
+ }
+ else if (milliseconds > 0) {
+ /* Non-blocking, but called with timeout. */
+ int res;
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += milliseconds / 1000;
+ ts.tv_nsec += (milliseconds % 1000) * 1000000;
+ if (ts.tv_nsec >= 1000000000L) {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000L;
+ }
+
+ while (!dev->input_reports && !dev->shutdown_thread) {
+ res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
+ if (res == 0) {
+ if (dev->input_reports) {
+ bytes_read = return_data(dev, data, length);
+ break;
+ }
+
+ /* If we're here, there was a spurious wake up
+ or the read thread was shutdown. Run the
+ loop again (ie: don't break). */
+ }
+ else if (res == ETIMEDOUT) {
+ /* Timed out. */
+ bytes_read = 0;
+ break;
+ }
+ else {
+ /* Error. */
+ bytes_read = -1;
+ break;
+ }
+ }
}
else {
+ /* Purely non-blocking */
bytes_read = 0;
}
ret:
pthread_mutex_unlock(&dev->mutex);
+ pthread_cleanup_pop(0);
return bytes_read;
}
+int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+ return hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0);
+}
+
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
{
dev->blocking = !nonblock;
View
@@ -69,14 +69,45 @@ extern "C" {
(Windows/Mac only).*/
unsigned short usage;
/** The USB interface which this logical device
- represents (Linux/libusb implementation only). */
+ represents. Valid on both Linux implementations
+ in all cases, and valid on the Windows implementation
+ only if the device contains more than one interface. */
int interface_number;
/** Pointer to the next device */
struct hid_device_info *next;
};
+ /** @brief Initialize the HIDAPI library.
+
+ This function initializes the HIDAPI library. Calling it is not
+ strictly necessary, as it will be called automatically by
+ hid_enumerate() and any of the hid_open_*() functions if it is
+ 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
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_init(void);
+
+ /** @brief Finalize the HIDAPI library.
+
+ This function frees all of the static data associated with
+ HIDAPI. It should be called at the end of execution to avoid
+ memory leaks.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_exit(void);
+
/** @brief Enumerate the HID Devices.
This function returns a linked list of all the HID devices
@@ -169,6 +200,26 @@ extern "C" {
*/
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
+ /** @brief Read an Input report from a HID device with timeout.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @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
+ the report number.
+ @param milliseconds timeout in milliseconds or -1 for blocking wait.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
+
/** @brief Read an Input report from a HID device.
Input reports are returned
Oops, something went wrong.

0 comments on commit b455f59

Please sign in to comment.