mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-04-03 14:19:20 +00:00
hidapi: Add support for NSO GameCube controller via libusb.
Thanks to Nohzockt for the initial libusb init and hidapi polling work!
This commit is contained in:
@@ -752,6 +752,14 @@ static struct
|
||||
int *actual_length,
|
||||
unsigned int timeout
|
||||
);
|
||||
int (LIBUSB_CALL *bulk_transfer)(
|
||||
libusb_device_handle *dev_handle,
|
||||
unsigned char endpoint,
|
||||
unsigned char *data,
|
||||
int length,
|
||||
int *transferred,
|
||||
unsigned int timeout
|
||||
);
|
||||
int (LIBUSB_CALL *handle_events)(libusb_context *ctx);
|
||||
int (LIBUSB_CALL *handle_events_completed)(libusb_context *ctx, int *completed);
|
||||
const char * (LIBUSB_CALL *error_name)(int errcode);
|
||||
@@ -785,6 +793,7 @@ static struct
|
||||
#define libusb_free_transfer libusb_ctx.free_transfer
|
||||
#define libusb_control_transfer libusb_ctx.control_transfer
|
||||
#define libusb_interrupt_transfer libusb_ctx.interrupt_transfer
|
||||
#define libusb_bulk_transfer libusb_ctx.bulk_transfer
|
||||
#define libusb_handle_events libusb_ctx.handle_events
|
||||
#define libusb_handle_events_completed libusb_ctx.handle_events_completed
|
||||
#define libusb_error_name libusb_ctx.error_name
|
||||
@@ -852,6 +861,7 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
|
||||
#undef libusb_free_transfer
|
||||
#undef libusb_control_transfer
|
||||
#undef libusb_interrupt_transfer
|
||||
#undef libusb_bulk_transfer
|
||||
#undef libusb_handle_events
|
||||
#undef libusb_handle_events_completed
|
||||
#undef libusb_error_name
|
||||
@@ -898,7 +908,9 @@ static const struct {
|
||||
Uint16 vendor;
|
||||
Uint16 product;
|
||||
} SDL_libusb_whitelist[] = {
|
||||
{ 0x057e, 0x0337 } // Nintendo WUP-028, Wii U/Switch GameCube Adapter
|
||||
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER },
|
||||
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_PRO },
|
||||
{ USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER },
|
||||
};
|
||||
|
||||
static bool IsInWhitelist(Uint16 vendor, Uint16 product)
|
||||
@@ -1221,6 +1233,7 @@ int SDL_hid_init(void)
|
||||
LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(struct libusb_transfer *), free_transfer)
|
||||
LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, uint8_t, uint8_t, uint16_t, uint16_t, unsigned char *, uint16_t, unsigned int), control_transfer)
|
||||
LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, unsigned char, unsigned char *, int, int *, unsigned int), interrupt_transfer)
|
||||
LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, unsigned char, unsigned char *, int, int *, unsigned int), bulk_transfer)
|
||||
LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context *), handle_events)
|
||||
LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context *, int *), handle_events_completed)
|
||||
LOAD_LIBUSB_SYMBOL(const char * (LIBUSB_CALL *)(int), error_name)
|
||||
|
||||
@@ -1324,6 +1324,79 @@ static void init_xboxone(libusb_device_handle *device_handle, unsigned short idV
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_ns2(unsigned short idVendor, unsigned short idProduct)
|
||||
{
|
||||
if (idVendor == 0x057e) {
|
||||
if (idProduct == 0x2069) {
|
||||
return true;
|
||||
}
|
||||
if (idProduct == 0x2073) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ns2_find_bulk_out_endpoint(libusb_device_handle* handle, uint8_t* endpoint_out)
|
||||
{
|
||||
struct libusb_config_descriptor* config;
|
||||
if (libusb_get_config_descriptor(libusb_get_device(handle), 0, &config) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < config->bNumInterfaces; i++) {
|
||||
const struct libusb_interface* iface = &config->interface[i];
|
||||
for (int j = 0; j < iface->num_altsetting; j++) {
|
||||
const struct libusb_interface_descriptor* altsetting = &iface->altsetting[j];
|
||||
if (altsetting->bInterfaceNumber == 1) {
|
||||
for (int k = 0; k < altsetting->bNumEndpoints; k++) {
|
||||
const struct libusb_endpoint_descriptor* ep = &altsetting->endpoint[k];
|
||||
if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK && (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) {
|
||||
*endpoint_out = ep->bEndpointAddress;
|
||||
libusb_free_config_descriptor(config);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_config_descriptor(config);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void init_ns2(libusb_device_handle *device_handle)
|
||||
{
|
||||
const unsigned char DEFAULT_REPORT_DATA[] = {
|
||||
0x03, 0x91, 0x00, 0x0d, 0x00, 0x08,
|
||||
0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
const unsigned char SET_LED_DATA[] = {
|
||||
0x09, 0x91, 0x00, 0x07, 0x00, 0x08,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
uint8_t endpoint_out = 0;
|
||||
if (!ns2_find_bulk_out_endpoint(device_handle, &endpoint_out)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int transferred;
|
||||
libusb_bulk_transfer(device_handle,
|
||||
endpoint_out,
|
||||
(unsigned char*)DEFAULT_REPORT_DATA,
|
||||
sizeof(DEFAULT_REPORT_DATA),
|
||||
&transferred,
|
||||
1000);
|
||||
|
||||
libusb_bulk_transfer(device_handle,
|
||||
endpoint_out,
|
||||
(unsigned char*)SET_LED_DATA,
|
||||
sizeof(SET_LED_DATA),
|
||||
&transferred,
|
||||
1000);
|
||||
}
|
||||
|
||||
static void calculate_device_quirks(hid_device *dev, unsigned short idVendor, unsigned short idProduct)
|
||||
{
|
||||
static const int VENDOR_SONY = 0x054c;
|
||||
@@ -1385,6 +1458,11 @@ static int hidapi_initialize_device(hid_device *dev, const struct libusb_interfa
|
||||
init_xboxone(dev->device_handle, desc.idVendor, desc.idProduct, conf_desc);
|
||||
}
|
||||
|
||||
/* Initialize NSO GameCube controllers */
|
||||
if (is_ns2(desc.idVendor, desc.idProduct)) {
|
||||
init_ns2(dev->device_handle);
|
||||
}
|
||||
|
||||
/* Store off the string descriptor indexes */
|
||||
dev->manufacturer_index = desc.iManufacturer;
|
||||
dev->product_index = desc.iProduct;
|
||||
|
||||
Reference in New Issue
Block a user