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