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