@@ -151,6 +151,8 @@ struct hid_device_ {
151
151
/* The interface number of the HID */
152
152
int interface ;
153
153
154
+ uint16_t report_descriptor_size ;
155
+
154
156
/* Endpoint information */
155
157
int input_endpoint ;
156
158
int output_endpoint ;
@@ -565,13 +567,18 @@ int HID_API_EXPORT hid_exit(void)
565
567
/**
566
568
* Requires an opened device with *claimed interface*.
567
569
*/
568
- static void fill_device_info_usage (struct hid_device_info * cur_dev , libusb_device_handle * handle , int interface_num )
570
+ static void fill_device_info_usage (struct hid_device_info * cur_dev , libusb_device_handle * handle , int interface_num , uint16_t report_descriptor_size )
569
571
{
570
572
unsigned char data [4096 ];
571
573
unsigned short page = 0 , usage = 0 ;
572
574
573
- /* Get the HID Report Descriptor. */
574
- int res = libusb_control_transfer (handle , LIBUSB_ENDPOINT_IN |LIBUSB_RECIPIENT_INTERFACE , LIBUSB_REQUEST_GET_DESCRIPTOR , (LIBUSB_DT_REPORT << 8 )|interface_num , 0 , data , sizeof (data ), 5000 );
575
+ if (report_descriptor_size > 4096 )
576
+ report_descriptor_size = 4096 ;
577
+
578
+ /* Get the HID Report Descriptor.
579
+ See USB HID Specificatin, sectin 7.1.1
580
+ */
581
+ int res = libusb_control_transfer (handle , LIBUSB_ENDPOINT_IN |LIBUSB_RECIPIENT_INTERFACE , LIBUSB_REQUEST_GET_DESCRIPTOR , (LIBUSB_DT_REPORT << 8 ), interface_num , data , report_descriptor_size , 5000 );
575
582
if (res >= 0 ) {
576
583
/* Parse the usage and usage page
577
584
out of the report descriptor. */
@@ -585,7 +592,7 @@ static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_devic
585
592
}
586
593
587
594
#ifdef INVASIVE_GET_USAGE
588
- static void invasive_fill_device_info_usage (struct hid_device_info * cur_dev , libusb_device_handle * handle , int interface_num )
595
+ static void invasive_fill_device_info_usage (struct hid_device_info * cur_dev , libusb_device_handle * handle , int interface_num , uint16_t report_descriptor_size )
589
596
{
590
597
int res = 0 ;
591
598
@@ -604,7 +611,7 @@ static void invasive_fill_device_info_usage(struct hid_device_info *cur_dev, lib
604
611
605
612
res = libusb_claim_interface (handle , interface_num );
606
613
if (res >= 0 ) {
607
- fill_device_info_usage (cur_dev , handle , interface_num );
614
+ fill_device_info_usage (cur_dev , handle , interface_num , report_descriptor_size );
608
615
609
616
/* Release the interface */
610
617
res = libusb_release_interface (handle , interface_num );
@@ -662,6 +669,59 @@ static struct hid_device_info * create_device_info_for_device(libusb_device *dev
662
669
return cur_dev ;
663
670
}
664
671
672
+ static uint16_t get_report_descriptor_size_from_interface_descriptors (const struct libusb_interface_descriptor * intf_desc )
673
+ {
674
+ int i = 0 ;
675
+ int found_hid_report_descriptor = 0 ;
676
+ uint16_t result = 4096 ;
677
+ const unsigned char * extra = intf_desc -> extra ;
678
+ int extra_length = intf_desc -> extra_length ;
679
+
680
+ /*
681
+ "extra" contains a HID descriptor
682
+ See section 6.2.1 of HID 1.1 specification.
683
+ */
684
+
685
+ while (extra_length >= 2 ) { /* Descriptor header: bLength/bDescriptorType */
686
+ if (extra [1 ] == LIBUSB_DT_HID ) { /* bDescriptorType */
687
+ if (extra_length < 6 ) {
688
+ LOG ("Broken HID descriptor: not enough data\n" );
689
+ break ;
690
+ }
691
+ unsigned char bNumDescriptors = extra [5 ];
692
+ if (extra_length < (6 + 3 * bNumDescriptors )) {
693
+ LOG ("Broken HID descriptor: not enough data for Report metadata\n" );
694
+ break ;
695
+ }
696
+ for (i = 0 ; i < bNumDescriptors ; i ++ ) {
697
+ if (extra [6 + 3 * i ] == LIBUSB_DT_REPORT ) {
698
+ result = (uint16_t )extra [6 + 3 * i + 2 ] << 8 | extra [6 + 3 * i + 1 ];
699
+ found_hid_report_descriptor = 1 ;
700
+ break ;
701
+ }
702
+ }
703
+
704
+ if (!found_hid_report_descriptor ) {
705
+ /* We expect to find exactly 1 HID descriptor (LIBUSB_DT_HID)
706
+ which should contain exactly one HID Report Descriptor metadata (LIBUSB_DT_REPORT). */
707
+ LOG ("Broken HID descriptor: missing Report descriptor\n" );
708
+ }
709
+ break ;
710
+ }
711
+
712
+ if (extra [0 ] == 0 ) { /* bLength */
713
+ LOG ("Broken HID Interface descriptors: zero-sized descriptor\n" );
714
+ break ;
715
+ }
716
+
717
+ /* Iterate over to the next Descriptor */
718
+ extra_length -= extra [0 ];
719
+ extra += extra [0 ];
720
+ }
721
+
722
+ return result ;
723
+ }
724
+
665
725
struct hid_device_info HID_API_EXPORT * hid_enumerate (unsigned short vendor_id , unsigned short product_id )
666
726
{
667
727
libusb_device * * devs ;
@@ -741,7 +801,9 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
741
801
field in the hid_device_info struct to distinguish
742
802
between interfaces. */
743
803
if (handle ) {
744
- invasive_fill_device_info_usage (tmp , handle , intf_desc -> bInterfaceNumber );
804
+ uint16_t report_descriptor_size = get_report_descriptor_size_from_interface_descriptors (intf_desc );
805
+
806
+ invasive_fill_device_info_usage (tmp , handle , intf_desc -> bInterfaceNumber , report_descriptor_size );
745
807
}
746
808
#endif /* INVASIVE_GET_USAGE */
747
809
@@ -1004,6 +1066,8 @@ static int hidapi_initialize_device(hid_device *dev, int config_number, const st
1004
1066
dev -> config_number = config_number ;
1005
1067
dev -> interface = intf_desc -> bInterfaceNumber ;
1006
1068
1069
+ dev -> report_descriptor_size = get_report_descriptor_size_from_interface_descriptors (intf_desc );
1070
+
1007
1071
dev -> input_endpoint = 0 ;
1008
1072
dev -> input_ep_max_packet_size = 0 ;
1009
1073
dev -> output_endpoint = 0 ;
@@ -1522,7 +1586,7 @@ HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_devi
1522
1586
// device error already set by create_device_info_for_device, if any
1523
1587
1524
1588
if (dev -> device_info ) {
1525
- fill_device_info_usage (dev -> device_info , dev -> device_handle , dev -> interface );
1589
+ fill_device_info_usage (dev -> device_info , dev -> device_handle , dev -> interface , dev -> report_descriptor_size );
1526
1590
}
1527
1591
}
1528
1592
0 commit comments