Atlas - hid.c

Home / ext / SDL / src / hidapi / netbsd Lines: 1 | Size: 29412 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
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/* Similar 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} 1174
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.