mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-06-04 19:07:40 +00:00
hidapi: Add support for Wii U/Switch USB GameCube controller adapter.
Note that a single USB device is responsible for all 4 joysticks, so a large rewrite of the DeviceDriver functions was necessary to allow a single device to produce multiple joysticks.
This commit is contained in:
parent
938a5508d1
commit
c528615626
13 changed files with 724 additions and 176 deletions
|
@ -50,18 +50,10 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
struct joystick_hwdata
|
||||
{
|
||||
SDL_HIDAPI_DeviceDriver *driver;
|
||||
void *context;
|
||||
|
||||
SDL_mutex *mutex;
|
||||
hid_device *dev;
|
||||
};
|
||||
|
||||
typedef struct _SDL_HIDAPI_Device
|
||||
{
|
||||
SDL_JoystickID instance_id;
|
||||
SDL_HIDAPI_DriverData devdata;
|
||||
SDL_mutex *mutex;
|
||||
char *name;
|
||||
char *path;
|
||||
Uint16 vendor_id;
|
||||
|
@ -95,6 +87,9 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
|
|||
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
&SDL_HIDAPI_DriverXboxOne,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
|
||||
&SDL_HIDAPI_DriverGameCube,
|
||||
#endif
|
||||
};
|
||||
static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
|
||||
static int SDL_HIDAPI_numjoysticks = 0;
|
||||
|
@ -393,6 +388,36 @@ HIDAPI_ShutdownDiscovery()
|
|||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_InitDriver(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
device->devdata.device = hid_open_path(device->path, 0);
|
||||
if (!device->devdata.device) {
|
||||
SDL_SetError("Couldn't open HID device %s", device->path);
|
||||
device->driver = NULL;
|
||||
} else {
|
||||
device->driver->InitDriver(
|
||||
&device->devdata,
|
||||
device->vendor_id,
|
||||
device->product_id,
|
||||
&SDL_HIDAPI_numjoysticks
|
||||
);
|
||||
device->mutex = SDL_CreateMutex();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_QuitDriver(SDL_HIDAPI_Device *device, SDL_bool send_event)
|
||||
{
|
||||
device->driver->QuitDriver(
|
||||
&device->devdata,
|
||||
send_event,
|
||||
&SDL_HIDAPI_numjoysticks
|
||||
);
|
||||
hid_close(device->devdata.device);
|
||||
SDL_DestroyMutex(device->mutex);
|
||||
device->driver = NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
|
||||
|
@ -605,15 +630,17 @@ HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device)
|
|||
}
|
||||
|
||||
static SDL_HIDAPI_Device *
|
||||
HIDAPI_GetJoystickByIndex(int device_index)
|
||||
HIDAPI_GetDeviceByIndex(int device_index)
|
||||
{
|
||||
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
|
||||
int joysticks;
|
||||
while (device) {
|
||||
if (device->driver) {
|
||||
if (device_index == 0) {
|
||||
joysticks = device->driver->NumJoysticks(&device->devdata);
|
||||
if (device_index < joysticks) {
|
||||
break;
|
||||
}
|
||||
--device_index;
|
||||
device_index -= joysticks;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
|
@ -660,20 +687,12 @@ SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldVal
|
|||
while (device) {
|
||||
if (device->driver) {
|
||||
if (!device->driver->enabled) {
|
||||
device->driver = NULL;
|
||||
|
||||
--SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickRemoved(device->instance_id);
|
||||
HIDAPI_QuitDriver(device, SDL_TRUE);
|
||||
}
|
||||
} else {
|
||||
device->driver = HIDAPI_GetDeviceDriver(device);
|
||||
if (device->driver) {
|
||||
device->instance_id = SDL_GetNextJoystickInstanceID();
|
||||
|
||||
++SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(device->instance_id);
|
||||
HIDAPI_InitDriver(device);
|
||||
}
|
||||
}
|
||||
device = device->next;
|
||||
|
@ -723,7 +742,6 @@ HIDAPI_AddDevice(struct hid_device_info *info)
|
|||
if (!device) {
|
||||
return;
|
||||
}
|
||||
device->instance_id = -1;
|
||||
device->seen = SDL_TRUE;
|
||||
device->vendor_id = info->vendor_id;
|
||||
device->product_id = info->product_id;
|
||||
|
@ -818,12 +836,8 @@ HIDAPI_AddDevice(struct hid_device_info *info)
|
|||
}
|
||||
|
||||
if (device->driver) {
|
||||
/* It's a joystick! */
|
||||
device->instance_id = SDL_GetNextJoystickInstanceID();
|
||||
|
||||
++SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(device->instance_id);
|
||||
/* It's a joystick device! */
|
||||
HIDAPI_InitDriver(device);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -840,11 +854,8 @@ HIDAPI_DelDevice(SDL_HIDAPI_Device *device, SDL_bool send_event)
|
|||
SDL_HIDAPI_devices = curr->next;
|
||||
}
|
||||
|
||||
if (device->driver && send_event) {
|
||||
/* Need to decrement the joystick count before we post the event */
|
||||
--SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickRemoved(device->instance_id);
|
||||
if (device->driver) {
|
||||
HIDAPI_QuitDriver(device, send_event);
|
||||
}
|
||||
|
||||
SDL_free(device->name);
|
||||
|
@ -931,7 +942,7 @@ HIDAPI_JoystickDetect(void)
|
|||
static const char *
|
||||
HIDAPI_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
return HIDAPI_GetJoystickByIndex(device_index)->name;
|
||||
return HIDAPI_GetDeviceByIndex(device_index)->name;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -943,89 +954,61 @@ HIDAPI_JoystickGetDevicePlayerIndex(int device_index)
|
|||
static SDL_JoystickGUID
|
||||
HIDAPI_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
return HIDAPI_GetJoystickByIndex(device_index)->guid;
|
||||
return HIDAPI_GetDeviceByIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
static SDL_JoystickID
|
||||
HIDAPI_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
return HIDAPI_GetJoystickByIndex(device_index)->instance_id;
|
||||
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
|
||||
int joysticks;
|
||||
while (device) {
|
||||
if (device->driver) {
|
||||
joysticks = device->driver->NumJoysticks(&device->devdata);
|
||||
if (device_index < joysticks) {
|
||||
break;
|
||||
}
|
||||
device_index -= joysticks;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
return device->driver->InstanceIDForIndex(&device->devdata, device_index);
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
SDL_HIDAPI_Device *device = HIDAPI_GetJoystickByIndex(device_index);
|
||||
struct joystick_hwdata *hwdata;
|
||||
SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index);
|
||||
|
||||
hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata));
|
||||
if (!hwdata) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
hwdata->driver = device->driver;
|
||||
hwdata->dev = hid_open_path(device->path, 0);
|
||||
if (!hwdata->dev) {
|
||||
SDL_free(hwdata);
|
||||
return SDL_SetError("Couldn't open HID device %s", device->path);
|
||||
}
|
||||
hwdata->mutex = SDL_CreateMutex();
|
||||
|
||||
if (!device->driver->Init(joystick, hwdata->dev, device->vendor_id, device->product_id, &hwdata->context)) {
|
||||
hid_close(hwdata->dev);
|
||||
SDL_free(hwdata);
|
||||
if (!device->driver->OpenJoystick(&device->devdata, joystick)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
joystick->hwdata = hwdata;
|
||||
joystick->hwdata = (struct joystick_hwdata *)device;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
struct joystick_hwdata *hwdata = joystick->hwdata;
|
||||
SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
|
||||
SDL_HIDAPI_Device *device = (SDL_HIDAPI_Device *)joystick->hwdata;
|
||||
int result;
|
||||
|
||||
SDL_LockMutex(hwdata->mutex);
|
||||
result = driver->Rumble(joystick, hwdata->dev, hwdata->context, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
SDL_UnlockMutex(hwdata->mutex);
|
||||
SDL_LockMutex(device->mutex);
|
||||
result = device->driver->Rumble(&device->devdata, joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
SDL_UnlockMutex(device->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
struct joystick_hwdata *hwdata = joystick->hwdata;
|
||||
SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
|
||||
SDL_bool succeeded;
|
||||
|
||||
SDL_LockMutex(hwdata->mutex);
|
||||
succeeded = driver->Update(joystick, hwdata->dev, hwdata->context);
|
||||
SDL_UnlockMutex(hwdata->mutex);
|
||||
|
||||
if (!succeeded) {
|
||||
SDL_HIDAPI_Device *device;
|
||||
for (device = SDL_HIDAPI_devices; device; device = device->next) {
|
||||
if (device->instance_id == joystick->instance_id) {
|
||||
HIDAPI_DelDevice(device, SDL_TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* No-op, all updates are done in SDL_HIDAPI_UpdateDevices */
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
struct joystick_hwdata *hwdata = joystick->hwdata;
|
||||
SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
|
||||
driver->Quit(joystick, hwdata->dev, hwdata->context);
|
||||
|
||||
hid_close(hwdata->dev);
|
||||
SDL_DestroyMutex(hwdata->mutex);
|
||||
SDL_free(hwdata);
|
||||
joystick->hwdata = NULL;
|
||||
}
|
||||
|
||||
|
@ -1050,6 +1033,30 @@ HIDAPI_JoystickQuit(void)
|
|||
hid_exit();
|
||||
}
|
||||
|
||||
void
|
||||
SDL_HIDAPI_UpdateDevices(void)
|
||||
{
|
||||
SDL_HIDAPI_Device *next, *device = SDL_HIDAPI_devices;
|
||||
SDL_bool succeeded;
|
||||
|
||||
while (device) {
|
||||
if (device->driver) {
|
||||
SDL_LockMutex(device->mutex);
|
||||
succeeded = device->driver->UpdateDriver(&device->devdata, &SDL_HIDAPI_numjoysticks);
|
||||
SDL_UnlockMutex(device->mutex);
|
||||
if (!succeeded) {
|
||||
next = device->next;
|
||||
HIDAPI_DelDevice(device, SDL_TRUE);
|
||||
device = next;
|
||||
} else {
|
||||
device = device->next;
|
||||
}
|
||||
} else {
|
||||
device = device->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_JoystickDriver SDL_HIDAPI_JoystickDriver =
|
||||
{
|
||||
HIDAPI_JoystickInit,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue