26
26
#ifdef SDL_JOYSTICK_HIDAPI
27
27
28
28
#include "../../SDL_hints_c.h"
29
+ #include "../../misc/SDL_libusb.h"
29
30
#include "../SDL_sysjoystick.h"
30
31
#include "SDL_hidapijoystick_c.h"
31
- #include "SDL_hidapi_rumble.h"
32
- #include "SDL_hidapi_nintendo.h"
33
32
34
33
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH2
35
34
35
+ typedef struct
36
+ {
37
+ SDL_LibUSBContext * libusb ;
38
+ libusb_device_handle * device_handle ;
39
+ bool interface_claimed ;
40
+ Uint8 interface_number ;
41
+ Uint8 bulk_endpoint ;
42
+ } SDL_DriverSwitch2_Context ;
43
+
36
44
static void HIDAPI_DriverSwitch2_RegisterHints (SDL_HintCallback callback , void * userdata )
37
45
{
38
46
SDL_AddHintCallback (SDL_HINT_JOYSTICK_HIDAPI_SWITCH2 , callback , userdata );
@@ -51,29 +59,138 @@ static bool HIDAPI_DriverSwitch2_IsEnabled(void)
51
59
static bool HIDAPI_DriverSwitch2_IsSupportedDevice (SDL_HIDAPI_Device * device , const char * name , SDL_GamepadType type , Uint16 vendor_id , Uint16 product_id , Uint16 version , int interface_number , int interface_class , int interface_subclass , int interface_protocol )
52
60
{
53
61
if (vendor_id == USB_VENDOR_NINTENDO ) {
54
- switch (product_id ) {
55
- case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER :
56
- case USB_PRODUCT_NINTENDO_SWITCH2_PRO :
62
+ switch (product_id ) {
63
+ case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER :
64
+ case USB_PRODUCT_NINTENDO_SWITCH2_PRO :
57
65
return true;
58
- }
66
+ }
59
67
}
60
68
61
69
return false;
62
70
}
63
71
72
+ static bool HIDAPI_DriverSwitch2_InitBluetooth (SDL_HIDAPI_Device * device )
73
+ {
74
+ // FIXME: Need to add Bluetooth support
75
+ return SDL_SetError ("Nintendo Switch2 controllers not supported over Bluetooth" );
76
+ }
77
+
78
+ static bool FindBulkOutEndpoint (SDL_LibUSBContext * libusb , libusb_device_handle * handle , Uint8 * bInterfaceNumber , Uint8 * bEndpointAddress )
79
+ {
80
+ struct libusb_config_descriptor * config ;
81
+ if (libusb -> get_config_descriptor (libusb -> get_device (handle ), 0 , & config ) != 0 ) {
82
+ return false;
83
+ }
84
+
85
+ for (int i = 0 ; i < config -> bNumInterfaces ; i ++ ) {
86
+ const struct libusb_interface * iface = & config -> interface [i ];
87
+ for (int j = 0 ; j < iface -> num_altsetting ; j ++ ) {
88
+ const struct libusb_interface_descriptor * altsetting = & iface -> altsetting [j ];
89
+ if (altsetting -> bInterfaceNumber == 1 ) {
90
+ for (int k = 0 ; k < altsetting -> bNumEndpoints ; k ++ ) {
91
+ const struct libusb_endpoint_descriptor * ep = & altsetting -> endpoint [k ];
92
+ if ((ep -> bmAttributes & LIBUSB_TRANSFER_TYPE_MASK ) == LIBUSB_TRANSFER_TYPE_BULK && (ep -> bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK ) == LIBUSB_ENDPOINT_OUT ) {
93
+
94
+ * bInterfaceNumber = altsetting -> bInterfaceNumber ;
95
+ * bEndpointAddress = ep -> bEndpointAddress ;
96
+ libusb -> free_config_descriptor (config );
97
+ return true;
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ libusb -> free_config_descriptor (config );
104
+ return false;
105
+ }
106
+
107
+ static bool HIDAPI_DriverSwitch2_InitUSB (SDL_HIDAPI_Device * device )
108
+ {
109
+ SDL_DriverSwitch2_Context * ctx = (SDL_DriverSwitch2_Context * )device -> context ;
110
+
111
+ if (!SDL_InitLibUSB (& ctx -> libusb )) {
112
+ return false;
113
+ }
114
+
115
+ ctx -> device_handle = (libusb_device_handle * )SDL_GetPointerProperty (SDL_hid_get_properties (device -> dev ), SDL_PROP_HIDAPI_LIBUSB_DEVICE_HANDLE_POINTER , NULL );
116
+ if (!ctx -> device_handle ) {
117
+ return SDL_SetError ("Couldn't get libusb device handle" );
118
+ }
119
+
120
+ if (!FindBulkOutEndpoint (ctx -> libusb , ctx -> device_handle , & ctx -> interface_number , & ctx -> bulk_endpoint )) {
121
+ return SDL_SetError ("Couldn't find bulk endpoint" );
122
+ }
123
+
124
+ int res = ctx -> libusb -> claim_interface (ctx -> device_handle , ctx -> interface_number );
125
+ if (res < 0 ) {
126
+ return SDL_SetError ("Couldn't claim interface %d: %d\n" , ctx -> interface_number , res );
127
+ }
128
+ ctx -> interface_claimed = true;
129
+
130
+ const unsigned char DEFAULT_REPORT_DATA [] = {
131
+ 0x03 , 0x91 , 0x00 , 0x0d , 0x00 , 0x08 ,
132
+ 0x00 , 0x00 , 0x01 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF
133
+ };
134
+ const unsigned char SET_LED_DATA [] = {
135
+ 0x09 , 0x91 , 0x00 , 0x07 , 0x00 , 0x08 ,
136
+ 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
137
+ };
138
+
139
+ int transferred ;
140
+ res = ctx -> libusb -> bulk_transfer (ctx -> device_handle ,
141
+ ctx -> bulk_endpoint ,
142
+ (unsigned char * )DEFAULT_REPORT_DATA ,
143
+ sizeof (DEFAULT_REPORT_DATA ),
144
+ & transferred ,
145
+ 1000 );
146
+ if (res < 0 ) {
147
+ return SDL_SetError ("Couldn't set report data: %d\n" , res );
148
+ }
149
+
150
+ res = ctx -> libusb -> bulk_transfer (ctx -> device_handle ,
151
+ ctx -> bulk_endpoint ,
152
+ (unsigned char * )SET_LED_DATA ,
153
+ sizeof (SET_LED_DATA ),
154
+ & transferred ,
155
+ 1000 );
156
+ if (res < 0 ) {
157
+ return SDL_SetError ("Couldn't set LED data: %d\n" , res );
158
+ }
159
+
160
+ return true;
161
+ }
162
+
64
163
static bool HIDAPI_DriverSwitch2_InitDevice (SDL_HIDAPI_Device * device )
65
164
{
66
- // Sometimes the device handle isn't available during enumeration so we don't get the device name, so set it explicitly
67
- switch (device -> product_id ) {
68
- case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER :
69
- HIDAPI_SetDeviceName (device , "Nintendo GameCube Controller" );
70
- break ;
71
- case USB_PRODUCT_NINTENDO_SWITCH2_PRO :
72
- HIDAPI_SetDeviceName (device , "Nintendo Switch Pro Controller" );
73
- break ;
74
- default :
75
- break ;
76
- }
165
+ SDL_DriverSwitch2_Context * ctx ;
166
+
167
+ ctx = (SDL_DriverSwitch2_Context * )SDL_calloc (1 , sizeof (* ctx ));
168
+ if (!ctx ) {
169
+ return false;
170
+ }
171
+ device -> context = ctx ;
172
+
173
+ if (device -> is_bluetooth ) {
174
+ if (!HIDAPI_DriverSwitch2_InitBluetooth (device )) {
175
+ return false;
176
+ }
177
+ } else {
178
+ if (!HIDAPI_DriverSwitch2_InitUSB (device )) {
179
+ return false;
180
+ }
181
+ }
182
+
183
+ // Sometimes the device handle isn't available during enumeration so we don't get the device name, so set it explicitly
184
+ switch (device -> product_id ) {
185
+ case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER :
186
+ HIDAPI_SetDeviceName (device , "Nintendo GameCube Controller" );
187
+ break ;
188
+ case USB_PRODUCT_NINTENDO_SWITCH2_PRO :
189
+ HIDAPI_SetDeviceName (device , "Nintendo Switch Pro Controller" );
190
+ break ;
191
+ default :
192
+ break ;
193
+ }
77
194
return HIDAPI_JoystickConnected (device , NULL );
78
195
}
79
196
@@ -250,6 +367,18 @@ static void HIDAPI_DriverSwitch2_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Jo
250
367
251
368
static void HIDAPI_DriverSwitch2_FreeDevice (SDL_HIDAPI_Device * device )
252
369
{
370
+ SDL_DriverSwitch2_Context * ctx = (SDL_DriverSwitch2_Context * )device -> context ;
371
+
372
+ if (ctx ) {
373
+ if (ctx -> interface_claimed ) {
374
+ ctx -> libusb -> release_interface (ctx -> device_handle , ctx -> interface_number );
375
+ ctx -> interface_claimed = false;
376
+ }
377
+ if (ctx -> libusb ) {
378
+ SDL_QuitLibUSB ();
379
+ ctx -> libusb = NULL ;
380
+ }
381
+ }
253
382
}
254
383
255
384
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch2 = {
0 commit comments