More progress on the HID driver

== DETAILS
I think I've about got the thread startup/teardown code worked
out. Logically, anyway, if not accurately.

The challenge has been figuring out how best to integrate the
features of HID2VPAD.

I found `input/connect/joypad_connection.c` and this seems like
the logical place for:

- Special-case driver for the Switch Pro controller
- Any other special cases HIDTOVPAD supports that core RetroArch
  doesn't
- Parsing of HIDTOVPAD config file to add custom button mapping

== TESTING
Compiles. Haven't tested with a real Wii U. Probably doesn't work
though. I very likely have the threading bit wrong.
This commit is contained in:
gblues 2017-12-03 22:42:23 -08:00 committed by twinaphex
parent 1657079c45
commit 203876a206

View File

@ -1,7 +1,7 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2013-2014 - Jason Fetters
* Copyright (C) 2011-2017 - Daniel De Matteis
*
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
@ -30,26 +30,41 @@
#define DEVICE_UNUSED 0
#define DEVICE_USED 1
typedef struct wiiu_hid_user wiiu_hid_user_t;
struct wiiu_hid_user
{
wiiu_hid_user_t *next;
uint8_t *buffer;
uint32_t transfersize;
uint32_t handle;
};
typedef struct wiiu_hid
{
HIDClient *client;
OSThread *polling_thread;
// memory accounting; keep a pointer to the stack buffer so we can clean up later.
void *polling_thread_stack;
// setting this to true tells the polling thread to quit
volatile bool polling_thread_quit;
} wiiu_hid_t;
typedef struct wiiu_hid_user
{
uint8_t *buffer;
uint32_t transfersize;
uint32_t handle;
} wiiu_hid_user_t;
/*
* The attach/detach callback has no access to the wiiu_hid_t object. Therefore, we need a
* global place to handle device data.
*/
static wiiu_hid_user_t *pad_list = NULL;
static OSFastMutex *pad_list_mutex;
static wiiu_hid_t *new_wiiu_hid_t(void);
static void delete_wiiu_hid_t(wiiu_hid_t *hid);
static wiiu_hid_user_t *new_wiiu_hid_user_t(void);
static void delete_wiiu_hid_user_t(wiiu_hid_user_t *user);
static HIDClient *new_hidclient(void);
static void delete_hidclient(HIDClient *hid);
static OSFastMutex *new_fastmutex(const char *name);
static void delete_fastmutex(OSFastMutex *mutex);
static int32_t wiiu_attach_callback(HIDClient *client, HIDDevice *device, uint32_t attach);
static void start_polling_thread(wiiu_hid_t *hid);
@ -57,6 +72,8 @@ static void stop_polling_thread(wiiu_hid_t *hid);
static int wiiu_hid_polling_thread(int argc, const char **argv);
static void wiiu_hid_do_poll(wiiu_hid_t *hid);
static void enqueue_device(void);
/**
* HID driver entrypoints registered with hid_driver_t
*/
@ -131,7 +148,11 @@ static void *wiiu_hid_init(void)
delete_wiiu_hid_t(hid);
}
if(client)
free(client);
delete_hidclient(client);
if(pad_list_mutex) {
delete_fastmutex(pad_list_mutex);
pad_list_mutex = NULL;
}
return NULL;
}
@ -146,6 +167,16 @@ static void wiiu_hid_free(void *data)
}
}
static void free_pad_list(void) {
wiiu_hid_user_t *top;
while(pad_list != NULL) {
top = pad_list;
pad_list = top->next;
delete_wiiu_hid_user_t(top);
}
}
/**
* This is a no-op because polling is done with a worker thread.
*/
@ -168,7 +199,11 @@ static void start_polling_thread(wiiu_hid_t *hid) {
OSThread *thread = memalign(8, sizeof(OSThread));
void *stack = memalign(32, stack_size);
if(!thread || !stack)
if(pad_list_mutex == NULL) {
pad_list_mutex = new_fastmutex("pad_list");
}
if(!thread || !stack || !pad_list_mutex)
goto error;
if(!OSCreateThread(thread, wiiu_hid_polling_thread, 1, (char *)hid, stack, stack_size, priority, attributes))
@ -179,6 +214,8 @@ static void start_polling_thread(wiiu_hid_t *hid) {
return;
error:
if(pad_list_mutex)
delete_fastmutex(pad_list_mutex);
if(stack)
free(stack);
if(thread)
@ -198,6 +235,11 @@ static void stop_polling_thread(wiiu_hid_t *hid) {
free(hid->polling_thread);
free(hid->polling_thread_stack);
// with the thread stopped, we don't need the mutex.
delete_fastmutex(pad_list_mutex);
pad_list_mutex = NULL;
free_pad_list();
}
/**
@ -219,6 +261,23 @@ static void wiiu_hid_do_poll(wiiu_hid_t *hid) {
usleep(POLL_THREAD_SLEEP);
}
int32_t wiiu_attach_device(HIDClient *client, HIDDevice *device) {
wiiu_hid_user_t *adapter = new_wiiu_hid_user_t();
if(!adapter)
goto error;
error:
if(adapter) {
delete_wiiu_hid_user_t(adapter);
}
return DEVICE_UNUSED;
}
int32_t wiiu_detach_device(HIDClient *client, HIDDevice *device) {
return DEVICE_UNUSED;
}
/**
* Callbacks
*/
@ -228,10 +287,10 @@ int32_t wiiu_attach_callback(HIDClient *client, HIDDevice *device, uint32_t atta
switch(attach) {
case HID_DEVICE_ATTACH:
// TODO: new device attached! Register it.
result = wiiu_attach_device(client, device);
break;
case HID_DEVICE_DETACH:
// TODO: device detached! Unregister it.
result = wiiu_detach_device(client, device);
break;
default:
// Undefined behavior, bail out
@ -280,7 +339,7 @@ static void delete_wiiu_hid_t(wiiu_hid_t *hid) {
free(hid);
}
static HIDClient *new_hidclient() {
static HIDClient *new_hidclient(void) {
HIDClient *client = calloc(1, sizeof(HIDClient));
if(client != NULL) {
memset(client, 0, sizeof(HIDClient));
@ -289,6 +348,17 @@ static HIDClient *new_hidclient() {
return client;
}
static OSFastMutex *new_fastmutex(const char *name) {
OSFastMutex *mutex = calloc(1, sizeof(OSFastMutex));
if(mutex != NULL) {
memset(mutex, 0, sizeof(OSFastMutex));
}
OSFastMutex_Init(mutex, name);
return mutex;
}
static void delete_hidclient(HIDClient *client) {
if(client)
free(client);
@ -309,6 +379,11 @@ static void delete_wiiu_hid_user_t(wiiu_hid_user_t *user) {
}
}
static void delete_fastmutex(OSFastMutex *mutex) {
if(mutex)
free(mutex);
}
hid_driver_t wiiu_hid = {
wiiu_hid_init,
wiiu_hid_joypad_query,