~mkas/mixxx/mysql

« back to all changes in this revision

Viewing changes to mixxx/lib/hidapi-0.7.0/mac/hid.c

  • Committer: MKas
  • Date: 2012-11-03 12:55:54 UTC
  • Revision ID: mkas@tux.lt-20121103125554-ez5ajqyk7bwehrp2
merge with trunk + sql fixes

Show diffs side-by-side

added added

removed removed

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