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 /* See Apple Technical Note TN2187 for details on IOHidManager. */
25 
26 #include <IOKit/hid/IOHIDManager.h>
27 #include <IOKit/hid/IOHIDKeys.h>
28 #include <CoreFoundation/CoreFoundation.h>
29 #include <wchar.h>
30 #include <pthread.h>
31 #include <sys/time.h>
32 #include <unistd.h>
33 
34 #include "../hidapi/hidapi.h"
35 
36 #define VALVE_USB_VID		0x28DE
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 
pthread_barrier_init(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned int count)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 
pthread_barrier_destroy(pthread_barrier_t * barrier)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 
pthread_barrier_wait(pthread_barrier_t * barrier)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 
new_hid_device(void)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 
free_hid_device(hid_device * dev)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 
get_int_property(IOHIDDeviceRef device,CFStringRef key)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 
get_vendor_id(IOHIDDeviceRef device)232 static unsigned short get_vendor_id(IOHIDDeviceRef device)
233 {
234 	return get_int_property(device, CFSTR(kIOHIDVendorIDKey));
235 }
236 
get_product_id(IOHIDDeviceRef device)237 static unsigned short get_product_id(IOHIDDeviceRef device)
238 {
239 	return get_int_property(device, CFSTR(kIOHIDProductIDKey));
240 }
241 
242 
get_max_report_length(IOHIDDeviceRef device)243 static int32_t get_max_report_length(IOHIDDeviceRef device)
244 {
245 	return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));
246 }
247 
get_string_property(IOHIDDeviceRef device,CFStringRef prop,wchar_t * buf,size_t len)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 	if (CFGetTypeID(prop) != CFStringGetTypeID())
256 		return 0;
257 
258 	str = (CFStringRef)IOHIDDeviceGetProperty(device, prop);
259 
260 	buf[0] = 0;
261 
262 	if (str) {
263 		len --;
264 
265 		CFIndex str_len = CFStringGetLength(str);
266 		CFRange range;
267 		range.location = 0;
268 		range.length = (str_len > len)? len: str_len;
269 		CFIndex used_buf_len;
270 		CFIndex chars_copied;
271 		chars_copied = CFStringGetBytes(str,
272 										range,
273 										kCFStringEncodingUTF32LE,
274 										(char)'?',
275 										FALSE,
276 										(UInt8*)buf,
277 										len,
278 										&used_buf_len);
279 
280 		buf[chars_copied] = 0;
281 		return (int)chars_copied;
282 	}
283 	else
284 		return 0;
285 
286 }
287 
get_string_property_utf8(IOHIDDeviceRef device,CFStringRef prop,char * buf,size_t len)288 static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len)
289 {
290 	CFStringRef str;
291 	if (!len)
292 		return 0;
293 
294 	if (CFGetTypeID(prop) != CFStringGetTypeID())
295 		return 0;
296 
297 	str = (CFStringRef)IOHIDDeviceGetProperty(device, prop);
298 
299 	buf[0] = 0;
300 
301 	if (str) {
302 		len--;
303 
304 		CFIndex str_len = CFStringGetLength(str);
305 		CFRange range;
306 		range.location = 0;
307 		range.length = (str_len > len)? len: str_len;
308 		CFIndex used_buf_len;
309 		CFIndex chars_copied;
310 		chars_copied = CFStringGetBytes(str,
311 										range,
312 										kCFStringEncodingUTF8,
313 										(char)'?',
314 										FALSE,
315 										(UInt8*)buf,
316 										len,
317 										&used_buf_len);
318 
319 		buf[chars_copied] = 0;
320 		return (int)used_buf_len;
321 	}
322 	else
323 		return 0;
324 }
325 
326 
get_serial_number(IOHIDDeviceRef device,wchar_t * buf,size_t len)327 static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)
328 {
329 	// This crashes on M1 Macs, tracked by radar bug 79667729
330 	//return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);
331 	buf[0] = 0;
332 	return 0;
333 }
334 
get_manufacturer_string(IOHIDDeviceRef device,wchar_t * buf,size_t len)335 static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
336 {
337 	return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len);
338 }
339 
get_product_string(IOHIDDeviceRef device,wchar_t * buf,size_t len)340 static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
341 {
342 	return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len);
343 }
344 
345 
346 /* Implementation of wcsdup() for Mac. */
dup_wcs(const wchar_t * s)347 static wchar_t *dup_wcs(const wchar_t *s)
348 {
349 	size_t len = wcslen(s);
350 	wchar_t *ret = (wchar_t *)malloc((len+1)*sizeof(wchar_t));
351 	wcscpy(ret, s);
352 
353 	return ret;
354 }
355 
356 
make_path(IOHIDDeviceRef device,char * buf,size_t len)357 static int make_path(IOHIDDeviceRef device, char *buf, size_t len)
358 {
359 	int res;
360 	unsigned short vid, pid;
361 	char transport[32];
362 
363 	buf[0] = '\0';
364 
365 	res = get_string_property_utf8(
366 								   device, CFSTR(kIOHIDTransportKey),
367 								   transport, sizeof(transport));
368 
369 	if (!res)
370 		return -1;
371 
372 	vid = get_vendor_id(device);
373 	pid = get_product_id(device);
374 
375 	res = snprintf(buf, len, "%s_%04hx_%04hx_%p",
376 				   transport, vid, pid, device);
377 
378 
379 	buf[len-1] = '\0';
380 	return res+1;
381 }
382 
hid_device_removal_callback(void * context,IOReturn result,void * sender,IOHIDDeviceRef hid_ref)383 static void hid_device_removal_callback(void *context, IOReturn result,
384                                         void *sender, IOHIDDeviceRef hid_ref)
385 {
386 	// The device removal callback is sometimes called even after being
387 	// unregistered, leading to a crash when trying to access fields in
388 	// the already freed hid_device. We keep a linked list of all created
389 	// hid_device's so that the one being removed can be checked against
390 	// the list to see if it really hasn't been closed yet and needs to
391 	// be dealt with here.
392 	struct hid_device_list_node *node = device_list;
393 	while (node) {
394 		if (node->dev->device_handle == hid_ref) {
395 			node->dev->disconnected = 1;
396 			CFRunLoopStop(node->dev->run_loop);
397 			break;
398 		}
399 
400 		node = node->next;
401 	}
402 }
403 
404 static CFDictionaryRef
create_usage_match(const UInt32 page,const UInt32 usage,int * okay)405 create_usage_match(const UInt32 page, const UInt32 usage, int *okay)
406 {
407 	CFDictionaryRef retval = NULL;
408 	CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
409 	CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
410 	const void *keys[2] = { (void *) CFSTR(kIOHIDDeviceUsagePageKey), (void *) CFSTR(kIOHIDDeviceUsageKey) };
411 	const void *vals[2] = { (void *) pageNumRef, (void *) usageNumRef };
412 
413 	if (pageNumRef && usageNumRef) {
414 		retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
415 	}
416 
417 	if (pageNumRef) {
418 		CFRelease(pageNumRef);
419 	}
420 	if (usageNumRef) {
421 		CFRelease(usageNumRef);
422 	}
423 
424 	if (!retval) {
425 		*okay = 0;
426 	}
427 
428 	return retval;
429 }
430 
431 static CFDictionaryRef
create_vendor_match(const UInt32 vendor,int * okay)432 create_vendor_match(const UInt32 vendor, int *okay)
433 {
434 	CFDictionaryRef retval = NULL;
435 	CFNumberRef vidNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
436 	const void *keys[1] = { (void *) CFSTR(kIOHIDVendorIDKey) };
437 	const void *vals[1] = { (void *) vidNumRef };
438 
439 	if (vidNumRef) {
440 		retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
441 		CFRelease(vidNumRef);
442 	}
443 
444 	if (!retval) {
445 		*okay = 0;
446 	}
447 
448 	return retval;
449 }
450 
451 /* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */
init_hid_manager(void)452 static int init_hid_manager(void)
453 {
454 	int okay = 1;
455 	const void *vals[] = {
456 		(void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, &okay),
457 		(void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, &okay),
458 		(void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay),
459 		(void *) create_vendor_match(VALVE_USB_VID, &okay),
460 	};
461 	const size_t numElements = SDL_arraysize(vals);
462 	CFArrayRef matchingArray = okay ? CFArrayCreate(kCFAllocatorDefault, vals, numElements, &kCFTypeArrayCallBacks) : NULL;
463 	size_t i;
464 
465 	for (i = 0; i < numElements; i++) {
466 		if (vals[i]) {
467 			CFRelease((CFTypeRef) vals[i]);
468 		}
469 	}
470 
471 	/* Initialize all the HID Manager Objects */
472 	hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
473 	if (hid_mgr) {
474 		IOHIDManagerSetDeviceMatchingMultiple(hid_mgr, matchingArray);
475 		IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
476 		IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback, NULL);
477 	}
478 
479 	if (matchingArray != NULL) {
480 		CFRelease(matchingArray);
481 	}
482 
483 	return hid_mgr ? 0 : -1;
484 }
485 
486 /* Initialize the IOHIDManager if necessary. This is the public function, and
487  it is safe to call this function repeatedly. Return 0 for success and -1
488  for failure. */
hid_init(void)489 int HID_API_EXPORT hid_init(void)
490 {
491 	if (!hid_mgr) {
492 		return init_hid_manager();
493 	}
494 
495 	/* Already initialized. */
496 	return 0;
497 }
498 
hid_exit(void)499 int HID_API_EXPORT hid_exit(void)
500 {
501 	if (hid_mgr) {
502 		/* Close the HID manager. */
503 		IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
504 		CFRelease(hid_mgr);
505 		hid_mgr = NULL;
506 	}
507 
508 	return 0;
509 }
510 
process_pending_events()511 static void process_pending_events() {
512 	SInt32 res;
513 	do {
514 		res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE);
515 	} while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
516 }
517 
hid_enumerate(unsigned short vendor_id,unsigned short product_id)518 struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
519 {
520 	struct hid_device_info *root = NULL; // return object
521 	struct hid_device_info *cur_dev = NULL;
522 	CFIndex num_devices;
523 	int i;
524 
525 	/* Set up the HID Manager if it hasn't been done */
526 	if (hid_init() < 0)
527 		return NULL;
528 
529 	/* give the IOHIDManager a chance to update itself */
530 	process_pending_events();
531 
532 	/* Get a list of the Devices */
533 	CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
534 	if (!device_set)
535 		return NULL;
536 
537 	/* Convert the list into a C array so we can iterate easily. */
538 	num_devices = CFSetGetCount(device_set);
539 	if (!num_devices) {
540 		CFRelease(device_set);
541 		return NULL;
542 	}
543 	IOHIDDeviceRef *device_array = (IOHIDDeviceRef*)calloc(num_devices, sizeof(IOHIDDeviceRef));
544 	CFSetGetValues(device_set, (const void **) device_array);
545 
546 	/* Iterate over each device, making an entry for it. */
547 	for (i = 0; i < num_devices; i++) {
548 		unsigned short dev_vid;
549 		unsigned short dev_pid;
550 #define BUF_LEN 256
551 		wchar_t buf[BUF_LEN];
552 		char cbuf[BUF_LEN];
553 
554 		IOHIDDeviceRef dev = device_array[i];
555 
556 		if (!dev) {
557 			continue;
558 		}
559 
560 #if defined(SDL_JOYSTICK_MFI)
561 		// We want to prefer Game Controller support where available,
562 		// as Apple will likely be requiring that for supported devices.
563 		extern SDL_bool IOS_SupportedHIDDevice(IOHIDDeviceRef device);
564 		if (IOS_SupportedHIDDevice(dev)) {
565 			continue;
566 		}
567 #endif
568 
569 		dev_vid = get_vendor_id(dev);
570 		dev_pid = get_product_id(dev);
571 
572 		/* Check the VID/PID against the arguments */
573 		if ((vendor_id == 0x0 && product_id == 0x0) ||
574 		    (vendor_id == dev_vid && product_id == dev_pid)) {
575 			struct hid_device_info *tmp;
576 			size_t len;
577 
578 			/* VID/PID match. Create the record. */
579 			tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
580 			if (cur_dev) {
581 				cur_dev->next = tmp;
582 			}
583 			else {
584 				root = tmp;
585 			}
586 			cur_dev = tmp;
587 
588 			// Get the Usage Page and Usage for this device.
589 			cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
590 			cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
591 
592 			/* Fill out the record */
593 			cur_dev->next = NULL;
594 			len = make_path(dev, cbuf, sizeof(cbuf));
595 			cur_dev->path = strdup(cbuf);
596 
597 			/* Serial Number */
598 			get_serial_number(dev, buf, BUF_LEN);
599 			cur_dev->serial_number = dup_wcs(buf);
600 
601 			/* Manufacturer and Product strings */
602 			get_manufacturer_string(dev, buf, BUF_LEN);
603 			cur_dev->manufacturer_string = dup_wcs(buf);
604 			get_product_string(dev, buf, BUF_LEN);
605 			cur_dev->product_string = dup_wcs(buf);
606 
607 			/* VID/PID */
608 			cur_dev->vendor_id = dev_vid;
609 			cur_dev->product_id = dev_pid;
610 
611 			/* Release Number */
612 			cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
613 
614 			/* Interface Number (Unsupported on Mac)*/
615 			cur_dev->interface_number = -1;
616 		}
617 	}
618 
619 	free(device_array);
620 	CFRelease(device_set);
621 
622 	return root;
623 }
624 
hid_free_enumeration(struct hid_device_info * devs)625 void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
626 {
627 	/* This function is identical to the Linux version. Platform independent. */
628 	struct hid_device_info *d = devs;
629 	while (d) {
630 		struct hid_device_info *next = d->next;
631 		free(d->path);
632 		free(d->serial_number);
633 		free(d->manufacturer_string);
634 		free(d->product_string);
635 		free(d);
636 		d = next;
637 	}
638 }
639 
hid_open(unsigned short vendor_id,unsigned short product_id,const wchar_t * serial_number)640 hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
641 {
642 	/* This function is identical to the Linux version. Platform independent. */
643 	struct hid_device_info *devs, *cur_dev;
644 	const char *path_to_open = NULL;
645 	hid_device * handle = NULL;
646 
647 	devs = hid_enumerate(vendor_id, product_id);
648 	cur_dev = devs;
649 	while (cur_dev) {
650 		if (cur_dev->vendor_id == vendor_id &&
651 		    cur_dev->product_id == product_id) {
652 			if (serial_number) {
653 				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
654 					path_to_open = cur_dev->path;
655 					break;
656 				}
657 			}
658 			else {
659 				path_to_open = cur_dev->path;
660 				break;
661 			}
662 		}
663 		cur_dev = cur_dev->next;
664 	}
665 
666 	if (path_to_open) {
667 		/* Open the device */
668 		handle = hid_open_path(path_to_open, 0);
669 	}
670 
671 	hid_free_enumeration(devs);
672 
673 	return handle;
674 }
675 
676 /* The Run Loop calls this function for each input report received.
677  This function puts the data into a linked list to be picked up by
678  hid_read(). */
hid_report_callback(void * context,IOReturn result,void * sender,IOHIDReportType report_type,uint32_t report_id,uint8_t * report,CFIndex report_length)679 static void hid_report_callback(void *context, IOReturn result, void *sender,
680 								IOHIDReportType report_type, uint32_t report_id,
681 								uint8_t *report, CFIndex report_length)
682 {
683 	struct input_report *rpt;
684 	hid_device *dev = (hid_device *)context;
685 
686 	/* Make a new Input Report object */
687 	rpt = (struct input_report *)calloc(1, sizeof(struct input_report));
688 	rpt->data = (uint8_t *)calloc(1, report_length);
689 	memcpy(rpt->data, report, report_length);
690 	rpt->len = report_length;
691 	rpt->next = NULL;
692 
693 	/* Lock this section */
694 	pthread_mutex_lock(&dev->mutex);
695 
696 	/* Attach the new report object to the end of the list. */
697 	if (dev->input_reports == NULL) {
698 		/* The list is empty. Put it at the root. */
699 		dev->input_reports = rpt;
700 	}
701 	else {
702 		/* Find the end of the list and attach. */
703 		struct input_report *cur = dev->input_reports;
704 		int num_queued = 0;
705 		while (cur->next != NULL) {
706 			cur = cur->next;
707 			num_queued++;
708 		}
709 		cur->next = rpt;
710 
711 		/* Pop one off if we've reached 30 in the queue. This
712 		 way we don't grow forever if the user never reads
713 		 anything from the device. */
714 		if (num_queued > 30) {
715 			return_data(dev, NULL, 0);
716 		}
717 	}
718 
719 	/* Signal a waiting thread that there is data. */
720 	pthread_cond_signal(&dev->condition);
721 
722 	/* Unlock */
723 	pthread_mutex_unlock(&dev->mutex);
724 
725 }
726 
727 /* This gets called when the read_thred's run loop gets signaled by
728  hid_close(), and serves to stop the read_thread's run loop. */
perform_signal_callback(void * context)729 static void perform_signal_callback(void *context)
730 {
731 	hid_device *dev = (hid_device *)context;
732 	CFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent()
733 }
734 
read_thread(void * param)735 static void *read_thread(void *param)
736 {
737 	hid_device *dev = (hid_device *)param;
738 
739 	/* Move the device's run loop to this thread. */
740 	IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
741 
742 	/* Create the RunLoopSource which is used to signal the
743 	 event loop to stop when hid_close() is called. */
744 	CFRunLoopSourceContext ctx;
745 	memset(&ctx, 0, sizeof(ctx));
746 	ctx.version = 0;
747 	ctx.info = dev;
748 	ctx.perform = &perform_signal_callback;
749 	dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);
750 	CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
751 
752 	/* Store off the Run Loop so it can be stopped from hid_close()
753 	 and on device disconnection. */
754 	dev->run_loop = CFRunLoopGetCurrent();
755 
756 	/* Notify the main thread that the read thread is up and running. */
757 	pthread_barrier_wait(&dev->barrier);
758 
759 	/* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
760 	 reports into the hid_report_callback(). */
761 	SInt32 code;
762 	while (!dev->shutdown_thread && !dev->disconnected) {
763 		code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);
764 		/* Return if the device has been disconnected */
765 		if (code == kCFRunLoopRunFinished) {
766 			dev->disconnected = 1;
767 			break;
768 		}
769 
770 
771 		/* Break if The Run Loop returns Finished or Stopped. */
772 		if (code != kCFRunLoopRunTimedOut &&
773 		    code != kCFRunLoopRunHandledSource) {
774 			/* There was some kind of error. Setting
775 			 shutdown seems to make sense, but
776 			 there may be something else more appropriate */
777 			dev->shutdown_thread = 1;
778 			break;
779 		}
780 	}
781 
782 	/* Now that the read thread is stopping, Wake any threads which are
783 	 waiting on data (in hid_read_timeout()). Do this under a mutex to
784 	 make sure that a thread which is about to go to sleep waiting on
785 	 the condition acutally will go to sleep before the condition is
786 	 signaled. */
787 	pthread_mutex_lock(&dev->mutex);
788 	pthread_cond_broadcast(&dev->condition);
789 	pthread_mutex_unlock(&dev->mutex);
790 
791 	/* Wait here until hid_close() is called and makes it past
792 	 the call to CFRunLoopWakeUp(). This thread still needs to
793 	 be valid when that function is called on the other thread. */
794 	pthread_barrier_wait(&dev->shutdown_barrier);
795 
796 	return NULL;
797 }
798 
hid_open_path(const char * path,int bExclusive)799 hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
800 {
801   	int i;
802 	hid_device *dev = NULL;
803 	CFIndex num_devices;
804 
805 	dev = new_hid_device();
806 
807 	/* Set up the HID Manager if it hasn't been done */
808 	if (hid_init() < 0)
809 		return NULL;
810 
811 	/* give the IOHIDManager a chance to update itself */
812 	process_pending_events();
813 
814 	CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
815 
816 	num_devices = CFSetGetCount(device_set);
817 	IOHIDDeviceRef *device_array = (IOHIDDeviceRef *)calloc(num_devices, sizeof(IOHIDDeviceRef));
818 	CFSetGetValues(device_set, (const void **) device_array);
819 	for (i = 0; i < num_devices; i++) {
820 		char cbuf[BUF_LEN];
821 		size_t len;
822 		IOHIDDeviceRef os_dev = device_array[i];
823 
824 		len = make_path(os_dev, cbuf, sizeof(cbuf));
825 		if (!strcmp(cbuf, path)) {
826 			// Matched Paths. Open this Device.
827 			IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
828 			if (ret == kIOReturnSuccess) {
829 				char str[32];
830 
831 				free(device_array);
832 				CFRelease(device_set);
833 				dev->device_handle = os_dev;
834 
835 				/* Create the buffers for receiving data */
836 				dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);
837 				dev->input_report_buf = (uint8_t *)calloc(dev->max_input_report_len, sizeof(uint8_t));
838 
839 				/* Create the Run Loop Mode for this device.
840 				 printing the reference seems to work. */
841 				sprintf(str, "HIDAPI_%p", os_dev);
842 				dev->run_loop_mode =
843 				CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
844 
845 				/* Attach the device to a Run Loop */
846 				IOHIDDeviceRegisterInputReportCallback(
847 													   os_dev, dev->input_report_buf, dev->max_input_report_len,
848 													   &hid_report_callback, dev);
849 
850 				struct hid_device_list_node *node = (struct hid_device_list_node *)calloc(1, sizeof(struct hid_device_list_node));
851 				node->dev = dev;
852 				node->next = device_list;
853 				device_list = node;
854 
855 				/* Start the read thread */
856 				pthread_create(&dev->thread, NULL, read_thread, dev);
857 
858 				/* Wait here for the read thread to be initialized. */
859 				pthread_barrier_wait(&dev->barrier);
860 
861 				return dev;
862 			}
863 			else {
864 				goto return_error;
865 			}
866 		}
867 	}
868 
869 return_error:
870 	free(device_array);
871 	CFRelease(device_set);
872 	free_hid_device(dev);
873 	return NULL;
874 }
875 
set_report(hid_device * dev,IOHIDReportType type,const unsigned char * data,size_t length)876 static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)
877 {
878 	const char *pass_through_magic = "MAGIC0";
879 	size_t pass_through_magic_length = strlen(pass_through_magic);
880 	unsigned char report_id = data[0];
881 	const unsigned char *data_to_send;
882 	size_t length_to_send;
883 	IOReturn res;
884 
885 	/* Return if the device has been disconnected. */
886    	if (dev->disconnected)
887    		return -1;
888 
889 	if (report_id == 0x0) {
890 		/* Not using numbered Reports.
891 		 Don't send the report number. */
892 		data_to_send = data+1;
893 		length_to_send = length-1;
894 	}
895 	else if (length > 6 && memcmp(data, pass_through_magic, pass_through_magic_length) == 0) {
896 		report_id = data[pass_through_magic_length];
897 		data_to_send = data+pass_through_magic_length;
898 		length_to_send = length-pass_through_magic_length;
899 	}
900 	else {
901 		/* Using numbered Reports.
902 		 Send the Report Number */
903 		data_to_send = data;
904 		length_to_send = length;
905 	}
906 
907 	if (!dev->disconnected) {
908 		res = IOHIDDeviceSetReport(dev->device_handle,
909 								   type,
910 								   report_id, /* Report ID*/
911 								   data_to_send, length_to_send);
912 
913 		if (res == kIOReturnSuccess) {
914 			return (int)length;
915 		}
916 		else if (res == kIOReturnUnsupported) {
917 			/*printf("kIOReturnUnsupported\n");*/
918 			return -1;
919 		}
920 		else {
921 			/*printf("0x%x\n", res);*/
922 			return -1;
923 		}
924 	}
925 
926 	return -1;
927 }
928 
hid_write(hid_device * dev,const unsigned char * data,size_t length)929 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
930 {
931 	return set_report(dev, kIOHIDReportTypeOutput, data, length);
932 }
933 
934 /* Helper function, so that this isn't duplicated in hid_read(). */
return_data(hid_device * dev,unsigned char * data,size_t length)935 static int return_data(hid_device *dev, unsigned char *data, size_t length)
936 {
937 	/* Copy the data out of the linked list item (rpt) into the
938 	 return buffer (data), and delete the liked list item. */
939 	struct input_report *rpt = dev->input_reports;
940 	size_t len = (length < rpt->len)? length: rpt->len;
941 	memcpy(data, rpt->data, len);
942 	dev->input_reports = rpt->next;
943 	free(rpt->data);
944 	free(rpt);
945 	return (int)len;
946 }
947 
cond_wait(const hid_device * dev,pthread_cond_t * cond,pthread_mutex_t * mutex)948 static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
949 {
950 	while (!dev->input_reports) {
951 		int res = pthread_cond_wait(cond, mutex);
952 		if (res != 0)
953 			return res;
954 
955 		/* A res of 0 means we may have been signaled or it may
956 		 be a spurious wakeup. Check to see that there's acutally
957 		 data in the queue before returning, and if not, go back
958 		 to sleep. See the pthread_cond_timedwait() man page for
959 		 details. */
960 
961 		if (dev->shutdown_thread || dev->disconnected)
962 			return -1;
963 	}
964 
965 	return 0;
966 }
967 
cond_timedwait(const hid_device * dev,pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)968 static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
969 {
970 	while (!dev->input_reports) {
971 		int res = pthread_cond_timedwait(cond, mutex, abstime);
972 		if (res != 0)
973 			return res;
974 
975 		/* A res of 0 means we may have been signaled or it may
976 		 be a spurious wakeup. Check to see that there's acutally
977 		 data in the queue before returning, and if not, go back
978 		 to sleep. See the pthread_cond_timedwait() man page for
979 		 details. */
980 
981 		if (dev->shutdown_thread || dev->disconnected)
982 			return -1;
983 	}
984 
985 	return 0;
986 
987 }
988 
hid_read_timeout(hid_device * dev,unsigned char * data,size_t length,int milliseconds)989 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
990 {
991 	int bytes_read = -1;
992 
993 	/* Lock the access to the report list. */
994 	pthread_mutex_lock(&dev->mutex);
995 
996 	/* There's an input report queued up. Return it. */
997 	if (dev->input_reports) {
998 		/* Return the first one */
999 		bytes_read = return_data(dev, data, length);
1000 		goto ret;
1001 	}
1002 
1003 	/* Return if the device has been disconnected. */
1004 	if (dev->disconnected) {
1005 		bytes_read = -1;
1006 		goto ret;
1007 	}
1008 
1009 	if (dev->shutdown_thread) {
1010 		/* This means the device has been closed (or there
1011 		 has been an error. An error code of -1 should
1012 		 be returned. */
1013 		bytes_read = -1;
1014 		goto ret;
1015 	}
1016 
1017 	/* There is no data. Go to sleep and wait for data. */
1018 
1019 	if (milliseconds == -1) {
1020 		/* Blocking */
1021 		int res;
1022 		res = cond_wait(dev, &dev->condition, &dev->mutex);
1023 		if (res == 0)
1024 			bytes_read = return_data(dev, data, length);
1025 		else {
1026 			/* There was an error, or a device disconnection. */
1027 			bytes_read = -1;
1028 		}
1029 	}
1030 	else if (milliseconds > 0) {
1031 		/* Non-blocking, but called with timeout. */
1032 		int res;
1033 		struct timespec ts;
1034 		struct timeval tv;
1035 		gettimeofday(&tv, NULL);
1036 		TIMEVAL_TO_TIMESPEC(&tv, &ts);
1037 		ts.tv_sec += milliseconds / 1000;
1038 		ts.tv_nsec += (milliseconds % 1000) * 1000000;
1039 		if (ts.tv_nsec >= 1000000000L) {
1040 			ts.tv_sec++;
1041 			ts.tv_nsec -= 1000000000L;
1042 		}
1043 
1044 		res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
1045 		if (res == 0)
1046 			bytes_read = return_data(dev, data, length);
1047 		else if (res == ETIMEDOUT)
1048 			bytes_read = 0;
1049 		else
1050 			bytes_read = -1;
1051 	}
1052 	else {
1053 		/* Purely non-blocking */
1054 		bytes_read = 0;
1055 	}
1056 
1057 ret:
1058 	/* Unlock */
1059 	pthread_mutex_unlock(&dev->mutex);
1060 	return bytes_read;
1061 }
1062 
hid_read(hid_device * dev,unsigned char * data,size_t length)1063 int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
1064 {
1065 	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
1066 }
1067 
hid_set_nonblocking(hid_device * dev,int nonblock)1068 int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
1069 {
1070 	/* All Nonblocking operation is handled by the library. */
1071 	dev->blocking = !nonblock;
1072 
1073 	return 0;
1074 }
1075 
hid_send_feature_report(hid_device * dev,const unsigned char * data,size_t length)1076 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
1077 {
1078 	return set_report(dev, kIOHIDReportTypeFeature, data, length);
1079 }
1080 
hid_get_feature_report(hid_device * dev,unsigned char * data,size_t length)1081 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
1082 {
1083 	CFIndex len = length;
1084 	IOReturn res;
1085 
1086 	/* Return if the device has been unplugged. */
1087 	if (dev->disconnected)
1088 		return -1;
1089 
1090 	int skipped_report_id = 0;
1091 	int report_number = data[0];
1092 	if (report_number == 0x0) {
1093 		/* Offset the return buffer by 1, so that the report ID
1094 		 will remain in byte 0. */
1095 		data++;
1096 		len--;
1097 		skipped_report_id = 1;
1098 	}
1099 
1100 	res = IOHIDDeviceGetReport(dev->device_handle,
1101 	                           kIOHIDReportTypeFeature,
1102 	                           report_number, /* Report ID */
1103 	                           data, &len);
1104 	if (res != kIOReturnSuccess)
1105 		return -1;
1106 
1107 	if (skipped_report_id)
1108 		len++;
1109 
1110 	return (int)len;
1111 }
1112 
1113 
hid_close(hid_device * dev)1114 void HID_API_EXPORT hid_close(hid_device *dev)
1115 {
1116 	if (!dev)
1117 		return;
1118 
1119 	/* Disconnect the report callback before close. */
1120 	if (!dev->disconnected) {
1121 		IOHIDDeviceRegisterInputReportCallback(
1122 											   dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
1123 											   NULL, dev);
1124 		IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
1125 		IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
1126 	}
1127 
1128 	/* Cause read_thread() to stop. */
1129 	dev->shutdown_thread = 1;
1130 
1131 	/* Wake up the run thread's event loop so that the thread can exit. */
1132 	CFRunLoopSourceSignal(dev->source);
1133 	CFRunLoopWakeUp(dev->run_loop);
1134 
1135 	/* Notify the read thread that it can shut down now. */
1136 	pthread_barrier_wait(&dev->shutdown_barrier);
1137 
1138 	/* Wait for read_thread() to end. */
1139 	pthread_join(dev->thread, NULL);
1140 
1141 	/* Close the OS handle to the device, but only if it's not
1142 	 been unplugged. If it's been unplugged, then calling
1143 	 IOHIDDeviceClose() will crash. */
1144 	if (!dev->disconnected) {
1145 		IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
1146 	}
1147 
1148 	/* Clear out the queue of received reports. */
1149 	pthread_mutex_lock(&dev->mutex);
1150 	while (dev->input_reports) {
1151 		return_data(dev, NULL, 0);
1152 	}
1153 	pthread_mutex_unlock(&dev->mutex);
1154 
1155 	free_hid_device(dev);
1156 }
1157 
hid_get_manufacturer_string(hid_device * dev,wchar_t * string,size_t maxlen)1158 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
1159 {
1160 	return get_manufacturer_string(dev->device_handle, string, maxlen);
1161 }
1162 
hid_get_product_string(hid_device * dev,wchar_t * string,size_t maxlen)1163 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1164 {
1165 	return get_product_string(dev->device_handle, string, maxlen);
1166 }
1167 
hid_get_serial_number_string(hid_device * dev,wchar_t * string,size_t maxlen)1168 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1169 {
1170 	return get_serial_number(dev->device_handle, string, maxlen);
1171 }
1172 
hid_get_indexed_string(hid_device * dev,int string_index,wchar_t * string,size_t maxlen)1173 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1174 {
1175 	// TODO:
1176 
1177 	return 0;
1178 }
1179 
1180 
hid_error(hid_device * dev)1181 HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
1182 {
1183 	// TODO:
1184 
1185 	return NULL;
1186 }
1187 
1188 
1189 
1190 
1191 
1192 
1193 #if 0
1194 static int32_t get_location_id(IOHIDDeviceRef device)
1195 {
1196 	return get_int_property(device, CFSTR(kIOHIDLocationIDKey));
1197 }
1198 
1199 static int32_t get_usage(IOHIDDeviceRef device)
1200 {
1201 	int32_t res;
1202 	res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
1203 	if (!res)
1204 		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
1205 	return res;
1206 }
1207 
1208 static int32_t get_usage_page(IOHIDDeviceRef device)
1209 {
1210 	int32_t res;
1211 	res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
1212 	if (!res)
1213 		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
1214 	return res;
1215 }
1216 
1217 static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)
1218 {
1219 	return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
1220 }
1221 
1222 
1223 int main(void)
1224 {
1225 	IOHIDManagerRef mgr;
1226 	int i;
1227 
1228 	mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1229 	IOHIDManagerSetDeviceMatching(mgr, NULL);
1230 	IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
1231 
1232 	CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
1233 
1234 	CFIndex num_devices = CFSetGetCount(device_set);
1235 	IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
1236 	CFSetGetValues(device_set, (const void **) device_array);
1237 
1238 	for (i = 0; i < num_devices; i++) {
1239 		IOHIDDeviceRef dev = device_array[i];
1240 		printf("Device: %p\n", dev);
1241 		printf("  %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
1242 
1243 		wchar_t serial[256], buf[256];
1244 		char cbuf[256];
1245 		get_serial_number(dev, serial, 256);
1246 
1247 
1248 		printf("  Serial: %ls\n", serial);
1249 		printf("  Loc: %ld\n", get_location_id(dev));
1250 		get_transport(dev, buf, 256);
1251 		printf("  Trans: %ls\n", buf);
1252 		make_path(dev, cbuf, 256);
1253 		printf("  Path: %s\n", cbuf);
1254 
1255 	}
1256 
1257 	return 0;
1258 }
1259 #endif
1260