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