36 #include <IOKit/hid/IOHIDManager.h>
37 #include <IOKit/hid/IOHIDKeys.h>
38 #include <CoreFoundation/CoreFoundation.h>
67 if (pthread_mutex_init(&barrier->
mutex, 0) < 0)
71 if (pthread_cond_init(&barrier->
cond, 0) < 0)
73 pthread_mutex_destroy(&barrier->
mutex);
84 pthread_cond_destroy(&barrier->
cond);
85 pthread_mutex_destroy(&barrier->
mutex);
91 pthread_mutex_lock(&barrier->
mutex);
96 pthread_cond_broadcast(&barrier->
cond);
97 pthread_mutex_unlock(&barrier->
mutex);
102 pthread_cond_wait(&barrier->
cond, &(barrier->
mutex));
103 pthread_mutex_unlock(&barrier->
mutex);
108 static int return_data(
hid_device *dev,
unsigned char *data,
size_t length);
132 pthread_mutex_t
mutex;
154 pthread_mutex_init(&dev->
mutex, NULL);
155 pthread_cond_init(&dev->
condition, NULL);
156 pthread_barrier_init(&dev->
barrier, NULL, 2);
188 pthread_barrier_destroy(&dev->
barrier);
190 pthread_mutex_destroy(&dev->
mutex);
196 static IOHIDManagerRef hid_mgr = 0x0;
205 static int32_t get_int_property(IOHIDDeviceRef
device, CFStringRef key)
210 ref = IOHIDDeviceGetProperty(
device, key);
213 if (CFGetTypeID(ref) == CFNumberGetTypeID())
215 CFNumberGetValue((CFNumberRef)ref, kCFNumberSInt32Type, &value);
222 static unsigned short get_vendor_id(IOHIDDeviceRef
device)
224 return get_int_property(
device, CFSTR(kIOHIDVendorIDKey));
227 static unsigned short get_product_id(IOHIDDeviceRef
device)
229 return get_int_property(
device, CFSTR(kIOHIDProductIDKey));
232 static int32_t get_max_report_length(IOHIDDeviceRef
device)
234 return get_int_property(
device, CFSTR(kIOHIDMaxInputReportSizeKey));
237 static int get_string_property(IOHIDDeviceRef
device, CFStringRef prop,
wchar_t *buf,
size_t len)
244 str = IOHIDDeviceGetProperty(
device, prop);
252 CFIndex str_len = CFStringGetLength(str);
255 range.length = (str_len > (long)
len) ?
len : str_len;
256 CFIndex used_buf_len;
257 CFIndex chars_copied;
259 CFStringGetBytes(str, range, kCFStringEncodingUTF32LE, (
char)
'?',
FALSE, (UInt8 *)buf,
len, &used_buf_len);
261 buf[chars_copied] = 0;
268 static int get_string_property_utf8(IOHIDDeviceRef
device, CFStringRef prop,
char *buf,
size_t len)
274 str = IOHIDDeviceGetProperty(
device, prop);
282 CFIndex str_len = CFStringGetLength(str);
285 range.length = (str_len > (long)
len) ?
len : str_len;
286 CFIndex used_buf_len;
287 CFIndex chars_copied;
289 CFStringGetBytes(str, range, kCFStringEncodingUTF8, (
char)
'?',
FALSE, (UInt8 *)buf,
len, &used_buf_len);
291 buf[chars_copied] = 0;
298 static int get_serial_number(IOHIDDeviceRef
device,
wchar_t *buf,
size_t len)
300 return get_string_property(
device, CFSTR(kIOHIDSerialNumberKey), buf,
len);
303 static int get_manufacturer_string(IOHIDDeviceRef
device,
wchar_t *buf,
size_t len)
305 return get_string_property(
device, CFSTR(kIOHIDManufacturerKey), buf,
len);
308 static int get_product_string(IOHIDDeviceRef
device,
wchar_t *buf,
size_t len)
310 return get_string_property(
device, CFSTR(kIOHIDProductKey), buf,
len);
314 static wchar_t *dup_wcs(
const wchar_t *s)
316 size_t len = wcslen(s);
317 wchar_t *ret = malloc((
len + 1) *
sizeof(
wchar_t));
323 static int make_path(IOHIDDeviceRef
device,
char *buf,
size_t len)
326 unsigned short vid, pid;
331 res = get_string_property_utf8(
device, CFSTR(kIOHIDTransportKey), transport,
sizeof(transport));
336 vid = get_vendor_id(
device);
337 pid = get_product_id(
device);
339 res = snprintf(buf,
len,
"%s_%04hx_%04hx_%p", transport, vid, pid,
device);
346 static int init_hid_manager(
void)
349 hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
352 IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
353 IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
367 return init_hid_manager();
379 IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
387 static void process_pending_events(
void)
392 res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001,
FALSE);
393 }
while (res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
408 process_pending_events();
411 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
414 num_devices = CFSetGetCount(device_set);
415 IOHIDDeviceRef *device_array = calloc(num_devices,
sizeof(IOHIDDeviceRef));
416 CFSetGetValues(device_set, (
const void **)device_array);
419 for (i = 0; i < num_devices; i++)
421 unsigned short dev_vid;
422 unsigned short dev_pid;
427 IOHIDDeviceRef dev = device_array[i];
433 dev_vid = get_vendor_id(dev);
434 dev_pid = get_product_id(dev);
455 cur_dev->
usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
456 cur_dev->
usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
459 cur_dev->
next = NULL;
460 len = make_path(dev, cbuf,
sizeof(cbuf));
461 cur_dev->
path = strdup(cbuf);
464 get_serial_number(dev, buf,
BUF_LEN);
468 get_manufacturer_string(dev, buf,
BUF_LEN);
470 get_product_string(dev, buf,
BUF_LEN);
478 cur_dev->
release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
486 CFRelease(device_set);
511 const char *path_to_open = NULL;
524 path_to_open = cur_dev->
path;
530 path_to_open = cur_dev->
path;
534 cur_dev = cur_dev->
next;
548 static void hid_device_removal_callback(
void *context, IOReturn result,
void *sender)
562 static void hid_report_callback(
void *context, IOReturn result,
void *sender, IOHIDReportType report_type,
563 uint32_t report_id, uint8_t *report, CFIndex report_length)
574 rpt->
data = calloc(1, report_length);
575 memcpy(rpt->
data, report, report_length);
576 rpt->
len = report_length;
580 pthread_mutex_lock(&dev->
mutex);
593 while (cur->
next != NULL)
605 return_data(dev, NULL, 0);
613 pthread_mutex_unlock(&dev->
mutex);
618 static void perform_signal_callback(
void *context)
624 static void *read_thread(
void *param)
633 CFRunLoopSourceContext ctx;
634 memset(&ctx, 0,
sizeof(ctx));
637 ctx.perform = &perform_signal_callback;
638 dev->
source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 , &ctx);
643 dev->
run_loop = CFRunLoopGetCurrent();
646 pthread_barrier_wait(&dev->
barrier);
655 if (code == kCFRunLoopRunFinished)
662 if (code != kCFRunLoopRunTimedOut && code != kCFRunLoopRunHandledSource)
677 pthread_mutex_lock(&dev->
mutex);
679 pthread_mutex_unlock(&dev->
mutex);
695 dev = new_hid_device();
702 process_pending_events();
704 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
706 num_devices = CFSetGetCount(device_set);
707 IOHIDDeviceRef *device_array = calloc(num_devices,
sizeof(IOHIDDeviceRef));
708 CFSetGetValues(device_set, (
const void **)device_array);
709 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))
719 IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
720 if (ret == kIOReturnSuccess)
726 CFRelease(device_set);
735 sprintf(str,
"HIDAPI_%p", os_dev);
736 dev->
run_loop_mode = CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
740 &hid_report_callback, dev);
741 IOHIDDeviceRegisterRemovalCallback(dev->
device_handle, hid_device_removal_callback, dev);
744 pthread_create(&dev->
thread, NULL, read_thread, dev);
747 pthread_barrier_wait(&dev->
barrier);
760 CFRelease(device_set);
761 free_hid_device(dev);
765 static int set_report(
hid_device *dev, IOHIDReportType
type,
const unsigned char *
data,
size_t length)
767 const unsigned char *data_to_send;
768 size_t length_to_send;
779 data_to_send =
data + 1;
780 length_to_send = length - 1;
787 length_to_send = length;
793 data_to_send, length_to_send);
795 if (res == kIOReturnSuccess)
808 return set_report(dev, kIOHIDReportTypeOutput,
data, length);
812 static int return_data(
hid_device *dev,
unsigned char *
data,
size_t length)
817 size_t len = (length < rpt->
len) ? length : rpt->
len;
825 static int cond_wait(
const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
829 int res = pthread_cond_wait(cond, mutex);
846 static int cond_timedwait(
const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex,
847 const struct timespec *abstime)
851 int res = pthread_cond_timedwait(cond, mutex, abstime);
873 pthread_mutex_lock(&dev->
mutex);
879 bytes_read = return_data(dev,
data, length);
901 if (milliseconds == -1)
907 bytes_read = return_data(dev,
data, length);
914 else if (milliseconds > 0)
920 gettimeofday(&tv, NULL);
921 TIMEVAL_TO_TIMESPEC(&tv, &ts);
922 ts.tv_sec += milliseconds / 1000;
923 ts.tv_nsec += (milliseconds % 1000) * 1000000;
924 if (ts.tv_nsec >= 1000000000L)
927 ts.tv_nsec -= 1000000000L;
932 bytes_read = return_data(dev, data, length);
933 else if (res == ETIMEDOUT)
946 pthread_mutex_unlock(&dev->
mutex);
965 return set_report(dev, kIOHIDReportTypeFeature, data, length);
970 CFIndex len = length;
977 res = IOHIDDeviceGetReport(dev->
device_handle, kIOHIDReportTypeFeature, data[0],
979 if (res == kIOReturnSuccess)
995 IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev);
997 IOHIDDeviceScheduleWithRunLoop(dev->
device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
1004 CFRunLoopSourceSignal(dev->
source);
1011 pthread_join(dev->
thread, NULL);
1018 IOHIDDeviceClose(dev->
device_handle, kIOHIDOptionsTypeNone);
1022 pthread_mutex_lock(&dev->
mutex);
1025 return_data(dev, NULL, 0);
1027 pthread_mutex_unlock(&dev->
mutex);
1030 free_hid_device(dev);
1035 return get_manufacturer_string(dev->
device_handle,
string, maxlen);
1040 return get_product_string(dev->
device_handle,
string, maxlen);
1045 return get_serial_number(dev->
device_handle,
string, maxlen);
1066 static int32_t get_location_id(IOHIDDeviceRef
device)
1068 return get_int_property(
device, CFSTR(kIOHIDLocationIDKey));
1071 static int32_t get_usage(IOHIDDeviceRef
device)
1074 res = get_int_property(
device, CFSTR(kIOHIDDeviceUsageKey));
1076 res = get_int_property(
device, CFSTR(kIOHIDPrimaryUsageKey));
1080 static int32_t get_usage_page(IOHIDDeviceRef
device)
1083 res = get_int_property(
device, CFSTR(kIOHIDDeviceUsagePageKey));
1085 res = get_int_property(
device, CFSTR(kIOHIDPrimaryUsagePageKey));
1089 static int get_transport(IOHIDDeviceRef
device,
wchar_t * buf,
size_t len)
1091 return get_string_property(
device, CFSTR(kIOHIDTransportKey), buf, len);
1097 IOHIDManagerRef mgr;
1100 mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1101 IOHIDManagerSetDeviceMatching(mgr, NULL);
1102 IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
1104 CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
1106 CFIndex num_devices = CFSetGetCount(device_set);
1107 IOHIDDeviceRef * device_array = calloc(num_devices,
sizeof(IOHIDDeviceRef));
1108 CFSetGetValues(device_set, (
const void **) device_array);
1110 for (i = 0; i < num_devices; i++)
1112 IOHIDDeviceRef dev = device_array[i];
1113 printf(
"Device: %p\n", dev);
1114 printf(
" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
1116 wchar_t serial[256], buf[256];
1118 get_serial_number(dev, serial, 256);
1121 printf(
" Serial: %ls\n", serial);
1122 printf(
" Loc: %ld\n", get_location_id(dev));
1123 get_transport(dev, buf, 256);
1124 printf(
" Trans: %ls\n", buf);
1125 make_path(dev, cbuf, 256);
1126 printf(
" Path: %s\n", cbuf);