Instrument Neutral Distributed Interface INDI  1.9.5
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 "indidevapi.h"
35 
36 #include <IOKit/hid/IOHIDManager.h>
37 #include <IOKit/hid/IOHIDKeys.h>
38 #include <CoreFoundation/CoreFoundation.h>
39 
40 #include <wchar.h>
41 #include <pthread.h>
42 #include <sys/time.h>
43 #include <unistd.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  size_t len;
441 
442  /* VID/PID match. Create the record. */
443  tmp = malloc(sizeof(struct hid_device_info));
444  if (cur_dev)
445  {
446  cur_dev->next = tmp;
447  }
448  else
449  {
450  root = tmp;
451  }
452  cur_dev = tmp;
453 
454  // Get the Usage Page and Usage for this device.
455  cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
456  cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
457 
458  /* Fill out the record */
459  cur_dev->next = NULL;
460  len = make_path(dev, cbuf, sizeof(cbuf));
461  cur_dev->path = strdup(cbuf);
462 
463  /* Serial Number */
464  get_serial_number(dev, buf, BUF_LEN);
465  cur_dev->serial_number = dup_wcs(buf);
466 
467  /* Manufacturer and Product strings */
468  get_manufacturer_string(dev, buf, BUF_LEN);
469  cur_dev->manufacturer_string = dup_wcs(buf);
470  get_product_string(dev, buf, BUF_LEN);
471  cur_dev->product_string = dup_wcs(buf);
472 
473  /* VID/PID */
474  cur_dev->vendor_id = dev_vid;
475  cur_dev->product_id = dev_pid;
476 
477  /* Release Number */
478  cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
479 
480  /* Interface Number (Unsupported on Mac)*/
481  cur_dev->interface_number = -1;
482  }
483  }
484 
485  free(device_array);
486  CFRelease(device_set);
487 
488  return root;
489 }
490 
492 {
493  /* This function is identical to the Linux version. Platform independent. */
494  struct hid_device_info *d = devs;
495  while (d)
496  {
497  struct hid_device_info *next = d->next;
498  free(d->path);
499  free(d->serial_number);
500  free(d->manufacturer_string);
501  free(d->product_string);
502  free(d);
503  d = next;
504  }
505 }
506 
507 hid_device *HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
508 {
509  /* This function is identical to the Linux version. Platform independent. */
510  struct hid_device_info *devs, *cur_dev;
511  const char *path_to_open = NULL;
512  hid_device *handle = NULL;
513 
515  cur_dev = devs;
516  while (cur_dev)
517  {
518  if (cur_dev->vendor_id == vendor_id && cur_dev->product_id == product_id)
519  {
520  if (serial_number)
521  {
522  if (wcscmp(serial_number, cur_dev->serial_number) == 0)
523  {
524  path_to_open = cur_dev->path;
525  break;
526  }
527  }
528  else
529  {
530  path_to_open = cur_dev->path;
531  break;
532  }
533  }
534  cur_dev = cur_dev->next;
535  }
536 
537  if (path_to_open)
538  {
539  /* Open the device */
540  handle = hid_open_path(path_to_open);
541  }
542 
543  hid_free_enumeration(devs);
544 
545  return handle;
546 }
547 
548 static void hid_device_removal_callback(void *context, IOReturn result, void *sender)
549 {
550  INDI_UNUSED(result);
551  INDI_UNUSED(sender);
552  /* Stop the Run Loop for this device. */
553  hid_device *d = context;
554 
555  d->disconnected = 1;
556  CFRunLoopStop(d->run_loop);
557 }
558 
559 /* The Run Loop calls this function for each input report received.
560  This function puts the data into a linked list to be picked up by
561  hid_read(). */
562 static void hid_report_callback(void *context, IOReturn result, void *sender, IOHIDReportType report_type,
563  uint32_t report_id, uint8_t *report, CFIndex report_length)
564 {
565  INDI_UNUSED(result);
566  INDI_UNUSED(sender);
567  INDI_UNUSED(report_type);
568  INDI_UNUSED(report_id);
569  struct input_report *rpt;
570  hid_device *dev = context;
571 
572  /* Make a new Input Report object */
573  rpt = calloc(1, sizeof(struct input_report));
574  rpt->data = calloc(1, report_length);
575  memcpy(rpt->data, report, report_length);
576  rpt->len = report_length;
577  rpt->next = NULL;
578 
579  /* Lock this section */
580  pthread_mutex_lock(&dev->mutex);
581 
582  /* Attach the new report object to the end of the list. */
583  if (dev->input_reports == NULL)
584  {
585  /* The list is empty. Put it at the root. */
586  dev->input_reports = rpt;
587  }
588  else
589  {
590  /* Find the end of the list and attach. */
591  struct input_report *cur = dev->input_reports;
592  int num_queued = 0;
593  while (cur->next != NULL)
594  {
595  cur = cur->next;
596  num_queued++;
597  }
598  cur->next = rpt;
599 
600  /* Pop one off if we've reached 30 in the queue. This
601  way we don't grow forever if the user never reads
602  anything from the device. */
603  if (num_queued > 30)
604  {
605  return_data(dev, NULL, 0);
606  }
607  }
608 
609  /* Signal a waiting thread that there is data. */
610  pthread_cond_signal(&dev->condition);
611 
612  /* Unlock */
613  pthread_mutex_unlock(&dev->mutex);
614 }
615 
616 /* This gets called when the read_thred's run loop gets signaled by
617  hid_close(), and serves to stop the read_thread's run loop. */
618 static void perform_signal_callback(void *context)
619 {
620  hid_device *dev = context;
621  CFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent()
622 }
623 
624 static void *read_thread(void *param)
625 {
626  hid_device *dev = param;
627 
628  /* Move the device's run loop to this thread. */
629  IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
630 
631  /* Create the RunLoopSource which is used to signal the
632  event loop to stop when hid_close() is called. */
633  CFRunLoopSourceContext ctx;
634  memset(&ctx, 0, sizeof(ctx));
635  ctx.version = 0;
636  ctx.info = dev;
637  ctx.perform = &perform_signal_callback;
638  dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 /*order*/, &ctx);
639  CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
640 
641  /* Store off the Run Loop so it can be stopped from hid_close()
642  and on device disconnection. */
643  dev->run_loop = CFRunLoopGetCurrent();
644 
645  /* Notify the main thread that the read thread is up and running. */
646  pthread_barrier_wait(&dev->barrier);
647 
648  /* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
649  reports into the hid_report_callback(). */
650  SInt32 code;
651  while (!dev->shutdown_thread && !dev->disconnected)
652  {
653  code = CFRunLoopRunInMode(dev->run_loop_mode, 1000 /*sec*/, FALSE);
654  /* Return if the device has been disconnected */
655  if (code == kCFRunLoopRunFinished)
656  {
657  dev->disconnected = 1;
658  break;
659  }
660 
661  /* Break if The Run Loop returns Finished or Stopped. */
662  if (code != kCFRunLoopRunTimedOut && code != kCFRunLoopRunHandledSource)
663  {
664  /* There was some kind of error. Setting
665  shutdown seems to make sense, but
666  there may be something else more appropriate */
667  dev->shutdown_thread = 1;
668  break;
669  }
670  }
671 
672  /* Now that the read thread is stopping, Wake any threads which are
673  waiting on data (in hid_read_timeout()). Do this under a mutex to
674  make sure that a thread which is about to go to sleep waiting on
675  the condition acutally will go to sleep before the condition is
676  signaled. */
677  pthread_mutex_lock(&dev->mutex);
678  pthread_cond_broadcast(&dev->condition);
679  pthread_mutex_unlock(&dev->mutex);
680 
681  /* Wait here until hid_close() is called and makes it past
682  the call to CFRunLoopWakeUp(). This thread still needs to
683  be valid when that function is called on the other thread. */
684  pthread_barrier_wait(&dev->shutdown_barrier);
685 
686  return NULL;
687 }
688 
690 {
691  int i;
692  hid_device *dev = NULL;
693  CFIndex num_devices;
694 
695  dev = new_hid_device();
696 
697  /* Set up the HID Manager if it hasn't been done */
698  if (hid_init() < 0)
699  return NULL;
700 
701  /* give the IOHIDManager a chance to update itself */
702  process_pending_events();
703 
704  CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
705 
706  num_devices = CFSetGetCount(device_set);
707  IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
708  CFSetGetValues(device_set, (const void **)device_array);
709  for (i = 0; i < num_devices; i++)
710  {
711  char cbuf[BUF_LEN];
712  size_t len;
713  IOHIDDeviceRef os_dev = device_array[i];
714 
715  len = make_path(os_dev, cbuf, sizeof(cbuf));
716  if (!strcmp(cbuf, path))
717  {
718  // Matched Paths. Open this Device.
719  IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
720  if (ret == kIOReturnSuccess)
721  {
722  char str[32];
723 
724  free(device_array);
725  CFRetain(os_dev);
726  CFRelease(device_set);
727  dev->device_handle = os_dev;
728 
729  /* Create the buffers for receiving data */
730  dev->max_input_report_len = (CFIndex)get_max_report_length(os_dev);
731  dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));
732 
733  /* Create the Run Loop Mode for this device.
734  printing the reference seems to work. */
735  sprintf(str, "HIDAPI_%p", os_dev);
736  dev->run_loop_mode = CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
737 
738  /* Attach the device to a Run Loop */
739  IOHIDDeviceRegisterInputReportCallback(os_dev, dev->input_report_buf, dev->max_input_report_len,
740  &hid_report_callback, dev);
741  IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev);
742 
743  /* Start the read thread */
744  pthread_create(&dev->thread, NULL, read_thread, dev);
745 
746  /* Wait here for the read thread to be initialized. */
747  pthread_barrier_wait(&dev->barrier);
748 
749  return dev;
750  }
751  else
752  {
753  goto return_error;
754  }
755  }
756  }
757 
758 return_error:
759  free(device_array);
760  CFRelease(device_set);
761  free_hid_device(dev);
762  return NULL;
763 }
764 
765 static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)
766 {
767  const unsigned char *data_to_send;
768  size_t length_to_send;
769  IOReturn res;
770 
771  /* Return if the device has been disconnected. */
772  if (dev->disconnected)
773  return -1;
774 
775  if (data[0] == 0x0)
776  {
777  /* Not using numbered Reports.
778  Don't send the report number. */
779  data_to_send = data + 1;
780  length_to_send = length - 1;
781  }
782  else
783  {
784  /* Using numbered Reports.
785  Send the Report Number */
786  data_to_send = data;
787  length_to_send = length;
788  }
789 
790  if (!dev->disconnected)
791  {
792  res = IOHIDDeviceSetReport(dev->device_handle, type, data[0], /* Report ID*/
793  data_to_send, length_to_send);
794 
795  if (res == kIOReturnSuccess)
796  {
797  return length;
798  }
799  else
800  return -1;
801  }
802 
803  return -1;
804 }
805 
806 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
807 {
808  return set_report(dev, kIOHIDReportTypeOutput, data, length);
809 }
810 
811 /* Helper function, so that this isn't duplicated in hid_read(). */
812 static int return_data(hid_device *dev, unsigned char *data, size_t length)
813 {
814  /* Copy the data out of the linked list item (rpt) into the
815  return buffer (data), and delete the liked list item. */
816  struct input_report *rpt = dev->input_reports;
817  size_t len = (length < rpt->len) ? length : rpt->len;
818  memcpy(data, rpt->data, len);
819  dev->input_reports = rpt->next;
820  free(rpt->data);
821  free(rpt);
822  return len;
823 }
824 
825 static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
826 {
827  while (!dev->input_reports)
828  {
829  int res = pthread_cond_wait(cond, mutex);
830  if (res != 0)
831  return res;
832 
833  /* A res of 0 means we may have been signaled or it may
834  be a spurious wakeup. Check to see that there's acutally
835  data in the queue before returning, and if not, go back
836  to sleep. See the pthread_cond_timedwait() man page for
837  details. */
838 
839  if (dev->shutdown_thread || dev->disconnected)
840  return -1;
841  }
842 
843  return 0;
844 }
845 
846 static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex,
847  const struct timespec *abstime)
848 {
849  while (!dev->input_reports)
850  {
851  int res = pthread_cond_timedwait(cond, mutex, abstime);
852  if (res != 0)
853  return res;
854 
855  /* A res of 0 means we may have been signaled or it may
856  be a spurious wakeup. Check to see that there's acutally
857  data in the queue before returning, and if not, go back
858  to sleep. See the pthread_cond_timedwait() man page for
859  details. */
860 
861  if (dev->shutdown_thread || dev->disconnected)
862  return -1;
863  }
864 
865  return 0;
866 }
867 
868 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
869 {
870  int bytes_read = -1;
871 
872  /* Lock the access to the report list. */
873  pthread_mutex_lock(&dev->mutex);
874 
875  /* There's an input report queued up. Return it. */
876  if (dev->input_reports)
877  {
878  /* Return the first one */
879  bytes_read = return_data(dev, data, length);
880  goto ret;
881  }
882 
883  /* Return if the device has been disconnected. */
884  if (dev->disconnected)
885  {
886  bytes_read = -1;
887  goto ret;
888  }
889 
890  if (dev->shutdown_thread)
891  {
892  /* This means the device has been closed (or there
893  has been an error. An error code of -1 should
894  be returned. */
895  bytes_read = -1;
896  goto ret;
897  }
898 
899  /* There is no data. Go to sleep and wait for data. */
900 
901  if (milliseconds == -1)
902  {
903  /* Blocking */
904  int res;
905  res = cond_wait(dev, &dev->condition, &dev->mutex);
906  if (res == 0)
907  bytes_read = return_data(dev, data, length);
908  else
909  {
910  /* There was an error, or a device disconnection. */
911  bytes_read = -1;
912  }
913  }
914  else if (milliseconds > 0)
915  {
916  /* Non-blocking, but called with timeout. */
917  int res;
918  struct timespec ts;
919  struct timeval tv;
920  gettimeofday(&tv, NULL);
921  TIMEVAL_TO_TIMESPEC(&tv, &ts);
922  ts.tv_sec += milliseconds / 1000;
923  ts.tv_nsec += (milliseconds % 1000) * 1000000;
924  if (ts.tv_nsec >= 1000000000L)
925  {
926  ts.tv_sec++;
927  ts.tv_nsec -= 1000000000L;
928  }
929 
930  res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
931  if (res == 0)
932  bytes_read = return_data(dev, data, length);
933  else if (res == ETIMEDOUT)
934  bytes_read = 0;
935  else
936  bytes_read = -1;
937  }
938  else
939  {
940  /* Purely non-blocking */
941  bytes_read = 0;
942  }
943 
944 ret:
945  /* Unlock */
946  pthread_mutex_unlock(&dev->mutex);
947  return bytes_read;
948 }
949 
950 int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
951 {
952  return hid_read_timeout(dev, data, length, (dev->blocking) ? -1 : 0);
953 }
954 
956 {
957  /* All Nonblocking operation is handled by the library. */
958  dev->blocking = !nonblock;
959 
960  return 0;
961 }
962 
963 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
964 {
965  return set_report(dev, kIOHIDReportTypeFeature, data, length);
966 }
967 
968 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
969 {
970  CFIndex len = length;
971  IOReturn res;
972 
973  /* Return if the device has been unplugged. */
974  if (dev->disconnected)
975  return -1;
976 
977  res = IOHIDDeviceGetReport(dev->device_handle, kIOHIDReportTypeFeature, data[0], /* Report ID */
978  data, &len);
979  if (res == kIOReturnSuccess)
980  return len;
981  else
982  return -1;
983 }
984 
986 {
987  if (!dev)
988  return;
989 
990  /* Disconnect the report callback before close. */
991  if (!dev->disconnected)
992  {
993  IOHIDDeviceRegisterInputReportCallback(dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
994  NULL, dev);
995  IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev);
996  IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
997  IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
998  }
999 
1000  /* Cause read_thread() to stop. */
1001  dev->shutdown_thread = 1;
1002 
1003  /* Wake up the run thread's event loop so that the thread can exit. */
1004  CFRunLoopSourceSignal(dev->source);
1005  CFRunLoopWakeUp(dev->run_loop);
1006 
1007  /* Notify the read thread that it can shut down now. */
1008  pthread_barrier_wait(&dev->shutdown_barrier);
1009 
1010  /* Wait for read_thread() to end. */
1011  pthread_join(dev->thread, NULL);
1012 
1013  /* Close the OS handle to the device, but only if it's not
1014  been unplugged. If it's been unplugged, then calling
1015  IOHIDDeviceClose() will crash. */
1016  if (!dev->disconnected)
1017  {
1018  IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
1019  }
1020 
1021  /* Clear out the queue of received reports. */
1022  pthread_mutex_lock(&dev->mutex);
1023  while (dev->input_reports)
1024  {
1025  return_data(dev, NULL, 0);
1026  }
1027  pthread_mutex_unlock(&dev->mutex);
1028  CFRelease(dev->device_handle);
1029 
1030  free_hid_device(dev);
1031 }
1032 
1033 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
1034 {
1035  return get_manufacturer_string(dev->device_handle, string, maxlen);
1036 }
1037 
1038 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1039 {
1040  return get_product_string(dev->device_handle, string, maxlen);
1041 }
1042 
1043 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1044 {
1045  return get_serial_number(dev->device_handle, string, maxlen);
1046 }
1047 
1048 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1049 {
1050  // TODO:
1051  INDI_UNUSED(dev);
1052  INDI_UNUSED(string_index);
1053  INDI_UNUSED(string);
1054  INDI_UNUSED(maxlen);
1055  return 0;
1056 }
1057 
1059 {
1060  // TODO:
1061  INDI_UNUSED(dev);
1062  return NULL;
1063 }
1064 
1065 #if 0
1066 static int32_t get_location_id(IOHIDDeviceRef device)
1067 {
1068  return get_int_property(device, CFSTR(kIOHIDLocationIDKey));
1069 }
1070 
1071 static int32_t get_usage(IOHIDDeviceRef device)
1072 {
1073  int32_t res;
1074  res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
1075  if (!res)
1076  res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
1077  return res;
1078 }
1079 
1080 static int32_t get_usage_page(IOHIDDeviceRef device)
1081 {
1082  int32_t res;
1083  res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
1084  if (!res)
1085  res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
1086  return res;
1087 }
1088 
1089 static int get_transport(IOHIDDeviceRef device, wchar_t * buf, size_t len)
1090 {
1091  return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
1092 }
1093 
1094 
1095 int main(void)
1096 {
1097  IOHIDManagerRef mgr;
1098  int i;
1099 
1100  mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1101  IOHIDManagerSetDeviceMatching(mgr, NULL);
1102  IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
1103 
1104  CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
1105 
1106  CFIndex num_devices = CFSetGetCount(device_set);
1107  IOHIDDeviceRef * device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
1108  CFSetGetValues(device_set, (const void **) device_array);
1109 
1110  for (i = 0; i < num_devices; i++)
1111  {
1112  IOHIDDeviceRef dev = device_array[i];
1113  printf("Device: %p\n", dev);
1114  printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
1115 
1116  wchar_t serial[256], buf[256];
1117  char cbuf[256];
1118  get_serial_number(dev, serial, 256);
1119 
1120 
1121  printf(" Serial: %ls\n", serial);
1122  printf(" Loc: %ld\n", get_location_id(dev));
1123  get_transport(dev, buf, 256);
1124  printf(" Trans: %ls\n", buf);
1125  make_path(dev, cbuf, 256);
1126  printf(" Path: %s\n", cbuf);
1127 
1128  }
1129 
1130  return 0;
1131 }
1132 #endif
hid_read_timeout
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:868
hid_get_indexed_string
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:1048
pthread_barrierattr_t
int pthread_barrierattr_t
Definition: hid_mac.c:49
hid_device_::blocking
int blocking
Definition: hid_libusb.c:112
pthread_barrier::mutex
pthread_mutex_t mutex
Definition: hid_mac.c:52
hid_device_::run_loop_mode
CFStringRef run_loop_mode
Definition: hid_mac.c:124
hid_device_info::interface_number
int interface_number
Definition: hidapi.h:82
hid_send_feature_report
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:963
pthread_barrier::cond
pthread_cond_t cond
Definition: hid_mac.c:53
hid_exit
int HID_API_EXPORT hid_exit(void)
Finalize the HIDAPI library.
Definition: hid_mac.c:374
BUF_LEN
#define BUF_LEN
hid_device_::barrier
pthread_barrier_t barrier
Definition: hid_libusb.c:118
hidapi.h
hid_device_::disconnected
int disconnected
Definition: hid_mac.c:123
hid_set_nonblocking
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
Set the device handle to be non-blocking.
Definition: hid_mac.c:955
hid_device_::mutex
pthread_mutex_t mutex
Definition: hid_libusb.c:116
hid_read
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:950
hid_device_::shutdown_thread
int shutdown_thread
Definition: hid_libusb.c:119
HID_API_EXPORT_CALL
#define HID_API_EXPORT_CALL
Definition: hidapi.h:46
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
hid_write
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:806
input_report::next
struct input_report * next
Definition: hid_libusb.c:90
hid_device_::source
CFRunLoopSourceRef source
Definition: hid_mac.c:126
hid_device_::run_loop
CFRunLoopRef run_loop
Definition: hid_mac.c:125
hid_close
void HID_API_EXPORT hid_close(hid_device *dev)
Close a HID device.
Definition: hid_mac.c:985
hid_device_info::manufacturer_string
wchar_t * manufacturer_string
Definition: hidapi.h:69
input_report::len
size_t len
Definition: hid_libusb.c:89
hid_get_feature_report
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:968
hid_device_::max_input_report_len
CFIndex max_input_report_len
Definition: hid_mac.c:128
pthread_barrier_t
struct pthread_barrier pthread_barrier_t
hid_device_::input_report_buf
uint8_t * input_report_buf
Definition: hid_mac.c:127
hid_device_info::next
struct hid_device_info * next
Definition: hidapi.h:85
hid_device_info
Definition: hidapi.h:55
hid_device_
Definition: hid_libusb.c:93
device
hid_device * device
Definition: activefocuser_utils.cpp:92
hid_open_path
hid_device *HID_API_EXPORT hid_open_path(const char *path)
Open a HID device by its path name.
Definition: hid_mac.c:689
type
__le16 type
Definition: pwc-ioctl.h:2
hid_device_::uses_numbered_reports
int uses_numbered_reports
Definition: hid_mac.c:122
hid_device_info::product_id
unsigned short product_id
Definition: hidapi.h:62
hid_device_::input_reports
struct input_report * input_reports
Definition: hid_libusb.c:123
indidevapi.h
Interface to the reference INDI C API device implementation on the Device Driver side.
hid_device_info::serial_number
wchar_t * serial_number
Definition: hidapi.h:64
hid_device_::condition
pthread_cond_t condition
Definition: hid_libusb.c:117
hid_get_serial_number_string
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:1043
hid_device_::device_handle
libusb_device_handle * device_handle
Definition: hid_libusb.c:96
hid_device_info::release_number
unsigned short release_number
Definition: hidapi.h:67
hid_get_product_string
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:1038
hid_device_info::usage
unsigned short usage
Definition: hidapi.h:77
hid_error
const HID_API_EXPORT wchar_t *HID_API_CALL hid_error(hid_device *dev)
Get a string describing the last error which occurred.
Definition: hid_mac.c:1058
pthread_barrier::trip_count
int trip_count
Definition: hid_mac.c:55
hid_free_enumeration
void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
Free an enumeration Linked List.
Definition: hid_mac.c:491
HID_API_CALL
#define HID_API_CALL
Definition: hidapi.h:43
input_report
Definition: hid_libusb.c:86
hid_device_info::usage_page
unsigned short usage_page
Definition: hidapi.h:74
main
int main(int, char **)
Definition: tutorial_client.cpp:53
hid_get_manufacturer_string
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:1033
hid_device_::shutdown_barrier
pthread_barrier_t shutdown_barrier
Definition: hid_mac.c:135
hid_device_::device_handle
IOHIDDeviceRef device_handle
Definition: hid_mac.c:120
FALSE
#define FALSE
Definition: stvdriver.c:53
hid_open
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:507
input_report::data
uint8_t * data
Definition: hid_libusb.c:88
hid_enumerate
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
hid_device_info::path
char * path
Definition: hidapi.h:58
hid_init
int HID_API_EXPORT hid_init(void)
Initialize the HIDAPI library.
Definition: hid_mac.c:363
pthread_barrier
Definition: hid_mac.c:50
pthread_barrier::count
int count
Definition: hid_mac.c:54
errno
int errno
hid_device_info::vendor_id
unsigned short vendor_id
Definition: hidapi.h:60
hid_device_info::product_string
wchar_t * product_string
Definition: hidapi.h:71
hid_device_::thread
pthread_t thread
Definition: hid_libusb.c:115
HID_API_EXPORT
#define HID_API_EXPORT
Definition: hidapi.h:42