Subversion Repositories seema-scanner

Rev

Details | Last modification | View Log | RSS feed

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