1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-08 20:25:47 +00:00

Finish HID implementation for WiiU GCA adapter

== DETAILS

(I think)

- Uncomment the call in the read loop to start feeding packets to the
  driver
- implement the GCA packet driver
- implement the pad interface
- fix indentations in GCA driver

== TESTING
Compiles. Haven't tested yet.
This commit is contained in:
gblues 2018-03-25 22:59:30 -07:00
parent 180d6a28bf
commit 8a4c5086fb
3 changed files with 213 additions and 41 deletions

View File

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "hid_device_driver.h"
#ifdef WII
@ -33,35 +33,44 @@ typedef struct wiiu_gca_instance {
joypad_connection_t *pads[4];
} wiiu_gca_instance_t;
typedef struct gca_pad_data
{
void *gca_handle; // instance handle for the GCA adapter
hid_driver_t *driver; // HID system driver interface
uint8_t data[9]; // pad data
uint32_t slot; // slot this pad occupies
uint32_t buttons; // digital button state
char *name; // name of the pad
} gca_pad_t;
static void update_pad_state(wiiu_gca_instance_t *instance);
static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance);
static void unregister_pad(wiiu_gca_instance_t *instance, int slot);
static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port);
static void unregister_pad(wiiu_gca_instance_t *instance, int port);
static void set_pad_name_for_port(gca_pad_t *pad, int port);
extern pad_connection_interface_t wiiu_gca_pad_connection;
static void *wiiu_gca_init(void *handle)
{
RARCH_LOG("[gca]: allocating driver instance...\n");
wiiu_gca_instance_t *instance = calloc(1, sizeof(wiiu_gca_instance_t));
if(instance == NULL) goto error;
RARCH_LOG("[gca]: zeroing memory...\n");
memset(instance, 0, sizeof(wiiu_gca_instance_t));
instance->handle = handle;
RARCH_LOG("[gca]: allocating driver instance...\n");
wiiu_gca_instance_t *instance = calloc(1, sizeof(wiiu_gca_instance_t));
if(instance == NULL) goto error;
memset(instance, 0, sizeof(wiiu_gca_instance_t));
instance->handle = handle;
RARCH_LOG("[gca]: sending activation packet to device...\n");
hid_instance.os_driver->send_control(handle, activation_packet, sizeof(activation_packet));
RARCH_LOG("[gca]: reading initial state packet...\n");
hid_instance.os_driver->read(handle, instance->device_state, sizeof(instance->device_state));
instance->online = true;
hid_instance.os_driver->send_control(handle, activation_packet, sizeof(activation_packet));
hid_instance.os_driver->read(handle, instance->device_state, sizeof(instance->device_state));
instance->online = true;
RARCH_LOG("[gca]: init done\n");
return instance;
RARCH_LOG("[gca]: init done\n");
return instance;
error:
RARCH_ERR("[gca]: init failed\n");
if(instance)
free(instance);
return NULL;
error:
RARCH_ERR("[gca]: init failed\n");
if(instance)
free(instance);
return NULL;
}
static void wiiu_gca_free(void *data) {
@ -72,50 +81,90 @@ static void wiiu_gca_free(void *data) {
instance->online = false;
for(i = 0; i < 4; i++)
unregister_pad(instance, i);
unregister_pad(instance, i);
free(instance);
}
}
}
static void wiiu_gca_handle_packet(void *data, uint8_t *buffer, size_t size)
{
wiiu_gca_instance_t *instance = (wiiu_gca_instance_t *)data;
if(!instance || !instance->online)
return;
wiiu_gca_instance_t *instance = (wiiu_gca_instance_t *)data;
if(!instance || !instance->online)
return;
if(size > sizeof(instance->device_state))
return;
if(size > sizeof(instance->device_state))
return;
memcpy(instance->device_state, buffer, size);
update_pad_state(instance);
memcpy(instance->device_state, buffer, size);
update_pad_state(instance);
}
static void update_pad_state(wiiu_gca_instance_t *instance)
{
int i, pad;
int i, port;
if(!instance || !instance->online)
return;
joypad_connection_t *pad;
/* process each pad */
for(i = 1; i < 37; i += 9)
{
pad = i / 9;
port = i / 9;
pad = instance->pads[port];
switch(instance->device_state[i])
{
case GCA_PORT_INITIALIZING:
case GCA_PORT_EMPTY:
if(instance->pads[pad] != NULL)
unregister_pad(instance, pad);
if(pad != NULL) {
RARCH_LOG("[gca]: Gamepad at port %d disconnected.\n", port+1);
unregister_pad(instance, port);
}
break;
case GCA_PORT_CONNECTED:
if(instance->pads[pad] == NULL)
instance->pads[pad] = register_pad(instance);
if(pad == NULL)
{
RARCH_LOG("[gca]: Gamepad at port %d connected.\n", port+1);
instance->pads[port] = register_pad(instance, port);
pad = instance->pads[port];
if(pad == NULL)
{
RARCH_ERR("[gca]: Failed to register pad.\n");
break;
}
}
pad->iface->packet_handler(pad->data, &instance->device_state[i], 9);
break;
}
}
}
static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance) {
/**
* This is kind of cheating because it's taking advantage of the fact that
* we know what the pad handle data format is. It'd be nice if the pad
* interface had a set_name function so this wouldn't be required.
*/
static void set_pad_name_for_port(gca_pad_t *pad, int port)
{
char buf[45];
if(port >= 4)
return;
snprintf(buf, 32, "Nintendo Gamecube Controller [GCA Port %d]", port);
if(pad->name)
{
free(pad->name);
pad->name = NULL;
}
pad->name = strdup(buf);
}
static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port) {
int slot;
joypad_connection_t *result;
@ -129,6 +178,7 @@ static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance) {
result = &(hid_instance.pad_list[slot]);
result->iface = &wiiu_gca_pad_connection;
result->data = result->iface->init(instance, slot, hid_instance.os_driver);
set_pad_name_for_port(result->data, port);
result->connected = true;
input_pad_connect(slot, hid_instance.pad_driver);
@ -159,8 +209,129 @@ hid_device_t wiiu_gca_hid_device = {
"Wii U Gamecube Adapter"
};
/**
* Pad connection interface implementation. This handles each individual
* GC controller (as opposed to the above that handles the GCA itself).
*/
static void *wiiu_gca_pad_init(void *data, uint32_t slot, hid_driver_t *driver)
{
gca_pad_t *pad = (gca_pad_t *)calloc(1, sizeof(gca_pad_t));
if(!pad)
return NULL;
memset(pad, 0, sizeof(gca_pad_t));
pad->gca_handle = data;
pad->driver = driver;
pad->slot = slot;
return pad;
}
static void wiiu_gca_pad_deinit(void *data)
{
gca_pad_t *pad = (gca_pad_t *)data;
if(pad)
{
if(pad->name)
free(pad->name);
free(pad);
}
}
static void wiiu_gca_get_buttons(void *data, retro_bits_t *state)
{
gca_pad_t *pad = (gca_pad_t *)data;
if(pad)
{
BITS_COPY16_PTR(state, pad->buttons);
} else {
BIT256_CLEAR_ALL_PTR(state);
}
}
static void wiiu_gca_packet_handler(void *data, uint8_t *packet, uint16_t size)
{
gca_pad_t *pad = (gca_pad_t *)data;
uint32_t i, pressed_keys;
static const uint32_t button_mapping[12] =
{
RETRO_DEVICE_ID_JOYPAD_A,
RETRO_DEVICE_ID_JOYPAD_B,
RETRO_DEVICE_ID_JOYPAD_X,
RETRO_DEVICE_ID_JOYPAD_Y,
RETRO_DEVICE_ID_JOYPAD_LEFT,
RETRO_DEVICE_ID_JOYPAD_RIGHT,
RETRO_DEVICE_ID_JOYPAD_DOWN,
RETRO_DEVICE_ID_JOYPAD_UP,
RETRO_DEVICE_ID_JOYPAD_START,
RETRO_DEVICE_ID_JOYPAD_SELECT,
RETRO_DEVICE_ID_JOYPAD_R,
RETRO_DEVICE_ID_JOYPAD_L,
};
if(!pad || !packet || size > sizeof(pad->data))
return;
memcpy(pad->data, packet, size);
pad->buttons = 0;
pressed_keys = pad->data[3] | (pad->data[4] << 8);
for(i = 0; i < 12; i++)
{
pad->buttons |= (pressed_keys & (1 << i)) ?
(1 << button_mapping[i]) : 0;
}
}
static void wiiu_gca_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength)
{
(void)data;
(void)effect;
(void)strength;
}
static int16_t wiiu_gca_get_axis(void *data, unsigned axis)
{
int16_t val;
gca_pad_t *pad = (gca_pad_t *)data;
if(!pad || axis >= 4)
return 0;
val = pad->data[5+axis];
switch(axis)
{
/* The Y axes are inverted. */
case 0: /* left Y */
case 2: /* right Y */
val = 0x8000 - (val << 8);
break;
default:
val = (val << 8) - 0x8000;
break;
}
if(val > 0x1000 || val < -0x1000)
return 0;
return val;
}
const char *wiiu_gca_get_name(void *data)
{
gca_pad_t *pad = (gca_pad_t *)data;
return pad->name;
}
pad_connection_interface_t wiiu_gca_pad_connection = {
/*
wiiu_gca_pad_init,
wiiu_gca_pad_deinit,
wiiu_gca_packet_handler,
@ -168,5 +339,4 @@ pad_connection_interface_t wiiu_gca_pad_connection = {
wiiu_gca_get_buttons,
wiiu_gca_get_axis,
wiiu_gca_get_name
*/
};

View File

@ -33,7 +33,11 @@
#include "wiiu_dbg.h"
#ifdef WIIU_HID
#define MAX_PADS 16
#else
#define MAX_PADS 5
#endif
static uint8_t keyboardChannel = 0x00;
static bool keyboardState[RETROK_LAST] = { 0 };

View File

@ -555,9 +555,7 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error,
int16_t r2 = ((error & 0xFFFF0000) >> 16);
RARCH_ERR("[hid]: read failed: %08x (%d:%d)\n", error, r2, r1);
} else {
#if 0
adapter->driver->handle_packet(adapter->driver_handle, buffer, buffer_size);
#endif
}
}