sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

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 */