summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c')
-rw-r--r--contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c1173
1 files changed, 1173 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c b/contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c
new file mode 100644
index 0000000..82f34d4
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c
@@ -0,0 +1,1173 @@
1/*******************************************************
2 HIDAPI - Multi-Platform library for
3 communication with HID devices.
4
5 James Buren
6 libusb/hidapi Team
7
8 Copyright 2023, All Rights Reserved.
9
10 At the discretion of the user of this library,
11 this software may be licensed under the terms of the
12 GNU General Public License v3, a BSD-Style license, or the
13 original HIDAPI license as outlined in the LICENSE.txt,
14 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
15 files located at the root of the source distribution.
16 These files may also be found in the public source
17 code repository located at:
18 https://github.com/libusb/hidapi .
19********************************************************/
20
21/* C */
22#include <stdlib.h>
23#include <stdarg.h>
24#include <string.h>
25#include <locale.h>
26#include <ctype.h>
27#include <errno.h>
28
29/* Unix */
30#include <unistd.h>
31#include <fcntl.h>
32#include <iconv.h>
33#include <poll.h>
34
35/* NetBSD */
36#include <sys/drvctlio.h>
37#include <dev/usb/usb.h>
38#include <dev/usb/usbhid.h>
39
40#include "../hidapi/hidapi.h"
41
42#define HIDAPI_MAX_CHILD_DEVICES 256
43
44struct hid_device_ {
45 int device_handle;
46 int blocking;
47 wchar_t *last_error_str;
48 struct hid_device_info *device_info;
49 size_t poll_handles_length;
50 struct pollfd poll_handles[256];
51 int report_handles[256];
52 char path[USB_MAX_DEVNAMELEN];
53};
54
55struct hid_enumerate_data {
56 struct hid_device_info *root;
57 struct hid_device_info *end;
58 int drvctl;
59 uint16_t vendor_id;
60 uint16_t product_id;
61};
62
63typedef void (*enumerate_devices_callback) (const struct usb_device_info *, void *);
64
65static wchar_t *last_global_error_str = NULL;
66
67/* The caller must free the returned string with free(). */
68static wchar_t *utf8_to_wchar_t(const char *utf8)
69{
70 wchar_t *ret = NULL;
71
72 if (utf8) {
73 size_t wlen = mbstowcs(NULL, utf8, 0);
74 if ((size_t) -1 == wlen) {
75 return wcsdup(L"");
76 }
77 ret = (wchar_t*) calloc(wlen+1, sizeof(wchar_t));
78 if (ret == NULL) {
79 /* as much as we can do at this point */
80 return NULL;
81 }
82 mbstowcs(ret, utf8, wlen+1);
83 ret[wlen] = 0x0000;
84 }
85
86 return ret;
87}
88
89/* Makes a copy of the given error message (and decoded according to the
90 * currently locale) into the wide string pointer pointed by error_str.
91 * The last stored error string is freed.
92 * Use register_error_str(NULL) to free the error message completely. */
93static void register_error_str(wchar_t **error_str, const char *msg)
94{
95 free(*error_str);
96 *error_str = utf8_to_wchar_t(msg);
97}
98
99/* Semilar to register_error_str, but allows passing a format string with va_list args into this function. */
100static void register_error_str_vformat(wchar_t **error_str, const char *format, va_list args)
101{
102 char msg[256];
103 vsnprintf(msg, sizeof(msg), format, args);
104
105 register_error_str(error_str, msg);
106}
107
108/* Set the last global error to be reported by hid_error(NULL).
109 * The given error message will be copied (and decoded according to the
110 * currently locale, so do not pass in string constants).
111 * The last stored global error message is freed.
112 * Use register_global_error(NULL) to indicate "no error". */
113static void register_global_error(const char *msg)
114{
115 register_error_str(&last_global_error_str, msg);
116}
117
118/* Similar to register_global_error, but allows passing a format string into this function. */
119static void register_global_error_format(const char *format, ...)
120{
121 va_list args;
122 va_start(args, format);
123 register_error_str_vformat(&last_global_error_str, format, args);
124 va_end(args);
125}
126
127/* Set the last error for a device to be reported by hid_error(dev).
128 * The given error message will be copied (and decoded according to the
129 * currently locale, so do not pass in string constants).
130 * The last stored device error message is freed.
131 * Use register_device_error(dev, NULL) to indicate "no error". */
132static void register_device_error(hid_device *dev, const char *msg)
133{
134 register_error_str(&dev->last_error_str, msg);
135}
136
137/* Similar to register_device_error, but you can pass a format string into this function. */
138static void register_device_error_format(hid_device *dev, const char *format, ...)
139{
140 va_list args;
141 va_start(args, format);
142 register_error_str_vformat(&dev->last_error_str, format, args);
143 va_end(args);
144}
145
146
147/*
148 * Gets the size of the HID item at the given position
149 * Returns 1 if successful, 0 if an invalid key
150 * Sets data_len and key_size when successful
151 */
152static int get_hid_item_size(const uint8_t *report_descriptor, uint32_t size, unsigned int pos, int *data_len, int *key_size)
153{
154 int key = report_descriptor[pos];
155 int size_code;
156
157 /*
158 * This is a Long Item. The next byte contains the
159 * length of the data section (value) for this key.
160 * See the HID specification, version 1.11, section
161 * 6.2.2.3, titled "Long Items."
162 */
163 if ((key & 0xf0) == 0xf0) {
164 if (pos + 1 < size)
165 {
166 *data_len = report_descriptor[pos + 1];
167 *key_size = 3;
168 return 1;
169 }
170 *data_len = 0; /* malformed report */
171 *key_size = 0;
172 }
173
174 /*
175 * This is a Short Item. The bottom two bits of the
176 * key contain the size code for the data section
177 * (value) for this key. Refer to the HID
178 * specification, version 1.11, section 6.2.2.2,
179 * titled "Short Items."
180 */
181 size_code = key & 0x3;
182 switch (size_code) {
183 case 0:
184 case 1:
185 case 2:
186 *data_len = size_code;
187 *key_size = 1;
188 return 1;
189 case 3:
190 *data_len = 4;
191 *key_size = 1;
192 return 1;
193 default:
194 /* Can't ever happen since size_code is & 0x3 */
195 *data_len = 0;
196 *key_size = 0;
197 break;
198 };
199
200 /* malformed report */
201 return 0;
202}
203
204/*
205 * Get bytes from a HID Report Descriptor.
206 * Only call with a num_bytes of 0, 1, 2, or 4.
207 */
208static uint32_t get_hid_report_bytes(const uint8_t *rpt, size_t len, size_t num_bytes, size_t cur)
209{
210 /* Return if there aren't enough bytes. */
211 if (cur + num_bytes >= len)
212 return 0;
213
214 if (num_bytes == 0)
215 return 0;
216 else if (num_bytes == 1)
217 return rpt[cur + 1];
218 else if (num_bytes == 2)
219 return (rpt[cur + 2] * 256 + rpt[cur + 1]);
220 else if (num_bytes == 4)
221 return (
222 rpt[cur + 4] * 0x01000000 +
223 rpt[cur + 3] * 0x00010000 +
224 rpt[cur + 2] * 0x00000100 +
225 rpt[cur + 1] * 0x00000001
226 );
227 else
228 return 0;
229}
230
231/*
232 * Iterates until the end of a Collection.
233 * Assumes that *pos is exactly at the beginning of a Collection.
234 * Skips all nested Collection, i.e. iterates until the end of current level Collection.
235 *
236 * The return value is non-0 when an end of current Collection is found,
237 * 0 when error is occurred (broken Descriptor, end of a Collection is found before its begin,
238 * or no Collection is found at all).
239 */
240static int hid_iterate_over_collection(const uint8_t *report_descriptor, uint32_t size, unsigned int *pos, int *data_len, int *key_size)
241{
242 int collection_level = 0;
243
244 while (*pos < size) {
245 int key = report_descriptor[*pos];
246 int key_cmd = key & 0xfc;
247
248 /* Determine data_len and key_size */
249 if (!get_hid_item_size(report_descriptor, size, *pos, data_len, key_size))
250 return 0; /* malformed report */
251
252 switch (key_cmd) {
253 case 0xa0: /* Collection 6.2.2.4 (Main) */
254 collection_level++;
255 break;
256 case 0xc0: /* End Collection 6.2.2.4 (Main) */
257 collection_level--;
258 break;
259 }
260
261 if (collection_level < 0) {
262 /* Broken descriptor or someone is using this function wrong,
263 * i.e. should be called exactly at the collection start */
264 return 0;
265 }
266
267 if (collection_level == 0) {
268 /* Found it!
269 * Also possible when called not at the collection start, but should not happen if used correctly */
270 return 1;
271 }
272
273 *pos += *data_len + *key_size;
274 }
275
276 return 0; /* Did not find the end of a Collection */
277}
278
279struct hid_usage_iterator {
280 unsigned int pos;
281 int usage_page_found;
282 unsigned short usage_page;
283};
284
285/*
286 * Retrieves the device's Usage Page and Usage from the report descriptor.
287 * The algorithm returns the current Usage Page/Usage pair whenever a new
288 * Collection is found and a Usage Local Item is currently in scope.
289 * Usage Local Items are consumed by each Main Item (See. 6.2.2.8).
290 * The algorithm should give similar results as Apple's:
291 * https://developer.apple.com/documentation/iokit/kiohiddeviceusagepairskey?language=objc
292 * Physical Collections are also matched (macOS does the same).
293 *
294 * This function can be called repeatedly until it returns non-0
295 * Usage is found. pos is the starting point (initially 0) and will be updated
296 * to the next search position.
297 *
298 * The return value is 0 when a pair is found.
299 * 1 when finished processing descriptor.
300 * -1 on a malformed report.
301 */
302static 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)
303{
304 int data_len, key_size;
305 int initial = ctx->pos == 0; /* Used to handle case where no top-level application collection is defined */
306
307 int usage_found = 0;
308
309 while (ctx->pos < size) {
310 int key = report_descriptor[ctx->pos];
311 int key_cmd = key & 0xfc;
312
313 /* Determine data_len and key_size */
314 if (!get_hid_item_size(report_descriptor, size, ctx->pos, &data_len, &key_size))
315 return -1; /* malformed report */
316
317 switch (key_cmd) {
318 case 0x4: /* Usage Page 6.2.2.7 (Global) */
319 ctx->usage_page = get_hid_report_bytes(report_descriptor, size, data_len, ctx->pos);
320 ctx->usage_page_found = 1;
321 break;
322
323 case 0x8: /* Usage 6.2.2.8 (Local) */
324 if (data_len == 4) { /* Usages 5.5 / Usage Page 6.2.2.7 */
325 ctx->usage_page = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos + 2);
326 ctx->usage_page_found = 1;
327 *usage = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos);
328 usage_found = 1;
329 }
330 else {
331 *usage = get_hid_report_bytes(report_descriptor, size, data_len, ctx->pos);
332 usage_found = 1;
333 }
334 break;
335
336 case 0xa0: /* Collection 6.2.2.4 (Main) */
337 if (!hid_iterate_over_collection(report_descriptor, size, &ctx->pos, &data_len, &key_size)) {
338 return -1;
339 }
340
341 /* A pair is valid - to be reported when Collection is found */
342 if (usage_found && ctx->usage_page_found) {
343 *usage_page = ctx->usage_page;
344 return 0;
345 }
346
347 break;
348 }
349
350 /* Skip over this key and its associated data */
351 ctx->pos += data_len + key_size;
352 }
353
354 /* If no top-level application collection is found and usage page/usage pair is found, pair is valid
355 https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections */
356 if (initial && usage_found && ctx->usage_page_found) {
357 *usage_page = ctx->usage_page;
358 return 0; /* success */
359 }
360
361 return 1; /* finished processing */
362}
363
364static struct hid_device_info *create_device_info(const struct usb_device_info *udi, const char *path, const struct usb_ctl_report_desc *ucrd)
365{
366 struct hid_device_info *root;
367 struct hid_device_info *end;
368
369 root = (struct hid_device_info *) calloc(1, sizeof(struct hid_device_info));
370 if (!root)
371 return NULL;
372
373 end = root;
374
375 /* Path */
376 end->path = (path) ? strdup(path) : NULL;
377
378 /* Vendor Id */
379 end->vendor_id = udi->udi_vendorNo;
380
381 /* Product Id */
382 end->product_id = udi->udi_productNo;
383
384 /* Serial Number */
385 end->serial_number = utf8_to_wchar_t(udi->udi_serial);
386
387 /* Release Number */
388 end->release_number = udi->udi_releaseNo;
389
390 /* Manufacturer String */
391 end->manufacturer_string = utf8_to_wchar_t(udi->udi_vendor);
392
393 /* Product String */
394 end->product_string = utf8_to_wchar_t(udi->udi_product);
395
396 /* Usage Page */
397 end->usage_page = 0;
398
399 /* Usage */
400 end->usage = 0;
401
402 /* Interface Number */
403 end->interface_number = -1;
404
405 /* Next Device Info */
406 end->next = NULL;
407
408 /* Bus Type */
409 end->bus_type = HID_API_BUS_USB;
410
411 if (ucrd) {
412 uint16_t page;
413 uint16_t usage;
414 struct hid_usage_iterator usage_iterator;
415
416 page = usage = 0;
417 memset(&usage_iterator, 0, sizeof(usage_iterator));
418
419 /*
420 * Parse the first usage and usage page
421 * out of the report descriptor.
422 */
423 if (get_next_hid_usage(ucrd->ucrd_data, ucrd->ucrd_size, &usage_iterator, &page, &usage) == 0) {
424 end->usage_page = page;
425 end->usage = usage;
426 }
427
428 /*
429 * Parse any additional usage and usage pages
430 * out of the report descriptor.
431 */
432 while (get_next_hid_usage(ucrd->ucrd_data, ucrd->ucrd_size, &usage_iterator, &page, &usage) == 0) {
433 /* Create new record for additional usage pairs */
434 struct hid_device_info *node = (struct hid_device_info *) calloc(1, sizeof(struct hid_device_info));
435
436 if (!node)
437 continue;
438
439 /* Update fields */
440 node->path = (end->path) ? strdup(end->path) : NULL;
441 node->vendor_id = end->vendor_id;
442 node->product_id = end->product_id;
443 node->serial_number = (end->serial_number) ? wcsdup(end->serial_number) : NULL;
444 node->release_number = end->release_number;
445 node->manufacturer_string = (end->manufacturer_string) ? wcsdup(end->manufacturer_string) : NULL;
446 node->product_string = (end->product_string) ? wcsdup(end->product_string) : NULL;
447 node->usage_page = page;
448 node->usage = usage;
449 node->interface_number = end->interface_number;
450 node->next = NULL;
451 node->bus_type = end->bus_type;
452
453 /* Insert node */
454 end->next = node;
455 end = node;
456 }
457 }
458
459 return root;
460}
461
462static int is_usb_controller(const char *s)
463{
464 return (!strncmp(s, "usb", 3) && isdigit((int) s[3]));
465}
466
467static int is_uhid_parent_device(const char *s)
468{
469 return (!strncmp(s, "uhidev", 6) && isdigit((int) s[6]));
470}
471
472static int is_uhid_device(const char *s)
473{
474 return (!strncmp(s, "uhid", 4) && isdigit((int) s[4]));
475}
476
477static 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 *))
478{
479 int res;
480 char childname[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN];
481 struct devlistargs dla;
482
483 if (depth && (!dev || !*dev))
484 return;
485
486 if (cmp(dev) && *len < HIDAPI_MAX_CHILD_DEVICES)
487 strlcpy(arr[(*len)++], dev, sizeof(*arr));
488
489 strlcpy(dla.l_devname, dev, sizeof(dla.l_devname));
490 dla.l_childname = childname;
491 dla.l_children = HIDAPI_MAX_CHILD_DEVICES;
492
493 res = ioctl(drvctl, DRVLISTDEV, &dla);
494 if (res == -1)
495 return;
496
497 /*
498 * DO NOT CHANGE THIS. This is a fail-safe check
499 * for the unlikely event that a parent device has
500 * more than HIDAPI_MAX_CHILD_DEVICES child devices
501 * to prevent iterating over uninitialized data.
502 */
503 if (dla.l_children > HIDAPI_MAX_CHILD_DEVICES)
504 return;
505
506 for (size_t i = 0; i < dla.l_children; i++)
507 walk_device_tree(drvctl, dla.l_childname[i], depth + 1, arr, len, cmp);
508}
509
510static void enumerate_usb_devices(int bus, uint8_t addr, enumerate_devices_callback func, void *data)
511{
512 int res;
513 struct usb_device_info udi;
514
515 udi.udi_addr = addr;
516
517 res = ioctl(bus, USB_DEVICEINFO, &udi);
518 if (res == -1)
519 return;
520
521 for (int port = 0; port < udi.udi_nports; port++) {
522 addr = udi.udi_ports[port];
523 if (addr >= USB_MAX_DEVICES)
524 continue;
525
526 enumerate_usb_devices(bus, addr, func, data);
527 }
528
529 func(&udi, data);
530}
531
532static void hid_enumerate_callback(const struct usb_device_info *udi, void *data)
533{
534 struct hid_enumerate_data *hed;
535
536 hed = (struct hid_enumerate_data *) data;
537
538 if (hed->vendor_id != 0 && hed->vendor_id != udi->udi_vendorNo)
539 return;
540
541 if (hed->product_id != 0 && hed->product_id != udi->udi_productNo)
542 return;
543
544 for (size_t i = 0; i < USB_MAX_DEVNAMES; i++) {
545 const char *parent_dev;
546 char arr[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN];
547 size_t len;
548 const char *child_dev;
549 char devpath[USB_MAX_DEVNAMELEN];
550 int uhid;
551 struct usb_ctl_report_desc ucrd;
552 int use_ucrd;
553 struct hid_device_info *node;
554
555 parent_dev = udi->udi_devnames[i];
556 if (!is_uhid_parent_device(parent_dev))
557 continue;
558
559 len = 0;
560 walk_device_tree(hed->drvctl, parent_dev, 0, arr, &len, is_uhid_device);
561
562 if (len == 0)
563 continue;
564
565 child_dev = arr[0];
566 strlcpy(devpath, "/dev/", sizeof(devpath));
567 strlcat(devpath, child_dev, sizeof(devpath));
568
569 uhid = open(devpath, O_RDONLY | O_CLOEXEC);
570 if (uhid >= 0) {
571 use_ucrd = (ioctl(uhid, USB_GET_REPORT_DESC, &ucrd) != -1);
572 close(uhid);
573 } else {
574 use_ucrd = 0;
575 }
576
577 node = create_device_info(udi, parent_dev, (use_ucrd) ? &ucrd : NULL);
578 if (!node)
579 continue;
580
581 if (!hed->root) {
582 hed->root = node;
583 hed->end = node;
584 } else {
585 hed->end->next = node;
586 hed->end = node;
587 }
588
589 while (hed->end->next)
590 hed->end = hed->end->next;
591 }
592}
593
594static int set_report(hid_device *dev, const uint8_t *data, size_t length, int report)
595{
596 int res;
597 int device_handle;
598 struct usb_ctl_report ucr;
599
600 if (length < 1) {
601 register_device_error(dev, "report must be greater than 1 byte");
602 return -1;
603 }
604
605 device_handle = dev->report_handles[*data];
606 if (device_handle < 0) {
607 register_device_error_format(dev, "unsupported report id: %hhu", *data);
608 return -1;
609 }
610
611 length--;
612 data++;
613
614 if (length > sizeof(ucr.ucr_data)) {
615 register_device_error_format(dev, "report must be less than or equal to %zu bytes", sizeof(ucr.ucr_data));
616 return -1;
617 }
618
619 ucr.ucr_report = report;
620 memcpy(ucr.ucr_data, data, length);
621
622 res = ioctl(device_handle, USB_SET_REPORT, &ucr);
623 if (res == -1) {
624 register_device_error_format(dev, "ioctl (USB_SET_REPORT): %s", strerror(errno));
625 return -1;
626 }
627
628 return (int) (length + 1);
629}
630
631static int get_report(hid_device *dev, uint8_t *data, size_t length, int report)
632{
633 int res;
634 int device_handle;
635 struct usb_ctl_report ucr;
636
637 if (length < 1) {
638 register_device_error(dev, "report must be greater than 1 byte");
639 return -1;
640 }
641
642 device_handle = dev->report_handles[*data];
643 if (device_handle < 0) {
644 register_device_error_format(dev, "unsupported report id: %hhu", *data);
645 return -1;
646 }
647
648 length--;
649 data++;
650
651 if (length > sizeof(ucr.ucr_data)) {
652 length = sizeof(ucr.ucr_data);
653 }
654
655 ucr.ucr_report = report;
656
657 res = ioctl(device_handle, USB_GET_REPORT, &ucr);
658 if (res == -1) {
659 register_device_error_format(dev, "ioctl (USB_GET_REPORT): %s", strerror(errno));
660 return -1;
661 }
662
663 memcpy(data, ucr.ucr_data, length);
664
665 return (int) (length + 1);
666}
667
668int HID_API_EXPORT HID_API_CALL hid_init(void)
669{
670 /* indicate no error */
671 register_global_error(NULL);
672
673 return 0;
674}
675
676int HID_API_EXPORT HID_API_CALL hid_exit(void)
677{
678 /* Free global error message */
679 register_global_error(NULL);
680
681 return 0;
682}
683
684struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
685{
686 int res;
687 int drvctl;
688 char arr[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN];
689 size_t len;
690 struct hid_enumerate_data hed;
691
692 res = hid_init();
693 if (res == -1)
694 return NULL;
695
696 drvctl = open(DRVCTLDEV, O_RDONLY | O_CLOEXEC);
697 if (drvctl == -1) {
698 register_global_error_format("failed to open drvctl: %s", strerror(errno));
699 return NULL;
700 }
701
702 len = 0;
703 walk_device_tree(drvctl, "", 0, arr, &len, is_usb_controller);
704
705 hed.root = NULL;
706 hed.end = NULL;
707 hed.drvctl = drvctl;
708 hed.vendor_id = vendor_id;
709 hed.product_id = product_id;
710
711 for (size_t i = 0; i < len; i++) {
712 char devpath[USB_MAX_DEVNAMELEN];
713 int bus;
714
715 strlcpy(devpath, "/dev/", sizeof(devpath));
716 strlcat(devpath, arr[i], sizeof(devpath));
717
718 bus = open(devpath, O_RDONLY | O_CLOEXEC);
719 if (bus == -1)
720 continue;
721
722 enumerate_usb_devices(bus, 0, hid_enumerate_callback, &hed);
723
724 close(bus);
725 }
726
727 close(drvctl);
728
729 return hed.root;
730}
731
732void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
733{
734 while (devs) {
735 struct hid_device_info *next = devs->next;
736 free(devs->path);
737 free(devs->serial_number);
738 free(devs->manufacturer_string);
739 free(devs->product_string);
740 free(devs);
741 devs = next;
742 }
743}
744
745HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
746{
747 struct hid_device_info *devs;
748 struct hid_device_info *dev;
749 char path[USB_MAX_DEVNAMELEN];
750
751 devs = hid_enumerate(vendor_id, product_id);
752 if (!devs)
753 return NULL;
754
755 *path = '\0';
756
757 for (dev = devs; dev; dev = dev->next) {
758 if (dev->vendor_id != vendor_id)
759 continue;
760
761 if (dev->product_id != product_id)
762 continue;
763
764 if (serial_number && wcscmp(dev->serial_number, serial_number))
765 continue;
766
767 strlcpy(path, dev->path, sizeof(path));
768
769 break;
770 }
771
772 hid_free_enumeration(devs);
773
774 if (*path == '\0') {
775 register_global_error("Device with requested VID/PID/(SerialNumber) not found");
776 return NULL;
777 }
778
779 return hid_open_path(path);
780}
781
782HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
783{
784 int res;
785 hid_device *dev;
786 int drvctl;
787 char arr[HIDAPI_MAX_CHILD_DEVICES][USB_MAX_DEVNAMELEN];
788 size_t len;
789
790 res = hid_init();
791 if (res == -1)
792 goto err_0;
793
794 dev = (hid_device *) calloc(1, sizeof(hid_device));
795 if (!dev) {
796 register_global_error("could not allocate hid_device");
797 goto err_0;
798 }
799
800 drvctl = open(DRVCTLDEV, O_RDONLY | O_CLOEXEC);
801 if (drvctl == -1) {
802 register_global_error_format("failed to open drvctl: %s", strerror(errno));
803 goto err_1;
804 }
805
806 if (!is_uhid_parent_device(path)) {
807 register_global_error("not a uhidev device");
808 goto err_2;
809 }
810
811 len = 0;
812 walk_device_tree(drvctl, path, 0, arr, &len, is_uhid_device);
813
814 dev->poll_handles_length = 0;
815 memset(dev->poll_handles, 0x00, sizeof(dev->poll_handles));
816 memset(dev->report_handles, 0xff, sizeof(dev->report_handles));
817
818 for (size_t i = 0; i < len; i++) {
819 const char *child_dev;
820 char devpath[USB_MAX_DEVNAMELEN];
821 int uhid;
822 int rep_id;
823 struct pollfd *ph;
824
825 child_dev = arr[i];
826 strlcpy(devpath, "/dev/", sizeof(devpath));
827 strlcat(devpath, child_dev, sizeof(devpath));
828
829 uhid = open(devpath, O_RDWR | O_CLOEXEC);
830 if (uhid == -1) {
831 register_global_error_format("failed to open %s: %s", child_dev, strerror(errno));
832 goto err_3;
833 }
834
835 res = ioctl(uhid, USB_GET_REPORT_ID, &rep_id);
836 if (res == -1) {
837 close(uhid);
838 register_global_error_format("failed to get report id %s: %s", child_dev, strerror(errno));
839 goto err_3;
840 }
841
842 ph = &dev->poll_handles[dev->poll_handles_length++];
843 ph->fd = uhid;
844 ph->events = POLLIN;
845 ph->revents = 0;
846 dev->report_handles[rep_id] = uhid;
847 dev->device_handle = uhid;
848 }
849
850 dev->blocking = 1;
851 dev->last_error_str = NULL;
852 dev->device_info = NULL;
853 strlcpy(dev->path, path, sizeof(dev->path));
854
855 register_global_error(NULL);
856 return dev;
857
858err_3:
859 for (size_t i = 0; i < dev->poll_handles_length; i++)
860 close(dev->poll_handles[i].fd);
861err_2:
862 close(drvctl);
863err_1:
864 free(dev);
865err_0:
866 return NULL;
867}
868
869int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
870{
871 return set_report(dev, data, length, UHID_OUTPUT_REPORT);
872}
873
874int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
875{
876 int res;
877 size_t i;
878 struct pollfd *ph;
879 ssize_t n;
880
881 res = poll(dev->poll_handles, dev->poll_handles_length, milliseconds);
882 if (res == -1) {
883 register_device_error_format(dev, "error while polling: %s", strerror(errno));
884 return -1;
885 }
886
887 if (res == 0)
888 return 0;
889
890 for (i = 0; i < dev->poll_handles_length; i++) {
891 ph = &dev->poll_handles[i];
892
893 if (ph->revents & (POLLERR | POLLHUP | POLLNVAL)) {
894 register_device_error(dev, "device IO error while polling");
895 return -1;
896 }
897
898 if (ph->revents & POLLIN)
899 break;
900 }
901
902 if (i == dev->poll_handles_length)
903 return 0;
904
905 n = read(ph->fd, data, length);
906 if (n == -1) {
907 if (errno == EAGAIN || errno == EINPROGRESS)
908 n = 0;
909 else
910 register_device_error_format(dev, "error while reading: %s", strerror(errno));
911 }
912
913 return n;
914}
915
916int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
917{
918 return hid_read_timeout(dev, data, length, (dev->blocking) ? -1 : 0);
919}
920
921int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
922{
923 dev->blocking = !nonblock;
924 return 0;
925}
926
927int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
928{
929 return set_report(dev, data, length, UHID_FEATURE_REPORT);
930}
931
932int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
933{
934 return get_report(dev, data, length, UHID_FEATURE_REPORT);
935}
936
937int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
938{
939 return get_report(dev, data, length, UHID_INPUT_REPORT);
940}
941
942void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
943{
944 if (!dev)
945 return;
946
947 /* Free the device error message */
948 register_device_error(dev, NULL);
949
950 hid_free_enumeration(dev->device_info);
951
952 for (size_t i = 0; i < dev->poll_handles_length; i++)
953 close(dev->poll_handles[i].fd);
954
955 free(dev);
956}
957
958int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
959{
960 struct hid_device_info *hdi;
961
962 if (!string || !maxlen) {
963 register_device_error(dev, "Zero buffer/length");
964 return -1;
965 }
966
967 hdi = hid_get_device_info(dev);
968 if (!dev)
969 return -1;
970
971 if (hdi->manufacturer_string) {
972 wcsncpy(string, hdi->manufacturer_string, maxlen);
973 string[maxlen - 1] = L'\0';
974 } else {
975 string[0] = L'\0';
976 }
977
978 return 0;
979}
980
981int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
982{
983 struct hid_device_info *hdi;
984
985 if (!string || !maxlen) {
986 register_device_error(dev, "Zero buffer/length");
987 return -1;
988 }
989
990 hdi = hid_get_device_info(dev);
991 if (!dev)
992 return -1;
993
994 if (hdi->product_string) {
995 wcsncpy(string, hdi->product_string, maxlen);
996 string[maxlen - 1] = L'\0';
997 } else {
998 string[0] = L'\0';
999 }
1000
1001 return 0;
1002}
1003
1004int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1005{
1006 struct hid_device_info *hdi;
1007
1008 if (!string || !maxlen) {
1009 register_device_error(dev, "Zero buffer/length");
1010 return -1;
1011 }
1012
1013 hdi = hid_get_device_info(dev);
1014 if (!dev)
1015 return -1;
1016
1017 if (hdi->serial_number) {
1018 wcsncpy(string, hdi->serial_number, maxlen);
1019 string[maxlen - 1] = L'\0';
1020 } else {
1021 string[0] = L'\0';
1022 }
1023
1024 return 0;
1025}
1026
1027struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_get_device_info(hid_device *dev)
1028{
1029 int res;
1030 struct usb_device_info udi;
1031 struct usb_ctl_report_desc ucrd;
1032 int use_ucrd;
1033 struct hid_device_info *hdi;
1034
1035 if (dev->device_info)
1036 return dev->device_info;
1037
1038 res = ioctl(dev->device_handle, USB_GET_DEVICEINFO, &udi);
1039 if (res == -1) {
1040 register_device_error_format(dev, "ioctl (USB_GET_DEVICEINFO): %s", strerror(errno));
1041 return NULL;
1042 }
1043
1044 use_ucrd = (ioctl(dev->device_handle, USB_GET_REPORT_DESC, &ucrd) != -1);
1045
1046 hdi = create_device_info(&udi, dev->path, (use_ucrd) ? &ucrd : NULL);
1047 if (!hdi) {
1048 register_device_error(dev, "failed to create device info");
1049 return NULL;
1050 }
1051
1052 dev->device_info = hdi;
1053
1054 return hdi;
1055}
1056
1057int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1058{
1059 int res;
1060 struct usb_string_desc usd;
1061 usb_string_descriptor_t *str;
1062 iconv_t ic;
1063 char *src;
1064 size_t srcleft;
1065 char *dst;
1066 size_t dstleft;
1067 size_t ic_res;
1068
1069 /* First let us get the supported language IDs. */
1070 usd.usd_string_index = 0;
1071 usd.usd_language_id = 0;
1072
1073 res = ioctl(dev->device_handle, USB_GET_STRING_DESC, &usd);
1074 if (res == -1) {
1075 register_device_error_format(dev, "ioctl (USB_GET_STRING_DESC): %s", strerror(errno));
1076 return -1;
1077 }
1078
1079 str = &usd.usd_desc;
1080
1081 if (str->bLength < 4) {
1082 register_device_error(dev, "failed to get supported language IDs");
1083 return -1;
1084 }
1085
1086 /* Now we can get the requested string. */
1087 usd.usd_string_index = string_index;
1088 usd.usd_language_id = UGETW(str->bString[0]);
1089
1090 res = ioctl(dev->device_handle, USB_GET_STRING_DESC, &usd);
1091 if (res == -1) {
1092 register_device_error_format(dev, "ioctl (USB_GET_STRING_DESC): %s", strerror(errno));
1093 return -1;
1094 }
1095
1096 /* Now we need to convert it, using iconv. */
1097#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
1098 ic = iconv_open("utf-32le", "utf-16le");
1099#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1100 ic = iconv_open("utf-32be", "utf-16le");
1101#endif
1102 if (ic == (iconv_t) -1) {
1103 register_device_error_format(dev, "iconv_open failed: %s", strerror(errno));
1104 return -1;
1105 }
1106
1107 src = (char *) str->bString;
1108 srcleft = str->bLength - 2;
1109 dst = (char *) string;
1110 dstleft = sizeof(wchar_t[maxlen]);
1111
1112 ic_res = iconv(ic, &src, &srcleft, &dst, &dstleft);
1113 iconv_close(ic);
1114 if (ic_res == (size_t) -1) {
1115 register_device_error_format(dev, "iconv failed: %s", strerror(errno));
1116 return -1;
1117 }
1118
1119 /* Write the terminating NULL. */
1120 string[maxlen - 1] = L'\0';
1121 if (dstleft >= sizeof(wchar_t))
1122 *((wchar_t *) dst) = L'\0';
1123
1124 return 0;
1125}
1126
1127int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
1128{
1129 int res;
1130 struct usb_ctl_report_desc ucrd;
1131
1132 res = ioctl(dev->device_handle, USB_GET_REPORT_DESC, &ucrd);
1133 if (res == -1) {
1134 register_device_error_format(dev, "ioctl (USB_GET_REPORT_DESC): %s", strerror(errno));
1135 return -1;
1136 }
1137
1138 if ((size_t) ucrd.ucrd_size < buf_size)
1139 buf_size = (size_t) ucrd.ucrd_size;
1140
1141 memcpy(buf, ucrd.ucrd_data, buf_size);
1142
1143 return (int) buf_size;
1144}
1145
1146HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev)
1147{
1148 if (dev) {
1149 if (dev->last_error_str == NULL)
1150 return L"Success";
1151 return dev->last_error_str;
1152 }
1153
1154 if (last_global_error_str == NULL)
1155 return L"Success";
1156 return last_global_error_str;
1157}
1158
1159HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void)
1160{
1161 static const struct hid_api_version api_version = {
1162 .major = HID_API_VERSION_MAJOR,
1163 .minor = HID_API_VERSION_MINOR,
1164 .patch = HID_API_VERSION_PATCH
1165 };
1166
1167 return &api_version;
1168}
1169
1170HID_API_EXPORT const char* HID_API_CALL hid_version_str(void)
1171{
1172 return HID_API_VERSION_STR;
1173}