From a4d8ce77533a5a90f84723561779b85cfa9c2d55 Mon Sep 17 00:00:00 2001 From: Nathan Strong Date: Sun, 3 Oct 2021 23:27:07 +0000 Subject: [PATCH] Try to support multi-pad HID devices == DETAILS I tried to modify the joypad connection interface to support multi-pad HID devices ... it doesn't work. I'm not sure why. --- input/connect/connect_nesusb.c | 2 + input/connect/connect_ps2adapter.c | 2 + input/connect/connect_ps3.c | 4 +- input/connect/connect_ps4.c | 4 +- input/connect/connect_ps4_hori_mini.c | 2 + input/connect/connect_psxadapter.c | 2 + input/connect/connect_retrode.c | 2 + input/connect/connect_snesusb.c | 2 + input/connect/connect_wii.c | 4 +- input/connect/connect_wiiugca.c | 249 +++++++++++++++++++----- input/connect/connect_wiiupro.c | 4 +- input/connect/joypad_connection.c | 174 ++++++++++++++--- input/connect/joypad_connection.h | 21 +- input/drivers_hid/wiiu_hid.c | 107 ++++++---- input/drivers_joypad/wiiu/kpad_driver.c | 2 +- input/drivers_joypad/wiiu/wpad_driver.c | 2 +- input/drivers_joypad/wiiu_joypad.c | 16 +- input/include/wiiu/hid.h | 3 +- input/include/wiiu/input.h | 1 - input/input_autodetect_builtin.c | 25 ++- 20 files changed, 492 insertions(+), 136 deletions(-) diff --git a/input/connect/connect_nesusb.c b/input/connect/connect_nesusb.c index cc557cee46..38493c4556 100644 --- a/input/connect/connect_nesusb.c +++ b/input/connect/connect_nesusb.c @@ -147,4 +147,6 @@ pad_connection_interface_t pad_connection_nesusb = { hidpad_nesusb_get_buttons, hidpad_nesusb_get_axis, hidpad_nesusb_get_name, + NULL, /* button */ + false, }; diff --git a/input/connect/connect_ps2adapter.c b/input/connect/connect_ps2adapter.c index 6a324b9491..74b1cd47be 100644 --- a/input/connect/connect_ps2adapter.c +++ b/input/connect/connect_ps2adapter.c @@ -182,4 +182,6 @@ pad_connection_interface_t pad_connection_ps2adapter = { hidpad_ps2adapter_get_buttons, hidpad_ps2adapter_get_axis, hidpad_ps2adapter_get_name, + NULL, + false, }; diff --git a/input/connect/connect_ps3.c b/input/connect/connect_ps3.c index 70aa6d3e0f..009c8c5b90 100644 --- a/input/connect/connect_ps3.c +++ b/input/connect/connect_ps3.c @@ -178,7 +178,6 @@ static void ds3_packet_handler(void *data, uint8_t *packet, uint16_t size) sizeof(instance->data), size); return; } - RARCH_LOG_BUFFER(packet, size); memcpy(instance->data, packet, size); ds3_update_pad_state(instance); @@ -275,5 +274,6 @@ pad_connection_interface_t pad_connection_ps3 = { ds3_get_buttons, ds3_get_axis, ds3_get_name, - ds3_button + ds3_button, + false, }; \ No newline at end of file diff --git a/input/connect/connect_ps4.c b/input/connect/connect_ps4.c index 31ccfe3f64..33e9ccc782 100644 --- a/input/connect/connect_ps4.c +++ b/input/connect/connect_ps4.c @@ -292,5 +292,7 @@ pad_connection_interface_t pad_connection_ps4 = { hidpad_ps4_set_rumble, hidpad_ps4_get_buttons, hidpad_ps4_get_axis, - NULL, + NULL, /* get_name */ + NULL, /* button */ + false }; diff --git a/input/connect/connect_ps4_hori_mini.c b/input/connect/connect_ps4_hori_mini.c index cd4e529622..ee38f5d73a 100644 --- a/input/connect/connect_ps4_hori_mini.c +++ b/input/connect/connect_ps4_hori_mini.c @@ -186,4 +186,6 @@ pad_connection_interface_t pad_connection_ps4_hori_mini = { hidpad_ps4_hori_mini_get_buttons, hidpad_ps4_hori_mini_get_axis, hidpad_ps4_hori_mini_get_name, + NULL, /* button */ + false }; diff --git a/input/connect/connect_psxadapter.c b/input/connect/connect_psxadapter.c index 27332a149f..89ec500e84 100644 --- a/input/connect/connect_psxadapter.c +++ b/input/connect/connect_psxadapter.c @@ -191,4 +191,6 @@ pad_connection_interface_t pad_connection_psxadapter = { hidpad_psxadapter_get_buttons, hidpad_psxadapter_get_axis, hidpad_psxadapter_get_name, + NULL, /* button */ + false }; diff --git a/input/connect/connect_retrode.c b/input/connect/connect_retrode.c index 58fc31f504..eaf5bd8d51 100644 --- a/input/connect/connect_retrode.c +++ b/input/connect/connect_retrode.c @@ -197,4 +197,6 @@ pad_connection_interface_t pad_connection_retrode = { hidpad_retrode_get_buttons, hidpad_retrode_get_axis, hidpad_retrode_get_name, + NULL, /* button */ + false, }; diff --git a/input/connect/connect_snesusb.c b/input/connect/connect_snesusb.c index 13bf4a0d14..7a452abe41 100644 --- a/input/connect/connect_snesusb.c +++ b/input/connect/connect_snesusb.c @@ -148,4 +148,6 @@ pad_connection_interface_t pad_connection_snesusb = { hidpad_snesusb_get_buttons, hidpad_snesusb_get_axis, hidpad_snesusb_get_name, + NULL, /* button */ + false }; diff --git a/input/connect/connect_wii.c b/input/connect/connect_wii.c index 7807be18d0..c3d5a5a783 100644 --- a/input/connect/connect_wii.c +++ b/input/connect/connect_wii.c @@ -729,5 +729,7 @@ pad_connection_interface_t pad_connection_wii = { hidpad_wii_set_rumble, hidpad_wii_get_buttons, hidpad_wii_get_axis, - NULL, + NULL, /* get_name */ + NULL, /* button */ + false, }; diff --git a/input/connect/connect_wiiugca.c b/input/connect/connect_wiiugca.c index 2988357b82..784bbc5d15 100644 --- a/input/connect/connect_wiiugca.c +++ b/input/connect/connect_wiiugca.c @@ -22,16 +22,39 @@ #include "joypad_connection.h" #include "../input_defines.h" +#define GCA_MAX_PAD 4 + +#define GCA_PORT_INITIALIZING 0x00 +#define GCA_PORT_POWERED 0x04 +#define GCA_PORT_CONNECTED 0x10 +#define GCA_WAVEBIRD_CONNECTED 0x22 + +typedef struct hidpad_wiiugca_pad_data gca_pad_data_t; +typedef struct hidpad_wiiugca_data gca_device_data_t; + +struct hidpad_wiiugca_pad_data +{ + gca_device_data_t *device_data; + joypad_connection_t *joypad; + int pad_index; + uint32_t buttons; + int16_t analog[3][2]; + uint8_t data[9]; +}; + struct hidpad_wiiugca_data { - struct pad_connection* connection; + void *handle; hid_driver_t *driver; - int pad_slots_map[4]; + char connected[GCA_MAX_PAD]; + gca_pad_data_t pad_data[GCA_MAX_PAD]; uint8_t data[64]; - uint32_t slot; - uint32_t buttons; }; +const char *GAMECUBE_PAD = "GameCube controller"; +const char *WAVEBIRD_PAD = "WaveBird controller"; +const char *DEVICE_NAME = "Wii U GC Controller Adapter"; + static void* hidpad_wiiugca_init(void *data, uint32_t slot, hid_driver_t *driver) { #ifdef WIIU @@ -39,70 +62,69 @@ static void* hidpad_wiiugca_init(void *data, uint32_t slot, hid_driver_t *driver #else static uint8_t magic_data[] = {0x01, 0x13}; /* Special command to enable reading */ #endif - struct pad_connection* connection = (struct pad_connection*)data; - struct hidpad_wiiugca_data* device = (struct hidpad_wiiugca_data*) - calloc(1, sizeof(struct hidpad_wiiugca_data)); + int i; + gca_device_data_t * device = (gca_device_data_t *)calloc(1, sizeof(gca_device_data_t)); if (!device) return NULL; - if (!connection) + if (!data) { free(device); return NULL; } - device->connection = connection; - device->slot = slot; + device->handle = data; + for(i = 0; i < GCA_MAX_PAD; i++) { + device->pad_data[i].device_data = device; + device->pad_data[i].joypad = NULL; + device->pad_data[i].pad_index = i; + } + device->driver = driver; - device->driver->send_control(device->connection, magic_data, sizeof(magic_data)); + device->driver->send_control(device->handle, magic_data, sizeof(magic_data)); return device; } -static void hidpad_wiiugca_deinit(void *data) +static void hidpad_wiiugca_deinit(void *device_data) { - struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data; + gca_device_data_t *device = (gca_device_data_t *)device_data; if (device) free(device); } -static void hidpad_wiiugca_get_buttons(void *data, input_bits_t *state) +static void hidpad_wiiugca_get_buttons(void *pad_data, input_bits_t *state) { - struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data; - if (device) - { - BITS_COPY16_PTR(state, device->buttons); - } - else - BIT256_CLEAR_ALL_PTR(state); + gca_pad_data_t *pad = (gca_pad_data_t *)pad_data; + if (pad) + { + BITS_COPY16_PTR(state, pad->buttons); + } + else + { + BIT256_CLEAR_ALL_PTR(state); + } } -static int16_t hidpad_wiiugca_get_axis(void *data, unsigned axis) +static int16_t hidpad_wiiugca_get_axis(void *pad_data, unsigned axis) { - int val; - struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data; + gca_pad_data_t *pad = (gca_pad_data_t *)pad_data; + axis_data axis_data; - if (!device || axis >= 4) + gamepad_read_axis_data(axis, &axis_data); + + if (!pad || axis_data.axis >= 4) return 0; - val = device->data[5 + axis]; - - if (axis % 2) /* the Y axis is inverted */ - val = 0x8000 - (val << 8); - else - val = (val << 8) - 0x8000; - - if (abs(val) > 0x1000) - return val; - return 0; + return gamepad_get_axis_value(pad->analog, &axis_data); } -static void hidpad_wiiugca_packet_handler(void *data, uint8_t *packet, uint16_t size) -{ +static void update_button_state(gca_pad_data_t *pad) { uint32_t i, pressed_keys; + static const uint32_t button_mapping[12] = { RETRO_DEVICE_ID_JOYPAD_A, @@ -118,20 +140,80 @@ static void hidpad_wiiugca_packet_handler(void *data, uint8_t *packet, uint16_t RETRO_DEVICE_ID_JOYPAD_R, RETRO_DEVICE_ID_JOYPAD_L, }; - struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data; + + if (!pad) + return; + + pressed_keys = pad->data[1] | (pad->data[2] << 8); + pad->buttons = 0; + + for (i = 0; i < 12; i++) + pad->buttons |= (pressed_keys & (1 << i)) ? + (1 << button_mapping[i]) : 0; +} + +static void update_analog_state(gca_pad_data_t *pad) { + int pad_axis; + int16_t interpolated; + unsigned stick, axis; + + /* GameCube analog axis are 8-bit unsigned, where 128/128 is center. + * So, we subtract 128 to get a signed, 0-based value and then mulitply + * by 256 to get the 16-bit range RetroArch expects. */ + for (pad_axis = 0; pad_axis < 4; pad_axis++) + { + axis = (pad_axis % 2) ? 0 : 1; + stick = pad_axis / 2; + interpolated = pad->data[3 + pad_axis]; + /* libretro requires "up" to be negative, so we invert the y axis */ + interpolated = (axis) ? + ((interpolated - 128) * 256) : + ((interpolated - 128) * -256); + + pad->analog[stick][axis] = interpolated; + } +} + +static void hidpad_wiiugca_pad_packet_handler(gca_pad_data_t *pad, uint8_t *packet, size_t size) { + if(size > 9) { + return; + } + + memcpy(pad->data, packet, size); + update_button_state(pad); + update_analog_state(pad); +} + + + +static void hidpad_wiiugca_packet_handler(void *device_data, uint8_t *packet, uint16_t size) +{ + uint32_t i; + int port; + unsigned char port_connected; + + gca_device_data_t *device = (gca_device_data_t *)device_data; if (!device) return; memcpy(device->data, packet, size); - device->buttons = 0; + for (i = 1; i < 37; i += 9) + { + port = i / 9; + port_connected = device->data[i]; - pressed_keys = device->data[3] | (device->data[4] << 8); - - for (i = 0; i < 12; i ++) - device->buttons |= (pressed_keys & (1 << i)) ? - (1 << button_mapping[i]) : 0; + if (port_connected > GCA_PORT_POWERED) + { + device->connected[port] = port_connected; + hidpad_wiiugca_pad_packet_handler(&device->pad_data[port], &device->data[i], 9); + } + else + { + device->connected[port] = 0; + } + } } static void hidpad_wiiugca_set_rumble(void *data, @@ -142,19 +224,78 @@ static void hidpad_wiiugca_set_rumble(void *data, (void)strength; } -const char *hidpad_wiiugca_get_name(void *data) +const char *hidpad_wiiugca_get_name(void *pad_data) { - (void)data; + gca_pad_data_t *pad = (gca_pad_data_t *)pad_data; + if(!pad) { + return DEVICE_NAME; + } + + switch(pad->device_data->connected[pad->pad_index]) { + case 0: + return DEVICE_NAME; + case GCA_WAVEBIRD_CONNECTED: + return WAVEBIRD_PAD; + default: + return GAMECUBE_PAD; + } + /* For now we return a single static name */ - return "Wii U GC Controller Adapter"; + } -static int32_t hidpad_wiiugca_button(void *data, uint16_t joykey) { - struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data; - if (!device || joykey > 31) +static int32_t hidpad_wiiugca_button(void *pad_data, uint16_t joykey) { + gca_pad_data_t *pad = (gca_pad_data_t *)pad_data; + if (!pad || !pad->device_data || joykey > 31 || pad->joypad == NULL) return 0; - return device->buttons & (1 << joykey); + return pad->buttons & (1 << joykey); +} + +static void *hidpad_wiiugca_pad_init(void *device_data, int pad_index, joypad_connection_t *joypad) { + gca_device_data_t *device = (gca_device_data_t *)device_data; + + if(!device || pad_index < 0 || pad_index >= GCA_MAX_PAD || joypad == NULL || device->pad_data[pad_index].joypad != NULL || !device->connected[pad_index]) { + return NULL; + } + + device->pad_data[pad_index].joypad = joypad; + return &device->pad_data[pad_index]; +} + +static void hidpad_wiiugca_pad_deinit(void *pad_data) { + gca_pad_data_t *pad = (gca_pad_data_t *)pad_data; + + if(!pad) { + return; + } + + pad->joypad = NULL; +} + +static int8_t hidpad_wiiugca_status(void *device_data, int pad_index) { + gca_device_data_t *device = (gca_device_data_t *)device_data; + int8_t result = 0; + + if(!device || pad_index < 0 || pad_index >= GCA_MAX_PAD) return 0; + + if(device->connected[pad_index]) { + result |= PAD_CONNECT_READY; + } + + if(device->pad_data[pad_index].joypad != NULL) { + result |= PAD_CONNECT_BOUND; + } + + return result; +} + +static joypad_connection_t *hidpad_wiiugca_joypad(void *device_data, int pad_index) { + gca_device_data_t *device = (gca_device_data_t *)device_data; + + if(!device || pad_index < 0 || pad_index >= GCA_MAX_PAD) return 0; + + return device->pad_data[pad_index].joypad; } pad_connection_interface_t pad_connection_wiiugca = { @@ -166,4 +307,10 @@ pad_connection_interface_t pad_connection_wiiugca = { hidpad_wiiugca_get_axis, hidpad_wiiugca_get_name, hidpad_wiiugca_button, + true, + GCA_MAX_PAD, + hidpad_wiiugca_pad_init, + hidpad_wiiugca_pad_deinit, + hidpad_wiiugca_status, + hidpad_wiiugca_joypad, }; diff --git a/input/connect/connect_wiiupro.c b/input/connect/connect_wiiupro.c index a6b1f11ff5..ff26bb5064 100644 --- a/input/connect/connect_wiiupro.c +++ b/input/connect/connect_wiiupro.c @@ -255,5 +255,7 @@ pad_connection_interface_t pad_connection_wiiupro = { hidpad_wiiupro_set_rumble, hidpad_wiiupro_get_buttons, hidpad_wiiupro_get_axis, - NULL, + NULL, /* get_name */ + NULL, /* button */ + false }; diff --git a/input/connect/joypad_connection.c b/input/connect/joypad_connection.c index 6148990019..1b6ad4c750 100644 --- a/input/connect/joypad_connection.c +++ b/input/connect/joypad_connection.c @@ -18,6 +18,7 @@ #include #include +#include "../tasks/tasks_internal.h" #include "../input_driver.h" #include "../../verbosity.h" @@ -164,45 +165,161 @@ joypad_connection_entry_t *find_connection_entry(int16_t vid, int16_t pid, const return NULL; } +void pad_connection_pad_deregister(joypad_connection_t *joyconn, pad_connection_interface_t *iface, void *pad_data) { + int i; + + RARCH_LOG("pad_connection_pad_deregister\n"); + for(i = 0; !joypad_is_end_of_list(&joyconn[i]); i++) { + RARCH_LOG("joyconn[i].connected = %d, joyconn[i].iface == iface = %d\n", joyconn[i].connected, joyconn[i].iface == iface); + if(joyconn[i].connected && joyconn[i].iface == iface) { + if(iface->set_rumble) { + RARCH_LOG("set_rumble"); + iface->set_rumble(joyconn[i].connection, RETRO_RUMBLE_STRONG, 0); + iface->set_rumble(joyconn[i].connection, RETRO_RUMBLE_WEAK, 0); + } + RARCH_LOG("deregistering pad"); + input_autoconfigure_disconnect(i, iface->get_name(joyconn[i].connection)); + if(iface->multi_pad) { + RARCH_LOG("multi-pad cleanup"); + iface->pad_deinit(&joyconn[i].connection); + } + RARCH_LOG("zeroing pad %d\n", i); + memset(&joyconn[i], 0, sizeof(joypad_connection_t)); + } + } +} + +static int joypad_to_slot(joypad_connection_t *haystack, joypad_connection_t *needle) { + int i; + + for(i = 0; !joypad_is_end_of_list(&haystack[i]); i++) { + if(&haystack[i] == needle) { + return i; + } + } + return -1; +} + +void pad_connection_pad_refresh(joypad_connection_t *joyconn, pad_connection_interface_t *iface, void *device_data, void *handle, input_device_driver_t *input_driver) { + int i, slot; + int8_t state; + joypad_connection_t *joypad; + + if(!iface->multi_pad || iface->max_pad < 1) { + return; + } + + for(i = 0; i < iface->max_pad; i++) { + state = iface->status(device_data, i); + switch(state) { + /* The pad slot is bound to a joypad that's no longer connected */ + case PAD_CONNECT_BOUND: + joypad = iface->joypad(device_data, i); + slot = joypad_to_slot(joyconn, joypad); + input_autoconfigure_disconnect(slot, iface->get_name(joypad->connection)); + + iface->pad_deinit(joypad->connection); + memset(joypad, 0, sizeof(joypad_connection_t)); + break; + /* The joypad is connected but has not been bound */ + case PAD_CONNECT_READY: + slot = pad_connection_find_vacant_pad(joyconn); + if(slot >= 0) { + joypad = &joyconn[slot]; + joypad->connection = iface->pad_init(device_data, i, joypad); + joypad->data = handle; + joypad->iface = iface; + joypad->input_driver = input_driver; + input_pad_connect(slot, input_driver); + } + break; + default: + break; + } + } +} + +void pad_connection_pad_register(joypad_connection_t *joyconn, pad_connection_interface_t *iface, void *device_data, void *handle, input_device_driver_t *input_driver, int slot) { + int i, status; + int found_slot; + int max_pad; + void *connection; + + if(iface->multi_pad && (iface->max_pad <= 1 || !iface->status || !iface->pad_init)) { + RARCH_ERR("pad_connection_pad_register: multi-pad driver has incomplete implementation\n"); + return; + } + + max_pad = iface->multi_pad ? iface->max_pad : 1; + + for(i = 0; i < max_pad; i++) { + status = iface->multi_pad ? iface->status(device_data, i) : PAD_CONNECT_READY; + RARCH_LOG("pad %d: status = %d\n", i, status); + if(status == PAD_CONNECT_READY) { + found_slot = (slot == SLOT_AUTO) ? pad_connection_find_vacant_pad(joyconn) : slot; + if(found_slot < 0) { + continue; + } + connection = device_data; + if(iface->multi_pad) { + RARCH_LOG("pad_connection_pad_register: multi-pad detected, initializing pad %d\n", i); + connection = iface->pad_init(device_data, i, &joyconn[found_slot]); + } + + joyconn[found_slot].iface = iface; + joyconn[found_slot].data = handle; + joyconn[found_slot].connection = connection; + joyconn[found_slot].input_driver = input_driver; + joyconn[found_slot].connected = true; + + RARCH_LOG("connecting pad to slot %d\n", found_slot); + input_pad_connect(found_slot, input_driver); + } + } +} + +int32_t pad_connection_pad_init_entry(joypad_connection_t *joyconn, joypad_connection_entry_t *entry, void *data, hid_driver_t *driver) { + joypad_connection_t *conn = NULL; + int pad = pad_connection_find_vacant_pad(joyconn); + + if(pad < 0) { + return -1; + } + + conn = &joyconn[pad]; + if(!conn) { + return -1; + } + + if(entry) { + conn->iface = entry->iface; + conn->data = data; + conn->connection = conn->iface->init(data, pad, driver); + conn->connected = true; + } else { + /* We failed to find a matching pad, set up one without an interface */ + RARCH_DBG("Pad was not matched. Setting up without an interface.\n"); + conn->iface = NULL; + conn->data = data; + conn->connected = true; + } + + return pad; +} + int32_t pad_connection_pad_init(joypad_connection_t *joyconn, const char *name, uint16_t vid, uint16_t pid, void *data, hid_driver_t *driver) { joypad_connection_entry_t *entry = NULL; - joypad_connection_t *s = NULL; - int pad = -1; if(pad_map[0].vid == 0) { init_pad_map(); } - entry = find_connection_entry(vid, pid, name); - pad = pad_connection_find_vacant_pad(joyconn); + entry = find_connection_entry(vid, pid, name); - if (pad == -1) - return -1; - - s = &joyconn[pad]; - - if (s) - { - if(entry) { - RARCH_DBG("Pad was matched to \"%s\". Setting up an interface.\n", entry->name); - s->iface = entry->iface; - s->data = data; - s->connection = s->iface->init(data, pad, driver); - s->connected = true; - } else { - /* We failed to find a matching pad, - * set up one without an interface */ - RARCH_DBG("Pad was not matched. Setting up without an interface.\n"); - s->iface = NULL; - s->data = data; - s->connected = true; - } - } - - return pad; + return pad_connection_pad_init_entry(joyconn, entry, data, driver); } void pad_connection_pad_deinit(joypad_connection_t *joyconn, uint32_t pad) @@ -212,6 +329,7 @@ void pad_connection_pad_deinit(joypad_connection_t *joyconn, uint32_t pad) if (joyconn->iface) { + joyconn->iface->set_rumble(joyconn->connection, RETRO_RUMBLE_STRONG, 0); joyconn->iface->set_rumble(joyconn->connection, RETRO_RUMBLE_WEAK, 0); diff --git a/input/connect/joypad_connection.h b/input/connect/joypad_connection.h index 45b9808b4b..8149205132 100644 --- a/input/connect/joypad_connection.h +++ b/input/connect/joypad_connection.h @@ -58,11 +58,19 @@ struct joypad_connection { struct pad_connection_interface *iface; + input_device_driver_t *input_driver; void* data; void* connection; bool connected; }; +#define PAD_CONNECT_OFFLINE 0x00 /* the pad is offline and cannot be used */ +#define PAD_CONNECT_READY 0x01 /* the pad is ready but is not bound to a RA slot */ +#define PAD_CONNECT_BOUND 0x02 /* the pad is offline and is bound to a RA slot */ +#define PAD_CONNECT_IN_USE 0x03 /* the pad is ready and is bound to a RA slot */ + +#define SLOT_AUTO -1 + typedef struct pad_connection_interface { void* (*init)(void *data, uint32_t slot, hid_driver_t *driver); @@ -74,6 +82,14 @@ typedef struct pad_connection_interface int16_t (*get_axis)(void *data, unsigned axis); const char* (*get_name)(void *data); int32_t (*button)(void *data, uint16_t joykey); + /* all fields/methods below this point are only required for multi-pad devices */ + bool multi_pad; /* does the device provide multiple pads? */ + int8_t max_pad; /* number of pads this device can provide */ + void* (*pad_init)(void *data, int pad_index, joypad_connection_t *joyconn); + void (*pad_deinit)(void *pad_data); + /* pad_index is a number from 0 to max_pad-1 */ + int8_t (*status)(void *data, int pad_index); /* returns a PAD_CONNECT_* state */ + joypad_connection_t* (*joypad)(void *device_data, int pad_index); } pad_connection_interface_t; typedef struct joypad_connection_entry { @@ -130,5 +146,8 @@ const char* pad_connection_get_name(joypad_connection_t *joyconn, unsigned idx); joypad_connection_entry_t *find_connection_entry(int16_t vid, int16_t pid, const char *name); - +int32_t pad_connection_pad_init_entry(joypad_connection_t *joyconn, joypad_connection_entry_t *entry, void *data, hid_driver_t *driver); +void pad_connection_pad_register(joypad_connection_t *joyconn, pad_connection_interface_t *iface, void *pad_data, void *handle, input_device_driver_t *input_driver, int slot); +void pad_connection_pad_deregister(joypad_connection_t *joyconn, pad_connection_interface_t *iface, void *pad_data); +void pad_connection_pad_refresh(joypad_connection_t *joyconn, pad_connection_interface_t *iface, void *device_data, void *handle, input_device_driver_t *input_driver); #endif diff --git a/input/drivers_hid/wiiu_hid.c b/input/drivers_hid/wiiu_hid.c index ae94ee7214..7bc1c3dcfd 100644 --- a/input/drivers_hid/wiiu_hid.c +++ b/input/drivers_hid/wiiu_hid.c @@ -16,6 +16,7 @@ #include "../include/wiiu/hid.h" #include +#include /* TODO/FIXME - static globals */ static wiiu_event_list events; @@ -367,20 +368,48 @@ static void log_device(HIDDevice *device) RARCH_LOG(" max_packet_size_tx: %d\n", device->max_packet_size_tx); } +static uint8_t try_init_driver_multi(wiiu_adapter_t *adapter, joypad_connection_entry_t *entry) { + adapter->pad_driver_data = entry->iface->init(adapter, -1, &wiiu_hid); + if(!adapter->pad_driver_data) { + return ADAPTER_STATE_DONE; + } + + pad_connection_pad_register(joypad_state.pads, adapter->pad_driver, adapter->pad_driver_data, adapter, &hidpad_driver, SLOT_AUTO); + return ADAPTER_STATE_READY; +} static uint8_t try_init_driver(wiiu_adapter_t *adapter) { - RARCH_LOG("Trying to find pad driver for vid 0x%04x pid 0x%04x\n", adapter->vendor_id, adapter->product_id); - int32_t pad = pad_connection_pad_init(joypad_state.pads, &adapter->device_name[0], adapter->vendor_id, adapter->product_id, adapter, &wiiu_hid); - if(pad >= 0) { - RARCH_LOG("Attached to pad %d\n", pad); - joypad_state.pad_drivers[pad] = &hidpad_driver; - adapter->pad = pad; - input_pad_connect(pad, &hidpad_driver); - return ADAPTER_STATE_READY; + joypad_connection_entry_t *entry; + int slot; + + entry = find_connection_entry(adapter->vendor_id, adapter->product_id, adapter->device_name); + if(!entry) { + RARCH_LOG("Failed to find entry for vid: 0x%x, pid: 0x%x, name: %s\n", adapter->vendor_id, adapter->product_id, adapter->device_name); + return ADAPTER_STATE_DONE; } - RARCH_LOG("Failed to find pad driver\n"); - return ADAPTER_STATE_DONE; + + adapter->pad_driver = entry->iface; + + if(entry->iface->multi_pad) { + return try_init_driver_multi(adapter, entry); + } + slot = pad_connection_find_vacant_pad(joypad_state.pads); + if(slot < 0) { + RARCH_LOG("try_init_driver: no slot available\n"); + return ADAPTER_STATE_DONE; + } + + adapter->pad_driver_data = entry->iface->init(adapter, slot, &wiiu_hid); + if(!adapter->pad_driver_data) { + RARCH_LOG("try_init_driver: pad init failed\n"); + return ADAPTER_STATE_DONE; + } + + RARCH_LOG("driver initialized, registering pad\n"); + pad_connection_pad_register(joypad_state.pads, adapter->pad_driver, adapter->pad_driver_data, adapter, &hidpad_driver, slot); + + return ADAPTER_STATE_READY; } static void synchronized_process_adapters(wiiu_hid_t *hid) @@ -401,25 +430,32 @@ static void synchronized_process_adapters(wiiu_hid_t *hid) adapter->state = try_init_driver(adapter); break; case ADAPTER_STATE_READY: + RARCH_LOG("ADAPTER_STATE_READY"); + if(adapter->pad_driver && adapter->pad_driver->multi_pad) { + pad_connection_pad_refresh(joypad_state.pads, adapter->pad_driver, adapter->pad_driver_data, adapter, &hidpad_driver); + } + break; case ADAPTER_STATE_READING: + RARCH_LOG("ADAPTER_STATE_READING"); + break; case ADAPTER_STATE_DONE: + RARCH_LOG("ADAPTER_STATE_DONE"); break; case ADAPTER_STATE_GC: - { - const char *pad_name = joypad_state.pads[adapter->pad].iface->get_name(joypad_state.pads[adapter->pad].connection); - /* remove from the list */ - if (!prev) - adapters.list = adapter->next; - else - prev->next = adapter->next; - - input_autoconfigure_disconnect(adapter->pad, pad_name); - pad_connection_pad_deinit(&joypad_state.pads[adapter->pad], adapter->pad); - /* adapter is no longer valid after this point */ - delete_adapter(adapter); - /* signal not to update prev ptr since adapter is now invalid */ - keep_prev = true; - } + { + RARCH_LOG("ADAPTER_STATE_GC"); + /* remove from the list */ + if (!prev) + adapters.list = adapter->next; + else + prev->next = adapter->next; + + pad_connection_pad_deregister(joypad_state.pads, adapter->pad_driver, adapter->pad_driver_data); + /* adapter is no longer valid after this point */ + delete_adapter(adapter); + /* signal not to update prev ptr since adapter is now invalid */ + keep_prev = true; + } break; default: @@ -554,9 +590,7 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, if (error == 0) { - joypad_state.pads[adapter->pad].iface->packet_handler( - joypad_state.pads[adapter->pad].connection, buffer, buffer_size - ); + adapter->pad_driver->packet_handler(adapter->pad_driver_data, buffer, buffer_size); } } } @@ -568,8 +602,7 @@ static void report_hid_error(const char *msg, wiiu_adapter_t *adapter, int32_t e int16_t hid_error_code = error & 0xffff; int16_t error_category = (error >> 16) & 0xffff; - const char *device = (adapter && adapter->pad >= 0) ? - joypad_state.pads[adapter->pad].iface->get_name(joypad_state.pads[adapter->pad].connection) : "unknown"; + const char *device = string_is_empty(adapter->device_name) ? "unknown" : adapter->device_name; switch(hid_error_code) { @@ -648,6 +681,7 @@ static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack) RARCH_LOG("[hid]: shutting down adapter..\n"); adapter = adapters.list; adapters.list = adapter->next; + pad_connection_pad_deregister(joypad_state.pads, adapter->pad_driver, adapter->pad_driver_data); delete_adapter(adapter); } } @@ -705,7 +739,7 @@ static void wiiu_poll_adapters(wiiu_hid_t *hid) wiiu_poll_adapter(it); if (it->state == ADAPTER_STATE_DONE) { - + RARCH_LOG("poll_adapters: read done, ready for garbage collection"); it->state = ADAPTER_STATE_GC; } } @@ -818,13 +852,10 @@ static void delete_adapter(wiiu_adapter_t *adapter) free(adapter->tx_buffer); adapter->tx_buffer = NULL; } - if(adapter->pad >= 0 && - joypad_state.pads[adapter->pad].iface && - joypad_state.pads[adapter->pad].connection) { - joypad_state.pads[adapter->pad].iface->deinit(joypad_state.pads[adapter->pad].connection); - joypad_state.pads[adapter->pad].connection = NULL; - joypad_state.pads[adapter->pad].iface = NULL; - } + if(adapter->pad_driver && adapter->pad_driver_data) { + adapter->pad_driver->deinit(adapter->pad_driver_data); + adapter->pad_driver_data = NULL; + } free(adapter); } diff --git a/input/drivers_joypad/wiiu/kpad_driver.c b/input/drivers_joypad/wiiu/kpad_driver.c index 2f07f56fa5..a7fd8c02c7 100644 --- a/input/drivers_joypad/wiiu/kpad_driver.c +++ b/input/drivers_joypad/wiiu/kpad_driver.c @@ -158,7 +158,7 @@ static void kpad_register(unsigned channel, uint8_t device_type) } joypad_state.kpad.wiimotes[channel].type = device_type; - joypad_state.pad_drivers[slot] = &kpad_driver; + joypad_state.pads[slot].input_driver = &kpad_driver; input_pad_connect(slot, &kpad_driver); } } diff --git a/input/drivers_joypad/wiiu/wpad_driver.c b/input/drivers_joypad/wiiu/wpad_driver.c index 8f1b0b316b..4e30022a15 100644 --- a/input/drivers_joypad/wiiu/wpad_driver.c +++ b/input/drivers_joypad/wiiu/wpad_driver.c @@ -85,7 +85,7 @@ static void wpad_register(unsigned channel) return; joypad_state.pads[slot].connected = true; - joypad_state.pad_drivers[slot] = &wpad_driver; + joypad_state.pads[slot].input_driver = &wpad_driver; input_pad_connect(slot, &wpad_driver); joypad_state.wpad.channel_slot_map[channel] = slot; } diff --git a/input/drivers_joypad/wiiu_joypad.c b/input/drivers_joypad/wiiu_joypad.c index 60c720ac7b..9628e0d6fa 100644 --- a/input/drivers_joypad/wiiu_joypad.c +++ b/input/drivers_joypad/wiiu_joypad.c @@ -40,8 +40,8 @@ static bool wiiu_joypad_query_pad(unsigned pad) { return ready && pad < MAX_USERS && - joypad_state.pad_drivers[pad] && - joypad_state.pad_drivers[pad]->query_pad(pad); + joypad_state.pads[pad].input_driver && + joypad_state.pads[pad].input_driver->query_pad(pad); } static void wiiu_joypad_destroy(void) @@ -59,21 +59,21 @@ static int32_t wiiu_joypad_button(unsigned port, uint16_t joykey) return 0; if (port >= DEFAULT_MAX_PADS) return 0; - return (joypad_state.pad_drivers[port]->button(port, joykey)); + return (joypad_state.pads[port].input_driver->button(port, joykey)); } static void wiiu_joypad_get_buttons(unsigned port, input_bits_t *state) { if (!wiiu_joypad_query_pad(port)) return; - joypad_state.pad_drivers[port]->get_buttons(port, state); + joypad_state.pads[port].input_driver->get_buttons(port, state); } static int16_t wiiu_joypad_axis(unsigned port, uint32_t joyaxis) { if (!wiiu_joypad_query_pad(port)) return 0; - return joypad_state.pad_drivers[port]->axis(port, joyaxis); + return joypad_state.pads[port].input_driver->axis(port, joyaxis); } static int16_t wiiu_joypad_state( @@ -99,11 +99,11 @@ static int16_t wiiu_joypad_state( ? binds[i].joyaxis : joypad_info->auto_binds[i].joyaxis; if ( (uint16_t)joykey != NO_BTN - && (joypad_state.pad_drivers[port]->button(port_idx, (uint16_t)joykey)) + && (joypad_state.pads[port].input_driver->button(port_idx, (uint16_t)joykey)) ) ret |= ( 1 << i); else if (joyaxis != AXIS_NONE && - ((float)abs(joypad_state.pad_drivers[port]->axis(port_idx, joyaxis)) + ((float)abs(joypad_state.pads[port].input_driver->axis(port_idx, joyaxis)) / 0x8000) > joypad_info->axis_threshold) ret |= (1 << i); } @@ -123,7 +123,7 @@ static const char* wiiu_joypad_name(unsigned pad) if (!wiiu_joypad_query_pad(pad)) return "N/A"; - return joypad_state.pad_drivers[pad]->name(pad); + return joypad_state.pads[pad].input_driver->name(pad); } input_device_driver_t wiiu_joypad = diff --git a/input/include/wiiu/hid.h b/input/include/wiiu/hid.h index fc8142028c..92c82a4344 100644 --- a/input/include/wiiu/hid.h +++ b/input/include/wiiu/hid.h @@ -51,7 +51,8 @@ struct wiiu_hid { */ struct wiiu_adapter { wiiu_adapter_t *next; - int pad; + pad_connection_interface_t *pad_driver; + void *pad_driver_data; wiiu_hid_t *hid; uint16_t vendor_id; uint16_t product_id; diff --git a/input/include/wiiu/input.h b/input/include/wiiu/input.h index 6bb20f06ae..e07ebc2508 100644 --- a/input/include/wiiu/input.h +++ b/input/include/wiiu/input.h @@ -94,7 +94,6 @@ typedef struct wiiu_hidpad { typedef struct wiiu_joypad { joypad_connection_t pads[MAX_USERS]; - input_device_driver_t *pad_drivers[MAX_USERS]; int max_slot; wiiu_kpad_t kpad; diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 7636821d77..2276886b9f 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -304,6 +304,28 @@ DECL_AXIS_EX(r_x_minus, -2, "C-stick left") \ DECL_AXIS_EX(r_y_plus, +3, "C-stick up") \ DECL_AXIS_EX(r_y_minus, -3, "C-stick down") +#define WIIUINPUT_WAVEBIRD_DEFAULT_BINDS \ +DECL_BTN_EX(a, 8, "A") \ +DECL_BTN_EX(b, 0, "B") \ +DECL_BTN_EX(x, 9, "X") \ +DECL_BTN_EX(y, 1, "Y") \ +DECL_BTN_EX(left, 6, "D-Pad Left") \ +DECL_BTN_EX(right, 7, "D-Pad Right") \ +DECL_BTN_EX(down, 5, "D-Pad Down") \ +DECL_BTN_EX(up, 4, "D-Pad Up") \ +DECL_BTN_EX(start, 3, "Start/Pause") \ +DECL_BTN_EX(select, 2, "Z") \ +DECL_BTN_EX(r, 10, "R Trigger") \ +DECL_BTN_EX(l, 11, "L Trigger") \ +DECL_AXIS_EX(l_x_plus, +0, "Analog right") \ +DECL_AXIS_EX(l_x_minus, -0, "Analog left") \ +DECL_AXIS_EX(l_y_plus, +1, "Analog up") \ +DECL_AXIS_EX(l_y_minus, -1, "Analog down") \ +DECL_AXIS_EX(r_x_plus, +2, "C-stick right") \ +DECL_AXIS_EX(r_x_minus, -2, "C-stick left") \ +DECL_AXIS_EX(r_y_plus, +3, "C-stick up") \ +DECL_AXIS_EX(r_y_minus, -3, "C-stick down") + #define WIIUINPUT_DS3_DEFAULT_BINDS \ DECL_BTN_EX(menu_toggle, 16, "Playstation") \ DECL_BTN_EX(select, 2, "Select") \ @@ -743,7 +765,8 @@ const char* const input_builtin_autoconfs[] = DECL_AUTOCONF_DEVICE(PAD_NAME_NUNCHUK, "wiiu", WIIUINPUT_NUNCHUK_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE(PAD_NAME_CLASSIC, "wiiu", WIIUINPUT_CLASSIC_CONTROLLER_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE(PAD_NAME_HID, "wiiu", WIIUINPUT_GAMEPAD_DEFAULT_BINDS), - DECL_AUTOCONF_DEVICE("Wii U GC Controller Adapter", "wiiu", WIIUINPUT_GAMECUBE_DEFAULT_BINDS), + DECL_AUTOCONF_DEVICE("GameCube controller", "wiiu", WIIUINPUT_GAMECUBE_DEFAULT_BINDS), + DECL_AUTOCONF_DEVICE("WaveBird controller", "wiiu", WIIUINPUT_WAVEBIRD_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE("PLAYSTATION(R)3 Controller", "wiiu", WIIUINPUT_DS3_DEFAULT_BINDS), #endif #ifdef __PS3__