diff -Nru libambit-0.2/debian/changelog libambit-0.2/debian/changelog --- libambit-0.2/debian/changelog 2014-08-24 19:57:32.000000000 +0000 +++ libambit-0.2/debian/changelog 2014-09-13 13:47:55.000000000 +0000 @@ -1,3 +1,21 @@ +libambit (0.2-1ubuntu0~ppa7~git20140913) trusty; urgency=medium + + * Exclude patch to remove copied hid-code, this does not work yet. + + -- Dominik Stadler (Ubuntu key) Sat, 13 Sep 2014 15:47:14 +0200 + +libambit (0.2-1ubuntu0~ppa6~git20140913ubuntu1) trusty; urgency=medium + + * Update to latest upstream release. + + -- Dominik Stadler (Ubuntu key) Sat, 13 Sep 2014 10:33:08 +0200 + +libambit (0.2-1ubuntu0~ppa5~git20140824) precise; urgency=medium + + * Upload to precise + + -- Dominik Stadler (Ubuntu key) Sun, 24 Aug 2014 22:22:17 +0200 + libambit (0.2-1ubuntu0~ppa4~git20140824) trusty; urgency=medium * Import current git to get support for current protocol. diff -Nru libambit-0.2/debian/control libambit-0.2/debian/control --- libambit-0.2/debian/control 2014-08-24 19:48:22.000000000 +0000 +++ libambit-0.2/debian/control 2014-08-24 21:28:54.000000000 +0000 @@ -1,7 +1,7 @@ Source: libambit Priority: extra Maintainer: Emil Ljungdahl -Build-Depends: dpkg (>= 1.16.1~), debhelper (>= 9), cmake (>= 2.8.5), libudev-dev, libusb-1.0-0-dev +Build-Depends: dpkg (>= 1.16.1~), debhelper (>= 9), cmake (>= 2.8.5), libudev-dev, libusb-1.0-0-dev, libhidapi-dev Standards-Version: 3.9.4 Section: libs Homepage: http://openambit.org/ diff -Nru libambit-0.2/debian/patches/01_git20140913.patch libambit-0.2/debian/patches/01_git20140913.patch --- libambit-0.2/debian/patches/01_git20140913.patch 1970-01-01 00:00:00.000000000 +0000 +++ libambit-0.2/debian/patches/01_git20140913.patch 2014-09-13 08:28:19.000000000 +0000 @@ -0,0 +1,314 @@ +diff -Nur -x debian -x .git -x .pc ./libambit.c ../openambit.git/src/libambit/libambit.c +--- ./libambit.c 2014-09-13 10:19:26.000000000 +0200 ++++ ../openambit.git/src/libambit/libambit.c 2014-09-13 09:17:12.336656237 +0200 +@@ -22,15 +22,23 @@ + #include "libambit.h" + #include "libambit_int.h" + ++#include + #include + #include + ++#include ++#include ++#include ++#include ++ + /* + * Local definitions + */ + #define SUUNTO_USB_VENDOR_ID 0x1493 + +-struct ambit_supported_device_s { ++typedef struct ambit_known_device_s ambit_known_device_t; ++ ++struct ambit_known_device_s { + uint16_t vid; + uint16_t pid; + char *model; +@@ -45,11 +53,15 @@ + */ + static int device_info_get(ambit_object_t *object, ambit_device_info_t *info); + static int lock_log(ambit_object_t *object, bool lock); ++static uint32_t version_number(const uint8_t version[4]); + + /* + * Static variables + */ +-static ambit_supported_device_t supported_devices[] = { ++static ambit_known_device_t known_devices[] = { ++ { SUUNTO_USB_VENDOR_ID, 0x001c, "Finch", {0x00,0x00,0x00,0x00}, "Suunto Ambit3 Sport", false, 0x0400 }, ++ { SUUNTO_USB_VENDOR_ID, 0x001b, "Emu", {0x00,0x00,0x00,0x00}, "Suunto Ambit3 Peak", false, 0x0400 }, ++ { SUUNTO_USB_VENDOR_ID, 0x001d, "Greentit", {0x00,0x00,0x00,0x00}, "Suunto Ambit2 R", true, 0x0400 }, + { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x01,0x01,0x02,0x00}, "Suunto Ambit2 S", true, 0x0400 }, + { SUUNTO_USB_VENDOR_ID, 0x0019, "Duck", {0x01,0x01,0x02,0x00}, "Suunto Ambit2", true, 0x0400 }, + { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x00,0x02,0x03,0x00}, "Suunto Ambit2 S", false, 0x0400 }, +@@ -64,6 +76,8 @@ + { 0x0000, 0x0000, NULL, {0x00,0x00,0x00,0x00}, NULL, false } + }; + ++static uint8_t komposti_version[] = { 0x01, 0x08, 0x01, 0x00 }; ++ + /* + * Public functions + */ +@@ -73,19 +87,21 @@ + struct hid_device_info *devs, *cur_dev; + ambit_object_t *ret_object = NULL; + int i; +- ambit_supported_device_t *device = NULL; ++ ambit_known_device_t *device = NULL; ++ char *path = NULL; + + LOG_INFO("Searching devices"); + + devs = hid_enumerate(0x0, 0x0); + cur_dev = devs; + while (cur_dev) { +- for (i=0; ivendor_id, cur_dev->product_id); +- if (cur_dev->vendor_id == supported_devices[i].vid && cur_dev->product_id == supported_devices[i].pid) { ++ LOG_INFO("vendor_id=%04x, product_id=%04x", cur_dev->vendor_id, cur_dev->product_id); ++ for (i=0; ivendor_id == known_devices[i].vid && cur_dev->product_id == known_devices[i].pid) { + LOG_INFO("match!"); + // Found at least one supported row, lets remember that! +- device = &supported_devices[i]; ++ device = &known_devices[i]; ++ path = strdup (cur_dev->path); + break; + } + } +@@ -113,24 +129,18 @@ + // Get device info to resolve supported functionality + if (device_info_get(ret_object, &ret_object->device_info) == 0) { + // Let's resolve the correct device +- for (i=0; ivid == supported_devices[i].vid && +- device->pid == supported_devices[i].pid && +- strncmp(device->model, ret_object->device_info.model, LIBAMBIT_MODEL_NAME_LENGTH) == 0 && +- (ret_object->device_info.fw_version[0] > device->min_sw_version[0] || +- (ret_object->device_info.fw_version[0] == device->min_sw_version[0] && +- (ret_object->device_info.fw_version[1] > device->min_sw_version[1] || +- (ret_object->device_info.fw_version[1] == device->min_sw_version[1] && +- (ret_object->device_info.fw_version[2] > device->min_sw_version[2] || +- (ret_object->device_info.fw_version[2] == device->min_sw_version[2] && +- (ret_object->device_info.fw_version[3] >= device->min_sw_version[3])))))))) { ++ for (i=0; ivendor_id == known_devices[i].vid && ++ ret_object->product_id == known_devices[i].pid && ++ strncmp(ret_object->device_info.model, known_devices[i].model, LIBAMBIT_MODEL_NAME_LENGTH) == 0 && ++ (version_number (ret_object->device_info.fw_version) >= version_number (known_devices[i].min_sw_version))) { + // Found matching entry, reset to this one! +- device = &supported_devices[i]; ++ device = &known_devices[i]; + break; + } + } +- ret_object->device = device; + strncpy(ret_object->device_info.name, device->name, LIBAMBIT_PRODUCT_NAME_LENGTH); ++ ret_object->device_info.is_supported = device->supported; + + // Initialize pmem + libambit_pmem20_init(ret_object, device->pmem20_chunksize); +@@ -144,10 +154,19 @@ + } + } + else { ++#ifdef DEBUG_PRINT_ERROR ++ int error = 0; ++ int fd = 0; ++ if (path) fd = open (path, O_RDWR); ++ if (-1 == fd) error = errno; ++ else close (fd); ++#endif + LOG_ERROR("Failed to open device \"%s (%s)\"", device->name, device->model); ++ LOG_ERROR("Reason: %s", (error ? strerror(error) : "Unknown")); + } + } + ++ if (path) free (path); + return ret_object; + } + +@@ -170,8 +189,8 @@ + { + bool ret = false; + +- if (object != NULL && object->device != NULL) { +- ret = object->device->supported; ++ if (object != NULL) { ++ ret = object->device_info.is_supported; + } + + return ret; +@@ -181,7 +200,7 @@ + { + int ret = -1; + +- if (object != NULL && object->device != NULL) { ++ if (object != NULL) { + if (info != NULL) { + memcpy(info, &object->device_info, sizeof(ambit_device_info_t)); + } +@@ -203,8 +222,8 @@ + + int libambit_date_time_set(ambit_object_t *object, struct tm *tm) + { +- uint8_t date_data[8]; +- uint8_t time_data[8] = { 0x09, 0x00, 0x01, 0x00 }; ++ uint8_t date_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 }; ++ uint8_t time_data[8]; + int ret = -1; + + LOG_INFO("Writing date and time to clock"); +@@ -213,9 +232,12 @@ + *(uint16_t*)(&date_data[0]) = htole16(1900 + tm->tm_year); + date_data[2] = 1 + tm->tm_mon; + date_data[3] = tm->tm_mday; +- memset(&date_data[4], 0, 4); // ????? Unknown data ++ // byte[4-7] unknown (but set to 0x28000000 in moveslink) + +- // Set time ++ // Set time (+date) ++ *(uint16_t*)(&time_data[0]) = htole16(1900 + tm->tm_year); ++ time_data[2] = 1 + tm->tm_mon; ++ time_data[3] = tm->tm_mday; + time_data[4] = tm->tm_hour; + time_data[5] = tm->tm_min; + *(uint16_t*)(&time_data[6]) = htole16(1000*tm->tm_sec); +@@ -280,7 +302,7 @@ + size_t replylen = 0; + int ret = -1; + +- if (libambit_protocol_command(object, ambit_command_gps_orbit_head, NULL, 0, &reply_data, &replylen, 0) == 0 && replylen == 9) { ++ if (libambit_protocol_command(object, ambit_command_gps_orbit_head, NULL, 0, &reply_data, &replylen, 0) == 0 && replylen >= 9) { + memcpy(data, &reply_data[1], 8); + libambit_protocol_free(reply_data); + +@@ -492,14 +514,13 @@ + + static int device_info_get(ambit_object_t *object, ambit_device_info_t *info) + { +- uint8_t send_data[] = { 0x01, 0x06, 0x14, 0x00 }; + uint8_t *reply_data = NULL; + size_t replylen; + int ret = -1; + + LOG_INFO("Reading device info"); + +- if (libambit_protocol_command(object, ambit_command_device_info, send_data, sizeof(send_data), &reply_data, &replylen, 1) == 0) { ++ if (libambit_protocol_command(object, ambit_command_device_info, komposti_version, sizeof(komposti_version), &reply_data, &replylen, 1) == 0) { + if (info != NULL) { + memcpy(info->model, reply_data, 16); + info->model[16] = 0; +@@ -511,7 +532,7 @@ + ret = 0; + } + else { +- LOG_WARNING("Failed to read log info"); ++ LOG_WARNING("Failed to device info"); + } + + libambit_protocol_free(reply_data); +@@ -549,3 +570,10 @@ + return ret; + } + ++static uint32_t version_number(const uint8_t version[4]) ++{ ++ return ( (version[0] << 24) ++ | (version[1] << 16) ++ | (version[2] << 0) ++ | (version[3] << 8)); ++} +diff -Nur -x debian -x .git -x .pc ./libambit.h ../openambit.git/src/libambit/libambit.h +--- ./libambit.h 2014-09-13 10:19:26.000000000 +0200 ++++ ../openambit.git/src/libambit/libambit.h 2014-09-13 09:17:12.336656237 +0200 +@@ -42,6 +42,7 @@ + char serial[LIBAMBIT_SERIAL_LENGTH+1]; + uint8_t fw_version[4]; + uint8_t hw_version[4]; ++ bool is_supported; + } ambit_device_info_t; + + typedef struct ambit_device_status_s { +@@ -309,7 +310,7 @@ + uint32_t heartrate_min_time; /* ms */ + uint8_t peak_training_effect; /* effect scale 0.1 */ + uint8_t activity_type; +- char activity_name[16]; ++ char activity_name[16+1]; /* name of activity in ISO 8859-1 */ + int16_t temperature_max; /* degree celsius scale 0.1 */ + int16_t temperature_min; /* degree celsius scale 0.1 */ + uint32_t temperature_max_time; /* ms */ +@@ -324,8 +325,11 @@ + + uint8_t unknown1[5]; + uint8_t unknown2; +- uint8_t unknown3[6]; +- uint8_t unknown4[8]; ++ uint8_t cadence_max; /* rpm */ ++ uint8_t cadence_avg; /* rpm */ ++ uint8_t unknown3[4]; ++ uint32_t cadence_max_time; /* ms */ ++ uint8_t unknown4[4]; + uint8_t unknown5[4]; + uint8_t unknown6[24]; + } ambit_log_header_t; +diff -Nur -x debian -x .git -x .pc ./libambit_int.h ../openambit.git/src/libambit/libambit_int.h +--- ./libambit_int.h 2014-09-13 10:19:26.000000000 +0200 ++++ ../openambit.git/src/libambit/libambit_int.h 2014-08-24 21:17:33.655393176 +0200 +@@ -26,14 +26,11 @@ + #include "hidapi/hidapi.h" + #include "libambit.h" + +-typedef struct ambit_supported_device_s ambit_supported_device_t; +- + struct ambit_object_s { + hid_device *handle; + uint16_t vendor_id; + uint16_t product_id; + uint16_t sequence_no; +- ambit_supported_device_t *device; + ambit_device_info_t device_info; + + struct { +diff -Nur -x debian -x .git -x .pc ./pmem20.c ../openambit.git/src/libambit/pmem20.c +--- ./pmem20.c 2014-09-13 10:19:26.000000000 +0200 ++++ ../openambit.git/src/libambit/pmem20.c 2014-08-23 12:29:25.031629155 +0200 +@@ -379,6 +379,7 @@ + log_header->peak_training_effect = read8inc(data, &offset); + log_header->activity_type = read8inc(data, &offset); + memcpy(log_header->activity_name, data + offset, 16); ++ log_header->activity_name[16] = 0; + offset += 16; + log_header->heartrate_min = read8inc(data, &offset); + +@@ -390,8 +391,11 @@ + log_header->samples_count = read32inc(data, &offset); + log_header->energy_consumption = read16inc(data, &offset); + +- memcpy(log_header->unknown3, data+offset, 6); +- offset += 6; ++ log_header->cadence_max = read8inc(data, &offset); ++ log_header->cadence_avg = read8inc(data, &offset); ++ ++ memcpy(log_header->unknown3, data+offset, 4); ++ offset += 4; + + log_header->speed_max_time = read32inc(data, &offset); + log_header->altitude_max_time = read32inc(data, &offset); +@@ -400,9 +404,10 @@ + log_header->heartrate_min_time = read32inc(data, &offset); + log_header->temperature_max_time = read32inc(data, &offset); + log_header->temperature_min_time = read32inc(data, &offset); ++ log_header->cadence_max_time = read32inc(data, &offset); + +- memcpy(log_header->unknown4, data+offset, 8); +- offset += 8; ++ memcpy(log_header->unknown4, data+offset, 4); ++ offset += 4; + + log_header->first_fix_time = read16inc(data, &offset)*1000; + log_header->battery_start = read8inc(data, &offset); diff -Nru libambit-0.2/debian/patches/02_use_hid_package.patch libambit-0.2/debian/patches/02_use_hid_package.patch --- libambit-0.2/debian/patches/02_use_hid_package.patch 1970-01-01 00:00:00.000000000 +0000 +++ libambit-0.2/debian/patches/02_use_hid_package.patch 2014-08-24 21:28:30.000000000 +0000 @@ -0,0 +1,2718 @@ +Index: libambit/hid-libusb.c +=================================================================== +--- libambit.orig/hid-libusb.c 2014-08-24 23:09:47.560218677 +0200 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,1427 +0,0 @@ +-/******************************************************* +- HIDAPI - Multi-Platform library for +- communication with HID devices. +- +- Alan Ott +- Signal 11 Software +- +- 8/22/2009 +- Linux Version - 6/2/2010 +- Libusb Version - 8/13/2010 +- FreeBSD Version - 11/1/2011 +- +- 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 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. +- These files may also be found in the public source +- code repository located at: +- http://github.com/signal11/hidapi . +-********************************************************/ +- +-#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */ +- +-/* C */ +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* Unix */ +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* GNU / LibUSB */ +-#include "libusb.h" +-#include "iconv.h" +- +-#include "hidapi.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#ifdef DEBUG_PRINTF +-#define LOG(...) fprintf(stderr, __VA_ARGS__) +-#else +-#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, 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(). +-libusb HIDAPI programs are encouraged to use the interface number +-instead to differentiate between interfaces on a composite HID device. */ +-/*#define INVASIVE_GET_USAGE*/ +- +-/* Linked List of input reports received from the device. */ +-struct input_report { +- uint8_t *data; +- size_t len; +- struct input_report *next; +-}; +- +- +-struct hid_device_ { +- /* Handle to the actual device. */ +- libusb_device_handle *device_handle; +- +- /* Endpoint information */ +- int input_endpoint; +- int output_endpoint; +- int input_ep_max_packet_size; +- +- /* The interface number of the HID */ +- int interface; +- +- /* Indexes of Strings */ +- int manufacturer_index; +- int product_index; +- int serial_index; +- +- /* Whether blocking reads are used */ +- int blocking; /* boolean */ +- +- /* Read thread objects */ +- pthread_t thread; +- pthread_mutex_t mutex; /* Protects input_reports */ +- 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 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); +- +-static hid_device *new_hid_device(void) +-{ +- hid_device *dev = calloc(1, sizeof(hid_device)); +- dev->blocking = 1; +- +- pthread_mutex_init(&dev->mutex, NULL); +- pthread_cond_init(&dev->condition, NULL); +- pthread_barrier_init(&dev->barrier, NULL, 2); +- +- return dev; +-} +- +-static void free_hid_device(hid_device *dev) +-{ +- /* Clean up the thread objects */ +- pthread_barrier_destroy(&dev->barrier); +- pthread_cond_destroy(&dev->condition); +- pthread_mutex_destroy(&dev->mutex); +- +- /* Free the device itself */ +- free(dev); +-} +- +-#if 0 +-/*TODO: Implement this funciton on hidapi/libusb.. */ +-static void register_error(hid_device *device, const char *op) +-{ +- +-} +-#endif +- +-#ifdef INVASIVE_GET_USAGE +-/* Get bytes from a HID Report Descriptor. +- Only call with a num_bytes of 0, 1, 2, or 4. */ +-static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur) +-{ +- /* Return if there aren't enough bytes. */ +- if (cur + num_bytes >= len) +- return 0; +- +- if (num_bytes == 0) +- return 0; +- else if (num_bytes == 1) { +- return rpt[cur+1]; +- } +- else if (num_bytes == 2) { +- return (rpt[cur+2] * 256 + rpt[cur+1]); +- } +- else if (num_bytes == 4) { +- return (rpt[cur+4] * 0x01000000 + +- rpt[cur+3] * 0x00010000 + +- rpt[cur+2] * 0x00000100 + +- rpt[cur+1] * 0x00000001); +- } +- else +- return 0; +-} +- +-/* Retrieves the device's Usage Page and Usage from the report +- descriptor. The algorithm is simple, as it just returns the first +- Usage and Usage Page that it finds in the descriptor. +- The return value is 0 on success and -1 on failure. */ +-static int get_usage(uint8_t *report_descriptor, size_t size, +- unsigned short *usage_page, unsigned short *usage) +-{ +- unsigned int i = 0; +- int size_code; +- int data_len, key_size; +- int usage_found = 0, usage_page_found = 0; +- +- while (i < size) { +- int key = report_descriptor[i]; +- int key_cmd = key & 0xfc; +- +- //printf("key: %02hhx\n", key); +- +- if ((key & 0xf0) == 0xf0) { +- /* This is a Long Item. The next byte contains the +- length of the data section (value) for this key. +- See the HID specification, version 1.11, section +- 6.2.2.3, titled "Long Items." */ +- if (i+1 < size) +- data_len = report_descriptor[i+1]; +- else +- data_len = 0; /* malformed report */ +- key_size = 3; +- } +- else { +- /* This is a Short Item. The bottom two bits of the +- key contain the size code for the data section +- (value) for this key. Refer to the HID +- specification, version 1.11, section 6.2.2.2, +- titled "Short Items." */ +- size_code = key & 0x3; +- switch (size_code) { +- case 0: +- case 1: +- case 2: +- data_len = size_code; +- break; +- case 3: +- data_len = 4; +- break; +- default: +- /* Can't ever happen since size_code is & 0x3 */ +- data_len = 0; +- break; +- }; +- key_size = 1; +- } +- +- if (key_cmd == 0x4) { +- *usage_page = get_bytes(report_descriptor, size, data_len, i); +- usage_page_found = 1; +- //printf("Usage Page: %x\n", (uint32_t)*usage_page); +- } +- if (key_cmd == 0x8) { +- *usage = get_bytes(report_descriptor, size, data_len, i); +- usage_found = 1; +- //printf("Usage: %x\n", (uint32_t)*usage); +- } +- +- if (usage_page_found && usage_found) +- return 0; /* success */ +- +- /* Skip over this key and it's associated data */ +- i += data_len + key_size; +- } +- +- return -1; /* failure */ +-} +-#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 +- USB string #0. */ +-static uint16_t get_first_language(libusb_device_handle *dev) +-{ +- uint16_t buf[32]; +- int len; +- +- /* Get the string from libusb. */ +- len = libusb_get_string_descriptor(dev, +- 0x0, /* String ID */ +- 0x0, /* Language */ +- (unsigned char*)buf, +- sizeof(buf)); +- if (len < 4) +- return 0x0; +- +- return buf[1]; /* First two bytes are len and descriptor type. */ +-} +- +-static int is_language_supported(libusb_device_handle *dev, uint16_t lang) +-{ +- uint16_t buf[32]; +- int len; +- int i; +- +- /* Get the string from libusb. */ +- len = libusb_get_string_descriptor(dev, +- 0x0, /* String ID */ +- 0x0, /* Language */ +- (unsigned char*)buf, +- sizeof(buf)); +- if (len < 4) +- return 0x0; +- +- +- len /= 2; /* language IDs are two-bytes each. */ +- /* Start at index 1 because there are two bytes of protocol data. */ +- for (i = 1; i < len; i++) { +- if (buf[i] == lang) +- return 1; +- } +- +- return 0; +-} +- +- +-/* This function returns a newly allocated wide string containing the USB +- device string numbered by the index. The returned string must be freed +- by using free(). */ +-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]; +- +- /* iconv variables */ +- iconv_t ic; +- 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. */ +- uint16_t lang; +- lang = get_usb_code_for_current_locale(); +- if (!is_language_supported(dev, lang)) +- lang = get_first_language(dev); +- +- /* Get the string from libusb. */ +- len = libusb_get_string_descriptor(dev, +- idx, +- lang, +- (unsigned char*)buf, +- sizeof(buf)); +- if (len < 0) +- return NULL; +- +- /* 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("WCHAR_T", "UTF-16LE"); +- if (ic == (iconv_t)-1) { +- LOG("iconv_open() failed\n"); +- return NULL; +- } +- +- /* 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) { +- LOG("iconv() failed\n"); +- goto err; +- } +- +- /* Write the terminating NULL. */ +- wbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000; +- if (outbytes >= sizeof(wbuf[0])) +- *((wchar_t*)outptr) = 0x00000000; +- +- /* Allocate and copy the string. */ +- str = wcsdup(wbuf); +- +-err: +- iconv_close(ic); +- +- return str; +-} +- +-static char *make_path(libusb_device *dev, int interface_number) +-{ +- char str[64]; +- snprintf(str, sizeof(str), "%04x:%04x:%02x", +- libusb_get_bus_number(dev), +- libusb_get_device_address(dev), +- interface_number); +- str[sizeof(str)-1] = '\0'; +- +- return strdup(str); +-} +- +- +-int HID_API_EXPORT hid_init(void) +-{ +- if (!usb_context) { +- const char *locale; +- +- /* Init Libusb */ +- if (libusb_init(&usb_context)) +- return -1; +- +- /* Set the locale if it's not set. */ +- locale = setlocale(LC_CTYPE, NULL); +- if (!locale) +- setlocale(LC_CTYPE, ""); +- } +- +- return 0; +-} +- +-int HID_API_EXPORT hid_exit(void) +-{ +- if (usb_context) { +- libusb_exit(usb_context); +- usb_context = NULL; +- } +- +- return 0; +-} +- +-struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) +-{ +- libusb_device **devs; +- libusb_device *dev; +- libusb_device_handle *handle; +- ssize_t num_devs; +- int i = 0; +- +- struct hid_device_info *root = NULL; /* return object */ +- struct hid_device_info *cur_dev = NULL; +- +- if(hid_init() < 0) +- return NULL; +- +- num_devs = libusb_get_device_list(usb_context, &devs); +- if (num_devs < 0) +- return NULL; +- while ((dev = devs[i++]) != NULL) { +- struct libusb_device_descriptor desc; +- struct libusb_config_descriptor *conf_desc = NULL; +- int j, k; +- int interface_num = 0; +- +- int res = libusb_get_device_descriptor(dev, &desc); +- unsigned short dev_vid = desc.idVendor; +- unsigned short dev_pid = desc.idProduct; +- +- res = libusb_get_active_config_descriptor(dev, &conf_desc); +- if (res < 0) +- libusb_get_config_descriptor(dev, 0, &conf_desc); +- if (conf_desc) { +- for (j = 0; j < conf_desc->bNumInterfaces; j++) { +- const struct libusb_interface *intf = &conf_desc->interface[j]; +- for (k = 0; k < intf->num_altsetting; k++) { +- const struct libusb_interface_descriptor *intf_desc; +- intf_desc = &intf->altsetting[k]; +- if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { +- interface_num = intf_desc->bInterfaceNumber; +- +- /* Check the VID/PID against the arguments */ +- 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. */ +- tmp = calloc(1, sizeof(struct hid_device_info)); +- if (cur_dev) { +- cur_dev->next = tmp; +- } +- else { +- root = tmp; +- } +- cur_dev = tmp; +- +- /* Fill out the record */ +- cur_dev->next = NULL; +- cur_dev->path = make_path(dev, interface_num); +- +- res = libusb_open(dev, &handle); +- +- if (res >= 0) { +- /* Serial Number */ +- if (desc.iSerialNumber > 0) +- cur_dev->serial_number = +- get_usb_string(handle, desc.iSerialNumber); +- +- /* Manufacturer and Product strings */ +- if (desc.iManufacturer > 0) +- cur_dev->manufacturer_string = +- get_usb_string(handle, desc.iManufacturer); +- if (desc.iProduct > 0) +- cur_dev->product_string = +- 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 +- and Usage requires parsing the HID Report +- descriptor. Getting a HID Report descriptor +- involves claiming the interface. Claiming the +- interface involves detaching the kernel driver. +- Detaching the kernel driver is hard on the system +- because it will unclaim interfaces (if another +- app has them claimed) and the re-attachment of +- the driver will sometimes change /dev entry names. +- It is for these reasons that this section is +- #if 0. For composite devices, use the interface +- field in the hid_device_info struct to distinguish +- between interfaces. */ +- 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) { +- res = libusb_detach_kernel_driver(handle, interface_num); +- if (res < 0) +- LOG("Couldn't detach kernel driver, even though a kernel driver was attached."); +- else +- detached = 1; +- } +-#endif +- res = libusb_claim_interface(handle, interface_num); +- if (res >= 0) { +- /* Get the HID Report Descriptor. */ +- res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000); +- if (res >= 0) { +- unsigned short page=0, usage=0; +- /* Parse the usage and usage page +- out of the report descriptor. */ +- get_usage(data, res, &page, &usage); +- cur_dev->usage_page = page; +- cur_dev->usage = usage; +- } +- else +- LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res); +- +- /* Release the interface */ +- res = libusb_release_interface(handle, interface_num); +- if (res < 0) +- LOG("Can't release the interface.\n"); +- } +- 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 /* INVASIVE_GET_USAGE */ +- +- libusb_close(handle); +- } +- /* VID/PID */ +- cur_dev->vendor_id = dev_vid; +- cur_dev->product_id = dev_pid; +- +- /* Release Number */ +- cur_dev->release_number = desc.bcdDevice; +- +- /* Interface Number */ +- cur_dev->interface_number = interface_num; +- } +- } +- } /* altsettings */ +- } /* interfaces */ +- libusb_free_config_descriptor(conf_desc); +- } +- } +- +- libusb_free_device_list(devs, 1); +- +- return root; +-} +- +-void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) +-{ +- struct hid_device_info *d = devs; +- while (d) { +- struct hid_device_info *next = d->next; +- free(d->path); +- free(d->serial_number); +- free(d->manufacturer_string); +- free(d->product_string); +- free(d); +- d = next; +- } +-} +- +-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; +- hid_device *handle = NULL; +- +- devs = hid_enumerate(vendor_id, product_id); +- cur_dev = devs; +- while (cur_dev) { +- 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) { +- path_to_open = cur_dev->path; +- break; +- } +- } +- else { +- path_to_open = cur_dev->path; +- break; +- } +- } +- cur_dev = cur_dev->next; +- } +- +- if (path_to_open) { +- /* Open the device */ +- handle = hid_open_path(path_to_open); +- } +- +- hid_free_enumeration(devs); +- +- return handle; +-} +- +-static void read_callback(struct libusb_transfer *transfer) +-{ +- hid_device *dev = transfer->user_data; +- int res; +- +- if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { +- +- struct input_report *rpt = malloc(sizeof(*rpt)); +- rpt->data = malloc(transfer->actual_length); +- memcpy(rpt->data, transfer->buffer, transfer->actual_length); +- rpt->len = transfer->actual_length; +- rpt->next = NULL; +- +- pthread_mutex_lock(&dev->mutex); +- +- /* Attach the new report object to the end of the list. */ +- if (dev->input_reports == NULL) { +- /* The list is empty. Put it at the root. */ +- dev->input_reports = rpt; +- pthread_cond_signal(&dev->condition); +- } +- else { +- /* Find the end of the list and attach. */ +- struct input_report *cur = dev->input_reports; +- int num_queued = 0; +- while (cur->next != NULL) { +- cur = cur->next; +- num_queued++; +- } +- cur->next = rpt; +- +- /* Pop one off if we've reached 30 in the queue. This +- way we don't grow forever if the user never reads +- anything from the device. */ +- if (num_queued > 30) { +- return_data(dev, NULL, 0); +- } +- } +- pthread_mutex_unlock(&dev->mutex); +- } +- 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) { +- //LOG("Timeout (normal)\n"); +- } +- else { +- LOG("Unknown transfer code: %d\n", transfer->status); +- } +- +- /* Re-submit the transfer object. */ +- 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; +- } +-} +- +- +-static void *read_thread(void *param) +-{ +- hid_device *dev = param; +- unsigned char *buf; +- const size_t length = dev->input_ep_max_packet_size; +- +- /* Set up the transfer object. */ +- buf = malloc(length); +- dev->transfer = libusb_alloc_transfer(0); +- libusb_fill_interrupt_transfer(dev->transfer, +- dev->device_handle, +- dev->input_endpoint, +- buf, +- length, +- read_callback, +- dev, +- 5000/*timeout*/); +- +- /* Make the first submission. Further submissions are made +- from inside read_callback() */ +- libusb_submit_transfer(dev->transfer); +- +- /* 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(usb_context); +- if (res < 0) { +- /* 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. */ +- 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 +- 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 +- could end either due to a disconnect or due to a user +- call to hid_close(). In both cases the objects can be safely +- cleaned up after the call to pthread_join() (in hid_close()), but +- since hid_close() calls libusb_cancel_transfer(), on these objects, +- they can not be cleaned up here. */ +- +- return NULL; +-} +- +- +-hid_device * HID_API_EXPORT hid_open_path(const char *path) +-{ +- hid_device *dev = NULL; +- +- libusb_device **devs; +- libusb_device *usb_dev; +- int res; +- int d = 0; +- int good_open = 0; +- +- 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; +- struct libusb_config_descriptor *conf_desc = NULL; +- int i,j,k; +- libusb_get_device_descriptor(usb_dev, &desc); +- +- if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0) +- continue; +- for (j = 0; j < conf_desc->bNumInterfaces; j++) { +- const struct libusb_interface *intf = &conf_desc->interface[j]; +- for (k = 0; k < intf->num_altsetting; k++) { +- const struct libusb_interface_descriptor *intf_desc; +- intf_desc = &intf->altsetting[k]; +- if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { +- char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber); +- if (!strcmp(dev_path, path)) { +- /* Matched Paths. Open this device */ +- +- /* OPEN HERE */ +- res = libusb_open(usb_dev, &dev->device_handle); +- if (res < 0) { +- LOG("can't open device\n"); +- free(dev_path); +- 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) { +- res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber); +- if (res < 0) { +- libusb_close(dev->device_handle); +- LOG("Unable to detach Kernel Driver\n"); +- free(dev_path); +- good_open = 0; +- 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); +- free(dev_path); +- libusb_close(dev->device_handle); +- good_open = 0; +- break; +- } +- +- /* Store off the string descriptor indexes */ +- dev->manufacturer_index = desc.iManufacturer; +- dev->product_index = desc.iProduct; +- dev->serial_index = desc.iSerialNumber; +- +- /* Store off the interface number */ +- dev->interface = intf_desc->bInterfaceNumber; +- +- /* Find the INPUT and OUTPUT endpoints. An +- OUTPUT endpoint is not required. */ +- for (i = 0; i < intf_desc->bNumEndpoints; i++) { +- const struct libusb_endpoint_descriptor *ep +- = &intf_desc->endpoint[i]; +- +- /* Determine the type and direction of this +- endpoint. */ +- int is_interrupt = +- (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) +- == LIBUSB_TRANSFER_TYPE_INTERRUPT; +- int is_output = +- (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) +- == LIBUSB_ENDPOINT_OUT; +- int is_input = +- (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) +- == LIBUSB_ENDPOINT_IN; +- +- /* Decide whether to use it for intput or output. */ +- if (dev->input_endpoint == 0 && +- is_interrupt && is_input) { +- /* Use this endpoint for INPUT */ +- dev->input_endpoint = ep->bEndpointAddress; +- dev->input_ep_max_packet_size = ep->wMaxPacketSize; +- } +- if (dev->output_endpoint == 0 && +- is_interrupt && is_output) { +- /* Use this endpoint for OUTPUT */ +- dev->output_endpoint = ep->bEndpointAddress; +- } +- } +- +- pthread_create(&dev->thread, NULL, read_thread, dev); +- +- /* Wait here for the read thread to be initialized. */ +- pthread_barrier_wait(&dev->barrier); +- +- } +- free(dev_path); +- } +- } +- } +- libusb_free_config_descriptor(conf_desc); +- +- } +- +- libusb_free_device_list(devs, 1); +- +- /* If we have a good handle, return it. */ +- if (good_open) { +- return dev; +- } +- else { +- /* Unable to open any devices. */ +- free_hid_device(dev); +- return NULL; +- } +-} +- +- +-int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) +-{ +- int res; +- int report_number = data[0]; +- int skipped_report_id = 0; +- +- if (report_number == 0x0) { +- data++; +- length--; +- skipped_report_id = 1; +- } +- +- +- if (dev->output_endpoint <= 0) { +- /* No interrput 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*/, +- (2/*HID output*/ << 8) | report_number, +- dev->interface, +- (unsigned char *)data, length, +- 1000/*timeout millis*/); +- +- if (res < 0) +- return -1; +- +- if (skipped_report_id) +- length++; +- +- return length; +- } +- else { +- /* Use the interrupt out endpoint */ +- int actual_length; +- res = libusb_interrupt_transfer(dev->device_handle, +- dev->output_endpoint, +- (unsigned char*)data, +- length, +- &actual_length, 1000); +- +- if (res < 0) +- return -1; +- +- if (skipped_report_id) +- actual_length++; +- +- return actual_length; +- } +-} +- +-/* Helper function, to simplify hid_read(). +- This should be called with dev->mutex locked. */ +-static int return_data(hid_device *dev, unsigned char *data, size_t length) +-{ +- /* Copy the data out of the linked list item (rpt) into the +- return buffer (data), and delete the liked list item. */ +- struct input_report *rpt = dev->input_reports; +- size_t len = (length < rpt->len)? length: rpt->len; +- if (len > 0) +- memcpy(data, rpt->data, len); +- dev->input_reports = rpt->next; +- free(rpt->data); +- free(rpt); +- return len; +-} +- +-static void cleanup_mutex(void *param) +-{ +- hid_device *dev = param; +- pthread_mutex_unlock(&dev->mutex); +-} +- +- +-int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +-{ +- int bytes_read = -1; +- +-#if 0 +- int transferred; +- int res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint, data, length, &transferred, 5000); +- LOG("transferred: %d\n", transferred); +- return transferred; +-#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) { +- /* Return the first one */ +- bytes_read = return_data(dev, data, length); +- goto ret; +- } +- +- if (dev->shutdown_thread) { +- /* This means the device has been disconnected. +- An error code of -1 should be returned. */ +- bytes_read = -1; +- goto ret; +- } +- +- 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; +- +- return 0; +-} +- +- +-int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +-{ +- int res = -1; +- int skipped_report_id = 0; +- int report_number = data[0]; +- +- if (report_number == 0x0) { +- data++; +- length--; +- skipped_report_id = 1; +- } +- +- res = libusb_control_transfer(dev->device_handle, +- LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, +- 0x09/*HID set_report*/, +- (3/*HID feature*/ << 8) | report_number, +- dev->interface, +- (unsigned char *)data, length, +- 1000/*timeout millis*/); +- +- if (res < 0) +- return -1; +- +- /* Account for the report ID */ +- if (skipped_report_id) +- length++; +- +- return length; +-} +- +-int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +-{ +- int res = -1; +- int skipped_report_id = 0; +- int report_number = data[0]; +- +- if (report_number == 0x0) { +- /* Offset the return buffer by 1, so that the report ID +- will remain in byte 0. */ +- data++; +- length--; +- skipped_report_id = 1; +- } +- res = libusb_control_transfer(dev->device_handle, +- LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN, +- 0x01/*HID get_report*/, +- (3/*HID feature*/ << 8) | report_number, +- dev->interface, +- (unsigned char *)data, length, +- 1000/*timeout millis*/); +- +- if (res < 0) +- return -1; +- +- if (skipped_report_id) +- res++; +- +- return res; +-} +- +- +-void HID_API_EXPORT hid_close(hid_device *dev) +-{ +- if (!dev) +- return; +- +- /* Cause read_thread() to stop. */ +- dev->shutdown_thread = 1; +- libusb_cancel_transfer(dev->transfer); +- +- /* Wait for read_thread() to end. */ +- pthread_join(dev->thread, NULL); +- +- /* Clean up the Transfer objects allocated in read_thread(). */ +- free(dev->transfer->buffer); +- libusb_free_transfer(dev->transfer); +- +- /* release the interface */ +- libusb_release_interface(dev->device_handle, dev->interface); +- +- /* Close the handle */ +- libusb_close(dev->device_handle); +- +- /* Clear out the queue of received reports. */ +- pthread_mutex_lock(&dev->mutex); +- while (dev->input_reports) { +- return_data(dev, NULL, 0); +- } +- pthread_mutex_unlock(&dev->mutex); +- +- free_hid_device(dev); +-} +- +- +-int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- return hid_get_indexed_string(dev, dev->manufacturer_index, string, maxlen); +-} +- +-int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- return hid_get_indexed_string(dev, dev->product_index, string, maxlen); +-} +- +-int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- return hid_get_indexed_string(dev, dev->serial_index, string, maxlen); +-} +- +-int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +-{ +- wchar_t *str; +- +- str = get_usb_string(dev->device_handle, string_index); +- if (str) { +- wcsncpy(string, str, maxlen); +- string[maxlen-1] = L'\0'; +- free(str); +- return 0; +- } +- else +- return -1; +-} +- +- +-HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +-{ +- return NULL; +-} +- +- +-struct lang_map_entry { +- const char *name; +- const char *string_code; +- uint16_t usb_code; +-}; +- +-#define LANG(name,code,usb_code) { name, code, usb_code } +-static struct lang_map_entry lang_map[] = { +- LANG("Afrikaans", "af", 0x0436), +- LANG("Albanian", "sq", 0x041C), +- LANG("Arabic - United Arab Emirates", "ar_ae", 0x3801), +- LANG("Arabic - Bahrain", "ar_bh", 0x3C01), +- LANG("Arabic - Algeria", "ar_dz", 0x1401), +- LANG("Arabic - Egypt", "ar_eg", 0x0C01), +- LANG("Arabic - Iraq", "ar_iq", 0x0801), +- LANG("Arabic - Jordan", "ar_jo", 0x2C01), +- LANG("Arabic - Kuwait", "ar_kw", 0x3401), +- LANG("Arabic - Lebanon", "ar_lb", 0x3001), +- LANG("Arabic - Libya", "ar_ly", 0x1001), +- LANG("Arabic - Morocco", "ar_ma", 0x1801), +- LANG("Arabic - Oman", "ar_om", 0x2001), +- LANG("Arabic - Qatar", "ar_qa", 0x4001), +- LANG("Arabic - Saudi Arabia", "ar_sa", 0x0401), +- LANG("Arabic - Syria", "ar_sy", 0x2801), +- LANG("Arabic - Tunisia", "ar_tn", 0x1C01), +- LANG("Arabic - Yemen", "ar_ye", 0x2401), +- LANG("Armenian", "hy", 0x042B), +- LANG("Azeri - Latin", "az_az", 0x042C), +- LANG("Azeri - Cyrillic", "az_az", 0x082C), +- LANG("Basque", "eu", 0x042D), +- LANG("Belarusian", "be", 0x0423), +- LANG("Bulgarian", "bg", 0x0402), +- LANG("Catalan", "ca", 0x0403), +- LANG("Chinese - China", "zh_cn", 0x0804), +- LANG("Chinese - Hong Kong SAR", "zh_hk", 0x0C04), +- LANG("Chinese - Macau SAR", "zh_mo", 0x1404), +- LANG("Chinese - Singapore", "zh_sg", 0x1004), +- LANG("Chinese - Taiwan", "zh_tw", 0x0404), +- LANG("Croatian", "hr", 0x041A), +- LANG("Czech", "cs", 0x0405), +- LANG("Danish", "da", 0x0406), +- LANG("Dutch - Netherlands", "nl_nl", 0x0413), +- LANG("Dutch - Belgium", "nl_be", 0x0813), +- LANG("English - Australia", "en_au", 0x0C09), +- LANG("English - Belize", "en_bz", 0x2809), +- LANG("English - Canada", "en_ca", 0x1009), +- LANG("English - Caribbean", "en_cb", 0x2409), +- LANG("English - Ireland", "en_ie", 0x1809), +- LANG("English - Jamaica", "en_jm", 0x2009), +- LANG("English - New Zealand", "en_nz", 0x1409), +- LANG("English - Phillippines", "en_ph", 0x3409), +- LANG("English - Southern Africa", "en_za", 0x1C09), +- LANG("English - Trinidad", "en_tt", 0x2C09), +- LANG("English - Great Britain", "en_gb", 0x0809), +- LANG("English - United States", "en_us", 0x0409), +- LANG("Estonian", "et", 0x0425), +- LANG("Farsi", "fa", 0x0429), +- LANG("Finnish", "fi", 0x040B), +- LANG("Faroese", "fo", 0x0438), +- LANG("French - France", "fr_fr", 0x040C), +- LANG("French - Belgium", "fr_be", 0x080C), +- LANG("French - Canada", "fr_ca", 0x0C0C), +- LANG("French - Luxembourg", "fr_lu", 0x140C), +- LANG("French - Switzerland", "fr_ch", 0x100C), +- LANG("Gaelic - Ireland", "gd_ie", 0x083C), +- LANG("Gaelic - Scotland", "gd", 0x043C), +- LANG("German - Germany", "de_de", 0x0407), +- LANG("German - Austria", "de_at", 0x0C07), +- LANG("German - Liechtenstein", "de_li", 0x1407), +- LANG("German - Luxembourg", "de_lu", 0x1007), +- LANG("German - Switzerland", "de_ch", 0x0807), +- LANG("Greek", "el", 0x0408), +- LANG("Hebrew", "he", 0x040D), +- LANG("Hindi", "hi", 0x0439), +- LANG("Hungarian", "hu", 0x040E), +- LANG("Icelandic", "is", 0x040F), +- LANG("Indonesian", "id", 0x0421), +- LANG("Italian - Italy", "it_it", 0x0410), +- LANG("Italian - Switzerland", "it_ch", 0x0810), +- LANG("Japanese", "ja", 0x0411), +- LANG("Korean", "ko", 0x0412), +- LANG("Latvian", "lv", 0x0426), +- LANG("Lithuanian", "lt", 0x0427), +- LANG("F.Y.R.O. Macedonia", "mk", 0x042F), +- LANG("Malay - Malaysia", "ms_my", 0x043E), +- LANG("Malay – Brunei", "ms_bn", 0x083E), +- LANG("Maltese", "mt", 0x043A), +- LANG("Marathi", "mr", 0x044E), +- LANG("Norwegian - Bokml", "no_no", 0x0414), +- LANG("Norwegian - Nynorsk", "no_no", 0x0814), +- LANG("Polish", "pl", 0x0415), +- LANG("Portuguese - Portugal", "pt_pt", 0x0816), +- LANG("Portuguese - Brazil", "pt_br", 0x0416), +- LANG("Raeto-Romance", "rm", 0x0417), +- LANG("Romanian - Romania", "ro", 0x0418), +- LANG("Romanian - Republic of Moldova", "ro_mo", 0x0818), +- LANG("Russian", "ru", 0x0419), +- LANG("Russian - Republic of Moldova", "ru_mo", 0x0819), +- LANG("Sanskrit", "sa", 0x044F), +- LANG("Serbian - Cyrillic", "sr_sp", 0x0C1A), +- LANG("Serbian - Latin", "sr_sp", 0x081A), +- LANG("Setsuana", "tn", 0x0432), +- LANG("Slovenian", "sl", 0x0424), +- LANG("Slovak", "sk", 0x041B), +- LANG("Sorbian", "sb", 0x042E), +- LANG("Spanish - Spain (Traditional)", "es_es", 0x040A), +- LANG("Spanish - Argentina", "es_ar", 0x2C0A), +- LANG("Spanish - Bolivia", "es_bo", 0x400A), +- LANG("Spanish - Chile", "es_cl", 0x340A), +- LANG("Spanish - Colombia", "es_co", 0x240A), +- LANG("Spanish - Costa Rica", "es_cr", 0x140A), +- LANG("Spanish - Dominican Republic", "es_do", 0x1C0A), +- LANG("Spanish - Ecuador", "es_ec", 0x300A), +- LANG("Spanish - Guatemala", "es_gt", 0x100A), +- LANG("Spanish - Honduras", "es_hn", 0x480A), +- LANG("Spanish - Mexico", "es_mx", 0x080A), +- LANG("Spanish - Nicaragua", "es_ni", 0x4C0A), +- LANG("Spanish - Panama", "es_pa", 0x180A), +- LANG("Spanish - Peru", "es_pe", 0x280A), +- LANG("Spanish - Puerto Rico", "es_pr", 0x500A), +- LANG("Spanish - Paraguay", "es_py", 0x3C0A), +- LANG("Spanish - El Salvador", "es_sv", 0x440A), +- LANG("Spanish - Uruguay", "es_uy", 0x380A), +- LANG("Spanish - Venezuela", "es_ve", 0x200A), +- LANG("Southern Sotho", "st", 0x0430), +- LANG("Swahili", "sw", 0x0441), +- LANG("Swedish - Sweden", "sv_se", 0x041D), +- LANG("Swedish - Finland", "sv_fi", 0x081D), +- LANG("Tamil", "ta", 0x0449), +- LANG("Tatar", "tt", 0X0444), +- LANG("Thai", "th", 0x041E), +- LANG("Turkish", "tr", 0x041F), +- LANG("Tsonga", "ts", 0x0431), +- LANG("Ukrainian", "uk", 0x0422), +- LANG("Urdu", "ur", 0x0420), +- LANG("Uzbek - Cyrillic", "uz_uz", 0x0843), +- LANG("Uzbek – Latin", "uz_uz", 0x0443), +- LANG("Vietnamese", "vi", 0x042A), +- LANG("Xhosa", "xh", 0x0434), +- LANG("Yiddish", "yi", 0x043D), +- LANG("Zulu", "zu", 0x0435), +- LANG(NULL, NULL, 0x0), +-}; +- +-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); +- if (!locale) +- return 0x0; +- +- /* Make a copy of the current locale string. */ +- strncpy(search_string, locale, sizeof(search_string)); +- search_string[sizeof(search_string)-1] = '\0'; +- +- /* Chop off the encoding part, and make it lower case. */ +- ptr = search_string; +- while (*ptr) { +- *ptr = tolower(*ptr); +- if (*ptr == '.') { +- *ptr = '\0'; +- break; +- } +- ptr++; +- } +- +- /* Find the entry which matches the string code of our locale. */ +- lang = lang_map; +- while (lang->string_code) { +- if (!strcmp(lang->string_code, search_string)) { +- return lang->usb_code; +- } +- lang++; +- } +- +- /* There was no match. Find with just the language only. */ +- /* Chop off the variant. Chop it off at the '_'. */ +- ptr = search_string; +- while (*ptr) { +- *ptr = tolower(*ptr); +- if (*ptr == '_') { +- *ptr = '\0'; +- break; +- } +- ptr++; +- } +- +-#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) { +- if (!strcmp(lang->string_code, search_string)) { +- return lang->usb_code; +- } +- lang++; +- } +-#endif +- +- /* Found nothing. */ +- return 0x0; +-} +- +-#ifdef __cplusplus +-} +-#endif +Index: libambit/hid.c +=================================================================== +--- libambit.orig/hid.c 2014-08-24 23:09:47.560218677 +0200 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,795 +0,0 @@ +-/******************************************************* +- HIDAPI - Multi-Platform library for +- communication with HID devices. +- +- Alan Ott +- Signal 11 Software +- +- 8/22/2009 +- Linux Version - 6/2/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 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. +- These files may also be found in the public source +- code repository located at: +- http://github.com/signal11/hidapi . +-********************************************************/ +- +-/* C */ +-#include +-#include +-#include +-#include +-#include +- +-/* Unix */ +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* Linux */ +-#include +-#include +-#include +-#include +- +-#include "hidapi.h" +- +-/* Definitions from linux/hidraw.h. Since these are new, some distros +- may not have header files which contain them. */ +-#ifndef HIDIOCSFEATURE +-#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) +-#endif +-#ifndef HIDIOCGFEATURE +-#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) +-#endif +- +- +-/* USB HID device property names */ +-const char *device_string_names[] = { +- "manufacturer", +- "product", +- "serial", +-}; +- +-/* Symbolic names for the properties above */ +-enum device_string_id { +- DEVICE_STRING_MANUFACTURER, +- DEVICE_STRING_PRODUCT, +- DEVICE_STRING_SERIAL, +- +- DEVICE_STRING_COUNT, +-}; +- +-struct hid_device_ { +- int device_handle; +- int blocking; +- int uses_numbered_reports; +-}; +- +- +-static __u32 kernel_version = 0; +- +-static __u32 detect_kernel_version(void) +-{ +- struct utsname name; +- int major, minor, release; +- int ret; +- +- uname(&name); +- ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release); +- if (ret == 3) { +- return KERNEL_VERSION(major, minor, release); +- } +- +- ret = sscanf(name.release, "%d.%d", &major, &minor); +- if (ret == 2) { +- return KERNEL_VERSION(major, minor, 0); +- } +- +- printf("Couldn't determine kernel version from version string \"%s\"\n", name.release); +- return 0; +-} +- +-static hid_device *new_hid_device(void) +-{ +- hid_device *dev = calloc(1, sizeof(hid_device)); +- dev->device_handle = -1; +- dev->blocking = 1; +- dev->uses_numbered_reports = 0; +- +- return dev; +-} +- +- +-/* The caller must free the returned string with free(). */ +-static wchar_t *utf8_to_wchar_t(const char *utf8) +-{ +- wchar_t *ret = NULL; +- +- if (utf8) { +- size_t wlen = mbstowcs(NULL, utf8, 0); +- if ((size_t) -1 == wlen) { +- return wcsdup(L""); +- } +- ret = calloc(wlen+1, sizeof(wchar_t)); +- mbstowcs(ret, utf8, wlen+1); +- ret[wlen] = 0x0000; +- } +- +- return ret; +-} +- +-/* Get an attribute value from a udev_device and return it as a whar_t +- string. The returned string must be freed with free() when done.*/ +-static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name) +-{ +- return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name)); +-} +- +-/* uses_numbered_reports() returns 1 if report_descriptor describes a device +- which contains numbered reports. */ +-static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) { +- unsigned int i = 0; +- int size_code; +- int data_len, key_size; +- +- while (i < size) { +- int key = report_descriptor[i]; +- +- /* Check for the Report ID key */ +- if (key == 0x85/*Report ID*/) { +- /* This device has a Report ID, which means it uses +- numbered reports. */ +- return 1; +- } +- +- //printf("key: %02hhx\n", key); +- +- if ((key & 0xf0) == 0xf0) { +- /* This is a Long Item. The next byte contains the +- length of the data section (value) for this key. +- See the HID specification, version 1.11, section +- 6.2.2.3, titled "Long Items." */ +- if (i+1 < size) +- data_len = report_descriptor[i+1]; +- else +- data_len = 0; /* malformed report */ +- key_size = 3; +- } +- else { +- /* This is a Short Item. The bottom two bits of the +- key contain the size code for the data section +- (value) for this key. Refer to the HID +- specification, version 1.11, section 6.2.2.2, +- titled "Short Items." */ +- size_code = key & 0x3; +- switch (size_code) { +- case 0: +- case 1: +- case 2: +- data_len = size_code; +- break; +- case 3: +- data_len = 4; +- break; +- default: +- /* Can't ever happen since size_code is & 0x3 */ +- data_len = 0; +- break; +- }; +- key_size = 1; +- } +- +- /* Skip over this key and it's associated data */ +- i += data_len + key_size; +- } +- +- /* Didn't find a Report ID key. Device doesn't use numbered reports. */ +- return 0; +-} +- +-/* +- * The caller is responsible for free()ing the (newly-allocated) character +- * strings pointed to by serial_number_utf8 and product_name_utf8 after use. +- */ +-static int +-parse_uevent_info(const char *uevent, int *bus_type, +- unsigned short *vendor_id, unsigned short *product_id, +- char **serial_number_utf8, char **product_name_utf8) +-{ +- char *tmp = strdup(uevent); +- char *saveptr = NULL; +- char *line; +- char *key; +- char *value; +- +- int found_id = 0; +- int found_serial = 0; +- int found_name = 0; +- +- line = strtok_r(tmp, "\n", &saveptr); +- while (line != NULL) { +- /* line: "KEY=value" */ +- key = line; +- value = strchr(line, '='); +- if (!value) { +- goto next_line; +- } +- *value = '\0'; +- value++; +- +- if (strcmp(key, "HID_ID") == 0) { +- /** +- * type vendor product +- * HID_ID=0003:000005AC:00008242 +- **/ +- int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id); +- if (ret == 3) { +- found_id = 1; +- } +- } else if (strcmp(key, "HID_NAME") == 0) { +- /* The caller has to free the product name */ +- *product_name_utf8 = strdup(value); +- found_name = 1; +- } else if (strcmp(key, "HID_UNIQ") == 0) { +- /* The caller has to free the serial number */ +- *serial_number_utf8 = strdup(value); +- found_serial = 1; +- } +- +-next_line: +- line = strtok_r(NULL, "\n", &saveptr); +- } +- +- free(tmp); +- return (found_id && found_name && found_serial); +-} +- +- +-static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen) +-{ +- struct udev *udev; +- struct udev_device *udev_dev, *parent, *hid_dev; +- struct stat s; +- int ret = -1; +- char *serial_number_utf8 = NULL; +- char *product_name_utf8 = NULL; +- +- /* Create the udev object */ +- udev = udev_new(); +- if (!udev) { +- printf("Can't create udev\n"); +- return -1; +- } +- +- /* Get the dev_t (major/minor numbers) from the file handle. */ +- fstat(dev->device_handle, &s); +- /* Open a udev device from the dev_t. 'c' means character device. */ +- udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev); +- if (udev_dev) { +- hid_dev = udev_device_get_parent_with_subsystem_devtype( +- udev_dev, +- "hid", +- NULL); +- if (hid_dev) { +- unsigned short dev_vid; +- unsigned short dev_pid; +- int bus_type; +- size_t retm; +- +- ret = parse_uevent_info( +- udev_device_get_sysattr_value(hid_dev, "uevent"), +- &bus_type, +- &dev_vid, +- &dev_pid, +- &serial_number_utf8, +- &product_name_utf8); +- +- if (bus_type == BUS_BLUETOOTH) { +- switch (key) { +- case DEVICE_STRING_MANUFACTURER: +- wcsncpy(string, L"", maxlen); +- ret = 0; +- break; +- case DEVICE_STRING_PRODUCT: +- retm = mbstowcs(string, product_name_utf8, maxlen); +- ret = (retm == (size_t)-1)? -1: 0; +- break; +- case DEVICE_STRING_SERIAL: +- retm = mbstowcs(string, serial_number_utf8, maxlen); +- ret = (retm == (size_t)-1)? -1: 0; +- break; +- case DEVICE_STRING_COUNT: +- default: +- ret = -1; +- break; +- } +- } +- else { +- /* This is a USB device. Find its parent USB Device node. */ +- parent = udev_device_get_parent_with_subsystem_devtype( +- udev_dev, +- "usb", +- "usb_device"); +- if (parent) { +- const char *str; +- const char *key_str = NULL; +- +- if (key >= 0 && key < DEVICE_STRING_COUNT) { +- key_str = device_string_names[key]; +- } else { +- ret = -1; +- goto end; +- } +- +- str = udev_device_get_sysattr_value(parent, key_str); +- if (str) { +- /* Convert the string from UTF-8 to wchar_t */ +- retm = mbstowcs(string, str, maxlen); +- ret = (retm == (size_t)-1)? -1: 0; +- goto end; +- } +- } +- } +- } +- } +- +-end: +- free(serial_number_utf8); +- free(product_name_utf8); +- +- udev_device_unref(udev_dev); +- /* parent and hid_dev don't need to be (and can't be) unref'd. +- I'm not sure why, but they'll throw double-free() errors. */ +- udev_unref(udev); +- +- return ret; +-} +- +-int HID_API_EXPORT hid_init(void) +-{ +- const char *locale; +- +- /* Set the locale if it's not set. */ +- locale = setlocale(LC_CTYPE, NULL); +- if (!locale) +- setlocale(LC_CTYPE, ""); +- +- kernel_version = detect_kernel_version(); +- +- return 0; +-} +- +-int HID_API_EXPORT hid_exit(void) +-{ +- /* Nothing to do for this in the Linux/hidraw implementation. */ +- return 0; +-} +- +- +-struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) +-{ +- struct udev *udev; +- struct udev_enumerate *enumerate; +- struct udev_list_entry *devices, *dev_list_entry; +- +- struct hid_device_info *root = NULL; /* return object */ +- struct hid_device_info *cur_dev = NULL; +- struct hid_device_info *prev_dev = NULL; /* previous device */ +- +- hid_init(); +- +- /* Create the udev object */ +- udev = udev_new(); +- if (!udev) { +- printf("Can't create udev\n"); +- return NULL; +- } +- +- /* Create a list of the devices in the 'hidraw' subsystem. */ +- enumerate = udev_enumerate_new(udev); +- udev_enumerate_add_match_subsystem(enumerate, "hidraw"); +- udev_enumerate_scan_devices(enumerate); +- devices = udev_enumerate_get_list_entry(enumerate); +- /* For each item, see if it matches the vid/pid, and if so +- create a udev_device record for it */ +- udev_list_entry_foreach(dev_list_entry, devices) { +- const char *sysfs_path; +- const char *dev_path; +- const char *str; +- struct udev_device *raw_dev; /* The device's hidraw udev node. */ +- struct udev_device *hid_dev; /* The device's HID udev node. */ +- struct udev_device *usb_dev; /* The device's USB udev node. */ +- struct udev_device *intf_dev; /* The device's interface (in the USB sense). */ +- unsigned short dev_vid; +- unsigned short dev_pid; +- char *serial_number_utf8 = NULL; +- char *product_name_utf8 = NULL; +- int bus_type; +- int result; +- +- /* Get the filename of the /sys entry for the device +- and create a udev_device object (dev) representing it */ +- sysfs_path = udev_list_entry_get_name(dev_list_entry); +- raw_dev = udev_device_new_from_syspath(udev, sysfs_path); +- dev_path = udev_device_get_devnode(raw_dev); +- +- hid_dev = udev_device_get_parent_with_subsystem_devtype( +- raw_dev, +- "hid", +- NULL); +- +- if (!hid_dev) { +- /* Unable to find parent hid device. */ +- goto next; +- } +- +- result = parse_uevent_info( +- udev_device_get_sysattr_value(hid_dev, "uevent"), +- &bus_type, +- &dev_vid, +- &dev_pid, +- &serial_number_utf8, +- &product_name_utf8); +- +- if (!result) { +- /* parse_uevent_info() failed for at least one field. */ +- goto next; +- } +- +- if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) { +- /* We only know how to handle USB and BT devices. */ +- goto next; +- } +- +- /* Check the VID/PID against the arguments */ +- 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. */ +- tmp = malloc(sizeof(struct hid_device_info)); +- if (cur_dev) { +- cur_dev->next = tmp; +- } +- else { +- root = tmp; +- } +- prev_dev = cur_dev; +- cur_dev = tmp; +- +- /* Fill out the record */ +- cur_dev->next = NULL; +- cur_dev->path = dev_path? strdup(dev_path): NULL; +- +- /* VID/PID */ +- cur_dev->vendor_id = dev_vid; +- cur_dev->product_id = dev_pid; +- +- /* Serial Number */ +- cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8); +- +- /* Release Number */ +- cur_dev->release_number = 0x0; +- +- /* Interface Number */ +- cur_dev->interface_number = -1; +- +- switch (bus_type) { +- case BUS_USB: +- /* The device pointed to by raw_dev contains information about +- the hidraw device. In order to get information about the +- USB device, get the parent device with the +- subsystem/devtype pair of "usb"/"usb_device". This will +- be several levels up the tree, but the function will find +- it. */ +- usb_dev = udev_device_get_parent_with_subsystem_devtype( +- raw_dev, +- "usb", +- "usb_device"); +- +- if (!usb_dev) { +- /* Free this device */ +- free(cur_dev->serial_number); +- free(cur_dev->path); +- free(cur_dev); +- +- /* Take it off the device list. */ +- if (prev_dev) { +- prev_dev->next = NULL; +- cur_dev = prev_dev; +- } +- else { +- cur_dev = root = NULL; +- } +- +- goto next; +- } +- +- /* Manufacturer and Product strings */ +- cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]); +- cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]); +- +- /* Release Number */ +- str = udev_device_get_sysattr_value(usb_dev, "bcdDevice"); +- cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0; +- +- /* Get a handle to the interface's udev node. */ +- intf_dev = udev_device_get_parent_with_subsystem_devtype( +- raw_dev, +- "usb", +- "usb_interface"); +- if (intf_dev) { +- str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber"); +- cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1; +- } +- +- break; +- +- case BUS_BLUETOOTH: +- /* Manufacturer and Product strings */ +- cur_dev->manufacturer_string = wcsdup(L""); +- cur_dev->product_string = utf8_to_wchar_t(product_name_utf8); +- +- break; +- +- default: +- /* Unknown device type - this should never happen, as we +- * check for USB and Bluetooth devices above */ +- break; +- } +- } +- +- next: +- free(serial_number_utf8); +- free(product_name_utf8); +- udev_device_unref(raw_dev); +- /* hid_dev, usb_dev and intf_dev don't need to be (and can't be) +- unref()d. It will cause a double-free() error. I'm not +- sure why. */ +- } +- /* Free the enumerator and udev objects. */ +- udev_enumerate_unref(enumerate); +- udev_unref(udev); +- +- return root; +-} +- +-void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) +-{ +- struct hid_device_info *d = devs; +- while (d) { +- struct hid_device_info *next = d->next; +- free(d->path); +- free(d->serial_number); +- free(d->manufacturer_string); +- free(d->product_string); +- free(d); +- d = next; +- } +-} +- +-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; +- hid_device *handle = NULL; +- +- devs = hid_enumerate(vendor_id, product_id); +- cur_dev = devs; +- while (cur_dev) { +- 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) { +- path_to_open = cur_dev->path; +- break; +- } +- } +- else { +- path_to_open = cur_dev->path; +- break; +- } +- } +- cur_dev = cur_dev->next; +- } +- +- if (path_to_open) { +- /* Open the device */ +- handle = hid_open_path(path_to_open); +- } +- +- hid_free_enumeration(devs); +- +- return handle; +-} +- +-hid_device * HID_API_EXPORT hid_open_path(const char *path) +-{ +- hid_device *dev = NULL; +- +- hid_init(); +- +- dev = new_hid_device(); +- +- /* OPEN HERE */ +- dev->device_handle = open(path, O_RDWR); +- +- /* If we have a good handle, return it. */ +- if (dev->device_handle > 0) { +- +- /* Get the report descriptor */ +- int res, desc_size = 0; +- struct hidraw_report_descriptor rpt_desc; +- +- memset(&rpt_desc, 0x0, sizeof(rpt_desc)); +- +- /* Get Report Descriptor Size */ +- res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size); +- if (res < 0) +- perror("HIDIOCGRDESCSIZE"); +- +- +- /* Get Report Descriptor */ +- rpt_desc.size = desc_size; +- res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc); +- if (res < 0) { +- perror("HIDIOCGRDESC"); +- } else { +- /* Determine if this device uses numbered reports. */ +- dev->uses_numbered_reports = +- uses_numbered_reports(rpt_desc.value, +- rpt_desc.size); +- } +- +- return dev; +- } +- else { +- /* Unable to open any devices. */ +- free(dev); +- return NULL; +- } +-} +- +- +-int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) +-{ +- int bytes_written; +- +- bytes_written = write(dev->device_handle, data, length); +- +- return bytes_written; +-} +- +- +-int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +-{ +- int bytes_read; +- +- if (milliseconds >= 0) { +- /* Milliseconds is either 0 (non-blocking) or > 0 (contains +- a valid timeout). In both cases we want to call poll() +- and wait for data to arrive. Don't rely on non-blocking +- operation (O_NONBLOCK) since some kernels don't seem to +- properly report device disconnection through read() when +- in non-blocking mode. */ +- int ret; +- struct pollfd fds; +- +- fds.fd = dev->device_handle; +- fds.events = POLLIN; +- fds.revents = 0; +- ret = poll(&fds, 1, milliseconds); +- if (ret == -1 || ret == 0) { +- /* Error or timeout */ +- return ret; +- } +- else { +- /* Check for errors on the file descriptor. This will +- indicate a device disconnection. */ +- if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) +- return -1; +- } +- } +- +- bytes_read = read(dev->device_handle, data, length); +- if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS)) +- bytes_read = 0; +- +- if (bytes_read >= 0 && +- kernel_version != 0 && +- kernel_version < KERNEL_VERSION(2,6,34) && +- dev->uses_numbered_reports) { +- /* Work around a kernel bug. Chop off the first byte. */ +- memmove(data, data+1, bytes_read); +- bytes_read--; +- } +- +- 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) +-{ +- /* Do all non-blocking in userspace using poll(), since it looks +- like there's a bug in the kernel in some versions where +- read() will not return -1 on disconnection of the USB device */ +- +- dev->blocking = !nonblock; +- return 0; /* Success */ +-} +- +- +-int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +-{ +- int res; +- +- res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data); +- if (res < 0) +- perror("ioctl (SFEATURE)"); +- +- return res; +-} +- +-int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +-{ +- int res; +- +- res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data); +- if (res < 0) +- perror("ioctl (GFEATURE)"); +- +- +- return res; +-} +- +- +-void HID_API_EXPORT hid_close(hid_device *dev) +-{ +- if (!dev) +- return; +- close(dev->device_handle); +- free(dev); +-} +- +- +-int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen); +-} +- +-int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen); +-} +- +-int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen); +-} +- +-int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +-{ +- return -1; +-} +- +- +-HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +-{ +- return NULL; +-} +Index: libambit/cmake/Findlibhid.cmake +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libambit/cmake/Findlibhid.cmake 2014-08-24 23:09:47.560218677 +0200 +@@ -0,0 +1,40 @@ ++# - Find libusb-1.0 library ++# This module defines ++# LIBUSB_INCLUDE_DIR, where to find bluetooth.h ++# LIBUSB_LIBRARIES, the libraries needed to use libusb-1.0. ++# LIBUSB_FOUND, If false, do not try to use libusb-1.0. ++# ++# Copyright (c) 2009, Michal Cihar, ++# ++# vim: expandtab sw=4 ts=4 sts=4: ++ ++if (NOT LIBUSB_FOUND) ++ find_package(PkgConfig) ++ pkg_check_modules (LIBUSB_PKG libusb-1.0) ++ ++ find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h ++ PATHS ++ ${LIBUSB_PKG_INCLUDE_DIRS} ++ /usr/include/libusb-1.0 ++ /usr/include ++ /usr/local/include ++ ) ++ ++ find_library(LIBUSB_LIBRARIES NAMES usb-1.0 ++ PATHS ++ ${LIBUSB_PKG_LIBRARY_DIRS} ++ /usr/lib ++ /usr/local/lib ++ ) ++ ++ if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) ++ set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found") ++ message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}") ++ else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) ++ set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") ++ message(STATUS "libusb-1.0 not found.") ++ endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) ++ ++ mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) ++endif (NOT LIBUSB_FOUND) ++ +Index: libambit/CMakeLists.txt +=================================================================== +--- libambit.orig/CMakeLists.txt 2014-08-24 23:03:32.000000000 +0200 ++++ libambit/CMakeLists.txt 2014-08-24 23:10:10.476414112 +0200 +@@ -24,7 +24,6 @@ + SHARED + crc16.c + debug.c +- hid.c + libambit.c + personal.c + pmem20.c +@@ -40,9 +39,5 @@ + + set_target_properties(ambit PROPERTIES VERSION 0.2.0 SOVERSION 0) + +-include_directories( +- hidapi +-) +- + install(TARGETS ambit DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(FILES libambit.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +Index: libambit/hidapi/hidapi.h +=================================================================== +--- libambit.orig/hidapi/hidapi.h 2014-08-24 23:03:32.000000000 +0200 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,387 +0,0 @@ +-/******************************************************* +- HIDAPI - Multi-Platform library for +- communication with HID devices. +- +- Alan Ott +- Signal 11 Software +- +- 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 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. +- These files may also be found in the public source +- code repository located at: +- http://github.com/signal11/hidapi . +-********************************************************/ +- +-/** @file +- * @defgroup API hidapi API +- */ +- +-#ifndef HIDAPI_H__ +-#define HIDAPI_H__ +- +-#include +- +-#ifdef _WIN32 +- #define HID_API_EXPORT __declspec(dllexport) +- #define HID_API_CALL +-#else +- #define HID_API_EXPORT /**< API export macro */ +- #define HID_API_CALL /**< API call macro */ +-#endif +- +-#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- struct hid_device_; +- typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ +- +- /** hidapi info structure */ +- struct hid_device_info { +- /** Platform-specific device path */ +- char *path; +- /** Device Vendor ID */ +- unsigned short vendor_id; +- /** Device Product ID */ +- unsigned short product_id; +- /** Serial Number */ +- wchar_t *serial_number; +- /** Device Release Number in binary-coded decimal, +- also known as Device Version Number */ +- unsigned short release_number; +- /** Manufacturer String */ +- wchar_t *manufacturer_string; +- /** Product string */ +- wchar_t *product_string; +- /** Usage Page for this Device/Interface +- (Windows/Mac only). */ +- unsigned short usage_page; +- /** Usage for this Device/Interface +- (Windows/Mac only).*/ +- unsigned short usage; +- /** The USB interface which this logical device +- 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 +- 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. +- +- @ingroup API +- @param vendor_id The Vendor ID (VID) of the types of device +- to open. +- @param product_id The Product ID (PID) of the types of +- device to open. +- +- @returns +- This function returns a pointer to a linked list of type +- struct #hid_device, containing information about the HID devices +- attached to the system, or NULL in the case of failure. Free +- this linked list by calling hid_free_enumeration(). +- */ +- struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); +- +- /** @brief Free an enumeration Linked List +- +- This function frees a linked list created by hid_enumerate(). +- +- @ingroup API +- @param devs Pointer to a list of struct_device returned from +- hid_enumerate(). +- */ +- void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); +- +- /** @brief Open a HID device using a Vendor ID (VID), Product ID +- (PID) and optionally a serial number. +- +- If @p serial_number is NULL, the first device with the +- specified VID and PID is opened. +- +- @ingroup API +- @param vendor_id The Vendor ID (VID) of the device to open. +- @param product_id The Product ID (PID) of the device to open. +- @param serial_number The Serial Number of the device to open +- (Optionally NULL). +- +- @returns +- 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, const wchar_t *serial_number); +- +- /** @brief Open a HID device by its path name. +- +- The path name be determined by calling hid_enumerate(), or a +- platform-specific path name can be used (eg: /dev/hidraw0 on +- Linux). +- +- @ingroup API +- @param path The path name of the device to open +- +- @returns +- 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_path(const char *path); +- +- /** @brief Write an Output report to a HID device. +- +- The first byte of @p data[] must contain the Report ID. For +- devices which only support a single report, this must be set +- to 0x0. The remaining bytes contain the report data. Since +- the Report ID is mandatory, calls to hid_write() will always +- contain one more byte than the report contains. For example, +- if a hid report is 16 bytes long, 17 bytes must be passed to +- hid_write(), the Report ID (or 0x0, for devices with a +- single report), followed by the report data (16 bytes). In +- this example, the length passed in would be 17. +- +- hid_write() will send the data on the first OUT endpoint, if +- one exists. If it does not, it will send the data through +- the Control Endpoint (Endpoint 0). +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- @param data The data to send, including the report number as +- the first byte. +- @param length The length in bytes of the data to send. +- +- @returns +- This function returns the actual number of bytes written and +- -1 on error. +- */ +- 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. 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); +- +- /** @brief Read an Input report from a HID device. +- +- 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. +- +- @returns +- This function returns the actual number of bytes read and +- -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); +- +- /** @brief Set the device handle to be non-blocking. +- +- In non-blocking mode calls to hid_read() will return +- immediately with a value of 0 if there is no data to be +- read. In blocking mode, hid_read() will wait (block) until +- there is data to read before returning. +- +- Nonblocking can be turned on and off at any time. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- @param nonblock enable or not the nonblocking reads +- - 1 to enable nonblocking +- - 0 to disable nonblocking. +- +- @returns +- This function returns 0 on success and -1 on error. +- */ +- int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); +- +- /** @brief Send a Feature report to the device. +- +- Feature reports are sent over the Control endpoint as a +- Set_Report transfer. The first byte of @p data[] must +- contain the Report ID. For devices which only support a +- single report, this must be set to 0x0. The remaining bytes +- contain the report data. Since the Report ID is mandatory, +- calls to hid_send_feature_report() will always contain one +- more byte than the report contains. For example, if a hid +- report is 16 bytes long, 17 bytes must be passed to +- hid_send_feature_report(): the Report ID (or 0x0, for +- devices which do not use numbered reports), followed by the +- report data (16 bytes). In this example, the length passed +- in would be 17. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- @param data The data to send, including the report number as +- the first byte. +- @param length The length in bytes of the data to send, including +- the report number. +- +- @returns +- This function returns the actual number of bytes written and +- -1 on error. +- */ +- int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); +- +- /** @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[]. +- +- @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. +- @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. +- */ +- int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); +- +- /** @brief Close a HID device. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- */ +- void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); +- +- /** @brief Get The Manufacturer String from a HID device. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- @param string A wide string buffer to put the data into. +- @param maxlen The length of the buffer in multiples of wchar_t. +- +- @returns +- This function returns 0 on success and -1 on error. +- */ +- int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); +- +- /** @brief Get The Product String from a HID device. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- @param string A wide string buffer to put the data into. +- @param maxlen The length of the buffer in multiples of wchar_t. +- +- @returns +- This function returns 0 on success and -1 on error. +- */ +- int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); +- +- /** @brief Get The Serial Number String from a HID device. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- @param string A wide string buffer to put the data into. +- @param maxlen The length of the buffer in multiples of wchar_t. +- +- @returns +- This function returns 0 on success and -1 on error. +- */ +- int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); +- +- /** @brief Get a string from a HID device, based on its string index. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- @param string_index The index of the string to get. +- @param string A wide string buffer to put the data into. +- @param maxlen The length of the buffer in multiples of wchar_t. +- +- @returns +- This function returns 0 on success and -1 on error. +- */ +- int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); +- +- /** @brief Get a string describing the last error which occurred. +- +- @ingroup API +- @param device A device handle returned from hid_open(). +- +- @returns +- This function returns a string containing the last error +- which occurred or NULL if none has occurred. +- */ +- HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif +- +Index: libambit/libambit_int.h +=================================================================== +--- libambit.orig/libambit_int.h 2014-08-24 23:09:47.512218278 +0200 ++++ libambit/libambit_int.h 2014-08-24 23:11:59.361344122 +0200 +@@ -23,7 +23,7 @@ + #define __LIBAMBIT_INT_H__ + + #include +-#include "hidapi/hidapi.h" ++#include + #include "libambit.h" + + struct ambit_object_s { +Index: libambit/protocol.c +=================================================================== +--- libambit.orig/protocol.c 2014-05-11 10:45:25.000000000 +0200 ++++ libambit/protocol.c 2014-08-24 23:11:48.985255402 +0200 +@@ -21,8 +21,8 @@ + */ + #include "libambit.h" + #include "libambit_int.h" +-#include "hidapi/hidapi.h" + ++#include + #include + #include + #include diff -Nru libambit-0.2/debian/patches/series libambit-0.2/debian/patches/series --- libambit-0.2/debian/patches/series 2014-08-24 19:50:50.000000000 +0000 +++ libambit-0.2/debian/patches/series 2014-09-13 13:47:08.000000000 +0000 @@ -1 +1,2 @@ -01_git20140824.patch +01_git20140913.patch +#02_use_hid_package.patch