OLD | NEW |
---|---|
(Empty) | |
1 /******************************************************* | |
2 HIDAPI - Multi-Platform library for | |
3 communication with HID devices. | |
4 | |
5 Alan Ott | |
6 Signal 11 Software | |
7 | |
8 8/22/2009 | |
9 Linux Version - 6/2/2009 | |
10 | |
11 Copyright 2009, All Rights Reserved. | |
12 | |
13 At the discretion of the user of this library, | |
14 this software may be licensed under the terms of the | |
15 GNU General Public License v3, a BSD-Style license, or the | |
16 original HIDAPI license as outlined in the LICENSE.txt, | |
17 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt | |
18 files located at the root of the source distribution. | |
19 These files may also be found in the public source | |
20 code repository located at: | |
21 http://github.com/signal11/hidapi . | |
22 ********************************************************/ | |
23 | |
24 /* C */ | |
25 #include <stdio.h> | |
26 #include <string.h> | |
27 #include <stdlib.h> | |
28 #include <locale.h> | |
29 #include <errno.h> | |
30 | |
31 /* Unix */ | |
32 #include <unistd.h> | |
33 #include <sys/types.h> | |
34 #include <sys/stat.h> | |
35 #include <sys/ioctl.h> | |
36 #include <sys/utsname.h> | |
37 #include <fcntl.h> | |
38 #include <poll.h> | |
39 | |
40 /* Linux */ | |
41 #include <linux/hidraw.h> | |
42 #include <linux/version.h> | |
43 #include <linux/input.h> | |
44 #include <libudev.h> | |
45 | |
46 #include "hidapi.h" | |
47 | |
48 /* Definitions from linux/hidraw.h. Since these are new, some distros | |
49 may not have header files which contain them. */ | |
50 #ifndef HIDIOCSFEATURE | |
51 #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) | |
52 #endif | |
53 #ifndef HIDIOCGFEATURE | |
54 #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) | |
55 #endif | |
56 | |
57 | |
58 /* USB HID device property names */ | |
59 const char *device_string_names[] = { | |
60 "manufacturer", | |
61 "product", | |
62 "serial", | |
63 }; | |
64 | |
65 /* Symbolic names for the properties above */ | |
66 enum device_string_id { | |
67 DEVICE_STRING_MANUFACTURER, | |
68 DEVICE_STRING_PRODUCT, | |
69 DEVICE_STRING_SERIAL, | |
70 | |
71 DEVICE_STRING_COUNT, | |
72 }; | |
73 | |
74 struct hid_device_ { | |
75 int device_handle; | |
76 int blocking; | |
77 int uses_numbered_reports; | |
78 }; | |
79 | |
80 | |
81 static __u32 kernel_version = 0; | |
82 | |
83 static hid_device *new_hid_device(void) | |
84 { | |
85 hid_device *dev = calloc(1, sizeof(hid_device)); | |
Kees Cook
2013/12/04 20:49:36
Need to check for NULL return here to avoid crashi
Bei Zhang
2013/12/10 22:24:11
Done.
| |
86 dev->device_handle = -1; | |
87 dev->blocking = 1; | |
88 dev->uses_numbered_reports = 0; | |
89 | |
90 return dev; | |
91 } | |
92 | |
93 | |
94 /* The caller must free the returned string with free(). */ | |
95 static wchar_t *utf8_to_wchar_t(const char *utf8) | |
96 { | |
97 wchar_t *ret = NULL; | |
98 | |
99 if (utf8) { | |
100 size_t wlen = mbstowcs(NULL, utf8, 0); | |
101 if ((size_t) -1 == wlen) { | |
102 return wcsdup(L""); | |
103 } | |
104 ret = calloc(wlen+1, sizeof(wchar_t)); | |
Kees Cook
2013/12/04 20:49:36
NULL check needed.
Bei Zhang
2013/12/10 22:24:11
Done.
| |
105 mbstowcs(ret, utf8, wlen+1); | |
106 ret[wlen] = 0x0000; | |
107 } | |
108 | |
109 return ret; | |
110 } | |
111 | |
112 /* Get an attribute value from a udev_device and return it as a whar_t | |
113 string. The returned string must be freed with free() when done.*/ | |
114 static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name) | |
115 { | |
116 return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name)); | |
117 } | |
118 | |
119 /* uses_numbered_reports() returns 1 if report_descriptor describes a device | |
120 which contains numbered reports. */ | |
121 static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) { | |
122 unsigned int i = 0; | |
123 int size_code; | |
124 int data_len, key_size; | |
125 | |
126 while (i < size) { | |
127 int key = report_descriptor[i]; | |
Kees Cook
2013/12/04 20:49:36
Why is "key" an int here? Would make more sense to
Bei Zhang
2013/12/10 22:24:11
Done.
| |
128 | |
129 /* Check for the Report ID key */ | |
130 if (key == 0x85/*Report ID*/) { | |
131 /* This device has a Report ID, which means it uses | |
132 numbered reports. */ | |
133 return 1; | |
134 } | |
135 | |
136 //printf("key: %02hhx\n", key); | |
137 | |
138 if ((key & 0xf0) == 0xf0) { | |
139 /* This is a Long Item. The next byte contains the | |
140 length of the data section (value) for this key. | |
141 See the HID specification, version 1.11, section | |
142 6.2.2.3, titled "Long Items." */ | |
143 if (i+1 < size) | |
144 data_len = report_descriptor[i+1]; | |
145 else | |
146 data_len = 0; /* malformed report */ | |
147 key_size = 3; | |
148 } | |
149 else { | |
150 /* This is a Short Item. The bottom two bits of the | |
151 key contain the size code for the data section | |
152 (value) for this key. Refer to the HID | |
153 specification, version 1.11, section 6.2.2.2, | |
154 titled "Short Items." */ | |
155 size_code = key & 0x3; | |
156 switch (size_code) { | |
157 case 0: | |
158 case 1: | |
159 case 2: | |
160 data_len = size_code; | |
161 break; | |
162 case 3: | |
163 data_len = 4; | |
164 break; | |
165 default: | |
166 /* Can't ever happen since size_code is & 0x3 */ | |
167 data_len = 0; | |
168 break; | |
169 }; | |
170 key_size = 1; | |
171 } | |
172 | |
173 /* Skip over this key and it's associated data */ | |
174 i += data_len + key_size; | |
175 } | |
176 | |
177 /* Didn't find a Report ID key. Device doesn't use numbered reports. */ | |
178 return 0; | |
179 } | |
180 | |
181 /* | |
182 * The caller is responsible for free()ing the (newly-allocated) character | |
183 * strings pointed to by serial_number_utf8 and product_name_utf8 after use. | |
184 */ | |
185 static int | |
186 parse_uevent_info(const char *uevent, int *bus_type, | |
187 unsigned short *vendor_id, unsigned short *product_id, | |
188 char **serial_number_utf8, char **product_name_utf8) | |
189 { | |
190 char *tmp = strdup(uevent); | |
191 char *saveptr = NULL; | |
192 char *line; | |
193 char *key; | |
194 char *value; | |
195 | |
196 int found_id = 0; | |
197 int found_serial = 0; | |
198 int found_name = 0; | |
199 | |
200 line = strtok_r(tmp, "\n", &saveptr); | |
201 while (line != NULL) { | |
202 /* line: "KEY=value" */ | |
203 key = line; | |
204 value = strchr(line, '='); | |
205 if (!value) { | |
206 goto next_line; | |
207 } | |
208 *value = '\0'; | |
209 value++; | |
Kees Cook
2013/12/04 20:49:36
Is a zero-length string in "value" considered vali
Bei Zhang
2013/12/10 22:24:11
I don't think it will cause any problem here.
On
| |
210 | |
211 if (strcmp(key, "HID_ID") == 0) { | |
212 /** | |
213 * type vendor product | |
214 * HID_ID=0003:000005AC:00008242 | |
215 **/ | |
216 int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_i d, product_id); | |
217 if (ret == 3) { | |
218 found_id = 1; | |
219 } | |
220 } else if (strcmp(key, "HID_NAME") == 0) { | |
221 /* The caller has to free the product name */ | |
222 *product_name_utf8 = strdup(value); | |
223 found_name = 1; | |
224 } else if (strcmp(key, "HID_UNIQ") == 0) { | |
225 /* The caller has to free the serial number */ | |
226 *serial_number_utf8 = strdup(value); | |
227 found_serial = 1; | |
228 } | |
229 | |
230 next_line: | |
231 line = strtok_r(NULL, "\n", &saveptr); | |
232 } | |
233 | |
234 free(tmp); | |
235 return (found_id && found_name && found_serial); | |
236 } | |
237 | |
238 | |
239 static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen) | |
240 { | |
241 struct udev *udev; | |
242 struct udev_device *udev_dev, *parent, *hid_dev; | |
243 struct stat s; | |
244 int ret = -1; | |
245 char *serial_number_utf8 = NULL; | |
246 char *product_name_utf8 = NULL; | |
Kees Cook
2013/12/04 20:49:36
space vs tab indenting?
Bei Zhang
2013/12/10 22:24:11
Done. Converted all tabs to spaces.
| |
247 | |
248 /* Create the udev object */ | |
249 udev = udev_new(); | |
250 if (!udev) { | |
251 printf("Can't create udev\n"); | |
252 return -1; | |
253 } | |
254 | |
255 /* Get the dev_t (major/minor numbers) from the file handle. */ | |
256 fstat(dev->device_handle, &s); | |
257 /* Open a udev device from the dev_t. 'c' means character device. */ | |
258 udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev); | |
259 if (udev_dev) { | |
260 hid_dev = udev_device_get_parent_with_subsystem_devtype( | |
261 udev_dev, | |
262 "hid", | |
263 NULL); | |
264 if (hid_dev) { | |
265 unsigned short dev_vid; | |
266 unsigned short dev_pid; | |
267 int bus_type; | |
268 size_t retm; | |
269 | |
270 ret = parse_uevent_info( | |
271 udev_device_get_sysattr_value(hid_dev, "ueven t"), | |
272 &bus_type, | |
273 &dev_vid, | |
274 &dev_pid, | |
275 &serial_number_utf8, | |
276 &product_name_utf8); | |
Kees Cook
2013/12/04 20:49:36
"ret" is unchecked, yet things like product_name_u
Bei Zhang
2013/12/10 22:24:11
Done.
| |
277 | |
278 if (bus_type == BUS_BLUETOOTH) { | |
279 switch (key) { | |
280 case DEVICE_STRING_MANUFACTURER: | |
281 wcsncpy(string, L"", maxlen); | |
282 ret = 0; | |
283 break; | |
284 case DEVICE_STRING_PRODUCT: | |
285 retm = mbstowcs(string, product_ name_utf8, maxlen); | |
Kees Cook
2013/12/04 20:49:36
If retm == maxlen, this string will not be NULL te
Bei Zhang
2013/12/10 22:24:11
Done.
| |
286 ret = (retm == (size_t)-1)? -1: 0; | |
287 break; | |
288 case DEVICE_STRING_SERIAL: | |
289 retm = mbstowcs(string, serial_n umber_utf8, maxlen); | |
290 ret = (retm == (size_t)-1)? -1: 0; | |
291 break; | |
292 case DEVICE_STRING_COUNT: | |
293 default: | |
294 ret = -1; | |
295 break; | |
296 } | |
297 } | |
298 else { | |
299 /* This is a USB device. Find its parent USB Dev ice node. */ | |
300 parent = udev_device_get_parent_with_subsystem_d evtype( | |
301 udev_dev, | |
302 "usb", | |
303 "usb_device"); | |
304 if (parent) { | |
305 const char *str; | |
306 const char *key_str = NULL; | |
307 | |
308 if (key < DEVICE_STRING_COUNT) { | |
309 key_str = device_string_names[ke y]; | |
310 } else { | |
311 ret = -1; | |
312 goto end; | |
313 } | |
314 | |
315 str = udev_device_get_sysattr_value(pare nt, key_str); | |
316 if (str) { | |
317 /* Convert the string from UTF-8 to wchar_t */ | |
318 retm = mbstowcs(string, str, max len); | |
319 ret = (retm == (size_t)-1)? -1: 0; | |
320 goto end; | |
321 } | |
322 } | |
323 } | |
324 } | |
325 } | |
326 | |
327 end: | |
328 free(serial_number_utf8); | |
329 free(product_name_utf8); | |
Kees Cook
2013/12/04 20:49:36
space vs tab indenting.
Bei Zhang
2013/12/10 22:24:11
Ditto.
On 2013/12/04 20:49:36, Kees Cook wrote:
| |
330 | |
331 udev_device_unref(udev_dev); | |
332 /* parent and hid_dev don't need to be (and can't be) unref'd. | |
333 I'm not sure why, but they'll throw double-free() errors. */ | |
334 udev_unref(udev); | |
335 | |
336 return ret; | |
337 } | |
338 | |
339 int HID_API_EXPORT hid_init(void) | |
340 { | |
341 const char *locale; | |
342 | |
343 /* Set the locale if it's not set. */ | |
344 locale = setlocale(LC_CTYPE, NULL); | |
345 if (!locale) | |
346 setlocale(LC_CTYPE, ""); | |
347 | |
348 return 0; | |
349 } | |
350 | |
351 int HID_API_EXPORT hid_exit(void) | |
352 { | |
353 /* Nothing to do for this in the Linux/hidraw implementation. */ | |
354 return 0; | |
355 } | |
356 | |
357 | |
358 struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) | |
359 { | |
360 struct udev *udev; | |
361 struct udev_enumerate *enumerate; | |
362 struct udev_list_entry *devices, *dev_list_entry; | |
363 | |
364 struct hid_device_info *root = NULL; /* return object */ | |
365 struct hid_device_info *cur_dev = NULL; | |
366 struct hid_device_info *prev_dev = NULL; /* previous device */ | |
367 | |
368 hid_init(); | |
369 | |
370 /* Create the udev object */ | |
371 udev = udev_new(); | |
372 if (!udev) { | |
373 printf("Can't create udev\n"); | |
374 return NULL; | |
375 } | |
376 | |
377 /* Create a list of the devices in the 'hidraw' subsystem. */ | |
378 enumerate = udev_enumerate_new(udev); | |
379 udev_enumerate_add_match_subsystem(enumerate, "hidraw"); | |
380 udev_enumerate_scan_devices(enumerate); | |
381 devices = udev_enumerate_get_list_entry(enumerate); | |
382 /* For each item, see if it matches the vid/pid, and if so | |
383 create a udev_device record for it */ | |
384 udev_list_entry_foreach(dev_list_entry, devices) { | |
385 const char *sysfs_path; | |
386 const char *dev_path; | |
387 const char *str; | |
388 struct udev_device *raw_dev; /* The device's hidraw udev node. * / | |
389 struct udev_device *hid_dev; /* The device's HID udev node. */ | |
390 struct udev_device *usb_dev; /* The device's USB udev node. */ | |
391 struct udev_device *intf_dev; /* The device's interface (in the USB sense). */ | |
392 unsigned short dev_vid; | |
393 unsigned short dev_pid; | |
394 char *serial_number_utf8 = NULL; | |
395 char *product_name_utf8 = NULL; | |
396 int bus_type; | |
397 int result; | |
398 | |
399 /* Get the filename of the /sys entry for the device | |
400 and create a udev_device object (dev) representing it */ | |
401 sysfs_path = udev_list_entry_get_name(dev_list_entry); | |
402 raw_dev = udev_device_new_from_syspath(udev, sysfs_path); | |
403 dev_path = udev_device_get_devnode(raw_dev); | |
404 | |
405 hid_dev = udev_device_get_parent_with_subsystem_devtype( | |
406 raw_dev, | |
407 "hid", | |
408 NULL); | |
409 | |
410 if (!hid_dev) { | |
411 /* Unable to find parent hid device. */ | |
412 goto next; | |
413 } | |
414 | |
415 result = parse_uevent_info( | |
416 udev_device_get_sysattr_value(hid_dev, "uevent"), | |
417 &bus_type, | |
418 &dev_vid, | |
419 &dev_pid, | |
420 &serial_number_utf8, | |
421 &product_name_utf8); | |
422 | |
423 if (!result) { | |
424 /* parse_uevent_info() failed for at least one field. */ | |
425 goto next; | |
426 } | |
427 | |
428 if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) { | |
429 /* We only know how to handle USB and BT devices. */ | |
430 goto next; | |
431 } | |
432 | |
433 /* Check the VID/PID against the arguments */ | |
434 if ((vendor_id == 0x0 || vendor_id == dev_vid) && | |
435 (product_id == 0x0 || product_id == dev_pid)) { | |
436 struct hid_device_info *tmp; | |
437 | |
438 /* VID/PID match. Create the record. */ | |
439 tmp = malloc(sizeof(struct hid_device_info)); | |
Kees Cook
2013/12/04 20:49:36
Check for NULL return.
Bei Zhang
2013/12/10 22:24:11
Done.
| |
440 if (cur_dev) { | |
441 cur_dev->next = tmp; | |
442 } | |
443 else { | |
444 root = tmp; | |
445 } | |
446 prev_dev = cur_dev; | |
447 cur_dev = tmp; | |
448 | |
449 /* Fill out the record */ | |
450 cur_dev->next = NULL; | |
451 cur_dev->path = dev_path? strdup(dev_path): NULL; | |
452 | |
453 /* VID/PID */ | |
454 cur_dev->vendor_id = dev_vid; | |
455 cur_dev->product_id = dev_pid; | |
456 | |
457 /* Serial Number */ | |
458 cur_dev->serial_number = utf8_to_wchar_t(serial_number_u tf8); | |
459 | |
460 /* Release Number */ | |
461 cur_dev->release_number = 0x0; | |
462 | |
463 /* Interface Number */ | |
464 cur_dev->interface_number = -1; | |
465 | |
466 switch (bus_type) { | |
467 case BUS_USB: | |
468 /* The device pointed to by raw_dev cont ains information about | |
469 the hidraw device. In order to get in formation about the | |
470 USB device, get the parent device wit h the | |
471 subsystem/devtype pair of "usb"/"usb_ device". This will | |
472 be several levels up the tree, but th e function will find | |
473 it. */ | |
474 usb_dev = udev_device_get_parent_with_su bsystem_devtype( | |
475 raw_dev, | |
476 "usb", | |
477 "usb_device"); | |
478 | |
479 if (!usb_dev) { | |
480 /* Free this device */ | |
481 free(cur_dev->serial_number); | |
482 free(cur_dev->path); | |
483 free(cur_dev); | |
484 | |
485 /* Take it off the device list. */ | |
486 if (prev_dev) { | |
487 prev_dev->next = NULL; | |
488 cur_dev = prev_dev; | |
489 } | |
490 else { | |
491 cur_dev = root = NULL; | |
492 } | |
493 | |
494 goto next; | |
495 } | |
496 | |
497 /* Manufacturer and Product strings */ | |
498 cur_dev->manufacturer_string = copy_udev _string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]); | |
499 cur_dev->product_string = copy_udev_stri ng(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]); | |
500 | |
501 /* Release Number */ | |
502 str = udev_device_get_sysattr_value(usb_ dev, "bcdDevice"); | |
503 cur_dev->release_number = (str)? strtol( str, NULL, 16): 0x0; | |
504 | |
505 /* Get a handle to the interface's udev node. */ | |
506 intf_dev = udev_device_get_parent_with_s ubsystem_devtype( | |
507 raw_dev, | |
508 "usb", | |
509 "usb_interface"); | |
510 if (intf_dev) { | |
511 str = udev_device_get_sysattr_va lue(intf_dev, "bInterfaceNumber"); | |
512 cur_dev->interface_number = (str )? strtol(str, NULL, 16): -1; | |
513 } | |
514 | |
515 break; | |
516 | |
517 case BUS_BLUETOOTH: | |
518 /* Manufacturer and Product strings */ | |
519 cur_dev->manufacturer_string = wcsdup(L" "); | |
520 cur_dev->product_string = utf8_to_wchar_ t(product_name_utf8); | |
521 | |
522 break; | |
523 | |
524 default: | |
525 /* Unknown device type - this should nev er happen, as we | |
526 * check for USB and Bluetooth devices a bove */ | |
527 break; | |
528 } | |
529 } | |
530 | |
531 next: | |
532 free(serial_number_utf8); | |
533 free(product_name_utf8); | |
534 udev_device_unref(raw_dev); | |
535 /* hid_dev, usb_dev and intf_dev don't need to be (and can't be) | |
536 unref()d. It will cause a double-free() error. I'm not | |
537 sure why. */ | |
538 } | |
539 /* Free the enumerator and udev objects. */ | |
540 udev_enumerate_unref(enumerate); | |
541 udev_unref(udev); | |
542 | |
543 return root; | |
544 } | |
545 | |
546 void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) | |
547 { | |
548 struct hid_device_info *d = devs; | |
549 while (d) { | |
550 struct hid_device_info *next = d->next; | |
551 free(d->path); | |
552 free(d->serial_number); | |
553 free(d->manufacturer_string); | |
554 free(d->product_string); | |
555 free(d); | |
556 d = next; | |
557 } | |
558 } | |
559 | |
560 hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) | |
561 { | |
562 struct hid_device_info *devs, *cur_dev; | |
563 const char *path_to_open = NULL; | |
564 hid_device *handle = NULL; | |
565 | |
566 devs = hid_enumerate(vendor_id, product_id); | |
567 cur_dev = devs; | |
568 while (cur_dev) { | |
569 if (cur_dev->vendor_id == vendor_id && | |
570 cur_dev->product_id == product_id) { | |
571 if (serial_number) { | |
572 if (wcscmp(serial_number, cur_dev->serial_number ) == 0) { | |
573 path_to_open = cur_dev->path; | |
574 break; | |
575 } | |
576 } | |
577 else { | |
578 path_to_open = cur_dev->path; | |
579 break; | |
580 } | |
581 } | |
582 cur_dev = cur_dev->next; | |
583 } | |
584 | |
585 if (path_to_open) { | |
586 /* Open the device */ | |
587 handle = hid_open_path(path_to_open); | |
588 } | |
589 | |
590 hid_free_enumeration(devs); | |
591 | |
592 return handle; | |
593 } | |
594 | |
595 hid_device * HID_API_EXPORT hid_open_path(const char *path) | |
596 { | |
597 hid_device *dev = NULL; | |
598 | |
599 hid_init(); | |
600 | |
601 dev = new_hid_device(); | |
602 | |
603 if (kernel_version == 0) { | |
604 struct utsname name; | |
605 int major, minor, release; | |
606 int ret; | |
607 uname(&name); | |
608 ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release) ; | |
609 if (ret == 3) { | |
610 kernel_version = major << 16 | minor << 8 | release; | |
611 //printf("Kernel Version: %d\n", kernel_version); | |
612 } | |
613 else { | |
614 printf("Couldn't sscanf() version string %s\n", name.rel ease); | |
615 } | |
616 } | |
617 | |
618 /* OPEN HERE */ | |
619 dev->device_handle = open(path, O_RDWR); | |
620 | |
621 /* If we have a good handle, return it. */ | |
622 if (dev->device_handle > 0) { | |
623 | |
624 /* Get the report descriptor */ | |
625 int res, desc_size = 0; | |
626 struct hidraw_report_descriptor rpt_desc; | |
627 | |
628 memset(&rpt_desc, 0x0, sizeof(rpt_desc)); | |
629 | |
630 /* Get Report Descriptor Size */ | |
631 res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size); | |
632 if (res < 0) | |
633 perror("HIDIOCGRDESCSIZE"); | |
Kees Cook
2013/12/04 20:49:36
Reports failure but continues execution? desc_size
Bei Zhang
2013/12/10 22:24:11
Done. Hidapi supports devices that does not contai
| |
634 | |
635 | |
636 /* Get Report Descriptor */ | |
637 rpt_desc.size = desc_size; | |
638 res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc); | |
639 if (res < 0) { | |
640 perror("HIDIOCGRDESC"); | |
641 } else { | |
642 /* Determine if this device uses numbered reports. */ | |
643 dev->uses_numbered_reports = | |
644 uses_numbered_reports(rpt_desc.value, | |
645 rpt_desc.size); | |
646 } | |
647 | |
648 return dev; | |
649 } | |
650 else { | |
651 /* Unable to open any devices. */ | |
652 free(dev); | |
653 return NULL; | |
654 } | |
655 } | |
656 | |
657 | |
658 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) | |
659 { | |
660 int bytes_written; | |
661 | |
662 bytes_written = write(dev->device_handle, data, length); | |
663 | |
664 return bytes_written; | |
665 } | |
666 | |
667 | |
668 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) | |
669 { | |
670 int bytes_read; | |
671 | |
672 if (milliseconds >= 0) { | |
673 /* Milliseconds is either 0 (non-blocking) or > 0 (contains | |
674 a valid timeout). In both cases we want to call poll() | |
675 and wait for data to arrive. Don't rely on non-blocking | |
676 operation (O_NONBLOCK) since some kernels don't seem to | |
677 properly report device disconnection through read() when | |
678 in non-blocking mode. */ | |
679 int ret; | |
680 struct pollfd fds; | |
681 | |
682 fds.fd = dev->device_handle; | |
683 fds.events = POLLIN; | |
684 fds.revents = 0; | |
685 ret = poll(&fds, 1, milliseconds); | |
686 if (ret == -1 || ret == 0) { | |
687 /* Error or timeout */ | |
688 return ret; | |
689 } | |
690 else { | |
691 /* Check for errors on the file descriptor. This will | |
692 indicate a device disconnection. */ | |
693 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) | |
694 return -1; | |
695 } | |
696 } | |
697 | |
698 bytes_read = read(dev->device_handle, data, length); | |
699 if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS)) | |
700 bytes_read = 0; | |
701 | |
702 if (bytes_read >= 0 && | |
Kees Cook
2013/12/04 20:49:36
This needs to be > 0, otherwise bytes_read-- will
Bei Zhang
2013/12/10 22:24:11
Done.
| |
703 kernel_version < KERNEL_VERSION(2,6,34) && | |
704 dev->uses_numbered_reports) { | |
705 /* Work around a kernel bug. Chop off the first byte. */ | |
706 memmove(data, data+1, bytes_read); | |
707 bytes_read--; | |
708 } | |
709 | |
710 return bytes_read; | |
711 } | |
712 | |
713 int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) | |
714 { | |
715 return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); | |
716 } | |
717 | |
718 int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) | |
719 { | |
720 /* Do all non-blocking in userspace using poll(), since it looks | |
721 like there's a bug in the kernel in some versions where | |
722 read() will not return -1 on disconnection of the USB device */ | |
723 | |
724 dev->blocking = !nonblock; | |
725 return 0; /* Success */ | |
726 } | |
727 | |
728 | |
729 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) | |
730 { | |
731 int res; | |
732 | |
733 res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data); | |
734 if (res < 0) | |
735 perror("ioctl (SFEATURE)"); | |
736 | |
737 return res; | |
738 } | |
739 | |
740 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) | |
741 { | |
742 int res; | |
743 | |
744 res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data); | |
745 if (res < 0) | |
746 perror("ioctl (GFEATURE)"); | |
747 | |
748 | |
749 return res; | |
750 } | |
751 | |
752 | |
753 void HID_API_EXPORT hid_close(hid_device *dev) | |
754 { | |
755 if (!dev) | |
756 return; | |
757 close(dev->device_handle); | |
758 free(dev); | |
759 } | |
760 | |
761 | |
762 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *st ring, size_t maxlen) | |
763 { | |
764 return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen ); | |
765 } | |
766 | |
767 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) | |
768 { | |
769 return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen); | |
770 } | |
771 | |
772 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s tring, size_t maxlen) | |
773 { | |
774 return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen); | |
775 } | |
776 | |
777 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index , wchar_t *string, size_t maxlen) | |
778 { | |
779 return -1; | |
780 } | |
781 | |
782 | |
783 HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) | |
784 { | |
785 return NULL; | |
786 } | |
OLD | NEW |