Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(704)

Side by Side Diff: third_party/hidapi/hidapi_linux.c

Issue 25666010: Adding third party library hidapi (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update Linux backend Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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));
86 if (dev == NULL)
87 return NULL;
88 dev->device_handle = -1;
89 dev->blocking = 1;
90 dev->uses_numbered_reports = 0;
91
92 return dev;
93 }
94
95
96 /* The caller must free the returned string with free(). */
97 static wchar_t *utf8_to_wchar_t(const char *utf8)
98 {
99 wchar_t *ret = NULL;
100
101 if (utf8) {
102 size_t wlen = mbstowcs(NULL, utf8, 0);
103 if ((size_t) -1 == wlen) {
104 return wcsdup(L"");
105 }
106 ret = calloc(wlen+1, sizeof(wchar_t));
107 if (ret == NULL)
108 return NULL;
109 mbstowcs(ret, utf8, wlen+1);
110 ret[wlen] = 0x0000;
111 }
112
113 return ret;
114 }
115
116 /* Get an attribute value from a udev_device and return it as a whar_t
117 string. The returned string must be freed with free() when done.*/
118 static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)
119 {
120 return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));
121 }
122
123 /* uses_numbered_reports() returns 1 if report_descriptor describes a device
124 which contains numbered reports. */
125 static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {
126 unsigned int i = 0;
127 int size_code;
128 int data_len, key_size;
129
130 while (i < size) {
131 __u8 key = report_descriptor[i];
132
133 /* Check for the Report ID key */
134 if (key == 0x85/*Report ID*/) {
135 /* This device has a Report ID, which means it uses
136 numbered reports. */
137 return 1;
138 }
139
140 //printf("key: %02hhx\n", key);
141
142 if ((key & 0xf0) == 0xf0) {
143 /* This is a Long Item. The next byte contains the
144 length of the data section (value) for this key.
145 See the HID specification, version 1.11, section
146 6.2.2.3, titled "Long Items." */
147 if (i+1 < size)
148 data_len = report_descriptor[i+1];
149 else
150 data_len = 0; /* malformed report */
151 key_size = 3;
152 }
153 else {
154 /* This is a Short Item. The bottom two bits of the
155 key contain the size code for the data section
156 (value) for this key. Refer to the HID
157 specification, version 1.11, section 6.2.2.2,
158 titled "Short Items." */
159 size_code = key & 0x3;
160 switch (size_code) {
161 case 0:
162 case 1:
163 case 2:
164 data_len = size_code;
165 break;
166 case 3:
167 data_len = 4;
168 break;
169 default:
170 /* Can't ever happen since size_code is & 0x3 */
171 data_len = 0;
172 break;
173 };
174 key_size = 1;
175 }
176
177 /* Skip over this key and it's associated data */
178 i += data_len + key_size;
179 }
180
181 /* Didn't find a Report ID key. Device doesn't use numbered reports. */
182 return 0;
183 }
184
185 /*
186 * The caller is responsible for free()ing the (newly-allocated) character
187 * strings pointed to by serial_number_utf8 and product_name_utf8 after use.
188 */
189 static int
190 parse_uevent_info(const char *uevent, int *bus_type,
191 unsigned short *vendor_id, unsigned short *product_id,
192 char **serial_number_utf8, char **product_name_utf8)
193 {
194 char *tmp = strdup(uevent);
195 char *saveptr = NULL;
196 char *line;
197 char *key;
198 char *value;
199
200 int found_id = 0;
201 int found_serial = 0;
202 int found_name = 0;
203
204 line = strtok_r(tmp, "\n", &saveptr);
205 while (line != NULL) {
206 /* line: "KEY=value" */
207 key = line;
208 value = strchr(line, '=');
209 if (!value) {
210 goto next_line;
211 }
212 *value = '\0';
213 value++;
214
215 if (strcmp(key, "HID_ID") == 0) {
216 /**
217 * type vendor product
218 * HID_ID=0003:000005AC:00008242
219 **/
220 int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id);
221 if (ret == 3) {
222 found_id = 1;
223 }
224 } else if (strcmp(key, "HID_NAME") == 0) {
225 /* The caller has to free the product name */
226 *product_name_utf8 = strdup(value);
227 found_name = 1;
228 } else if (strcmp(key, "HID_UNIQ") == 0) {
229 /* The caller has to free the serial number */
230 *serial_number_utf8 = strdup(value);
231 found_serial = 1;
232 }
233
234 next_line:
235 line = strtok_r(NULL, "\n", &saveptr);
236 }
237
238 free(tmp);
239 return (found_id && found_name && found_serial);
240 }
241
242
243 static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen)
244 {
245 struct udev *udev;
246 struct udev_device *udev_dev, *parent, *hid_dev;
247 struct stat s;
248 int ret = -1;
249 char *serial_number_utf8 = NULL;
250 char *product_name_utf8 = NULL;
251
252 /* Create the udev object */
253 udev = udev_new();
254 if (!udev) {
255 printf("Can't create udev\n");
256 return -1;
257 }
258
259 /* Get the dev_t (major/minor numbers) from the file handle. */
260 fstat(dev->device_handle, &s);
261 /* Open a udev device from the dev_t. 'c' means character device. */
262 udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
263 if (udev_dev) {
264 hid_dev = udev_device_get_parent_with_subsystem_devtype(
265 udev_dev,
266 "hid",
267 NULL);
268 if (hid_dev) {
269 unsigned short dev_vid;
270 unsigned short dev_pid;
271 int bus_type;
272 size_t retm;
273
274 serial_number_utf8 = NULL;
275 product_name_utf8 = NULL;
276
277 ret = parse_uevent_info(
278 udev_device_get_sysattr_value(hid_dev, "uevent"),
279 &bus_type,
280 &dev_vid,
281 &dev_pid,
282 &serial_number_utf8,
283 &product_name_utf8);
284
285 if (!ret) goto end;
286
287 if (bus_type == BUS_BLUETOOTH) {
288 switch (key) {
289 case DEVICE_STRING_MANUFACTURER:
290 wcsncpy(string, L"", maxlen);
291 ret = 0;
292 break;
293 case DEVICE_STRING_PRODUCT:
294 retm = mbstowcs(string, product_name_utf8, maxlen - 1);
295 ret = (retm == (size_t)-1)? -1: 0;
296 break;
297 case DEVICE_STRING_SERIAL:
298 retm = mbstowcs(string, serial_number_utf8, maxlen - 1);
299 ret = (retm == (size_t)-1)? -1: 0;
300 break;
301 case DEVICE_STRING_COUNT:
302 default:
303 ret = -1;
304 break;
305 }
306 }
307 else {
308 /* This is a USB device. Find its parent USB Device node. */
309 parent = udev_device_get_parent_with_subsystem_devtype(
310 udev_dev,
311 "usb",
312 "usb_device");
313 if (parent) {
314 const char *str;
315 const char *key_str = NULL;
316
317 if (key < DEVICE_STRING_COUNT) {
318 key_str = device_string_names[key];
319 } else {
320 ret = -1;
321 goto end;
322 }
323
324 str = udev_device_get_sysattr_value(parent, key_str);
325 if (str) {
326 /* Convert the string from UTF-8 to wchar_t */
327 retm = mbstowcs(string, str, maxlen);
328 ret = (retm == (size_t)-1)? -1: 0;
329 goto end;
330 }
331 }
332 }
333 }
334 }
335
336 end:
337 free(serial_number_utf8);
338 free(product_name_utf8);
339
340 udev_device_unref(udev_dev);
341 /* parent and hid_dev don't need to be (and can't be) unref'd.
342 I'm not sure why, but they'll throw double-free() errors. */
343 udev_unref(udev);
344
345 return ret;
346 }
347
348 int HID_API_EXPORT hid_init(void)
349 {
350 const char *locale;
351
352 /* Set the locale if it's not set. */
353 locale = setlocale(LC_CTYPE, NULL);
354 if (!locale)
355 setlocale(LC_CTYPE, "");
356
357 return 0;
358 }
359
360 int HID_API_EXPORT hid_exit(void)
361 {
362 /* Nothing to do for this in the Linux/hidraw implementation. */
363 return 0;
364 }
365
366
367 struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, u nsigned short product_id)
368 {
369 struct udev *udev;
370 struct udev_enumerate *enumerate;
371 struct udev_list_entry *devices, *dev_list_entry;
372
373 struct hid_device_info *root = NULL; /* return object */
374 struct hid_device_info *cur_dev = NULL;
375 struct hid_device_info *prev_dev = NULL; /* previous device */
376
377 hid_init();
378
379 /* Create the udev object */
380 udev = udev_new();
381 if (!udev) {
382 printf("Can't create udev\n");
383 return NULL;
384 }
385
386 /* Create a list of the devices in the 'hidraw' subsystem. */
387 enumerate = udev_enumerate_new(udev);
388 udev_enumerate_add_match_subsystem(enumerate, "hidraw");
389 udev_enumerate_scan_devices(enumerate);
390 devices = udev_enumerate_get_list_entry(enumerate);
391 /* For each item, see if it matches the vid/pid, and if so
392 create a udev_device record for it */
393 udev_list_entry_foreach(dev_list_entry, devices) {
394 const char *sysfs_path;
395 const char *dev_path;
396 const char *str;
397 struct udev_device *raw_dev; /* The device's hidraw udev node. */
398 struct udev_device *hid_dev; /* The device's HID udev node. */
399 struct udev_device *usb_dev; /* The device's USB udev node. */
400 struct udev_device *intf_dev; /* The device's interface (in the USB sense). */
401 unsigned short dev_vid;
402 unsigned short dev_pid;
403 char *serial_number_utf8 = NULL;
404 char *product_name_utf8 = NULL;
405 int bus_type;
406 int result;
407
408 /* Get the filename of the /sys entry for the device
409 and create a udev_device object (dev) representing it */
410 sysfs_path = udev_list_entry_get_name(dev_list_entry);
411 raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
412 dev_path = udev_device_get_devnode(raw_dev);
413
414 hid_dev = udev_device_get_parent_with_subsystem_devtype(
415 raw_dev,
416 "hid",
417 NULL);
418
419 if (!hid_dev) {
420 /* Unable to find parent hid device. */
421 goto next;
422 }
423
424 result = parse_uevent_info(
425 udev_device_get_sysattr_value(hid_dev, "uevent"),
426 &bus_type,
427 &dev_vid,
428 &dev_pid,
429 &serial_number_utf8,
430 &product_name_utf8);
431
432 if (!result) {
433 /* parse_uevent_info() failed for at least one field. */
434 goto next;
435 }
436
437 if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {
438 /* We only know how to handle USB and BT devices. */
439 goto next;
440 }
441
442 /* Check the VID/PID against the arguments */
443 if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
444 (product_id == 0x0 || product_id == dev_pid)) {
445 struct hid_device_info *tmp;
446
447 /* VID/PID match. Create the record. */
448 tmp = malloc(sizeof(struct hid_device_info));
449 if (tmp == NULL) {
450 goto next;
451 }
452
453 if (cur_dev) {
454 cur_dev->next = tmp;
455 }
456 else {
457 root = tmp;
458 }
459 prev_dev = cur_dev;
460 cur_dev = tmp;
461
462 /* Fill out the record */
463 cur_dev->next = NULL;
464 cur_dev->path = dev_path? strdup(dev_path): NULL;
465
466 /* VID/PID */
467 cur_dev->vendor_id = dev_vid;
468 cur_dev->product_id = dev_pid;
469
470 /* Serial Number */
471 cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);
472
473 /* Release Number */
474 cur_dev->release_number = 0x0;
475
476 /* Interface Number */
477 cur_dev->interface_number = -1;
478
479 switch (bus_type) {
480 case BUS_USB:
481 /* The device pointed to by raw_dev contains information about
482 the hidraw device. In order to get information about the
483 USB device, get the parent device with the
484 subsystem/devtype pair of "usb"/"usb_device". This will
485 be several levels up the tree, but the function will find
486 it. */
487 usb_dev = udev_device_get_parent_with_subsystem_devtype(
488 raw_dev,
489 "usb",
490 "usb_device");
491
492 if (!usb_dev) {
493 /* Free this device */
494 free(cur_dev->serial_number);
495 free(cur_dev->path);
496 free(cur_dev);
497
498 /* Take it off the device list. */
499 if (prev_dev) {
500 prev_dev->next = NULL;
501 cur_dev = prev_dev;
502 }
503 else {
504 cur_dev = root = NULL;
505 }
506
507 goto next;
508 }
509
510 /* Manufacturer and Product strings */
511 cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string _names[DEVICE_STRING_MANUFACTURER]);
512 cur_dev->product_string = copy_udev_string(usb_dev, device_string_name s[DEVICE_STRING_PRODUCT]);
513
514 /* Release Number */
515 str = udev_device_get_sysattr_value(usb_dev, "bcdDevice");
516 cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;
517
518 /* Get a handle to the interface's udev node. */
519 intf_dev = udev_device_get_parent_with_subsystem_devtype(
520 raw_dev,
521 "usb",
522 "usb_interface");
523 if (intf_dev) {
524 str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");
525 cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;
526 }
527
528 break;
529
530 case BUS_BLUETOOTH:
531 /* Manufacturer and Product strings */
532 cur_dev->manufacturer_string = wcsdup(L"");
533 cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
534
535 break;
536
537 default:
538 /* Unknown device type - this should never happen, as we
539 * check for USB and Bluetooth devices above */
540 break;
541 }
542 }
543
544 next:
545 free(serial_number_utf8);
546 free(product_name_utf8);
547 udev_device_unref(raw_dev);
548 /* hid_dev, usb_dev and intf_dev don't need to be (and can't be)
549 unref()d. It will cause a double-free() error. I'm not
550 sure why. */
551 }
552 /* Free the enumerator and udev objects. */
553 udev_enumerate_unref(enumerate);
554 udev_unref(udev);
555
556 return root;
557 }
558
559 void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
560 {
561 struct hid_device_info *d = devs;
562 while (d) {
563 struct hid_device_info *next = d->next;
564 free(d->path);
565 free(d->serial_number);
566 free(d->manufacturer_string);
567 free(d->product_string);
568 free(d);
569 d = next;
570 }
571 }
572
573 hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
574 {
575 struct hid_device_info *devs, *cur_dev;
576 const char *path_to_open = NULL;
577 hid_device *handle = NULL;
578
579 devs = hid_enumerate(vendor_id, product_id);
580 cur_dev = devs;
581 while (cur_dev) {
582 if (cur_dev->vendor_id == vendor_id &&
583 cur_dev->product_id == product_id) {
584 if (serial_number) {
585 if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
586 path_to_open = cur_dev->path;
587 break;
588 }
589 }
590 else {
591 path_to_open = cur_dev->path;
592 break;
593 }
594 }
595 cur_dev = cur_dev->next;
596 }
597
598 if (path_to_open) {
599 /* Open the device */
600 handle = hid_open_path(path_to_open);
601 }
602
603 hid_free_enumeration(devs);
604
605 return handle;
606 }
607
608 hid_device * HID_API_EXPORT hid_open_path(const char *path)
609 {
610 hid_device *dev = NULL;
611
612 hid_init();
613
614 dev = new_hid_device();
615
616 if (kernel_version == 0) {
617 struct utsname name;
618 int major, minor, release;
619 int ret;
620 uname(&name);
621 ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release);
622 if (ret == 3) {
623 kernel_version = major << 16 | minor << 8 | release;
624 //printf("Kernel Version: %d\n", kernel_version);
625 }
626 else {
627 printf("Couldn't sscanf() version string %s\n", name.release);
628 }
629 }
630
631 /* OPEN HERE */
632 dev->device_handle = open(path, O_RDWR);
633
634 /* If we have a good handle, return it. */
635 if (dev->device_handle > 0) {
636
637 /* Get the report descriptor */
638 int res, desc_size = 0;
639 struct hidraw_report_descriptor rpt_desc;
640
641 memset(&rpt_desc, 0x0, sizeof(rpt_desc));
642
643 /* Get Report Descriptor Size */
644 res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
645 if (res < 0) {
646 perror("HIDIOCGRDESCSIZE");
647 } else {
648 /* Get Report Descriptor */
649 rpt_desc.size = desc_size;
650 res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);
651
652 if (res < 0) {
653 perror("HIDIOCGRDESC");
654 } else {
655 /* Determine if this device uses numbered reports. */
656 dev->uses_numbered_reports =
657 uses_numbered_reports(rpt_desc.value,
658 rpt_desc.size);
659 }
660 }
661
662 return dev;
663 }
664 else {
665 /* Unable to open any devices. */
666 free(dev);
667 return NULL;
668 }
669 }
670
671
672 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
673 {
674 int bytes_written;
675
676 bytes_written = write(dev->device_handle, data, length);
677
678 return bytes_written;
679 }
680
681
682 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
683 {
684 int bytes_read;
685
686 if (milliseconds >= 0) {
687 /* Milliseconds is either 0 (non-blocking) or > 0 (contains
688 a valid timeout). In both cases we want to call poll()
689 and wait for data to arrive. Don't rely on non-blocking
690 operation (O_NONBLOCK) since some kernels don't seem to
691 properly report device disconnection through read() when
692 in non-blocking mode. */
693 int ret;
694 struct pollfd fds;
695
696 fds.fd = dev->device_handle;
697 fds.events = POLLIN;
698 fds.revents = 0;
699 ret = poll(&fds, 1, milliseconds);
700 if (ret == -1 || ret == 0) {
701 /* Error or timeout */
702 return ret;
703 }
704 else {
705 /* Check for errors on the file descriptor. This will
706 indicate a device disconnection. */
707 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
708 return -1;
709 }
710 }
711
712 bytes_read = read(dev->device_handle, data, length);
713 if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS))
714 bytes_read = 0;
715
716 if (bytes_read > 0 &&
717 kernel_version < KERNEL_VERSION(2,6,34) &&
718 dev->uses_numbered_reports) {
719 /* Work around a kernel bug. Chop off the first byte. */
720 memmove(data, data+1, bytes_read);
721 bytes_read--;
722 }
723
724 return bytes_read;
725 }
726
727 int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
728 {
729 return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
730 }
731
732 int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
733 {
734 /* Do all non-blocking in userspace using poll(), since it looks
735 like there's a bug in the kernel in some versions where
736 read() will not return -1 on disconnection of the USB device */
737
738 dev->blocking = !nonblock;
739 return 0; /* Success */
740 }
741
742
743 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
744 {
745 int res;
746
747 res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
748 if (res < 0)
749 perror("ioctl (SFEATURE)");
750
751 return res;
752 }
753
754 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
755 {
756 int res;
757
758 res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
759 if (res < 0)
760 perror("ioctl (GFEATURE)");
761
762
763 return res;
764 }
765
766
767 void HID_API_EXPORT hid_close(hid_device *dev)
768 {
769 if (!dev)
770 return;
771 close(dev->device_handle);
772 free(dev);
773 }
774
775
776 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *st ring, size_t maxlen)
777 {
778 return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen);
779 }
780
781 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
782 {
783 return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen);
784 }
785
786 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s tring, size_t maxlen)
787 {
788 return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen);
789 }
790
791 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index , wchar_t *string, size_t maxlen)
792 {
793 return -1;
794 }
795
796
797 HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
798 {
799 return NULL;
800 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698