@@ -675,6 +675,107 @@ static uint16_t get_report_descriptor_size_from_interface_descriptors(const stru
675675 return result ;
676676}
677677
678+ static int is_xbox360 (unsigned short vendor_id , const struct libusb_interface_descriptor * intf_desc )
679+ {
680+ static const int xb360_iface_subclass = 93 ;
681+ static const int xb360_iface_protocol = 1 ; /* Wired */
682+ static const int xb360w_iface_protocol = 129 ; /* Wireless */
683+ static const int supported_vendors [] = {
684+ 0x0079 , /* GPD Win 2 */
685+ 0x044f , /* Thrustmaster */
686+ 0x045e , /* Microsoft */
687+ 0x046d , /* Logitech */
688+ 0x056e , /* Elecom */
689+ 0x06a3 , /* Saitek */
690+ 0x0738 , /* Mad Catz */
691+ 0x07ff , /* Mad Catz */
692+ 0x0e6f , /* PDP */
693+ 0x0f0d , /* Hori */
694+ 0x1038 , /* SteelSeries */
695+ 0x11c9 , /* Nacon */
696+ 0x12ab , /* Unknown */
697+ 0x1430 , /* RedOctane */
698+ 0x146b , /* BigBen */
699+ 0x1532 , /* Razer Sabertooth */
700+ 0x15e4 , /* Numark */
701+ 0x162e , /* Joytech */
702+ 0x1689 , /* Razer Onza */
703+ 0x1949 , /* Lab126, Inc. */
704+ 0x1bad , /* Harmonix */
705+ 0x20d6 , /* PowerA */
706+ 0x24c6 , /* PowerA */
707+ 0x2c22 , /* Qanba */
708+ 0x2dc8 , /* 8BitDo */
709+ 0x9886 , /* ASTRO Gaming */
710+ };
711+
712+ if (intf_desc -> bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
713+ intf_desc -> bInterfaceSubClass == xb360_iface_subclass &&
714+ (intf_desc -> bInterfaceProtocol == xb360_iface_protocol ||
715+ intf_desc -> bInterfaceProtocol == xb360w_iface_protocol )) {
716+ size_t i ;
717+ for (i = 0 ; i < sizeof (supported_vendors )/sizeof (supported_vendors [0 ]); ++ i ) {
718+ if (vendor_id == supported_vendors [i ]) {
719+ return 1 ;
720+ }
721+ }
722+ }
723+ return 0 ;
724+ }
725+
726+ static int is_xboxone (unsigned short vendor_id , const struct libusb_interface_descriptor * intf_desc )
727+ {
728+ static const int xb1_iface_subclass = 71 ;
729+ static const int xb1_iface_protocol = 208 ;
730+ static const int supported_vendors [] = {
731+ 0x044f , /* Thrustmaster */
732+ 0x045e , /* Microsoft */
733+ 0x0738 , /* Mad Catz */
734+ 0x0e6f , /* PDP */
735+ 0x0f0d , /* Hori */
736+ 0x10f5 , /* Turtle Beach */
737+ 0x1532 , /* Razer Wildcat */
738+ 0x20d6 , /* PowerA */
739+ 0x24c6 , /* PowerA */
740+ 0x2dc8 , /* 8BitDo */
741+ 0x2e24 , /* Hyperkin */
742+ 0x3537 , /* GameSir */
743+ };
744+
745+ if (intf_desc -> bInterfaceNumber == 0 &&
746+ intf_desc -> bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
747+ intf_desc -> bInterfaceSubClass == xb1_iface_subclass &&
748+ intf_desc -> bInterfaceProtocol == xb1_iface_protocol ) {
749+ size_t i ;
750+ for (i = 0 ; i < sizeof (supported_vendors )/sizeof (supported_vendors [0 ]); ++ i ) {
751+ if (vendor_id == supported_vendors [i ]) {
752+ return 1 ;
753+ }
754+ }
755+ }
756+ return 0 ;
757+ }
758+
759+ static int should_enumerate_interface (unsigned short vendor_id , const struct libusb_interface_descriptor * intf_desc )
760+ {
761+ #if 0
762+ printf ("Checking interface 0x%x %d/%d/%d/%d\n" , vendor_id , intf_desc -> bInterfaceNumber , intf_desc -> bInterfaceClass , intf_desc -> bInterfaceSubClass , intf_desc -> bInterfaceProtocol );
763+ #endif
764+
765+ if (intf_desc -> bInterfaceClass == LIBUSB_CLASS_HID )
766+ return 1 ;
767+
768+ /* Also enumerate Xbox 360 controllers */
769+ if (is_xbox360 (vendor_id , intf_desc ))
770+ return 1 ;
771+
772+ /* Also enumerate Xbox One controllers */
773+ if (is_xboxone (vendor_id , intf_desc ))
774+ return 1 ;
775+
776+ return 0 ;
777+ }
778+
678779struct hid_device_info HID_API_EXPORT * hid_enumerate (unsigned short vendor_id , unsigned short product_id )
679780{
680781 libusb_device * * devs ;
@@ -718,7 +819,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
718819 for (k = 0 ; k < intf -> num_altsetting ; k ++ ) {
719820 const struct libusb_interface_descriptor * intf_desc ;
720821 intf_desc = & intf -> altsetting [k ];
721- if (intf_desc -> bInterfaceClass == LIBUSB_CLASS_HID ) {
822+ if (should_enumerate_interface ( dev_vid , intf_desc ) ) {
722823 struct hid_device_info * tmp ;
723824
724825 res = libusb_open (dev , & handle );
@@ -982,8 +1083,71 @@ static void *read_thread(void *param)
9821083 return NULL ;
9831084}
9841085
1086+ static void init_xbox360 (libusb_device_handle * device_handle , unsigned short idVendor , unsigned short idProduct , const struct libusb_config_descriptor * conf_desc )
1087+ {
1088+ (void )conf_desc ;
1089+
1090+ if ((idVendor == 0x05ac && idProduct == 0x055b ) /* Gamesir-G3w */ ||
1091+ idVendor == 0x0f0d /* Hori Xbox controllers */ ) {
1092+ unsigned char data [20 ];
1093+
1094+ /* The HORIPAD FPS for Nintendo Switch requires this to enable input reports.
1095+ This VID/PID is also shared with other HORI controllers, but they all seem
1096+ to be fine with this as well.
1097+ */
1098+ memset (data , 0 , sizeof (data ));
1099+ libusb_control_transfer (device_handle , 0xC1 , 0x01 , 0x100 , 0x0 , data , sizeof (data ), 100 );
1100+ }
1101+ }
1102+
1103+ static void init_xboxone (libusb_device_handle * device_handle , unsigned short idVendor , unsigned short idProduct , const struct libusb_config_descriptor * conf_desc )
1104+ {
1105+ static const int vendor_microsoft = 0x045e ;
1106+ static const int xb1_iface_subclass = 71 ;
1107+ static const int xb1_iface_protocol = 208 ;
1108+ int j , k , res ;
1109+
1110+ (void )idProduct ;
1111+
1112+ for (j = 0 ; j < conf_desc -> bNumInterfaces ; j ++ ) {
1113+ const struct libusb_interface * intf = & conf_desc -> interface [j ];
1114+ for (k = 0 ; k < intf -> num_altsetting ; k ++ ) {
1115+ const struct libusb_interface_descriptor * intf_desc = & intf -> altsetting [k ];
1116+ if (intf_desc -> bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
1117+ intf_desc -> bInterfaceSubClass == xb1_iface_subclass &&
1118+ intf_desc -> bInterfaceProtocol == xb1_iface_protocol ) {
1119+ int bSetAlternateSetting = 0 ;
1120+
1121+ /* Newer Microsoft Xbox One controllers have a high speed alternate setting */
1122+ if (idVendor == vendor_microsoft &&
1123+ intf_desc -> bInterfaceNumber == 0 && intf_desc -> bAlternateSetting == 1 ) {
1124+ bSetAlternateSetting = 1 ;
1125+ } else if (intf_desc -> bInterfaceNumber != 0 && intf_desc -> bAlternateSetting == 0 ) {
1126+ bSetAlternateSetting = 1 ;
1127+ }
1128+
1129+ if (bSetAlternateSetting ) {
1130+ res = libusb_claim_interface (device_handle , intf_desc -> bInterfaceNumber );
1131+ if (res < 0 ) {
1132+ LOG ("can't claim interface %d: %d\n" , intf_desc -> bInterfaceNumber , res );
1133+ continue ;
1134+ }
1135+
1136+ LOG ("Setting alternate setting for VID/PID 0x%x/0x%x interface %d to %d\n" , idVendor , idProduct , intf_desc -> bInterfaceNumber , intf_desc -> bAlternateSetting );
9851137
986- static int hidapi_initialize_device (hid_device * dev , int config_number , const struct libusb_interface_descriptor * intf_desc )
1138+ res = libusb_set_interface_alt_setting (device_handle , intf_desc -> bInterfaceNumber , intf_desc -> bAlternateSetting );
1139+ if (res < 0 ) {
1140+ LOG ("xbox init: can't set alt setting %d: %d\n" , intf_desc -> bInterfaceNumber , res );
1141+ }
1142+
1143+ libusb_release_interface (device_handle , intf_desc -> bInterfaceNumber );
1144+ }
1145+ }
1146+ }
1147+ }
1148+ }
1149+
1150+ static int hidapi_initialize_device (hid_device * dev , const struct libusb_interface_descriptor * intf_desc , const struct libusb_config_descriptor * conf_desc )
9871151{
9881152 int i = 0 ;
9891153 int res = 0 ;
@@ -1020,13 +1184,23 @@ static int hidapi_initialize_device(hid_device *dev, int config_number, const st
10201184 return 0 ;
10211185 }
10221186
1187+ /* Initialize XBox 360 controllers */
1188+ if (is_xbox360 (desc .idVendor , intf_desc )) {
1189+ init_xbox360 (dev -> device_handle , desc .idVendor , desc .idProduct , conf_desc );
1190+ }
1191+
1192+ /* Initialize XBox One controllers */
1193+ if (is_xboxone (desc .idVendor , intf_desc )) {
1194+ init_xboxone (dev -> device_handle , desc .idVendor , desc .idProduct , conf_desc );
1195+ }
1196+
10231197 /* Store off the string descriptor indexes */
10241198 dev -> manufacturer_index = desc .iManufacturer ;
10251199 dev -> product_index = desc .iProduct ;
10261200 dev -> serial_index = desc .iSerialNumber ;
10271201
10281202 /* Store off the USB information */
1029- dev -> config_number = config_number ;
1203+ dev -> config_number = conf_desc -> bConfigurationValue ;
10301204 dev -> interface = intf_desc -> bInterfaceNumber ;
10311205
10321206 dev -> report_descriptor_size = get_report_descriptor_size_from_interface_descriptors (intf_desc );
@@ -1110,7 +1284,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
11101284 const struct libusb_interface * intf = & conf_desc -> interface [j ];
11111285 for (k = 0 ; k < intf -> num_altsetting && !good_open ; k ++ ) {
11121286 const struct libusb_interface_descriptor * intf_desc = & intf -> altsetting [k ];
1113- if (intf_desc -> bInterfaceClass == LIBUSB_CLASS_HID ) {
1287+ if (should_enumerate_interface ( desc . idVendor , intf_desc ) ) {
11141288 char dev_path [64 ];
11151289 get_path (& dev_path , usb_dev , conf_desc -> bConfigurationValue , intf_desc -> bInterfaceNumber );
11161290 if (!strcmp (dev_path , path )) {
@@ -1122,7 +1296,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
11221296 LOG ("can't open device\n" );
11231297 break ;
11241298 }
1125- good_open = hidapi_initialize_device (dev , conf_desc -> bConfigurationValue , intf_desc );
1299+ good_open = hidapi_initialize_device (dev , intf_desc , conf_desc );
11261300 if (!good_open )
11271301 libusb_close (dev -> device_handle );
11281302 }
@@ -1200,7 +1374,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys
12001374 goto err ;
12011375 }
12021376
1203- if (!hidapi_initialize_device (dev , conf_desc -> bConfigurationValue , selected_intf_desc ))
1377+ if (!hidapi_initialize_device (dev , selected_intf_desc , conf_desc ))
12041378 goto err ;
12051379
12061380 return dev ;
0 commit comments