mirror of
https://github.com/RPCS3/hidapi.git
synced 2026-07-19 21:43:36 -04:00
Sync with v0.10.1 (master)
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
image: archlinux
|
||||
packages:
|
||||
- autoconf
|
||||
- automake
|
||||
- libtool
|
||||
- libusb
|
||||
- libudev0
|
||||
sources:
|
||||
- https://github.com/libusb/hidapi
|
||||
tasks:
|
||||
|
||||
@@ -20,3 +20,5 @@ windows/Makefile.in
|
||||
Makefile
|
||||
stamp-h1
|
||||
libtool
|
||||
|
||||
.DS_Store
|
||||
|
||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
||||
Pod::Spec.new do |spec|
|
||||
|
||||
spec.name = "hidapi"
|
||||
spec.version = "<fill me up from VERSION file, before submit>"
|
||||
spec.version = File.read('../VERSION')
|
||||
spec.summary = "A Simple library for communicating with USB and Bluetooth HID devices on Linux, Mac and Windows."
|
||||
|
||||
spec.description = <<-DESC
|
||||
@@ -26,6 +26,6 @@ Pod::Spec.new do |spec|
|
||||
|
||||
spec.public_header_files = "hidapi/hidapi.h"
|
||||
|
||||
spec.frameworks = "IOKit", "CoreFoundation"
|
||||
spec.frameworks = "IOKit", "CoreFoundation", "AppKit"
|
||||
|
||||
end
|
||||
|
||||
+7
-7
@@ -48,12 +48,12 @@
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_VERSION_MINOR 9
|
||||
#define HID_API_VERSION_MINOR 10
|
||||
/** @brief Static/compile-time patch version of the library.
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_VERSION_PATCH 0
|
||||
#define HID_API_VERSION_PATCH 1
|
||||
|
||||
/* Helper macros */
|
||||
#define HID_API_AS_STR_IMPL(x) #x
|
||||
@@ -96,10 +96,10 @@ extern "C" {
|
||||
/** Product string */
|
||||
wchar_t *product_string;
|
||||
/** Usage Page for this Device/Interface
|
||||
(Windows/Mac only). */
|
||||
(Windows/Mac/hidraw only) */
|
||||
unsigned short usage_page;
|
||||
/** Usage for this Device/Interface
|
||||
(Windows/Mac only).*/
|
||||
(Windows/Mac/hidraw only) */
|
||||
unsigned short usage;
|
||||
/** The USB interface which this logical device
|
||||
represents.
|
||||
@@ -124,7 +124,7 @@ extern "C" {
|
||||
needed. This function should be called at the beginning of
|
||||
execution however, if there is a chance of HIDAPI handles
|
||||
being opened by different threads simultaneously.
|
||||
|
||||
|
||||
@ingroup API
|
||||
|
||||
@returns
|
||||
@@ -478,7 +478,7 @@ extern "C" {
|
||||
@returns
|
||||
Pointer to statically allocated struct, that contains version.
|
||||
*/
|
||||
HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version();
|
||||
HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void);
|
||||
|
||||
|
||||
/** @brief Get a runtime version string of the library.
|
||||
@@ -488,7 +488,7 @@ extern "C" {
|
||||
@returns
|
||||
Pointer to statically allocated string, that contains version string.
|
||||
*/
|
||||
HID_API_EXPORT const char* HID_API_CALL hid_version_str();
|
||||
HID_API_EXPORT const char* HID_API_CALL hid_version_str(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+8
-10
@@ -7,7 +7,7 @@
|
||||
8/22/2009
|
||||
|
||||
Copyright 2009
|
||||
|
||||
|
||||
This contents of this file may be used by anyone
|
||||
for any reason without any conditions and may be
|
||||
used as a starting point for your own applications
|
||||
@@ -29,6 +29,9 @@
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
int res;
|
||||
unsigned char buf[256];
|
||||
#define MAX_STR 255
|
||||
@@ -36,11 +39,6 @@ int main(int argc, char* argv[])
|
||||
hid_device *handle;
|
||||
int i;
|
||||
|
||||
#ifdef WIN32
|
||||
UNREFERENCED_PARAMETER(argc);
|
||||
UNREFERENCED_PARAMETER(argv);
|
||||
#endif
|
||||
|
||||
struct hid_device_info *devs, *cur_dev;
|
||||
|
||||
printf("hidapi test/example tool. Compiled with hidapi version %s, runtime version %s.\n", HID_API_VERSION_STR, hid_version_str());
|
||||
@@ -55,7 +53,7 @@ int main(int argc, char* argv[])
|
||||
return -1;
|
||||
|
||||
devs = hid_enumerate(0x0, 0x0);
|
||||
cur_dev = devs;
|
||||
cur_dev = devs;
|
||||
while (cur_dev) {
|
||||
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
|
||||
printf("\n");
|
||||
@@ -73,7 +71,7 @@ int main(int argc, char* argv[])
|
||||
memset(buf,0x00,sizeof(buf));
|
||||
buf[0] = 0x01;
|
||||
buf[1] = 0x81;
|
||||
|
||||
|
||||
|
||||
// Open the device using the VID, PID,
|
||||
// and optionally the Serial number.
|
||||
@@ -115,7 +113,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Set the hid_read() function to be non-blocking.
|
||||
hid_set_nonblocking(handle, 1);
|
||||
|
||||
|
||||
// Try to read from the device. There should be no
|
||||
// data here, but execution should not block.
|
||||
res = hid_read(handle, buf, 17);
|
||||
@@ -158,7 +156,7 @@ int main(int argc, char* argv[])
|
||||
printf("Unable to write()\n");
|
||||
printf("Error: %ls\n", hid_error(handle));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Request state (cmd 0x81). The first byte is the report number (0x1).
|
||||
buf[0] = 0x1;
|
||||
|
||||
+6
-2
@@ -1098,18 +1098,21 @@ static void cleanup_mutex(void *param)
|
||||
|
||||
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
|
||||
/* by initialising this variable right here, GCC gives a compilation warning/error: */
|
||||
/* error: variable ‘bytes_read’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered] */
|
||||
int bytes_read; /* = -1; */
|
||||
|
||||
pthread_mutex_lock(&dev->mutex);
|
||||
pthread_cleanup_push(&cleanup_mutex, dev);
|
||||
|
||||
bytes_read = -1;
|
||||
|
||||
/* There's an input report queued up. Return it. */
|
||||
if (dev->input_reports) {
|
||||
/* Return the first one */
|
||||
@@ -1359,6 +1362,7 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index
|
||||
|
||||
HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
|
||||
{
|
||||
(void)dev;
|
||||
return L"hid_error is not implemented yet";
|
||||
}
|
||||
|
||||
|
||||
+329
-85
@@ -123,6 +123,19 @@ static void register_global_error(const char *msg)
|
||||
last_global_error_str = utf8_to_wchar_t(msg);
|
||||
}
|
||||
|
||||
/* See register_global_error, but you can pass a format string into this function. */
|
||||
static void register_global_error_format(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char msg[100];
|
||||
vsnprintf(msg, sizeof(msg), format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
register_global_error(msg);
|
||||
}
|
||||
|
||||
/* Set the last error for a device to be reported by hid_error(device).
|
||||
* The given error message will be copied (and decoded according to the
|
||||
@@ -158,11 +171,67 @@ 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));
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the size of the HID item at the given position
|
||||
* Returns 1 if successful, 0 if an invalid key
|
||||
* Sets data_len and key_size when successful
|
||||
*/
|
||||
static int get_hid_item_size(__u8 *report_descriptor, unsigned int pos, __u32 size, int *data_len, int *key_size)
|
||||
{
|
||||
int key = report_descriptor[pos];
|
||||
int size_code;
|
||||
|
||||
/*
|
||||
* 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 ((key & 0xf0) == 0xf0) {
|
||||
if (pos + 1 < size)
|
||||
{
|
||||
*data_len = report_descriptor[pos + 1];
|
||||
*key_size = 3;
|
||||
return 1;
|
||||
}
|
||||
*data_len = 0; /* malformed report */
|
||||
*key_size = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
*key_size = 1;
|
||||
return 1;
|
||||
case 3:
|
||||
*data_len = 4;
|
||||
*key_size = 1;
|
||||
return 1;
|
||||
default:
|
||||
/* Can't ever happen since size_code is & 0x3 */
|
||||
*data_len = 0;
|
||||
*key_size = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
/* malformed report */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
@@ -175,42 +244,9 @@ static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {
|
||||
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;
|
||||
}
|
||||
/* Determine data_len and key_size */
|
||||
if (!get_hid_item_size(report_descriptor, i, size, &data_len, &key_size))
|
||||
return 0; /* malformed report */
|
||||
|
||||
/* Skip over this key and it's associated data */
|
||||
i += data_len + key_size;
|
||||
@@ -220,12 +256,163 @@ static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get bytes from a HID Report Descriptor.
|
||||
* Only call with a num_bytes of 0, 1, 2, or 4.
|
||||
*/
|
||||
static __u32 get_hid_report_bytes(__u8 *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 returns the current Usage Page/Usage pair whenever a new
|
||||
* Collection is found and a Usage Local Item is currently in scope.
|
||||
* Usage Local Items are consumed by each Main Item (See. 6.2.2.8).
|
||||
* The algorithm should give similar results as Apple's:
|
||||
* https://developer.apple.com/documentation/iokit/kiohiddeviceusagepairskey?language=objc
|
||||
* Physical Collections are also matched (macOS does the same).
|
||||
*
|
||||
* This function can be called repeatedly until it returns non-0
|
||||
* Usage is found. pos is the starting point (initially 0) and will be updated
|
||||
* to the next search position.
|
||||
*
|
||||
* The return value is 0 when a pair is found.
|
||||
* 1 when finished processing descriptor.
|
||||
* -1 on a malformed report.
|
||||
*/
|
||||
static int get_next_hid_usage(__u8 *report_descriptor, __u32 size, unsigned int *pos, unsigned short *usage_page, unsigned short *usage)
|
||||
{
|
||||
int data_len, key_size;
|
||||
int initial = *pos == 0; /* Used to handle case where no top-level application collection is defined */
|
||||
int usage_pair_ready = 0;
|
||||
|
||||
/* Usage is a Local Item, it must be set before each Main Item (Collection) before a pair is returned */
|
||||
int usage_found = 0;
|
||||
|
||||
while (*pos < size) {
|
||||
int key = report_descriptor[*pos];
|
||||
int key_cmd = key & 0xfc;
|
||||
|
||||
/* Determine data_len and key_size */
|
||||
if (!get_hid_item_size(report_descriptor, *pos, size, &data_len, &key_size))
|
||||
return -1; /* malformed report */
|
||||
|
||||
switch (key_cmd) {
|
||||
case 0x4: /* Usage Page 6.2.2.7 (Global) */
|
||||
*usage_page = get_hid_report_bytes(report_descriptor, size, data_len, *pos);
|
||||
break;
|
||||
|
||||
case 0x8: /* Usage 6.2.2.8 (Local) */
|
||||
*usage = get_hid_report_bytes(report_descriptor, size, data_len, *pos);
|
||||
usage_found = 1;
|
||||
break;
|
||||
|
||||
case 0xa0: /* Collection 6.2.2.4 (Main) */
|
||||
/* A Usage Item (Local) must be found for the pair to be valid */
|
||||
if (usage_found)
|
||||
usage_pair_ready = 1;
|
||||
|
||||
/* Usage is a Local Item, unset it */
|
||||
usage_found = 0;
|
||||
break;
|
||||
|
||||
case 0x80: /* Input 6.2.2.4 (Main) */
|
||||
case 0x90: /* Output 6.2.2.4 (Main) */
|
||||
case 0xb0: /* Feature 6.2.2.4 (Main) */
|
||||
case 0xc0: /* End Collection 6.2.2.4 (Main) */
|
||||
/* Usage is a Local Item, unset it */
|
||||
usage_found = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip over this key and it's associated data */
|
||||
*pos += data_len + key_size;
|
||||
|
||||
/* Return usage pair */
|
||||
if (usage_pair_ready)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If no top-level application collection is found and usage page/usage pair is found, pair is valid
|
||||
https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections */
|
||||
if (initial && usage_found)
|
||||
return 0; /* success */
|
||||
|
||||
return 1; /* finished processing */
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves the hidraw report descriptor from a file.
|
||||
* When using this form, <sysfs_path>/device/report_descriptor, elevated priviledges are not required.
|
||||
*/
|
||||
static int get_hid_report_descriptor(const char *rpt_path, struct hidraw_report_descriptor *rpt_desc)
|
||||
{
|
||||
int rpt_handle;
|
||||
ssize_t res;
|
||||
|
||||
rpt_handle = open(rpt_path, O_RDONLY);
|
||||
if (rpt_handle < 0) {
|
||||
register_global_error_format("open failed (%s): %s", rpt_path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in the Report Descriptor
|
||||
* The sysfs file has a maximum size of 4096 (which is the same as HID_MAX_DESCRIPTOR_SIZE) so we should always
|
||||
* be ok when reading the descriptor.
|
||||
* In practice if the HID descriptor is any larger I suspect many other things will break.
|
||||
*/
|
||||
memset(rpt_desc, 0x0, sizeof(*rpt_desc));
|
||||
res = read(rpt_handle, rpt_desc->value, HID_MAX_DESCRIPTOR_SIZE);
|
||||
if (res < 0) {
|
||||
register_global_error_format("read failed (%s): %s", rpt_path, strerror(errno));
|
||||
}
|
||||
rpt_desc->size = (__u32) res;
|
||||
|
||||
close(rpt_handle);
|
||||
return (int) res;
|
||||
}
|
||||
|
||||
static int get_hid_report_descriptor_from_sysfs(const char *sysfs_path, struct hidraw_report_descriptor *rpt_desc)
|
||||
{
|
||||
int res = -1;
|
||||
/* Construct <sysfs_path>/device/report_descriptor */
|
||||
size_t rpt_path_len = strlen(sysfs_path) + 25 + 1;
|
||||
char* rpt_path = (char*) calloc(1, rpt_path_len);
|
||||
snprintf(rpt_path, rpt_path_len, "%s/device/report_descriptor", sysfs_path);
|
||||
|
||||
res = get_hid_report_descriptor(rpt_path, rpt_desc);
|
||||
free(rpt_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
parse_uevent_info(const char *uevent, unsigned *bus_type,
|
||||
unsigned short *vendor_id, unsigned short *product_id,
|
||||
char **serial_number_utf8, char **product_name_utf8)
|
||||
{
|
||||
@@ -284,8 +471,8 @@ static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t
|
||||
struct udev_device *udev_dev, *parent, *hid_dev;
|
||||
struct stat s;
|
||||
int ret = -1;
|
||||
char *serial_number_utf8 = NULL;
|
||||
char *product_name_utf8 = NULL;
|
||||
char *serial_number_utf8 = NULL;
|
||||
char *product_name_utf8 = NULL;
|
||||
|
||||
/* Create the udev object */
|
||||
udev = udev_new();
|
||||
@@ -308,7 +495,7 @@ static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t
|
||||
if (hid_dev) {
|
||||
unsigned short dev_vid;
|
||||
unsigned short dev_pid;
|
||||
int bus_type;
|
||||
unsigned bus_type;
|
||||
size_t retm;
|
||||
|
||||
ret = parse_uevent_info(
|
||||
@@ -319,27 +506,8 @@ static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t
|
||||
&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 {
|
||||
/* Standard USB device */
|
||||
if (bus_type == BUS_USB) {
|
||||
/* This is a USB device. Find its parent USB Device node. */
|
||||
parent = udev_device_get_parent_with_subsystem_devtype(
|
||||
udev_dev,
|
||||
@@ -361,16 +529,46 @@ static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t
|
||||
/* Convert the string from UTF-8 to wchar_t */
|
||||
retm = mbstowcs(string, str, maxlen);
|
||||
ret = (retm == (size_t)-1)? -1: 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* USB information parsed */
|
||||
goto end;
|
||||
}
|
||||
else {
|
||||
/* Correctly handled below */
|
||||
}
|
||||
}
|
||||
|
||||
/* USB information not available (uhid) or another type of HID bus */
|
||||
switch (bus_type) {
|
||||
case BUS_BLUETOOTH:
|
||||
case BUS_I2C:
|
||||
case BUS_USB:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
free(serial_number_utf8);
|
||||
free(product_name_utf8);
|
||||
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.
|
||||
@@ -449,8 +647,9 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
unsigned short dev_pid;
|
||||
char *serial_number_utf8 = NULL;
|
||||
char *product_name_utf8 = NULL;
|
||||
int bus_type;
|
||||
unsigned bus_type;
|
||||
int result;
|
||||
struct hidraw_report_descriptor report_desc;
|
||||
|
||||
/* Get the filename of the /sys entry for the device
|
||||
and create a udev_device object (dev) representing it */
|
||||
@@ -481,9 +680,15 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {
|
||||
/* We only know how to handle USB and BT devices. */
|
||||
goto next;
|
||||
/* Filter out unhandled devices right away */
|
||||
switch (bus_type) {
|
||||
case BUS_BLUETOOTH:
|
||||
case BUS_I2C:
|
||||
case BUS_USB:
|
||||
break;
|
||||
|
||||
default:
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Check the VID/PID against the arguments */
|
||||
@@ -532,22 +737,14 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
"usb",
|
||||
"usb_device");
|
||||
|
||||
/* uhid USB devices
|
||||
Since this is a virtual hid interface, no USB information will
|
||||
be available. */
|
||||
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 = wcsdup(L"");
|
||||
cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Manufacturer and Product strings */
|
||||
@@ -571,6 +768,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
break;
|
||||
|
||||
case BUS_BLUETOOTH:
|
||||
case BUS_I2C:
|
||||
/* Manufacturer and Product strings */
|
||||
cur_dev->manufacturer_string = wcsdup(L"");
|
||||
cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
|
||||
@@ -582,6 +780,45 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
* check for USB and Bluetooth devices above */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Usage Page and Usage */
|
||||
result = get_hid_report_descriptor_from_sysfs(sysfs_path, &report_desc);
|
||||
if (result >= 0) {
|
||||
unsigned short page = 0, usage = 0;
|
||||
unsigned int pos = 0;
|
||||
/*
|
||||
* Parse the first usage and usage page
|
||||
* out of the report descriptor.
|
||||
*/
|
||||
if (!get_next_hid_usage(report_desc.value, report_desc.size, &pos, &page, &usage)) {
|
||||
cur_dev->usage_page = page;
|
||||
cur_dev->usage = usage;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse any additional usage and usage pages
|
||||
* out of the report descriptor.
|
||||
*/
|
||||
while (!get_next_hid_usage(report_desc.value, report_desc.size, &pos, &page, &usage)) {
|
||||
/* Create new record for additional usage pairs */
|
||||
tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
|
||||
cur_dev->next = tmp;
|
||||
prev_dev = cur_dev;
|
||||
cur_dev = tmp;
|
||||
|
||||
/* Update fields */
|
||||
cur_dev->path = strdup(dev_path);
|
||||
cur_dev->vendor_id = dev_vid;
|
||||
cur_dev->product_id = dev_pid;
|
||||
cur_dev->serial_number = prev_dev->serial_number? wcsdup(prev_dev->serial_number): NULL;
|
||||
cur_dev->release_number = prev_dev->release_number;
|
||||
cur_dev->interface_number = prev_dev->interface_number;
|
||||
cur_dev->manufacturer_string = prev_dev->manufacturer_string? wcsdup(prev_dev->manufacturer_string): NULL;
|
||||
cur_dev->product_string = prev_dev->product_string? wcsdup(prev_dev->product_string): NULL;
|
||||
cur_dev->usage_page = page;
|
||||
cur_dev->usage = usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
@@ -668,7 +905,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
|
||||
dev->device_handle = open(path, O_RDWR);
|
||||
|
||||
/* If we have a good handle, return it. */
|
||||
if (dev->device_handle > 0) {
|
||||
if (dev->device_handle >= 0) {
|
||||
/* Set device error to none */
|
||||
register_device_error(dev, NULL);
|
||||
|
||||
@@ -809,6 +1046,9 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data,
|
||||
// Not supported by Linux HidRaw yet
|
||||
int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
|
||||
{
|
||||
(void)dev;
|
||||
(void)data;
|
||||
(void)length;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -845,6 +1085,10 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s
|
||||
|
||||
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
|
||||
{
|
||||
(void)dev;
|
||||
(void)string_index;
|
||||
(void)string;
|
||||
(void)maxlen;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ typedef struct pthread_barrier {
|
||||
|
||||
static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
|
||||
{
|
||||
(void) attr;
|
||||
|
||||
if(count == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -274,8 +276,8 @@ static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t
|
||||
len * sizeof(wchar_t),
|
||||
&used_buf_len);
|
||||
|
||||
if (chars_copied == len)
|
||||
buf[len] = 0; /* len is decremented above */
|
||||
if (chars_copied <= 0)
|
||||
buf[0] = 0;
|
||||
else
|
||||
buf[chars_copied] = 0;
|
||||
|
||||
@@ -581,6 +583,9 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
}
|
||||
|
||||
CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
|
||||
if (device_set == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Convert the list into a C array so we can iterate easily. */
|
||||
num_devices = CFSetGetCount(device_set);
|
||||
@@ -674,6 +679,9 @@ hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short pr
|
||||
static void hid_device_removal_callback(void *context, IOReturn result,
|
||||
void *sender)
|
||||
{
|
||||
(void) result;
|
||||
(void) sender;
|
||||
|
||||
/* Stop the Run Loop for this device. */
|
||||
hid_device *d = (hid_device*) context;
|
||||
|
||||
@@ -688,6 +696,11 @@ static void hid_report_callback(void *context, IOReturn result, void *sender,
|
||||
IOHIDReportType report_type, uint32_t report_id,
|
||||
uint8_t *report, CFIndex report_length)
|
||||
{
|
||||
(void) result;
|
||||
(void) sender;
|
||||
(void) report_type;
|
||||
(void) report_id;
|
||||
|
||||
struct input_report *rpt;
|
||||
hid_device *dev = (hid_device*) context;
|
||||
|
||||
@@ -1178,6 +1191,11 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s
|
||||
|
||||
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
|
||||
{
|
||||
(void) dev;
|
||||
(void) string_index;
|
||||
(void) string;
|
||||
(void) maxlen;
|
||||
|
||||
/* TODO: */
|
||||
|
||||
return 0;
|
||||
@@ -1186,6 +1204,7 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index
|
||||
|
||||
HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
|
||||
{
|
||||
(void) dev;
|
||||
/* TODO: */
|
||||
|
||||
return L"hid_error is not implemented yet";
|
||||
|
||||
+1
-1
@@ -192,7 +192,7 @@ static void register_error(hid_device *dev, const char *op)
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPVOID)&msg, 0/*sz*/,
|
||||
(LPWSTR)&msg, 0/*sz*/,
|
||||
NULL);
|
||||
|
||||
/* Get rid of the CR and LF that FormatMessage() sticks at the
|
||||
|
||||
Reference in New Issue
Block a user