From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c | 1173 ----------------------------- 1 file changed, 1173 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c (limited to 'contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c') diff --git a/contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c b/contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c deleted file mode 100644 index 82f34d4..0000000 --- a/contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c +++ /dev/null @@ -1,1173 +0,0 @@ -/******************************************************* - HIDAPI - Multi-Platform library for - communication with HID devices. - - James Buren - libusb/hidapi Team - - Copyright 2023, 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: - https://github.com/libusb/hidapi . -********************************************************/ - -/* C */ -#include -#include -#include -#include -#include -#include - -/* Unix */ -#include -#include -#include -#include - -/* NetBSD */ -#include -#include -#include - -#include "../hidapi/hidapi.h" - -#define HIDAPI_MAX_CHILD_DEVICES 256 - -struct hid_device_ { - int device_handle; - int blocking; - wchar_t *last_error_str; - struct hid_device_info *device_info; - size_t poll_handles_length; - struct pollfd poll_handles[256]; - int report_handles[256]; - char path[USB_MAX_DEVNAMELEN]; -}; - -struct hid_enumerate_data { - struct hid_device_info *root; - struct hid_device_info *end; - int drvctl; - uint16_t vendor_id; - uint16_t product_id; -}; - -typedef void (*enumerate_devices_callback) (const struct usb_device_info *, void *); - -static wchar_t *last_global_error_str = NULL; - -/* 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 = (wchar_t*) calloc(wlen+1, sizeof(wchar_t)); - if (ret == NULL) { - /* as much as we can do at this point */ - return NULL; - } - mbstowcs(ret, utf8, wlen+1); - ret[wlen] = 0x0000; - } - - return ret; -} - -/* Makes a copy of the given error message (and decoded according to the - * currently locale) into the wide string pointer pointed by error_str. - * The last stored error string is freed. - * Use register_error_str(NULL) to free the error message completely. */ -static void register_error_str(wchar_t **error_str, const char *msg) -{ - free(*error_str); - *error_str = utf8_to_wchar_t(msg); -} - -/* Semilar to register_error_str, but allows passing a format string with va_list args into this function. */ -static void register_error_str_vformat(wchar_t **error_str, const char *format, va_list args) -{ - char msg[256]; - vsnprintf(msg, sizeof(msg), format, args); - - register_error_str(error_str, msg); -} - -/* Set the last global error to be reported by hid_error(NULL). - * The given error message will be copied (and decoded according to the - * currently locale, so do not pass in string constants). - * The last stored global error message is freed. - * Use register_global_error(NULL) to indicate "no error". */ -static void register_global_error(const char *msg) -{ - register_error_str(&last_global_error_str, msg); -} - -/* Similar to register_global_error, but allows passing a format string into this function. */ -static void register_global_error_format(const char *format, ...) -{ - va_list args; - va_start(args, format); - register_error_str_vformat(&last_global_error_str, format, args); - va_end(args); -} - -/* Set the last error for a device to be reported by hid_error(dev). - * The given error message will be copied (and decoded according to the - * currently locale, so do not pass in string constants). - * The last stored device error message is freed. - * Use register_device_error(dev, NULL) to indicate "no error". */ -static void register_device_error(hid_device *dev, const char *msg) -{ - register_error_str(&dev->last_error_str, msg); -} - -/* Similar to register_device_error, but you can pass a format string into this function. */ -static void register_device_error_format(hid_device *dev, const char *format, ...) -{ - va_list args; - va_start(args, format); - register_error_str_vformat(&dev->last_error_str, format, args); - va_end(args); -} - - -/* - * 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(const uint8_t *report_descriptor, uint32_t size, unsigned int pos, 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; -} - -/* - * Get bytes from a HID Report Descriptor. - * Only call with a num_bytes of 0, 1, 2, or 4. - */ -static uint32_t get_hid_report_bytes(const 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; -} - -/* - * Iterates until the end of a Collection. - * Assumes that *pos is exactly at the beginning of a Collection. - * Skips all nested Collection, i.e. iterates until the end of current level Collection. - * - * The return value is non-0 when an end of current Collection is found, - * 0 when error is occurred (broken Descriptor, end of a Collection is found before its begin, - * or no Collection is found at all). - */ -static int hid_iterate_over_collection(const uint8_t *report_descriptor, uint32_t size, unsigned int *pos, int *data_len, int *key_size) -{ - int collection_level = 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, size, *pos, data_len, key_size)) - return 0; /* malformed report */ - - switch (key_cmd) { - case 0xa0: /* Collection 6.2.2.4 (Main) */ - collection_level++; - break; - case 0xc0: /* End Collection 6.2.2.4 (Main) */ - collection_level--; - break; - } - - if (collection_level < 0) { - /* Broken descriptor or someone is using this function wrong, - * i.e. should be called exactly at the collection start */ - return 0; - } - - if (collection_level == 0) { - /* Found it! - * Also possible when called not at the collection start, but should not happen if used correctly */ - return 1; - } - - *pos += *data_len + *key_size; - } - - return 0; /* Did not find the end of a Collection */ -} - -struct hid_usage_iterator { - unsigned int pos; - int usage_page_found; - unsigned short usage_page; -}; - -/* - * 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(const uint8_t *report_descriptor, uint32_t size, struct hid_usage_iterator *ctx, unsigned short *usage_page, unsigned short *usage) -{ - int data_len, key_size; - int initial = ctx->pos == 0; /* Used to handle case where no top-level application collection is defined */ - - int usage_found = 0; - - while (ctx->pos < size) { - int key = report_descriptor[ctx->pos]; - int key_cmd = key & 0xfc; - - /* Determine data_len and key_size */ - if (!get_hid_item_size(report_descriptor, size, ctx->pos, &data_len, &key_size)) - return -1; /* malformed report */ - - switch (key_cmd) { - case 0x4: /* Usage Page 6.2.2.7 (Global) */ - ctx->usage_page = get_hid_report_bytes(report_descriptor, size, data_len, ctx->pos); - ctx->usage_page_found = 1; - break; - - case 0x8: /* Usage 6.2.2.8 (Local) */ - if (data_len == 4) { /* Usages 5.5 / Usage Page 6.2.2.7 */ - ctx->usage_page = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos + 2); - ctx->usage_page_found = 1; - *usage = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos); - usage_found = 1; - } - else { - *usage = get_hid_report_bytes(report_descriptor, size, data_len, ctx->pos); - usage_found = 1; - } - break; - - case 0xa0: /* Collection 6.2.2.4 (Main) */ - if (!hid_iterate_over_collection(report_descriptor, size, &ctx->pos, &data_len, &key_size)) { - return -1; - } - - /* A pair is valid - to be reported when Collection is found */ - if (usage_found && ctx->usage_page_found) { - *usage_page = ctx->usage_page; - return 0; - } - - break; - } - - /* Skip over this key and its associated data */ - ctx->pos += data_len + key_size; - } - - /* 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 && ctx->usage_page_found) { - *usage_page = ctx->usage_page; - return 0; /* success */ - } - - return 1; /* finished processing */ -} - -static struct hid_device_info *create_device_info(const struct usb_device_info *udi, const char *path, const struct usb_ctl_report_desc *ucrd) -{ - struct hid_device_info *root; - struct hid_device_info *end; - - root = (struct hid_device_info *) calloc(1, sizeof(struct hid_device_info)); - if (!root) - return NULL; - - end = root; - - /* Path */ - end->path = (path) ? strdup(path) : NULL; - - /* Vendor Id */ - end->vendor_id = udi->udi_vendorNo; - - /* Product Id */ - end->product_id = udi->udi_productNo; - - /* Serial Number */ - end->serial_number = utf8_to_wchar_t(udi->udi_serial); - - /* Release Number */ - end->release_number = udi->udi_releaseNo; - - /* Manufacturer String */ - end->manufacturer_string = utf8_to_wchar_t(udi->udi_vendor); - - /* Product String */ - end->product_string = utf8_to_wchar_t(udi->udi_product); - - /* Usage Page */ - end->usage_page = 0; - - /* Usage */ - end->usage = 0; - - /* Interface Number */ - end->interface_number = -1; - - /* Next Device Info */ - end->next = NULL; - - /* Bus Type */ - end->bus_type = HID_API_BUS_USB; - - if (ucrd) { - uint16_t page; - uint16_t usage; - struct hid_usage_iterator usage_iterator; - - page = usage = 0; - memset(&usage_iterator, 0, sizeof(usage_iterator)); - - /* - * Parse the first usage and usage page - * out of the report descriptor. - */ - if (get_next_hid_usage(ucrd->ucrd_data, ucrd->ucrd_size, &usage_iterator, &page, &usage) == 0) { - end->usage_page = page; - end->usage = usage; - } - - /* - * Parse any additional usage and usage pages - * out of the report descriptor. - */ - while (get_next_hid_usage(ucrd->ucrd_data, ucrd->ucrd_size, &usage_iterator, &page, &usage) == 0) { - /* Create new record for additional usage pairs */ - struct hid_device_info *node = (struct hid_device_info *) calloc(1, sizeof(struct hid_device_info)); - - if (!node) - continue; - - /* Update fields */ - node->path = (end->path) ? strdup(end->path) : NULL; - node->vendor_id = end->vendor_id; - node->product_id = end->product_id; - node->serial_number = (end->serial_number) ? wcsdup(end->serial_number) : NULL; - node->release_number = end->release_number; - node->manufacturer_string = (end->manufacturer_string) ? wcsdup(end->manufacturer_string) : NULL; - node->product_string = (end->product_string) ? wcsdup(end->product_string) : NULL; - node->usage_page = page; - node->usage = usage; - node->interface_number = end->interface_number; - node->next = NULL; - node->bus_type = end->bus_type; - - /* Insert node */ - end->next = node; - end = node; - } - } - - return root; -} - -static int is_usb_controller(const char *s) -{ - return (!strncmp(s, "usb", 3) && isdigit((int) s[3])); -} - -static int is_uhid_parent_device(const char *s) -{ - return (!strncmp(s, "uhidev", 6) && isdigit((int) s[6])); -} - -static int is_uhid_device(const char *s) -{ - return (!strncmp(s, "uhid", 4) && isdigit((int) s[4])); -} - -static void walk_device_tree(int drvctl, const char *dev, int depth, char arr[static HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN], size_t *len, int (*cmp) (const char *)) -{ - int res; - char childname[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN]; - struct devlistargs dla; - - if (depth && (!dev || !*dev)) - return; - - if (cmp(dev) && *len < HIDAPI_MAX_CHILD_DEVICES) - strlcpy(arr[(*len)++], dev, sizeof(*arr)); - - strlcpy(dla.l_devname, dev, sizeof(dla.l_devname)); - dla.l_childname = childname; - dla.l_children = HIDAPI_MAX_CHILD_DEVICES; - - res = ioctl(drvctl, DRVLISTDEV, &dla); - if (res == -1) - return; - - /* - * DO NOT CHANGE THIS. This is a fail-safe check - * for the unlikely event that a parent device has - * more than HIDAPI_MAX_CHILD_DEVICES child devices - * to prevent iterating over uninitialized data. - */ - if (dla.l_children > HIDAPI_MAX_CHILD_DEVICES) - return; - - for (size_t i = 0; i < dla.l_children; i++) - walk_device_tree(drvctl, dla.l_childname[i], depth + 1, arr, len, cmp); -} - -static void enumerate_usb_devices(int bus, uint8_t addr, enumerate_devices_callback func, void *data) -{ - int res; - struct usb_device_info udi; - - udi.udi_addr = addr; - - res = ioctl(bus, USB_DEVICEINFO, &udi); - if (res == -1) - return; - - for (int port = 0; port < udi.udi_nports; port++) { - addr = udi.udi_ports[port]; - if (addr >= USB_MAX_DEVICES) - continue; - - enumerate_usb_devices(bus, addr, func, data); - } - - func(&udi, data); -} - -static void hid_enumerate_callback(const struct usb_device_info *udi, void *data) -{ - struct hid_enumerate_data *hed; - - hed = (struct hid_enumerate_data *) data; - - if (hed->vendor_id != 0 && hed->vendor_id != udi->udi_vendorNo) - return; - - if (hed->product_id != 0 && hed->product_id != udi->udi_productNo) - return; - - for (size_t i = 0; i < USB_MAX_DEVNAMES; i++) { - const char *parent_dev; - char arr[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN]; - size_t len; - const char *child_dev; - char devpath[USB_MAX_DEVNAMELEN]; - int uhid; - struct usb_ctl_report_desc ucrd; - int use_ucrd; - struct hid_device_info *node; - - parent_dev = udi->udi_devnames[i]; - if (!is_uhid_parent_device(parent_dev)) - continue; - - len = 0; - walk_device_tree(hed->drvctl, parent_dev, 0, arr, &len, is_uhid_device); - - if (len == 0) - continue; - - child_dev = arr[0]; - strlcpy(devpath, "/dev/", sizeof(devpath)); - strlcat(devpath, child_dev, sizeof(devpath)); - - uhid = open(devpath, O_RDONLY | O_CLOEXEC); - if (uhid >= 0) { - use_ucrd = (ioctl(uhid, USB_GET_REPORT_DESC, &ucrd) != -1); - close(uhid); - } else { - use_ucrd = 0; - } - - node = create_device_info(udi, parent_dev, (use_ucrd) ? &ucrd : NULL); - if (!node) - continue; - - if (!hed->root) { - hed->root = node; - hed->end = node; - } else { - hed->end->next = node; - hed->end = node; - } - - while (hed->end->next) - hed->end = hed->end->next; - } -} - -static int set_report(hid_device *dev, const uint8_t *data, size_t length, int report) -{ - int res; - int device_handle; - struct usb_ctl_report ucr; - - if (length < 1) { - register_device_error(dev, "report must be greater than 1 byte"); - return -1; - } - - device_handle = dev->report_handles[*data]; - if (device_handle < 0) { - register_device_error_format(dev, "unsupported report id: %hhu", *data); - return -1; - } - - length--; - data++; - - if (length > sizeof(ucr.ucr_data)) { - register_device_error_format(dev, "report must be less than or equal to %zu bytes", sizeof(ucr.ucr_data)); - return -1; - } - - ucr.ucr_report = report; - memcpy(ucr.ucr_data, data, length); - - res = ioctl(device_handle, USB_SET_REPORT, &ucr); - if (res == -1) { - register_device_error_format(dev, "ioctl (USB_SET_REPORT): %s", strerror(errno)); - return -1; - } - - return (int) (length + 1); -} - -static int get_report(hid_device *dev, uint8_t *data, size_t length, int report) -{ - int res; - int device_handle; - struct usb_ctl_report ucr; - - if (length < 1) { - register_device_error(dev, "report must be greater than 1 byte"); - return -1; - } - - device_handle = dev->report_handles[*data]; - if (device_handle < 0) { - register_device_error_format(dev, "unsupported report id: %hhu", *data); - return -1; - } - - length--; - data++; - - if (length > sizeof(ucr.ucr_data)) { - length = sizeof(ucr.ucr_data); - } - - ucr.ucr_report = report; - - res = ioctl(device_handle, USB_GET_REPORT, &ucr); - if (res == -1) { - register_device_error_format(dev, "ioctl (USB_GET_REPORT): %s", strerror(errno)); - return -1; - } - - memcpy(data, ucr.ucr_data, length); - - return (int) (length + 1); -} - -int HID_API_EXPORT HID_API_CALL hid_init(void) -{ - /* indicate no error */ - register_global_error(NULL); - - return 0; -} - -int HID_API_EXPORT HID_API_CALL hid_exit(void) -{ - /* Free global error message */ - register_global_error(NULL); - - return 0; -} - -struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) -{ - int res; - int drvctl; - char arr[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN]; - size_t len; - struct hid_enumerate_data hed; - - res = hid_init(); - if (res == -1) - return NULL; - - drvctl = open(DRVCTLDEV, O_RDONLY | O_CLOEXEC); - if (drvctl == -1) { - register_global_error_format("failed to open drvctl: %s", strerror(errno)); - return NULL; - } - - len = 0; - walk_device_tree(drvctl, "", 0, arr, &len, is_usb_controller); - - hed.root = NULL; - hed.end = NULL; - hed.drvctl = drvctl; - hed.vendor_id = vendor_id; - hed.product_id = product_id; - - for (size_t i = 0; i < len; i++) { - char devpath[USB_MAX_DEVNAMELEN]; - int bus; - - strlcpy(devpath, "/dev/", sizeof(devpath)); - strlcat(devpath, arr[i], sizeof(devpath)); - - bus = open(devpath, O_RDONLY | O_CLOEXEC); - if (bus == -1) - continue; - - enumerate_usb_devices(bus, 0, hid_enumerate_callback, &hed); - - close(bus); - } - - close(drvctl); - - return hed.root; -} - -void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) -{ - while (devs) { - struct hid_device_info *next = devs->next; - free(devs->path); - free(devs->serial_number); - free(devs->manufacturer_string); - free(devs->product_string); - free(devs); - devs = next; - } -} - -HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) -{ - struct hid_device_info *devs; - struct hid_device_info *dev; - char path[USB_MAX_DEVNAMELEN]; - - devs = hid_enumerate(vendor_id, product_id); - if (!devs) - return NULL; - - *path = '\0'; - - for (dev = devs; dev; dev = dev->next) { - if (dev->vendor_id != vendor_id) - continue; - - if (dev->product_id != product_id) - continue; - - if (serial_number && wcscmp(dev->serial_number, serial_number)) - continue; - - strlcpy(path, dev->path, sizeof(path)); - - break; - } - - hid_free_enumeration(devs); - - if (*path == '\0') { - register_global_error("Device with requested VID/PID/(SerialNumber) not found"); - return NULL; - } - - return hid_open_path(path); -} - -HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) -{ - int res; - hid_device *dev; - int drvctl; - char arr[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN]; - size_t len; - - res = hid_init(); - if (res == -1) - goto err_0; - - dev = (hid_device *) calloc(1, sizeof(hid_device)); - if (!dev) { - register_global_error("could not allocate hid_device"); - goto err_0; - } - - drvctl = open(DRVCTLDEV, O_RDONLY | O_CLOEXEC); - if (drvctl == -1) { - register_global_error_format("failed to open drvctl: %s", strerror(errno)); - goto err_1; - } - - if (!is_uhid_parent_device(path)) { - register_global_error("not a uhidev device"); - goto err_2; - } - - len = 0; - walk_device_tree(drvctl, path, 0, arr, &len, is_uhid_device); - - dev->poll_handles_length = 0; - memset(dev->poll_handles, 0x00, sizeof(dev->poll_handles)); - memset(dev->report_handles, 0xff, sizeof(dev->report_handles)); - - for (size_t i = 0; i < len; i++) { - const char *child_dev; - char devpath[USB_MAX_DEVNAMELEN]; - int uhid; - int rep_id; - struct pollfd *ph; - - child_dev = arr[i]; - strlcpy(devpath, "/dev/", sizeof(devpath)); - strlcat(devpath, child_dev, sizeof(devpath)); - - uhid = open(devpath, O_RDWR | O_CLOEXEC); - if (uhid == -1) { - register_global_error_format("failed to open %s: %s", child_dev, strerror(errno)); - goto err_3; - } - - res = ioctl(uhid, USB_GET_REPORT_ID, &rep_id); - if (res == -1) { - close(uhid); - register_global_error_format("failed to get report id %s: %s", child_dev, strerror(errno)); - goto err_3; - } - - ph = &dev->poll_handles[dev->poll_handles_length++]; - ph->fd = uhid; - ph->events = POLLIN; - ph->revents = 0; - dev->report_handles[rep_id] = uhid; - dev->device_handle = uhid; - } - - dev->blocking = 1; - dev->last_error_str = NULL; - dev->device_info = NULL; - strlcpy(dev->path, path, sizeof(dev->path)); - - register_global_error(NULL); - return dev; - -err_3: - for (size_t i = 0; i < dev->poll_handles_length; i++) - close(dev->poll_handles[i].fd); -err_2: - close(drvctl); -err_1: - free(dev); -err_0: - return NULL; -} - -int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) -{ - return set_report(dev, data, length, UHID_OUTPUT_REPORT); -} - -int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) -{ - int res; - size_t i; - struct pollfd *ph; - ssize_t n; - - res = poll(dev->poll_handles, dev->poll_handles_length, milliseconds); - if (res == -1) { - register_device_error_format(dev, "error while polling: %s", strerror(errno)); - return -1; - } - - if (res == 0) - return 0; - - for (i = 0; i < dev->poll_handles_length; i++) { - ph = &dev->poll_handles[i]; - - if (ph->revents & (POLLERR | POLLHUP | POLLNVAL)) { - register_device_error(dev, "device IO error while polling"); - return -1; - } - - if (ph->revents & POLLIN) - break; - } - - if (i == dev->poll_handles_length) - return 0; - - n = read(ph->fd, data, length); - if (n == -1) { - if (errno == EAGAIN || errno == EINPROGRESS) - n = 0; - else - register_device_error_format(dev, "error while reading: %s", strerror(errno)); - } - - return n; -} - -int HID_API_EXPORT HID_API_CALL 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_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) -{ - dev->blocking = !nonblock; - return 0; -} - -int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) -{ - return set_report(dev, data, length, UHID_FEATURE_REPORT); -} - -int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) -{ - return get_report(dev, data, length, UHID_FEATURE_REPORT); -} - -int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) -{ - return get_report(dev, data, length, UHID_INPUT_REPORT); -} - -void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) -{ - if (!dev) - return; - - /* Free the device error message */ - register_device_error(dev, NULL); - - hid_free_enumeration(dev->device_info); - - for (size_t i = 0; i < dev->poll_handles_length; i++) - close(dev->poll_handles[i].fd); - - free(dev); -} - -int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) -{ - struct hid_device_info *hdi; - - if (!string || !maxlen) { - register_device_error(dev, "Zero buffer/length"); - return -1; - } - - hdi = hid_get_device_info(dev); - if (!dev) - return -1; - - if (hdi->manufacturer_string) { - wcsncpy(string, hdi->manufacturer_string, maxlen); - string[maxlen - 1] = L'\0'; - } else { - string[0] = L'\0'; - } - - return 0; -} - -int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) -{ - struct hid_device_info *hdi; - - if (!string || !maxlen) { - register_device_error(dev, "Zero buffer/length"); - return -1; - } - - hdi = hid_get_device_info(dev); - if (!dev) - return -1; - - if (hdi->product_string) { - wcsncpy(string, hdi->product_string, maxlen); - string[maxlen - 1] = L'\0'; - } else { - string[0] = L'\0'; - } - - return 0; -} - -int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) -{ - struct hid_device_info *hdi; - - if (!string || !maxlen) { - register_device_error(dev, "Zero buffer/length"); - return -1; - } - - hdi = hid_get_device_info(dev); - if (!dev) - return -1; - - if (hdi->serial_number) { - wcsncpy(string, hdi->serial_number, maxlen); - string[maxlen - 1] = L'\0'; - } else { - string[0] = L'\0'; - } - - return 0; -} - -struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_get_device_info(hid_device *dev) -{ - int res; - struct usb_device_info udi; - struct usb_ctl_report_desc ucrd; - int use_ucrd; - struct hid_device_info *hdi; - - if (dev->device_info) - return dev->device_info; - - res = ioctl(dev->device_handle, USB_GET_DEVICEINFO, &udi); - if (res == -1) { - register_device_error_format(dev, "ioctl (USB_GET_DEVICEINFO): %s", strerror(errno)); - return NULL; - } - - use_ucrd = (ioctl(dev->device_handle, USB_GET_REPORT_DESC, &ucrd) != -1); - - hdi = create_device_info(&udi, dev->path, (use_ucrd) ? &ucrd : NULL); - if (!hdi) { - register_device_error(dev, "failed to create device info"); - return NULL; - } - - dev->device_info = hdi; - - return hdi; -} - -int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) -{ - int res; - struct usb_string_desc usd; - usb_string_descriptor_t *str; - iconv_t ic; - char *src; - size_t srcleft; - char *dst; - size_t dstleft; - size_t ic_res; - - /* First let us get the supported language IDs. */ - usd.usd_string_index = 0; - usd.usd_language_id = 0; - - res = ioctl(dev->device_handle, USB_GET_STRING_DESC, &usd); - if (res == -1) { - register_device_error_format(dev, "ioctl (USB_GET_STRING_DESC): %s", strerror(errno)); - return -1; - } - - str = &usd.usd_desc; - - if (str->bLength < 4) { - register_device_error(dev, "failed to get supported language IDs"); - return -1; - } - - /* Now we can get the requested string. */ - usd.usd_string_index = string_index; - usd.usd_language_id = UGETW(str->bString[0]); - - res = ioctl(dev->device_handle, USB_GET_STRING_DESC, &usd); - if (res == -1) { - register_device_error_format(dev, "ioctl (USB_GET_STRING_DESC): %s", strerror(errno)); - return -1; - } - - /* Now we need to convert it, using iconv. */ -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - ic = iconv_open("utf-32le", "utf-16le"); -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - ic = iconv_open("utf-32be", "utf-16le"); -#endif - if (ic == (iconv_t) -1) { - register_device_error_format(dev, "iconv_open failed: %s", strerror(errno)); - return -1; - } - - src = (char *) str->bString; - srcleft = str->bLength - 2; - dst = (char *) string; - dstleft = sizeof(wchar_t[maxlen]); - - ic_res = iconv(ic, &src, &srcleft, &dst, &dstleft); - iconv_close(ic); - if (ic_res == (size_t) -1) { - register_device_error_format(dev, "iconv failed: %s", strerror(errno)); - return -1; - } - - /* Write the terminating NULL. */ - string[maxlen - 1] = L'\0'; - if (dstleft >= sizeof(wchar_t)) - *((wchar_t *) dst) = L'\0'; - - return 0; -} - -int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size) -{ - int res; - struct usb_ctl_report_desc ucrd; - - res = ioctl(dev->device_handle, USB_GET_REPORT_DESC, &ucrd); - if (res == -1) { - register_device_error_format(dev, "ioctl (USB_GET_REPORT_DESC): %s", strerror(errno)); - return -1; - } - - if ((size_t) ucrd.ucrd_size < buf_size) - buf_size = (size_t) ucrd.ucrd_size; - - memcpy(buf, ucrd.ucrd_data, buf_size); - - return (int) buf_size; -} - -HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev) -{ - if (dev) { - if (dev->last_error_str == NULL) - return L"Success"; - return dev->last_error_str; - } - - if (last_global_error_str == NULL) - return L"Success"; - return last_global_error_str; -} - -HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void) -{ - static const struct hid_api_version api_version = { - .major = HID_API_VERSION_MAJOR, - .minor = HID_API_VERSION_MINOR, - .patch = HID_API_VERSION_PATCH - }; - - return &api_version; -} - -HID_API_EXPORT const char* HID_API_CALL hid_version_str(void) -{ - return HID_API_VERSION_STR; -} -- cgit v1.2.3