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