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