hid.c (30610B)
1 /******************************************************* 2 HIDAPI - Multi-Platform library for 3 communication with HID devices. 4 5 Alan Ott 6 Signal 11 Software 7 8 2010-07-03 9 10 Copyright 2010, All Rights Reserved. 11 12 At the discretion of the user of this library, 13 this software may be licensed under the terms of the 14 GNU Public License v3, a BSD-Style license, or the 15 original HIDAPI license as outlined in the LICENSE.txt, 16 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt 17 files located at the root of the source distribution. 18 These files may also be found in the public source 19 code repository located at: 20 https://github.com/libusb/hidapi . 21 ********************************************************/ 22 #include "../../SDL_internal.h" 23 24 #ifdef SDL_JOYSTICK_HIDAPI 25 26 /* See Apple Technical Note TN2187 for details on IOHidManager. */ 27 28 #include <IOKit/hid/IOHIDManager.h> 29 #include <IOKit/hid/IOHIDKeys.h> 30 #include <CoreFoundation/CoreFoundation.h> 31 #include <wchar.h> 32 #include <pthread.h> 33 #include <sys/time.h> 34 #include <unistd.h> 35 36 #include "hidapi.h" 37 38 /* Barrier implementation because Mac OSX doesn't have pthread_barrier. 39 It also doesn't have clock_gettime(). So much for POSIX and SUSv2. 40 This implementation came from Brent Priddy and was posted on 41 StackOverflow. It is used with his permission. */ 42 typedef int pthread_barrierattr_t; 43 typedef struct pthread_barrier { 44 pthread_mutex_t mutex; 45 pthread_cond_t cond; 46 int count; 47 int trip_count; 48 } pthread_barrier_t; 49 50 static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count) 51 { 52 if(count == 0) { 53 errno = EINVAL; 54 return -1; 55 } 56 57 if(pthread_mutex_init(&barrier->mutex, 0) < 0) { 58 return -1; 59 } 60 if(pthread_cond_init(&barrier->cond, 0) < 0) { 61 pthread_mutex_destroy(&barrier->mutex); 62 return -1; 63 } 64 barrier->trip_count = count; 65 barrier->count = 0; 66 67 return 0; 68 } 69 70 static int pthread_barrier_destroy(pthread_barrier_t *barrier) 71 { 72 pthread_cond_destroy(&barrier->cond); 73 pthread_mutex_destroy(&barrier->mutex); 74 return 0; 75 } 76 77 static int pthread_barrier_wait(pthread_barrier_t *barrier) 78 { 79 pthread_mutex_lock(&barrier->mutex); 80 ++(barrier->count); 81 if(barrier->count >= barrier->trip_count) 82 { 83 barrier->count = 0; 84 pthread_cond_broadcast(&barrier->cond); 85 pthread_mutex_unlock(&barrier->mutex); 86 return 1; 87 } 88 else 89 { 90 pthread_cond_wait(&barrier->cond, &(barrier->mutex)); 91 pthread_mutex_unlock(&barrier->mutex); 92 return 0; 93 } 94 } 95 96 static int return_data(hid_device *dev, unsigned char *data, size_t length); 97 98 /* Linked List of input reports received from the device. */ 99 struct input_report { 100 uint8_t *data; 101 size_t len; 102 struct input_report *next; 103 }; 104 105 struct hid_device_ { 106 IOHIDDeviceRef device_handle; 107 int blocking; 108 int uses_numbered_reports; 109 int disconnected; 110 CFStringRef run_loop_mode; 111 CFRunLoopRef run_loop; 112 CFRunLoopSourceRef source; 113 uint8_t *input_report_buf; 114 CFIndex max_input_report_len; 115 struct input_report *input_reports; 116 117 pthread_t thread; 118 pthread_mutex_t mutex; /* Protects input_reports */ 119 pthread_cond_t condition; 120 pthread_barrier_t barrier; /* Ensures correct startup sequence */ 121 pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */ 122 int shutdown_thread; 123 }; 124 125 struct hid_device_list_node 126 { 127 struct hid_device_ *dev; 128 struct hid_device_list_node *next; 129 }; 130 131 static IOHIDManagerRef hid_mgr = 0x0; 132 static struct hid_device_list_node *device_list = 0x0; 133 134 static hid_device *new_hid_device(void) 135 { 136 hid_device *dev = (hid_device*)calloc(1, sizeof(hid_device)); 137 dev->device_handle = NULL; 138 dev->blocking = 1; 139 dev->uses_numbered_reports = 0; 140 dev->disconnected = 0; 141 dev->run_loop_mode = NULL; 142 dev->run_loop = NULL; 143 dev->source = NULL; 144 dev->input_report_buf = NULL; 145 dev->input_reports = NULL; 146 dev->shutdown_thread = 0; 147 148 /* Thread objects */ 149 pthread_mutex_init(&dev->mutex, NULL); 150 pthread_cond_init(&dev->condition, NULL); 151 pthread_barrier_init(&dev->barrier, NULL, 2); 152 pthread_barrier_init(&dev->shutdown_barrier, NULL, 2); 153 154 return dev; 155 } 156 157 static void free_hid_device(hid_device *dev) 158 { 159 if (!dev) 160 return; 161 162 /* Delete any input reports still left over. */ 163 struct input_report *rpt = dev->input_reports; 164 while (rpt) { 165 struct input_report *next = rpt->next; 166 free(rpt->data); 167 free(rpt); 168 rpt = next; 169 } 170 171 /* Free the string and the report buffer. The check for NULL 172 is necessary here as CFRelease() doesn't handle NULL like 173 free() and others do. */ 174 if (dev->run_loop_mode) 175 CFRelease(dev->run_loop_mode); 176 if (dev->source) 177 CFRelease(dev->source); 178 free(dev->input_report_buf); 179 180 if (device_list) { 181 if (device_list->dev == dev) { 182 device_list = device_list->next; 183 } 184 else { 185 struct hid_device_list_node *node = device_list; 186 while (node) { 187 if (node->next && node->next->dev == dev) { 188 struct hid_device_list_node *new_next = node->next->next; 189 free(node->next); 190 node->next = new_next; 191 break; 192 } 193 194 node = node->next; 195 } 196 } 197 } 198 199 /* Clean up the thread objects */ 200 pthread_barrier_destroy(&dev->shutdown_barrier); 201 pthread_barrier_destroy(&dev->barrier); 202 pthread_cond_destroy(&dev->condition); 203 pthread_mutex_destroy(&dev->mutex); 204 205 /* Free the structure itself. */ 206 free(dev); 207 } 208 209 #if 0 210 static void register_error(hid_device *device, const char *op) 211 { 212 213 } 214 #endif 215 216 217 static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key) 218 { 219 CFTypeRef ref; 220 int32_t value; 221 222 ref = IOHIDDeviceGetProperty(device, key); 223 if (ref) { 224 if (CFGetTypeID(ref) == CFNumberGetTypeID()) { 225 CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value); 226 return value; 227 } 228 } 229 return 0; 230 } 231 232 static unsigned short get_vendor_id(IOHIDDeviceRef device) 233 { 234 return get_int_property(device, CFSTR(kIOHIDVendorIDKey)); 235 } 236 237 static unsigned short get_product_id(IOHIDDeviceRef device) 238 { 239 return get_int_property(device, CFSTR(kIOHIDProductIDKey)); 240 } 241 242 243 static int32_t get_max_report_length(IOHIDDeviceRef device) 244 { 245 return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey)); 246 } 247 248 static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len) 249 { 250 CFStringRef str; 251 252 if (!len) 253 return 0; 254 255 str = (CFStringRef)IOHIDDeviceGetProperty(device, prop); 256 257 buf[0] = 0; 258 259 if (str) { 260 len --; 261 262 CFIndex str_len = CFStringGetLength(str); 263 CFRange range; 264 range.location = 0; 265 range.length = (str_len > len)? len: str_len; 266 CFIndex used_buf_len; 267 CFIndex chars_copied; 268 chars_copied = CFStringGetBytes(str, 269 range, 270 kCFStringEncodingUTF32LE, 271 (char)'?', 272 FALSE, 273 (UInt8*)buf, 274 len, 275 &used_buf_len); 276 277 buf[chars_copied] = 0; 278 return (int)chars_copied; 279 } 280 else 281 return 0; 282 283 } 284 285 static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len) 286 { 287 CFStringRef str; 288 if (!len) 289 return 0; 290 291 str = (CFStringRef)IOHIDDeviceGetProperty(device, prop); 292 293 buf[0] = 0; 294 295 if (str) { 296 len--; 297 298 CFIndex str_len = CFStringGetLength(str); 299 CFRange range; 300 range.location = 0; 301 range.length = (str_len > len)? len: str_len; 302 CFIndex used_buf_len; 303 CFIndex chars_copied; 304 chars_copied = CFStringGetBytes(str, 305 range, 306 kCFStringEncodingUTF8, 307 (char)'?', 308 FALSE, 309 (UInt8*)buf, 310 len, 311 &used_buf_len); 312 313 buf[chars_copied] = 0; 314 return (int)used_buf_len; 315 } 316 else 317 return 0; 318 } 319 320 321 static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len) 322 { 323 return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len); 324 } 325 326 static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) 327 { 328 return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len); 329 } 330 331 static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) 332 { 333 return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len); 334 } 335 336 337 /* Implementation of wcsdup() for Mac. */ 338 static wchar_t *dup_wcs(const wchar_t *s) 339 { 340 size_t len = wcslen(s); 341 wchar_t *ret = (wchar_t *)malloc((len+1)*sizeof(wchar_t)); 342 wcscpy(ret, s); 343 344 return ret; 345 } 346 347 348 static int make_path(IOHIDDeviceRef device, char *buf, size_t len) 349 { 350 int res; 351 unsigned short vid, pid; 352 char transport[32]; 353 354 buf[0] = '\0'; 355 356 res = get_string_property_utf8( 357 device, CFSTR(kIOHIDTransportKey), 358 transport, sizeof(transport)); 359 360 if (!res) 361 return -1; 362 363 vid = get_vendor_id(device); 364 pid = get_product_id(device); 365 366 res = snprintf(buf, len, "%s_%04hx_%04hx_%p", 367 transport, vid, pid, device); 368 369 370 buf[len-1] = '\0'; 371 return res+1; 372 } 373 374 static void hid_device_removal_callback(void *context, IOReturn result, 375 void *sender, IOHIDDeviceRef hid_ref) 376 { 377 // The device removal callback is sometimes called even after being 378 // unregistered, leading to a crash when trying to access fields in 379 // the already freed hid_device. We keep a linked list of all created 380 // hid_device's so that the one being removed can be checked against 381 // the list to see if it really hasn't been closed yet and needs to 382 // be dealt with here. 383 struct hid_device_list_node *node = device_list; 384 while (node) { 385 if (node->dev->device_handle == hid_ref) { 386 node->dev->disconnected = 1; 387 CFRunLoopStop(node->dev->run_loop); 388 break; 389 } 390 391 node = node->next; 392 } 393 } 394 395 /* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */ 396 static int init_hid_manager(void) 397 { 398 399 /* Initialize all the HID Manager Objects */ 400 hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); 401 if (hid_mgr) { 402 IOHIDManagerSetDeviceMatching(hid_mgr, NULL); 403 IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 404 IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback, NULL); 405 return 0; 406 } 407 408 return -1; 409 } 410 411 /* Initialize the IOHIDManager if necessary. This is the public function, and 412 it is safe to call this function repeatedly. Return 0 for success and -1 413 for failure. */ 414 int HID_API_EXPORT hid_init(void) 415 { 416 if (!hid_mgr) { 417 return init_hid_manager(); 418 } 419 420 /* Already initialized. */ 421 return 0; 422 } 423 424 int HID_API_EXPORT hid_exit(void) 425 { 426 if (hid_mgr) { 427 /* Close the HID manager. */ 428 IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone); 429 CFRelease(hid_mgr); 430 hid_mgr = NULL; 431 } 432 433 return 0; 434 } 435 436 static void process_pending_events() { 437 SInt32 res; 438 do { 439 res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE); 440 } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut); 441 } 442 443 struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) 444 { 445 struct hid_device_info *root = NULL; // return object 446 struct hid_device_info *cur_dev = NULL; 447 CFIndex num_devices; 448 int i; 449 450 /* Set up the HID Manager if it hasn't been done */ 451 if (hid_init() < 0) 452 return NULL; 453 454 /* give the IOHIDManager a chance to update itself */ 455 process_pending_events(); 456 457 /* Get a list of the Devices */ 458 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); 459 if (!device_set) 460 return NULL; 461 462 /* Convert the list into a C array so we can iterate easily. */ 463 num_devices = CFSetGetCount(device_set); 464 if (!num_devices) { 465 CFRelease(device_set); 466 return NULL; 467 } 468 IOHIDDeviceRef *device_array = (IOHIDDeviceRef*)calloc(num_devices, sizeof(IOHIDDeviceRef)); 469 CFSetGetValues(device_set, (const void **) device_array); 470 471 /* Iterate over each device, making an entry for it. */ 472 for (i = 0; i < num_devices; i++) { 473 unsigned short dev_vid; 474 unsigned short dev_pid; 475 #define BUF_LEN 256 476 wchar_t buf[BUF_LEN]; 477 char cbuf[BUF_LEN]; 478 479 IOHIDDeviceRef dev = device_array[i]; 480 481 if (!dev) { 482 continue; 483 } 484 485 dev_vid = get_vendor_id(dev); 486 dev_pid = get_product_id(dev); 487 488 /* Check the VID/PID against the arguments */ 489 if ((vendor_id == 0x0 && product_id == 0x0) || 490 (vendor_id == dev_vid && product_id == dev_pid)) { 491 struct hid_device_info *tmp; 492 size_t len; 493 494 /* VID/PID match. Create the record. */ 495 tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info)); 496 if (cur_dev) { 497 cur_dev->next = tmp; 498 } 499 else { 500 root = tmp; 501 } 502 cur_dev = tmp; 503 504 // Get the Usage Page and Usage for this device. 505 cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey)); 506 cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey)); 507 508 /* Fill out the record */ 509 cur_dev->next = NULL; 510 len = make_path(dev, cbuf, sizeof(cbuf)); 511 cur_dev->path = strdup(cbuf); 512 513 /* Serial Number */ 514 get_serial_number(dev, buf, BUF_LEN); 515 cur_dev->serial_number = dup_wcs(buf); 516 517 /* Manufacturer and Product strings */ 518 get_manufacturer_string(dev, buf, BUF_LEN); 519 cur_dev->manufacturer_string = dup_wcs(buf); 520 get_product_string(dev, buf, BUF_LEN); 521 cur_dev->product_string = dup_wcs(buf); 522 523 /* VID/PID */ 524 cur_dev->vendor_id = dev_vid; 525 cur_dev->product_id = dev_pid; 526 527 /* Release Number */ 528 cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey)); 529 530 /* Interface Number (Unsupported on Mac)*/ 531 cur_dev->interface_number = -1; 532 } 533 } 534 535 free(device_array); 536 CFRelease(device_set); 537 538 return root; 539 } 540 541 void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) 542 { 543 /* This function is identical to the Linux version. Platform independent. */ 544 struct hid_device_info *d = devs; 545 while (d) { 546 struct hid_device_info *next = d->next; 547 free(d->path); 548 free(d->serial_number); 549 free(d->manufacturer_string); 550 free(d->product_string); 551 free(d); 552 d = next; 553 } 554 } 555 556 hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) 557 { 558 /* This function is identical to the Linux version. Platform independent. */ 559 struct hid_device_info *devs, *cur_dev; 560 const char *path_to_open = NULL; 561 hid_device * handle = NULL; 562 563 devs = hid_enumerate(vendor_id, product_id); 564 cur_dev = devs; 565 while (cur_dev) { 566 if (cur_dev->vendor_id == vendor_id && 567 cur_dev->product_id == product_id) { 568 if (serial_number) { 569 if (wcscmp(serial_number, cur_dev->serial_number) == 0) { 570 path_to_open = cur_dev->path; 571 break; 572 } 573 } 574 else { 575 path_to_open = cur_dev->path; 576 break; 577 } 578 } 579 cur_dev = cur_dev->next; 580 } 581 582 if (path_to_open) { 583 /* Open the device */ 584 handle = hid_open_path(path_to_open, 0); 585 } 586 587 hid_free_enumeration(devs); 588 589 return handle; 590 } 591 592 /* The Run Loop calls this function for each input report received. 593 This function puts the data into a linked list to be picked up by 594 hid_read(). */ 595 static void hid_report_callback(void *context, IOReturn result, void *sender, 596 IOHIDReportType report_type, uint32_t report_id, 597 uint8_t *report, CFIndex report_length) 598 { 599 struct input_report *rpt; 600 hid_device *dev = (hid_device *)context; 601 602 /* Make a new Input Report object */ 603 rpt = (struct input_report *)calloc(1, sizeof(struct input_report)); 604 rpt->data = (uint8_t *)calloc(1, report_length); 605 memcpy(rpt->data, report, report_length); 606 rpt->len = report_length; 607 rpt->next = NULL; 608 609 /* Lock this section */ 610 pthread_mutex_lock(&dev->mutex); 611 612 /* Attach the new report object to the end of the list. */ 613 if (dev->input_reports == NULL) { 614 /* The list is empty. Put it at the root. */ 615 dev->input_reports = rpt; 616 } 617 else { 618 /* Find the end of the list and attach. */ 619 struct input_report *cur = dev->input_reports; 620 int num_queued = 0; 621 while (cur->next != NULL) { 622 cur = cur->next; 623 num_queued++; 624 } 625 cur->next = rpt; 626 627 /* Pop one off if we've reached 30 in the queue. This 628 way we don't grow forever if the user never reads 629 anything from the device. */ 630 if (num_queued > 30) { 631 return_data(dev, NULL, 0); 632 } 633 } 634 635 /* Signal a waiting thread that there is data. */ 636 pthread_cond_signal(&dev->condition); 637 638 /* Unlock */ 639 pthread_mutex_unlock(&dev->mutex); 640 641 } 642 643 /* This gets called when the read_thred's run loop gets signaled by 644 hid_close(), and serves to stop the read_thread's run loop. */ 645 static void perform_signal_callback(void *context) 646 { 647 hid_device *dev = (hid_device *)context; 648 CFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent() 649 } 650 651 static void *read_thread(void *param) 652 { 653 hid_device *dev = (hid_device *)param; 654 655 /* Move the device's run loop to this thread. */ 656 IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode); 657 658 /* Create the RunLoopSource which is used to signal the 659 event loop to stop when hid_close() is called. */ 660 CFRunLoopSourceContext ctx; 661 memset(&ctx, 0, sizeof(ctx)); 662 ctx.version = 0; 663 ctx.info = dev; 664 ctx.perform = &perform_signal_callback; 665 dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx); 666 CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode); 667 668 /* Store off the Run Loop so it can be stopped from hid_close() 669 and on device disconnection. */ 670 dev->run_loop = CFRunLoopGetCurrent(); 671 672 /* Notify the main thread that the read thread is up and running. */ 673 pthread_barrier_wait(&dev->barrier); 674 675 /* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input 676 reports into the hid_report_callback(). */ 677 SInt32 code; 678 while (!dev->shutdown_thread && !dev->disconnected) { 679 code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE); 680 /* Return if the device has been disconnected */ 681 if (code == kCFRunLoopRunFinished) { 682 dev->disconnected = 1; 683 break; 684 } 685 686 687 /* Break if The Run Loop returns Finished or Stopped. */ 688 if (code != kCFRunLoopRunTimedOut && 689 code != kCFRunLoopRunHandledSource) { 690 /* There was some kind of error. Setting 691 shutdown seems to make sense, but 692 there may be something else more appropriate */ 693 dev->shutdown_thread = 1; 694 break; 695 } 696 } 697 698 /* Now that the read thread is stopping, Wake any threads which are 699 waiting on data (in hid_read_timeout()). Do this under a mutex to 700 make sure that a thread which is about to go to sleep waiting on 701 the condition acutally will go to sleep before the condition is 702 signaled. */ 703 pthread_mutex_lock(&dev->mutex); 704 pthread_cond_broadcast(&dev->condition); 705 pthread_mutex_unlock(&dev->mutex); 706 707 /* Wait here until hid_close() is called and makes it past 708 the call to CFRunLoopWakeUp(). This thread still needs to 709 be valid when that function is called on the other thread. */ 710 pthread_barrier_wait(&dev->shutdown_barrier); 711 712 return NULL; 713 } 714 715 hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive) 716 { 717 int i; 718 hid_device *dev = NULL; 719 CFIndex num_devices; 720 721 dev = new_hid_device(); 722 723 /* Set up the HID Manager if it hasn't been done */ 724 if (hid_init() < 0) 725 return NULL; 726 727 /* give the IOHIDManager a chance to update itself */ 728 process_pending_events(); 729 730 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); 731 732 num_devices = CFSetGetCount(device_set); 733 IOHIDDeviceRef *device_array = (IOHIDDeviceRef *)calloc(num_devices, sizeof(IOHIDDeviceRef)); 734 CFSetGetValues(device_set, (const void **) device_array); 735 for (i = 0; i < num_devices; i++) { 736 char cbuf[BUF_LEN]; 737 size_t len; 738 IOHIDDeviceRef os_dev = device_array[i]; 739 740 len = make_path(os_dev, cbuf, sizeof(cbuf)); 741 if (!strcmp(cbuf, path)) { 742 // Matched Paths. Open this Device. 743 IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone); 744 if (ret == kIOReturnSuccess) { 745 char str[32]; 746 747 free(device_array); 748 CFRelease(device_set); 749 dev->device_handle = os_dev; 750 751 /* Create the buffers for receiving data */ 752 dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev); 753 dev->input_report_buf = (uint8_t *)calloc(dev->max_input_report_len, sizeof(uint8_t)); 754 755 /* Create the Run Loop Mode for this device. 756 printing the reference seems to work. */ 757 sprintf(str, "HIDAPI_%p", os_dev); 758 dev->run_loop_mode = 759 CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII); 760 761 /* Attach the device to a Run Loop */ 762 IOHIDDeviceRegisterInputReportCallback( 763 os_dev, dev->input_report_buf, dev->max_input_report_len, 764 &hid_report_callback, dev); 765 766 struct hid_device_list_node *node = (struct hid_device_list_node *)calloc(1, sizeof(struct hid_device_list_node)); 767 node->dev = dev; 768 node->next = device_list; 769 device_list = node; 770 771 /* Start the read thread */ 772 pthread_create(&dev->thread, NULL, read_thread, dev); 773 774 /* Wait here for the read thread to be initialized. */ 775 pthread_barrier_wait(&dev->barrier); 776 777 return dev; 778 } 779 else { 780 goto return_error; 781 } 782 } 783 } 784 785 return_error: 786 free(device_array); 787 CFRelease(device_set); 788 free_hid_device(dev); 789 return NULL; 790 } 791 792 static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length) 793 { 794 const char *pass_through_magic = "MAGIC0"; 795 size_t pass_through_magic_length = strlen(pass_through_magic); 796 unsigned char report_id = data[0]; 797 const unsigned char *data_to_send; 798 size_t length_to_send; 799 IOReturn res; 800 801 /* Return if the device has been disconnected. */ 802 if (dev->disconnected) 803 return -1; 804 805 if (report_id == 0x0) { 806 /* Not using numbered Reports. 807 Don't send the report number. */ 808 data_to_send = data+1; 809 length_to_send = length-1; 810 } 811 else if (length > 6 && memcmp(data, pass_through_magic, pass_through_magic_length) == 0) { 812 report_id = data[pass_through_magic_length]; 813 data_to_send = data+pass_through_magic_length; 814 length_to_send = length-pass_through_magic_length; 815 } 816 else { 817 /* Using numbered Reports. 818 Send the Report Number */ 819 data_to_send = data; 820 length_to_send = length; 821 } 822 823 if (!dev->disconnected) { 824 res = IOHIDDeviceSetReport(dev->device_handle, 825 type, 826 report_id, /* Report ID*/ 827 data_to_send, length_to_send); 828 829 if (res == kIOReturnSuccess) { 830 return (int)length; 831 } 832 else if (res == kIOReturnUnsupported) { 833 /*printf("kIOReturnUnsupported\n");*/ 834 return -1; 835 } 836 else { 837 /*printf("0x%x\n", res);*/ 838 return -1; 839 } 840 } 841 842 return -1; 843 } 844 845 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) 846 { 847 return set_report(dev, kIOHIDReportTypeOutput, data, length); 848 } 849 850 /* Helper function, so that this isn't duplicated in hid_read(). */ 851 static int return_data(hid_device *dev, unsigned char *data, size_t length) 852 { 853 /* Copy the data out of the linked list item (rpt) into the 854 return buffer (data), and delete the liked list item. */ 855 struct input_report *rpt = dev->input_reports; 856 size_t len = (length < rpt->len)? length: rpt->len; 857 memcpy(data, rpt->data, len); 858 dev->input_reports = rpt->next; 859 free(rpt->data); 860 free(rpt); 861 return (int)len; 862 } 863 864 static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex) 865 { 866 while (!dev->input_reports) { 867 int res = pthread_cond_wait(cond, mutex); 868 if (res != 0) 869 return res; 870 871 /* A res of 0 means we may have been signaled or it may 872 be a spurious wakeup. Check to see that there's acutally 873 data in the queue before returning, and if not, go back 874 to sleep. See the pthread_cond_timedwait() man page for 875 details. */ 876 877 if (dev->shutdown_thread || dev->disconnected) 878 return -1; 879 } 880 881 return 0; 882 } 883 884 static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) 885 { 886 while (!dev->input_reports) { 887 int res = pthread_cond_timedwait(cond, mutex, abstime); 888 if (res != 0) 889 return res; 890 891 /* A res of 0 means we may have been signaled or it may 892 be a spurious wakeup. Check to see that there's acutally 893 data in the queue before returning, and if not, go back 894 to sleep. See the pthread_cond_timedwait() man page for 895 details. */ 896 897 if (dev->shutdown_thread || dev->disconnected) 898 return -1; 899 } 900 901 return 0; 902 903 } 904 905 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) 906 { 907 int bytes_read = -1; 908 909 /* Lock the access to the report list. */ 910 pthread_mutex_lock(&dev->mutex); 911 912 /* There's an input report queued up. Return it. */ 913 if (dev->input_reports) { 914 /* Return the first one */ 915 bytes_read = return_data(dev, data, length); 916 goto ret; 917 } 918 919 /* Return if the device has been disconnected. */ 920 if (dev->disconnected) { 921 bytes_read = -1; 922 goto ret; 923 } 924 925 if (dev->shutdown_thread) { 926 /* This means the device has been closed (or there 927 has been an error. An error code of -1 should 928 be returned. */ 929 bytes_read = -1; 930 goto ret; 931 } 932 933 /* There is no data. Go to sleep and wait for data. */ 934 935 if (milliseconds == -1) { 936 /* Blocking */ 937 int res; 938 res = cond_wait(dev, &dev->condition, &dev->mutex); 939 if (res == 0) 940 bytes_read = return_data(dev, data, length); 941 else { 942 /* There was an error, or a device disconnection. */ 943 bytes_read = -1; 944 } 945 } 946 else if (milliseconds > 0) { 947 /* Non-blocking, but called with timeout. */ 948 int res; 949 struct timespec ts; 950 struct timeval tv; 951 gettimeofday(&tv, NULL); 952 TIMEVAL_TO_TIMESPEC(&tv, &ts); 953 ts.tv_sec += milliseconds / 1000; 954 ts.tv_nsec += (milliseconds % 1000) * 1000000; 955 if (ts.tv_nsec >= 1000000000L) { 956 ts.tv_sec++; 957 ts.tv_nsec -= 1000000000L; 958 } 959 960 res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts); 961 if (res == 0) 962 bytes_read = return_data(dev, data, length); 963 else if (res == ETIMEDOUT) 964 bytes_read = 0; 965 else 966 bytes_read = -1; 967 } 968 else { 969 /* Purely non-blocking */ 970 bytes_read = 0; 971 } 972 973 ret: 974 /* Unlock */ 975 pthread_mutex_unlock(&dev->mutex); 976 return bytes_read; 977 } 978 979 int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) 980 { 981 return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); 982 } 983 984 int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) 985 { 986 /* All Nonblocking operation is handled by the library. */ 987 dev->blocking = !nonblock; 988 989 return 0; 990 } 991 992 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) 993 { 994 return set_report(dev, kIOHIDReportTypeFeature, data, length); 995 } 996 997 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) 998 { 999 CFIndex len = length; 1000 IOReturn res; 1001 1002 /* Return if the device has been unplugged. */ 1003 if (dev->disconnected) 1004 return -1; 1005 1006 int skipped_report_id = 0; 1007 int report_number = data[0]; 1008 if (report_number == 0x0) { 1009 /* Offset the return buffer by 1, so that the report ID 1010 will remain in byte 0. */ 1011 data++; 1012 len--; 1013 skipped_report_id = 1; 1014 } 1015 1016 res = IOHIDDeviceGetReport(dev->device_handle, 1017 kIOHIDReportTypeFeature, 1018 report_number, /* Report ID */ 1019 data, &len); 1020 if (res != kIOReturnSuccess) 1021 return -1; 1022 1023 if (skipped_report_id) 1024 len++; 1025 1026 return (int)len; 1027 } 1028 1029 1030 void HID_API_EXPORT hid_close(hid_device *dev) 1031 { 1032 if (!dev) 1033 return; 1034 1035 /* Disconnect the report callback before close. */ 1036 if (!dev->disconnected) { 1037 IOHIDDeviceRegisterInputReportCallback( 1038 dev->device_handle, dev->input_report_buf, dev->max_input_report_len, 1039 NULL, dev); 1040 IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode); 1041 IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode); 1042 } 1043 1044 /* Cause read_thread() to stop. */ 1045 dev->shutdown_thread = 1; 1046 1047 /* Wake up the run thread's event loop so that the thread can exit. */ 1048 CFRunLoopSourceSignal(dev->source); 1049 CFRunLoopWakeUp(dev->run_loop); 1050 1051 /* Notify the read thread that it can shut down now. */ 1052 pthread_barrier_wait(&dev->shutdown_barrier); 1053 1054 /* Wait for read_thread() to end. */ 1055 pthread_join(dev->thread, NULL); 1056 1057 /* Close the OS handle to the device, but only if it's not 1058 been unplugged. If it's been unplugged, then calling 1059 IOHIDDeviceClose() will crash. */ 1060 if (!dev->disconnected) { 1061 IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone); 1062 } 1063 1064 /* Clear out the queue of received reports. */ 1065 pthread_mutex_lock(&dev->mutex); 1066 while (dev->input_reports) { 1067 return_data(dev, NULL, 0); 1068 } 1069 pthread_mutex_unlock(&dev->mutex); 1070 1071 free_hid_device(dev); 1072 } 1073 1074 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) 1075 { 1076 return get_manufacturer_string(dev->device_handle, string, maxlen); 1077 } 1078 1079 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) 1080 { 1081 return get_product_string(dev->device_handle, string, maxlen); 1082 } 1083 1084 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) 1085 { 1086 return get_serial_number(dev->device_handle, string, maxlen); 1087 } 1088 1089 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) 1090 { 1091 // TODO: 1092 1093 return 0; 1094 } 1095 1096 1097 HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) 1098 { 1099 // TODO: 1100 1101 return NULL; 1102 } 1103 1104 1105 1106 1107 1108 1109 #if 0 1110 static int32_t get_location_id(IOHIDDeviceRef device) 1111 { 1112 return get_int_property(device, CFSTR(kIOHIDLocationIDKey)); 1113 } 1114 1115 static int32_t get_usage(IOHIDDeviceRef device) 1116 { 1117 int32_t res; 1118 res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey)); 1119 if (!res) 1120 res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey)); 1121 return res; 1122 } 1123 1124 static int32_t get_usage_page(IOHIDDeviceRef device) 1125 { 1126 int32_t res; 1127 res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey)); 1128 if (!res) 1129 res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey)); 1130 return res; 1131 } 1132 1133 static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len) 1134 { 1135 return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len); 1136 } 1137 1138 1139 int main(void) 1140 { 1141 IOHIDManagerRef mgr; 1142 int i; 1143 1144 mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); 1145 IOHIDManagerSetDeviceMatching(mgr, NULL); 1146 IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone); 1147 1148 CFSetRef device_set = IOHIDManagerCopyDevices(mgr); 1149 1150 CFIndex num_devices = CFSetGetCount(device_set); 1151 IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); 1152 CFSetGetValues(device_set, (const void **) device_array); 1153 1154 for (i = 0; i < num_devices; i++) { 1155 IOHIDDeviceRef dev = device_array[i]; 1156 printf("Device: %p\n", dev); 1157 printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev)); 1158 1159 wchar_t serial[256], buf[256]; 1160 char cbuf[256]; 1161 get_serial_number(dev, serial, 256); 1162 1163 1164 printf(" Serial: %ls\n", serial); 1165 printf(" Loc: %ld\n", get_location_id(dev)); 1166 get_transport(dev, buf, 256); 1167 printf(" Trans: %ls\n", buf); 1168 make_path(dev, cbuf, 256); 1169 printf(" Path: %s\n", cbuf); 1170 1171 } 1172 1173 return 0; 1174 } 1175 #endif 1176 1177 #endif /* SDL_JOYSTICK_HIDAPI */