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