1
/*******************************************************
2
HIDAPI - Multi-Platform library for
3
communication with HID devices.
10
Copyright 2010, All Rights Reserved.
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
http://github.com/signal11/hidapi .
21
********************************************************/
23
/* See Apple Technical Note TN2187 for details on IOHidManager. */
25
#include <IOKit/hid/IOHIDManager.h>
26
#include <IOKit/hid/IOHIDKeys.h>
27
#include <CoreFoundation/CoreFoundation.h>
36
/* Barrier implementation because Mac OSX doesn't have pthread_barrier.
37
It also doesn't have clock_gettime(). So much for POSIX and SUSv2.
38
This implementation came from Brent Priddy and was posted on
39
StackOverflow. It is used with his permission. */
40
typedef int pthread_barrierattr_t;
41
typedef struct pthread_barrier {
42
pthread_mutex_t mutex;
48
static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
55
if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
58
if(pthread_cond_init(&barrier->cond, 0) < 0) {
59
pthread_mutex_destroy(&barrier->mutex);
62
barrier->trip_count = count;
68
static int pthread_barrier_destroy(pthread_barrier_t *barrier)
70
pthread_cond_destroy(&barrier->cond);
71
pthread_mutex_destroy(&barrier->mutex);
75
static int pthread_barrier_wait(pthread_barrier_t *barrier)
77
pthread_mutex_lock(&barrier->mutex);
79
if(barrier->count >= barrier->trip_count)
82
pthread_cond_broadcast(&barrier->cond);
83
pthread_mutex_unlock(&barrier->mutex);
88
pthread_cond_wait(&barrier->cond, &(barrier->mutex));
89
pthread_mutex_unlock(&barrier->mutex);
94
static int return_data(hid_device *dev, unsigned char *data, size_t length);
96
/* Linked List of input reports received from the device. */
100
struct input_report *next;
104
IOHIDDeviceRef device_handle;
106
int uses_numbered_reports;
108
CFStringRef run_loop_mode;
109
CFRunLoopRef run_loop;
110
CFRunLoopSourceRef source;
111
uint8_t *input_report_buf;
112
CFIndex max_input_report_len;
113
struct input_report *input_reports;
116
pthread_mutex_t mutex; /* Protects input_reports */
117
pthread_cond_t condition;
118
pthread_barrier_t barrier; /* Ensures correct startup sequence */
119
pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */
125
/* Static list of all the devices open. This way when a device gets
126
disconnected, its hid_device structure can be marked as disconnected
127
from hid_device_removal_callback(). */
128
static hid_device *device_list = NULL;
129
static pthread_mutex_t device_list_mutex = PTHREAD_MUTEX_INITIALIZER;
131
static hid_device *new_hid_device(void)
133
hid_device *dev = calloc(1, sizeof(hid_device));
134
dev->device_handle = NULL;
136
dev->uses_numbered_reports = 0;
137
dev->disconnected = 0;
138
dev->run_loop_mode = NULL;
139
dev->run_loop = NULL;
141
dev->input_report_buf = NULL;
142
dev->input_reports = NULL;
143
dev->shutdown_thread = 0;
147
pthread_mutex_init(&dev->mutex, NULL);
148
pthread_cond_init(&dev->condition, NULL);
149
pthread_barrier_init(&dev->barrier, NULL, 2);
150
pthread_barrier_init(&dev->shutdown_barrier, NULL, 2);
152
/* Add the new record to the device_list. */
153
pthread_mutex_lock(&device_list_mutex);
157
hid_device *d = device_list;
166
pthread_mutex_unlock(&device_list_mutex);
171
static void free_hid_device(hid_device *dev)
176
/* Delete any input reports still left over. */
177
struct input_report *rpt = dev->input_reports;
179
struct input_report *next = rpt->next;
185
/* Free the string and the report buffer. The check for NULL
186
is necessary here as CFRelease() doesn't handle NULL like
187
free() and others do. */
188
if (dev->run_loop_mode)
189
CFRelease(dev->run_loop_mode);
191
CFRelease(dev->source);
192
free(dev->input_report_buf);
194
/* Clean up the thread objects */
195
pthread_barrier_destroy(&dev->shutdown_barrier);
196
pthread_barrier_destroy(&dev->barrier);
197
pthread_cond_destroy(&dev->condition);
198
pthread_mutex_destroy(&dev->mutex);
200
/* Remove it from the device list. */
201
pthread_mutex_lock(&device_list_mutex);
202
hid_device *d = device_list;
204
device_list = d->next;
208
if (d->next == dev) {
209
d->next = d->next->next;
216
pthread_mutex_unlock(&device_list_mutex);
218
/* Free the structure itself. */
222
static IOHIDManagerRef hid_mgr = 0x0;
226
static void register_error(hid_device *device, const char *op)
233
static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key)
238
ref = IOHIDDeviceGetProperty(device, key);
240
if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
241
CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value);
248
static unsigned short get_vendor_id(IOHIDDeviceRef device)
250
return get_int_property(device, CFSTR(kIOHIDVendorIDKey));
253
static unsigned short get_product_id(IOHIDDeviceRef device)
255
return get_int_property(device, CFSTR(kIOHIDProductIDKey));
259
static int32_t get_max_report_length(IOHIDDeviceRef device)
261
return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));
264
static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len)
266
CFStringRef str = IOHIDDeviceGetProperty(device, prop);
274
CFIndex used_buf_len;
275
CFStringGetBytes(str,
277
kCFStringEncodingUTF32LE,
283
buf[len-1] = 0x00000000;
291
static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len)
293
CFStringRef str = IOHIDDeviceGetProperty(device, prop);
301
CFIndex used_buf_len;
302
CFStringGetBytes(str,
304
kCFStringEncodingUTF8,
310
buf[len-1] = 0x00000000;
319
static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)
321
return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);
324
static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
326
return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len);
329
static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
331
return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len);
335
/* Implementation of wcsdup() for Mac. */
336
static wchar_t *dup_wcs(const wchar_t *s)
338
size_t len = wcslen(s);
339
wchar_t *ret = malloc((len+1)*sizeof(wchar_t));
346
static int make_path(IOHIDDeviceRef device, char *buf, size_t len)
349
unsigned short vid, pid;
354
res = get_string_property_utf8(
355
device, CFSTR(kIOHIDTransportKey),
356
transport, sizeof(transport));
361
vid = get_vendor_id(device);
362
pid = get_product_id(device);
364
res = snprintf(buf, len, "%s_%04hx_%04hx_%p",
365
transport, vid, pid, device);
372
static int init_hid_manager(void)
376
/* Initialize all the HID Manager Objects */
377
hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
378
IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
379
IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
380
res = IOHIDManagerOpen(hid_mgr, kIOHIDOptionsTypeNone);
381
return (res == kIOReturnSuccess)? 0: -1;
384
int HID_API_EXPORT hid_init(void)
387
if (init_hid_manager() < 0) {
395
int HID_API_EXPORT hid_exit(void)
398
/* Close the HID manager. */
399
IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
407
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
409
struct hid_device_info *root = NULL; // return object
410
struct hid_device_info *cur_dev = NULL;
414
setlocale(LC_ALL,"");
416
/* Set up the HID Manager if it hasn't been done */
419
/* Get a list of the Devices */
420
CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
422
/* Convert the list into a C array so we can iterate easily. */
423
num_devices = CFSetGetCount(device_set);
424
IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
425
CFSetGetValues(device_set, (const void **) device_array);
427
/* Iterate over each device, making an entry for it. */
428
for (i = 0; i < num_devices; i++) {
429
unsigned short dev_vid;
430
unsigned short dev_pid;
432
wchar_t buf[BUF_LEN];
435
IOHIDDeviceRef dev = device_array[i];
440
dev_vid = get_vendor_id(dev);
441
dev_pid = get_product_id(dev);
443
/* Check the VID/PID against the arguments */
444
if ((vendor_id == 0x0 && product_id == 0x0) ||
445
(vendor_id == dev_vid && product_id == dev_pid)) {
446
struct hid_device_info *tmp;
449
/* VID/PID match. Create the record. */
450
tmp = malloc(sizeof(struct hid_device_info));
459
// Get the Usage Page and Usage for this device.
460
cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
461
cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
463
/* Fill out the record */
464
cur_dev->next = NULL;
465
len = make_path(dev, cbuf, sizeof(cbuf));
466
cur_dev->path = strdup(cbuf);
469
get_serial_number(dev, buf, BUF_LEN);
470
cur_dev->serial_number = dup_wcs(buf);
472
/* Manufacturer and Product strings */
473
get_manufacturer_string(dev, buf, BUF_LEN);
474
cur_dev->manufacturer_string = dup_wcs(buf);
475
get_product_string(dev, buf, BUF_LEN);
476
cur_dev->product_string = dup_wcs(buf);
479
cur_dev->vendor_id = dev_vid;
480
cur_dev->product_id = dev_pid;
483
cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
485
/* Interface Number (Unsupported on Mac)*/
486
cur_dev->interface_number = -1;
491
CFRelease(device_set);
496
void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
498
/* This function is identical to the Linux version. Platform independent. */
499
struct hid_device_info *d = devs;
501
struct hid_device_info *next = d->next;
503
free(d->serial_number);
504
free(d->manufacturer_string);
505
free(d->product_string);
511
hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number)
513
/* This function is identical to the Linux version. Platform independent. */
514
struct hid_device_info *devs, *cur_dev;
515
const char *path_to_open = NULL;
516
hid_device * handle = NULL;
518
devs = hid_enumerate(vendor_id, product_id);
521
if (cur_dev->vendor_id == vendor_id &&
522
cur_dev->product_id == product_id) {
524
if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
525
path_to_open = cur_dev->path;
530
path_to_open = cur_dev->path;
534
cur_dev = cur_dev->next;
538
/* Open the device */
539
handle = hid_open_path(path_to_open);
542
hid_free_enumeration(devs);
547
static void hid_device_removal_callback(void *context, IOReturn result,
548
void *sender, IOHIDDeviceRef dev_ref)
550
/* Stop the Run Loop for this device. */
551
pthread_mutex_lock(&device_list_mutex);
552
hid_device *d = device_list;
554
if (d->device_handle == dev_ref) {
556
CFRunLoopStop(d->run_loop);
561
pthread_mutex_unlock(&device_list_mutex);
564
/* The Run Loop calls this function for each input report received.
565
This function puts the data into a linked list to be picked up by
567
static void hid_report_callback(void *context, IOReturn result, void *sender,
568
IOHIDReportType report_type, uint32_t report_id,
569
uint8_t *report, CFIndex report_length)
571
struct input_report *rpt;
572
hid_device *dev = context;
574
/* Make a new Input Report object */
575
rpt = calloc(1, sizeof(struct input_report));
576
rpt->data = calloc(1, report_length);
577
memcpy(rpt->data, report, report_length);
578
rpt->len = report_length;
581
/* Lock this section */
582
pthread_mutex_lock(&dev->mutex);
584
/* Attach the new report object to the end of the list. */
585
if (dev->input_reports == NULL) {
586
/* The list is empty. Put it at the root. */
587
dev->input_reports = rpt;
590
/* Find the end of the list and attach. */
591
struct input_report *cur = dev->input_reports;
593
while (cur->next != NULL) {
599
/* Pop one off if we've reached 30 in the queue. This
600
way we don't grow forever if the user never reads
601
anything from the device. */
602
if (num_queued > 30) {
603
return_data(dev, NULL, 0);
607
/* Signal a waiting thread that there is data. */
608
pthread_cond_signal(&dev->condition);
611
pthread_mutex_unlock(&dev->mutex);
615
/* This gets called when the read_thred's run loop gets signaled by
616
hid_close(), and serves to stop the read_thread's run loop. */
617
static void perform_signal_callback(void *context)
619
hid_device *dev = context;
620
CFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent()
623
static void *read_thread(void *param)
625
hid_device *dev = param;
627
/* Move the device's run loop to this thread. */
628
IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
630
/* Create the RunLoopSource which is used to signal the
631
event loop to stop when hid_close() is called. */
632
CFRunLoopSourceContext ctx;
633
memset(&ctx, 0, sizeof(ctx));
636
ctx.perform = &perform_signal_callback;
637
dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);
638
CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
640
/* Store off the Run Loop so it can be stopped from hid_close()
641
and on device disconnection. */
642
dev->run_loop = CFRunLoopGetCurrent();
644
/* Notify the main thread that the read thread is up and running. */
645
pthread_barrier_wait(&dev->barrier);
647
/* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
648
reports into the hid_report_callback(). */
650
while (!dev->shutdown_thread && !dev->disconnected) {
651
code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);
652
/* Return if the device has been disconnected */
653
if (code == kCFRunLoopRunFinished) {
654
dev->disconnected = 1;
659
/* Break if The Run Loop returns Finished or Stopped. */
660
if (code != kCFRunLoopRunTimedOut &&
661
code != kCFRunLoopRunHandledSource) {
662
/* There was some kind of error. Setting
663
shutdown seems to make sense, but
664
there may be something else more appropriate */
665
dev->shutdown_thread = 1;
670
/* Now that the read thread is stopping, Wake any threads which are
671
waiting on data (in hid_read_timeout()). Do this under a mutex to
672
make sure that a thread which is about to go to sleep waiting on
673
the condition acutally will go to sleep before the condition is
675
pthread_mutex_lock(&dev->mutex);
676
pthread_cond_broadcast(&dev->condition);
677
pthread_mutex_unlock(&dev->mutex);
679
/* Close the OS handle to the device, but only if it's not
680
been unplugged. If it's been unplugged, then calling
681
IOHIDDeviceClose() will crash. */
682
if (!dev->disconnected) {
683
IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
686
/* Wait here until hid_close() is called and makes it past
687
the call to CFRunLoopWakeUp(). This thread still needs to
688
be valid when that function is called on the other thread. */
689
pthread_barrier_wait(&dev->shutdown_barrier);
694
hid_device * HID_API_EXPORT hid_open_path(const char *path)
697
hid_device *dev = NULL;
700
dev = new_hid_device();
702
/* Set up the HID Manager if it hasn't been done */
705
CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
707
num_devices = CFSetGetCount(device_set);
708
IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
709
CFSetGetValues(device_set, (const void **) device_array);
710
for (i = 0; i < num_devices; i++) {
713
IOHIDDeviceRef os_dev = device_array[i];
715
len = make_path(os_dev, cbuf, sizeof(cbuf));
716
if (!strcmp(cbuf, path)) {
717
// Matched Paths. Open this Device.
718
IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
719
if (ret == kIOReturnSuccess) {
723
CFRelease(device_set);
724
dev->device_handle = os_dev;
726
/* Create the buffers for receiving data */
727
dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);
728
dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));
730
/* Create the Run Loop Mode for this device.
731
printing the reference seems to work. */
732
sprintf(str, "HIDAPI_%p", os_dev);
734
CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
736
/* Attach the device to a Run Loop */
737
IOHIDDeviceRegisterInputReportCallback(
738
os_dev, dev->input_report_buf, dev->max_input_report_len,
739
&hid_report_callback, dev);
740
IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback, NULL);
742
/* Start the read thread */
743
pthread_create(&dev->thread, NULL, read_thread, dev);
745
/* Wait here for the read thread to be initialized. */
746
pthread_barrier_wait(&dev->barrier);
758
CFRelease(device_set);
759
free_hid_device(dev);
763
static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)
765
const unsigned char *data_to_send;
766
size_t length_to_send;
769
/* Return if the device has been disconnected. */
770
if (dev->disconnected)
773
if (data[0] == 0x0) {
774
/* Not using numbered Reports.
775
Don't send the report number. */
776
data_to_send = data+1;
777
length_to_send = length-1;
780
/* Using numbered Reports.
781
Send the Report Number */
783
length_to_send = length;
786
if (!dev->disconnected) {
787
res = IOHIDDeviceSetReport(dev->device_handle,
789
data[0], /* Report ID*/
790
data_to_send, length_to_send);
792
if (res == kIOReturnSuccess) {
802
int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
804
return set_report(dev, kIOHIDReportTypeOutput, data, length);
807
/* Helper function, so that this isn't duplicated in hid_read(). */
808
static int return_data(hid_device *dev, unsigned char *data, size_t length)
810
/* Copy the data out of the linked list item (rpt) into the
811
return buffer (data), and delete the liked list item. */
812
struct input_report *rpt = dev->input_reports;
813
size_t len = (length < rpt->len)? length: rpt->len;
814
memcpy(data, rpt->data, len);
815
dev->input_reports = rpt->next;
821
static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
823
while (!dev->input_reports) {
824
int res = pthread_cond_wait(cond, mutex);
828
/* A res of 0 means we may have been signaled or it may
829
be a spurious wakeup. Check to see that there's acutally
830
data in the queue before returning, and if not, go back
831
to sleep. See the pthread_cond_timedwait() man page for
834
if (dev->shutdown_thread || dev->disconnected)
841
static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
843
while (!dev->input_reports) {
844
int res = pthread_cond_timedwait(cond, mutex, abstime);
848
/* A res of 0 means we may have been signaled or it may
849
be a spurious wakeup. Check to see that there's acutally
850
data in the queue before returning, and if not, go back
851
to sleep. See the pthread_cond_timedwait() man page for
854
if (dev->shutdown_thread || dev->disconnected)
862
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
866
/* Lock the access to the report list. */
867
pthread_mutex_lock(&dev->mutex);
869
/* There's an input report queued up. Return it. */
870
if (dev->input_reports) {
871
/* Return the first one */
872
bytes_read = return_data(dev, data, length);
876
/* Return if the device has been disconnected. */
877
if (dev->disconnected) {
882
if (dev->shutdown_thread) {
883
/* This means the device has been closed (or there
884
has been an error. An error code of -1 should
890
/* There is no data. Go to sleep and wait for data. */
892
if (milliseconds == -1) {
895
res = cond_wait(dev, &dev->condition, &dev->mutex);
897
bytes_read = return_data(dev, data, length);
899
/* There was an error, or a device disconnection. */
903
else if (milliseconds > 0) {
904
/* Non-blocking, but called with timeout. */
908
gettimeofday(&tv, NULL);
909
TIMEVAL_TO_TIMESPEC(&tv, &ts);
910
ts.tv_sec += milliseconds / 1000;
911
ts.tv_nsec += (milliseconds % 1000) * 1000000;
912
if (ts.tv_nsec >= 1000000000L) {
914
ts.tv_nsec -= 1000000000L;
917
res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
919
bytes_read = return_data(dev, data, length);
920
else if (res == ETIMEDOUT)
926
/* Purely non-blocking */
932
pthread_mutex_unlock(&dev->mutex);
936
int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
938
return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
941
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
943
/* All Nonblocking operation is handled by the library. */
944
dev->blocking = !nonblock;
949
int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
951
return set_report(dev, kIOHIDReportTypeFeature, data, length);
954
int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
956
CFIndex len = length;
959
/* Return if the device has been unplugged. */
960
if (dev->disconnected)
963
res = IOHIDDeviceGetReport(dev->device_handle,
964
kIOHIDReportTypeFeature,
965
data[0], /* Report ID */
967
if (res == kIOReturnSuccess)
974
void HID_API_EXPORT hid_close(hid_device *dev)
979
/* Disconnect the report callback before close. */
980
if (!dev->disconnected) {
981
IOHIDDeviceRegisterInputReportCallback(
982
dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
984
IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev);
985
IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
986
IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
989
/* Cause read_thread() to stop. */
990
dev->shutdown_thread = 1;
992
/* Wake up the run thread's event loop so that the thread can exit. */
993
CFRunLoopSourceSignal(dev->source);
994
CFRunLoopWakeUp(dev->run_loop);
996
/* Notify the read thread that it can shut down now. */
997
pthread_barrier_wait(&dev->shutdown_barrier);
999
/* Wait for read_thread() to end. */
1000
pthread_join(dev->thread, NULL);
1002
/* Close the OS handle to the device, but only if it's not
1003
been unplugged. If it's been unplugged, then calling
1004
IOHIDDeviceClose() will crash. */
1005
if (!dev->disconnected) {
1006
IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
1009
/* Clear out the queue of received reports. */
1010
pthread_mutex_lock(&dev->mutex);
1011
while (dev->input_reports) {
1012
return_data(dev, NULL, 0);
1014
pthread_mutex_unlock(&dev->mutex);
1016
free_hid_device(dev);
1019
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
1021
return get_manufacturer_string(dev->device_handle, string, maxlen);
1024
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1026
return get_product_string(dev->device_handle, string, maxlen);
1029
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1031
return get_serial_number(dev->device_handle, string, maxlen);
1034
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1042
HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
1055
static int32_t get_location_id(IOHIDDeviceRef device)
1057
return get_int_property(device, CFSTR(kIOHIDLocationIDKey));
1060
static int32_t get_usage(IOHIDDeviceRef device)
1063
res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
1065
res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
1069
static int32_t get_usage_page(IOHIDDeviceRef device)
1072
res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
1074
res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
1078
static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)
1080
return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
1086
IOHIDManagerRef mgr;
1089
mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1090
IOHIDManagerSetDeviceMatching(mgr, NULL);
1091
IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
1093
CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
1095
CFIndex num_devices = CFSetGetCount(device_set);
1096
IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
1097
CFSetGetValues(device_set, (const void **) device_array);
1099
setlocale(LC_ALL, "");
1101
for (i = 0; i < num_devices; i++) {
1102
IOHIDDeviceRef dev = device_array[i];
1103
printf("Device: %p\n", dev);
1104
printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
1106
wchar_t serial[256], buf[256];
1108
get_serial_number(dev, serial, 256);
1111
printf(" Serial: %ls\n", serial);
1112
printf(" Loc: %ld\n", get_location_id(dev));
1113
get_transport(dev, buf, 256);
1114
printf(" Trans: %ls\n", buf);
1115
make_path(dev, cbuf, 256);
1116
printf(" Path: %s\n", cbuf);