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