Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(680)

Side by Side Diff: third_party/hidapi/hidapi_mac.c

Issue 25666010: Adding third party library hidapi (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update Linux backend Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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_barrie rattr_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, cha r *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 l en)
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 res = snprintf(buf, len, "%s_%04hx_%04hx_%x",
355 transport, vid, pid, location);
356
357
358 buf[len-1] = '\0';
359 return res+1;
360 }
361
362 /* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */
363 static int init_hid_manager(void)
364 {
365 /* Initialize all the HID Manager Objects */
366 hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
367 if (hid_mgr) {
368 IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
369 IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDe faultMode);
370 return 0;
371 }
372
373 return -1;
374 }
375
376 /* Initialize the IOHIDManager if necessary. This is the public function, and
377 it is safe to call this function repeatedly. Return 0 for success and -1
378 for failure. */
379 int HID_API_EXPORT hid_init(void)
380 {
381 if (!hid_mgr) {
382 return init_hid_manager();
383 }
384
385 /* Already initialized. */
386 return 0;
387 }
388
389 int HID_API_EXPORT hid_exit(void)
390 {
391 if (hid_mgr) {
392 /* Close the HID manager. */
393 IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
394 CFRelease(hid_mgr);
395 hid_mgr = NULL;
396 }
397
398 return 0;
399 }
400
401 static void process_pending_events(void) {
402 SInt32 res;
403 do {
404 res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE);
405 } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
406 }
407
408 struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
409 {
410 struct hid_device_info *root = NULL; /* return object */
411 struct hid_device_info *cur_dev = NULL;
412 CFIndex num_devices;
413 int i;
414
415 /* Set up the HID Manager if it hasn't been done */
416 if (hid_init() < 0)
417 return NULL;
418
419 /* give the IOHIDManager a chance to update itself */
420 process_pending_events();
421
422 /* Get a list of the Devices */
423 IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
424 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
425
426 /* Convert the list into a C array so we can iterate easily. */
427 num_devices = CFSetGetCount(device_set);
428 IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
429 CFSetGetValues(device_set, (const void **) device_array);
430
431 /* Iterate over each device, making an entry for it. */
432 for (i = 0; i < num_devices; i++) {
433 unsigned short dev_vid;
434 unsigned short dev_pid;
435 #define BUF_LEN 256
436 wchar_t buf[BUF_LEN];
437 char cbuf[BUF_LEN];
438
439 IOHIDDeviceRef dev = device_array[i];
440
441 if (!dev) {
442 continue;
443 }
444 dev_vid = get_vendor_id(dev);
445 dev_pid = get_product_id(dev);
446
447 /* Check the VID/PID against the arguments */
448 if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
449 (product_id == 0x0 || product_id == dev_pid)) {
450 struct hid_device_info *tmp;
451 size_t len;
452
453 /* VID/PID match. Create the record. */
454 tmp = malloc(sizeof(struct hid_device_info));
455 if (cur_dev) {
456 cur_dev->next = tmp;
457 }
458 else {
459 root = tmp;
460 }
461 cur_dev = tmp;
462
463 /* Get the Usage Page and Usage for this device. */
464 cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKe y));
465 cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
466
467 /* Fill out the record */
468 cur_dev->next = NULL;
469 len = make_path(dev, cbuf, sizeof(cbuf));
470 cur_dev->path = strdup(cbuf);
471
472 /* Serial Number */
473 get_serial_number(dev, buf, BUF_LEN);
474 cur_dev->serial_number = dup_wcs(buf);
475
476 /* Manufacturer and Product strings */
477 get_manufacturer_string(dev, buf, BUF_LEN);
478 cur_dev->manufacturer_string = dup_wcs(buf);
479 get_product_string(dev, buf, BUF_LEN);
480 cur_dev->product_string = dup_wcs(buf);
481
482 /* VID/PID */
483 cur_dev->vendor_id = dev_vid;
484 cur_dev->product_id = dev_pid;
485
486 /* Release Number */
487 cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberK ey));
488
489 /* Interface Number (Unsupported on Mac)*/
490 cur_dev->interface_number = -1;
491 }
492 }
493
494 free(device_array);
495 CFRelease(device_set);
496
497 return root;
498 }
499
500 void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
501 {
502 /* This function is identical to the Linux version. Platform independent. */
503 struct hid_device_info *d = devs;
504 while (d) {
505 struct hid_device_info *next = d->next;
506 free(d->path);
507 free(d->serial_number);
508 free(d->manufacturer_string);
509 free(d->product_string);
510 free(d);
511 d = next;
512 }
513 }
514
515 hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short pr oduct_id, const wchar_t *serial_number)
516 {
517 /* This function is identical to the Linux version. Platform independent. */
518 struct hid_device_info *devs, *cur_dev;
519 const char *path_to_open = NULL;
520 hid_device * handle = NULL;
521
522 devs = hid_enumerate(vendor_id, product_id);
523 cur_dev = devs;
524 while (cur_dev) {
525 if (cur_dev->vendor_id == vendor_id &&
526 cur_dev->product_id == product_id) {
527 if (serial_number) {
528 if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
529 path_to_open = cur_dev->path;
530 break;
531 }
532 }
533 else {
534 path_to_open = cur_dev->path;
535 break;
536 }
537 }
538 cur_dev = cur_dev->next;
539 }
540
541 if (path_to_open) {
542 /* Open the device */
543 handle = hid_open_path(path_to_open);
544 }
545
546 hid_free_enumeration(devs);
547
548 return handle;
549 }
550
551 static void hid_device_removal_callback(void *context, IOReturn result,
552 void *sender)
553 {
554 /* Stop the Run Loop for this device. */
555 hid_device *d = context;
556
557 d->disconnected = 1;
558 CFRunLoopStop(d->run_loop);
559 }
560
561 /* The Run Loop calls this function for each input report received.
562 This function puts the data into a linked list to be picked up by
563 hid_read(). */
564 static void hid_report_callback(void *context, IOReturn result, void *sender,
565 IOHIDReportType report_type, uint32_t report_id,
566 uint8_t *report, CFIndex report_length)
567 {
568 struct input_report *rpt;
569 hid_device *dev = context;
570
571 /* Make a new Input Report object */
572 rpt = calloc(1, sizeof(struct input_report));
573 rpt->data = calloc(1, report_length);
574 memcpy(rpt->data, report, report_length);
575 rpt->len = report_length;
576 rpt->next = NULL;
577
578 /* Lock this section */
579 pthread_mutex_lock(&dev->mutex);
580
581 /* Attach the new report object to the end of the list. */
582 if (dev->input_reports == NULL) {
583 /* The list is empty. Put it at the root. */
584 dev->input_reports = rpt;
585 }
586 else {
587 /* Find the end of the list and attach. */
588 struct input_report *cur = dev->input_reports;
589 int num_queued = 0;
590 while (cur->next != NULL) {
591 cur = cur->next;
592 num_queued++;
593 }
594 cur->next = rpt;
595
596 /* Pop one off if we've reached 30 in the queue. This
597 way we don't grow forever if the user never reads
598 anything from the device. */
599 if (num_queued > 30) {
600 return_data(dev, NULL, 0);
601 }
602 }
603
604 /* Signal a waiting thread that there is data. */
605 pthread_cond_signal(&dev->condition);
606
607 /* Unlock */
608 pthread_mutex_unlock(&dev->mutex);
609
610 }
611
612 /* This gets called when the read_thred's run loop gets signaled by
613 hid_close(), and serves to stop the read_thread's run loop. */
614 static void perform_signal_callback(void *context)
615 {
616 hid_device *dev = context;
617 CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/
618 }
619
620 static void *read_thread(void *param)
621 {
622 hid_device *dev = param;
623 SInt32 code;
624
625 /* Move the device's run loop to this thread. */
626 IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev- >run_loop_mode);
627
628 /* Create the RunLoopSource which is used to signal the
629 event loop to stop when hid_close() is called. */
630 CFRunLoopSourceContext ctx;
631 memset(&ctx, 0, sizeof(ctx));
632 ctx.version = 0;
633 ctx.info = dev;
634 ctx.perform = &perform_signal_callback;
635 dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);
636 CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
637
638 /* Store off the Run Loop so it can be stopped from hid_close()
639 and on device disconnection. */
640 dev->run_loop = CFRunLoopGetCurrent();
641
642 /* Notify the main thread that the read thread is up and running. */
643 pthread_barrier_wait(&dev->barrier);
644
645 /* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
646 reports into the hid_report_callback(). */
647 while (!dev->shutdown_thread && !dev->disconnected) {
648 code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);
649 /* Return if the device has been disconnected */
650 if (code == kCFRunLoopRunFinished) {
651 dev->disconnected = 1;
652 break;
653 }
654
655
656 /* Break if The Run Loop returns Finished or Stopped. */
657 if (code != kCFRunLoopRunTimedOut &&
658 code != kCFRunLoopRunHandledSource) {
659 /* There was some kind of error. Setting
660 shutdown seems to make sense, but
661 there may be something else more appropriate */
662 dev->shutdown_thread = 1;
663 break;
664 }
665 }
666
667 /* Now that the read thread is stopping, Wake any threads which are
668 waiting on data (in hid_read_timeout()). Do this under a mutex to
669 make sure that a thread which is about to go to sleep waiting on
670 the condition acutally will go to sleep before the condition is
671 signaled. */
672 pthread_mutex_lock(&dev->mutex);
673 pthread_cond_broadcast(&dev->condition);
674 pthread_mutex_unlock(&dev->mutex);
675
676 /* Wait here until hid_close() is called and makes it past
677 the call to CFRunLoopWakeUp(). This thread still needs to
678 be valid when that function is called on the other thread. */
679 pthread_barrier_wait(&dev->shutdown_barrier);
680
681 return NULL;
682 }
683
684 hid_device * HID_API_EXPORT hid_open_path(const char *path)
685 {
686 int i;
687 hid_device *dev = NULL;
688 CFIndex num_devices;
689
690 dev = new_hid_device();
691
692 /* Set up the HID Manager if it hasn't been done */
693 if (hid_init() < 0)
694 return NULL;
695
696 /* give the IOHIDManager a chance to update itself */
697 process_pending_events();
698
699 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
700
701 num_devices = CFSetGetCount(device_set);
702 IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
703 CFSetGetValues(device_set, (const void **) device_array);
704 for (i = 0; i < num_devices; i++) {
705 char cbuf[BUF_LEN];
706 size_t len;
707 IOHIDDeviceRef os_dev = device_array[i];
708
709 len = make_path(os_dev, cbuf, sizeof(cbuf));
710 if (!strcmp(cbuf, path)) {
711 /* Matched Paths. Open this Device. */
712 IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeSeizeDevice);
713 if (ret == kIOReturnSuccess) {
714 char str[32];
715
716 free(device_array);
717 CFRetain(os_dev);
718 CFRelease(device_set);
719 dev->device_handle = os_dev;
720
721 /* Create the buffers for receiving data */
722 dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);
723 dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t ));
724
725 /* Create the Run Loop Mode for this device.
726 printing the reference seems to work. */
727 sprintf(str, "HIDAPI_%p", os_dev);
728 dev->run_loop_mode =
729 CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
730
731 /* Attach the device to a Run Loop */
732 IOHIDDeviceRegisterInputReportCallback(
733 os_dev, dev->input_report_buf, dev->max_input_report_len,
734 &hid_report_callback, dev);
735 IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_remova l_callback, dev);
736
737 /* Start the read thread */
738 pthread_create(&dev->thread, NULL, read_thread, dev);
739
740 /* Wait here for the read thread to be initialized. */
741 pthread_barrier_wait(&dev->barrier);
742
743 return dev;
744 }
745 else {
746 goto return_error;
747 }
748 }
749 }
750
751 return_error:
752 free(device_array);
753 CFRelease(device_set);
754 free_hid_device(dev);
755 return NULL;
756 }
757
758 static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)
759 {
760 const unsigned char *data_to_send;
761 size_t length_to_send;
762 IOReturn res;
763
764 /* Return if the device has been disconnected. */
765 if (dev->disconnected)
766 return -1;
767
768 if (data[0] == 0x0) {
769 /* Not using numbered Reports.
770 Don't send the report number. */
771 data_to_send = data+1;
772 length_to_send = length-1;
773 }
774 else {
775 /* Using numbered Reports.
776 Send the Report Number */
777 data_to_send = data;
778 length_to_send = length;
779 }
780
781 if (!dev->disconnected) {
782 res = IOHIDDeviceSetReport(dev->device_handle,
783 type,
784 data[0], /* Report ID*/
785 data_to_send, length_to_send);
786
787 if (res == kIOReturnSuccess) {
788 return length;
789 }
790 else
791 return -1;
792 }
793
794 return -1;
795 }
796
797 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
798 {
799 return set_report(dev, kIOHIDReportTypeOutput, data, length);
800 }
801
802 /* Helper function, so that this isn't duplicated in hid_read(). */
803 static int return_data(hid_device *dev, unsigned char *data, size_t length)
804 {
805 /* Copy the data out of the linked list item (rpt) into the
806 return buffer (data), and delete the liked list item. */
807 struct input_report *rpt = dev->input_reports;
808 size_t len = (length < rpt->len)? length: rpt->len;
809 memcpy(data, rpt->data, len);
810 dev->input_reports = rpt->next;
811 free(rpt->data);
812 free(rpt);
813 return len;
814 }
815
816 static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_ t *mutex)
817 {
818 while (!dev->input_reports) {
819 int res = pthread_cond_wait(cond, mutex);
820 if (res != 0)
821 return res;
822
823 /* A res of 0 means we may have been signaled or it may
824 be a spurious wakeup. Check to see that there's acutally
825 data in the queue before returning, and if not, go back
826 to sleep. See the pthread_cond_timedwait() man page for
827 details. */
828
829 if (dev->shutdown_thread || dev->disconnected)
830 return -1;
831 }
832
833 return 0;
834 }
835
836 static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_m utex_t *mutex, const struct timespec *abstime)
837 {
838 while (!dev->input_reports) {
839 int res = pthread_cond_timedwait(cond, mutex, abstime);
840 if (res != 0)
841 return res;
842
843 /* A res of 0 means we may have been signaled or it may
844 be a spurious wakeup. Check to see that there's acutally
845 data in the queue before returning, and if not, go back
846 to sleep. See the pthread_cond_timedwait() man page for
847 details. */
848
849 if (dev->shutdown_thread || dev->disconnected)
850 return -1;
851 }
852
853 return 0;
854
855 }
856
857 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
858 {
859 int bytes_read = -1;
860
861 /* Lock the access to the report list. */
862 pthread_mutex_lock(&dev->mutex);
863
864 /* There's an input report queued up. Return it. */
865 if (dev->input_reports) {
866 /* Return the first one */
867 bytes_read = return_data(dev, data, length);
868 goto ret;
869 }
870
871 /* Return if the device has been disconnected. */
872 if (dev->disconnected) {
873 bytes_read = -1;
874 goto ret;
875 }
876
877 if (dev->shutdown_thread) {
878 /* This means the device has been closed (or there
879 has been an error. An error code of -1 should
880 be returned. */
881 bytes_read = -1;
882 goto ret;
883 }
884
885 /* There is no data. Go to sleep and wait for data. */
886
887 if (milliseconds == -1) {
888 /* Blocking */
889 int res;
890 res = cond_wait(dev, &dev->condition, &dev->mutex);
891 if (res == 0)
892 bytes_read = return_data(dev, data, length);
893 else {
894 /* There was an error, or a device disconnection. */
895 bytes_read = -1;
896 }
897 }
898 else if (milliseconds > 0) {
899 /* Non-blocking, but called with timeout. */
900 int res;
901 struct timespec ts;
902 struct timeval tv;
903 gettimeofday(&tv, NULL);
904 TIMEVAL_TO_TIMESPEC(&tv, &ts);
905 ts.tv_sec += milliseconds / 1000;
906 ts.tv_nsec += (milliseconds % 1000) * 1000000;
907 if (ts.tv_nsec >= 1000000000L) {
908 ts.tv_sec++;
909 ts.tv_nsec -= 1000000000L;
910 }
911
912 res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
913 if (res == 0)
914 bytes_read = return_data(dev, data, length);
915 else if (res == ETIMEDOUT)
916 bytes_read = 0;
917 else
918 bytes_read = -1;
919 }
920 else {
921 /* Purely non-blocking */
922 bytes_read = 0;
923 }
924
925 ret:
926 /* Unlock */
927 pthread_mutex_unlock(&dev->mutex);
928 return bytes_read;
929 }
930
931 int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
932 {
933 return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
934 }
935
936 int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
937 {
938 /* All Nonblocking operation is handled by the library. */
939 dev->blocking = !nonblock;
940
941 return 0;
942 }
943
944 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
945 {
946 return set_report(dev, kIOHIDReportTypeFeature, data, length);
947 }
948
949 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
950 {
951 CFIndex len = length;
952 IOReturn res;
953
954 /* Return if the device has been unplugged. */
955 if (dev->disconnected)
956 return -1;
957
958 res = IOHIDDeviceGetReport(dev->device_handle,
959 kIOHIDReportTypeFeature,
960 data[0], /* Report ID */
961 data, &len);
962 if (res == kIOReturnSuccess)
963 return len;
964 else
965 return -1;
966 }
967
968
969 void HID_API_EXPORT hid_close(hid_device *dev)
970 {
971 if (!dev)
972 return;
973
974 /* Disconnect the report callback before close. */
975 if (!dev->disconnected) {
976 IOHIDDeviceRegisterInputReportCallback(
977 dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
978 NULL, dev);
979 IOHIDDeviceRegisterRemovalCallback(dev->device_handle, NULL, dev);
980 IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run _loop_mode);
981 IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRu nLoopDefaultMode);
982 }
983
984 /* Cause read_thread() to stop. */
985 dev->shutdown_thread = 1;
986
987 /* Wake up the run thread's event loop so that the thread can exit. */
988 CFRunLoopSourceSignal(dev->source);
989 CFRunLoopWakeUp(dev->run_loop);
990
991 /* Notify the read thread that it can shut down now. */
992 pthread_barrier_wait(&dev->shutdown_barrier);
993
994 /* Wait for read_thread() to end. */
995 pthread_join(dev->thread, NULL);
996
997 /* Close the OS handle to the device, but only if it's not
998 been unplugged. If it's been unplugged, then calling
999 IOHIDDeviceClose() will crash. */
1000 if (!dev->disconnected) {
1001 IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);
1002 }
1003
1004 /* Clear out the queue of received reports. */
1005 pthread_mutex_lock(&dev->mutex);
1006 while (dev->input_reports) {
1007 return_data(dev, NULL, 0);
1008 }
1009 pthread_mutex_unlock(&dev->mutex);
1010 CFRelease(dev->device_handle);
1011
1012 free_hid_device(dev);
1013 }
1014
1015 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *st ring, size_t maxlen)
1016 {
1017 return get_manufacturer_string(dev->device_handle, string, maxlen);
1018 }
1019
1020 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1021 {
1022 return get_product_string(dev->device_handle, string, maxlen);
1023 }
1024
1025 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s tring, size_t maxlen)
1026 {
1027 return get_serial_number(dev->device_handle, string, maxlen);
1028 }
1029
1030 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index , wchar_t *string, size_t maxlen)
1031 {
1032 /* TODO: */
1033
1034 return 0;
1035 }
1036
1037
1038 HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
1039 {
1040 /* TODO: */
1041
1042 return NULL;
1043 }
1044
1045
1046
1047
1048
1049
1050
1051 #if 0
1052 static int32_t get_usage(IOHIDDeviceRef device)
1053 {
1054 int32_t res;
1055 res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
1056 if (!res)
1057 res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
1058 return res;
1059 }
1060
1061 static int32_t get_usage_page(IOHIDDeviceRef device)
1062 {
1063 int32_t res;
1064 res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
1065 if (!res)
1066 res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
1067 return res;
1068 }
1069
1070 static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)
1071 {
1072 return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
1073 }
1074
1075
1076 int main(void)
1077 {
1078 IOHIDManagerRef mgr;
1079 int i;
1080
1081 mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1082 IOHIDManagerSetDeviceMatching(mgr, NULL);
1083 IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
1084
1085 CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
1086
1087 CFIndex num_devices = CFSetGetCount(device_set);
1088 IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
1089 CFSetGetValues(device_set, (const void **) device_array);
1090
1091 for (i = 0; i < num_devices; i++) {
1092 IOHIDDeviceRef dev = device_array[i];
1093 printf("Device: %p\n", dev);
1094 printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
1095
1096 wchar_t serial[256], buf[256];
1097 char cbuf[256];
1098 get_serial_number(dev, serial, 256);
1099
1100
1101 printf(" Serial: %ls\n", serial);
1102 printf(" Loc: %ld\n", get_location_id(dev));
1103 get_transport(dev, buf, 256);
1104 printf(" Trans: %ls\n", buf);
1105 make_path(dev, cbuf, 256);
1106 printf(" Path: %s\n", cbuf);
1107
1108 }
1109
1110 return 0;
1111 }
1112 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698