From ae19eed00f0aaff0bea6af7ed9d4c6fe1f50cf67 Mon Sep 17 00:00:00 2001 From: gblues Date: Mon, 5 Feb 2018 23:21:00 -0800 Subject: [PATCH 01/31] implement hid device search --- Makefile.wiiu | 8 +++++-- input/common/hid/device_ds3.c | 26 ++++++++++++++++++++ input/common/hid/device_ds4.c | 26 ++++++++++++++++++++ input/common/hid/device_wiiu_gca.c | 25 +++++++++++++++++++ input/common/hid/hid_device_driver.c | 36 ++++++++++++++++++++++++++++ input/common/hid/hid_device_driver.h | 32 +++++++++++++++++++++++++ wiiu/include/wiiu/pad_driver.h | 2 ++ wiiu/input/wiiu_hid.c | 8 +++++++ 8 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 input/common/hid/device_ds3.c create mode 100644 input/common/hid/device_ds4.c create mode 100644 input/common/hid/device_wiiu_gca.c create mode 100644 input/common/hid/hid_device_driver.c create mode 100644 input/common/hid/hid_device_driver.h diff --git a/Makefile.wiiu b/Makefile.wiiu index 4b5eeafc02..798028e5de 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -6,7 +6,7 @@ DEBUG = 0 GRIFFIN_BUILD = 0 SALAMANDER_BUILD = 0 WHOLE_ARCHIVE_LINK = 0 -WIIU_HID = 0 +WIIU_HID = 1 WIIU_LOG_RPX = 0 BUILD_DIR = objs/wiiu PC_DEVELOPMENT_IP_ADDRESS ?= @@ -56,7 +56,11 @@ ifeq ($(WIIU_HID),1) input/connect/connect_nesusb.o \ input/connect/connect_snesusb.o \ input/connect/connect_wiiupro.o \ - input/connect/connect_wiiugca.o + input/connect/connect_wiiugca.o \ + input/common/hid/hid_device_driver.o \ + input/common/hid/device_wiiu_gca.o \ + input/common/hid/device_ds3.o \ + input/common/hid/device_ds4.o endif ifeq ($(SALAMANDER_BUILD),1) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c new file mode 100644 index 0000000000..04325ace7b --- /dev/null +++ b/input/common/hid/device_ds3.c @@ -0,0 +1,26 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "hid_device_driver.h" + +static bool ds3_detect(uint16_t vendor_id, uint16_t product_id) +{ + return false; +} + +hid_device_t ds3_hid_device = { + ds3_detect +}; diff --git a/input/common/hid/device_ds4.c b/input/common/hid/device_ds4.c new file mode 100644 index 0000000000..0f049e5cbc --- /dev/null +++ b/input/common/hid/device_ds4.c @@ -0,0 +1,26 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "hid_device_driver.h" + +static bool ds4_detect(uint16_t vendor_id, uint16_t product_id) +{ + return false; +} + +hid_device_t ds4_hid_device = { + ds4_detect +}; diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c new file mode 100644 index 0000000000..0829a22ac1 --- /dev/null +++ b/input/common/hid/device_wiiu_gca.c @@ -0,0 +1,25 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "hid_device_driver.h" + +static bool wiiu_gca_detect(uint16_t vendor_id, uint16_t product_id) { + return false; +} + +hid_device_t wiiu_gca_hid_device = { + wiiu_gca_detect +}; diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c new file mode 100644 index 0000000000..0f049ca728 --- /dev/null +++ b/input/common/hid/hid_device_driver.c @@ -0,0 +1,36 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "hid_device_driver.h" + +hid_device_t *hid_device_list[] = { + &wiiu_gca_hid_device, + &ds3_hid_device, + &ds4_hid_device, + NULL /* must be last entry in list */ +}; + +hid_device_t *hid_device_driver_lookup(uint16_t vendor_id, uint16_t product_id) { + int i = 0; + + for(i = 0; hid_device_list[i] != NULL; i++) { + if(hid_device_list[i]->detect(vendor_id, product_id)) + return hid_device_list[i]; + } + + return NULL; +} + diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h new file mode 100644 index 0000000000..90e0659026 --- /dev/null +++ b/input/common/hid/hid_device_driver.h @@ -0,0 +1,32 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef HID_DEVICE_DRIVER__H +#define HID_DEVICE_DRIVER__H + +#include "../../input_driver.h" + +typedef struct hid_device { + bool (*detect)(uint16_t vid, uint16_t pid); +} hid_device_t; + +extern hid_device_t wiiu_gca_hid_device; +extern hid_device_t ds3_hid_device; +extern hid_device_t ds4_hid_device; + +hid_device_t *hid_device_driver_lookup(uint16_t vendor_id, uint16_t product_id); + +#endif /* HID_DEVICE_DRIVER__H */ diff --git a/wiiu/include/wiiu/pad_driver.h b/wiiu/include/wiiu/pad_driver.h index 376b899f43..8a93798de7 100644 --- a/wiiu/include/wiiu/pad_driver.h +++ b/wiiu/include/wiiu/pad_driver.h @@ -31,6 +31,7 @@ #include #include "../../input/input_driver.h" +#include "../../input/common/hid/hid_device_driver.h" #include "../../input/connect/joypad_connection.h" #include "../../tasks/tasks_internal.h" #include "../../retroarch.h" @@ -149,6 +150,7 @@ typedef struct wiiu_attach wiiu_attach_event; struct wiiu_attach { wiiu_attach_event *next; + hid_device_t *driver; uint32_t type; uint32_t handle; uint16_t vendor_id; diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index db0fcd074b..43eb372752 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -649,10 +649,18 @@ static void delete_adapter(wiiu_adapter_t *adapter) static wiiu_attach_event *new_attach_event(HIDDevice *device) { + hid_device_t *driver = hid_device_driver_lookup(device->vid, device->pid); + if(!driver) + { + RARCH_ERR("[hid]: Failed to locate driver for device vid=%04x pid=%04x\n", + device->vid, device->pid); + return NULL; + } wiiu_attach_event *event = alloc_zeroed(4, sizeof(wiiu_attach_event)); if(!event) return NULL; + event->driver = driver; event->handle = device->handle; event->vendor_id = device->vid; event->product_id = device->pid; From 41ce8853d7bb7a40e0e064e285c0542460bf5f22 Mon Sep 17 00:00:00 2001 From: gblues Date: Wed, 7 Feb 2018 22:28:25 -0800 Subject: [PATCH 02/31] Add name for hid device; implement detect == DETAILS - detect() methods in device_* files now check for VID/PID instead of just returning false - add "name" field on hid device, mainly for logging purposes == TESTING Verified my WiiU GC adapter detected properly --- input/common/hid/device_ds3.c | 5 +++-- input/common/hid/device_ds4.c | 5 +++-- input/common/hid/device_wiiu_gca.c | 5 +++-- input/common/hid/hid_device_driver.h | 2 ++ wiiu/input/wiiu_hid.c | 1 + 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 04325ace7b..9af43ac1c6 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -18,9 +18,10 @@ static bool ds3_detect(uint16_t vendor_id, uint16_t product_id) { - return false; + return vendor_id == VID_SONY && product_id == PID_SONY_DS3; } hid_device_t ds3_hid_device = { - ds3_detect + ds3_detect, + "Sony DualShock 3" }; diff --git a/input/common/hid/device_ds4.c b/input/common/hid/device_ds4.c index 0f049e5cbc..7c90ebaf0a 100644 --- a/input/common/hid/device_ds4.c +++ b/input/common/hid/device_ds4.c @@ -18,9 +18,10 @@ static bool ds4_detect(uint16_t vendor_id, uint16_t product_id) { - return false; + return vendor_id == VID_SONY && product_id == PID_SONY_DS4; } hid_device_t ds4_hid_device = { - ds4_detect + ds4_detect, + "Sony DualShock 4" }; diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 0829a22ac1..ec68aa897d 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -17,9 +17,10 @@ #include "hid_device_driver.h" static bool wiiu_gca_detect(uint16_t vendor_id, uint16_t product_id) { - return false; + return vendor_id == VID_NINTENDO && product_id == PID_NINTENDO_GCA; } hid_device_t wiiu_gca_hid_device = { - wiiu_gca_detect + wiiu_gca_detect, + "Wii U Gamecube Adapter" }; diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h index 90e0659026..a3259aee52 100644 --- a/input/common/hid/hid_device_driver.h +++ b/input/common/hid/hid_device_driver.h @@ -18,9 +18,11 @@ #define HID_DEVICE_DRIVER__H #include "../../input_driver.h" +#include "../../connect/joypad_connection.h" typedef struct hid_device { bool (*detect)(uint16_t vid, uint16_t pid); + const char *name; } hid_device_t; extern hid_device_t wiiu_gca_hid_device; diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 43eb372752..f2656a4cbb 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -656,6 +656,7 @@ static wiiu_attach_event *new_attach_event(HIDDevice *device) device->vid, device->pid); return NULL; } + RARCH_LOG("[hid]: Found HID device driver: %s\n", driver->name); wiiu_attach_event *event = alloc_zeroed(4, sizeof(wiiu_attach_event)); if(!event) return NULL; From 0100d58ffb376315de9060f723a03a76a3f676c6 Mon Sep 17 00:00:00 2001 From: gblues Date: Wed, 21 Feb 2018 22:57:28 -0800 Subject: [PATCH 03/31] WIP: evolve driver implementation == DETAILS I've created the concept of a hid_driver_instance_t which is basically a central place to store the hid pad driver, hid subsystem driver, the pad list, and the instance data for the above in a central location. The HID pad device drivers can use it to perform HID operations in a generic manner. This is more-or-less a pause point so I can catch up with upstream. == TESTING Haven't tested this yet. Compiles without warnings though! --- input/common/hid/device_ds3.c | 26 +++++++ input/common/hid/device_ds4.c | 26 +++++++ input/common/hid/device_wiiu_gca.c | 112 +++++++++++++++++++++++++++ input/common/hid/hid_device_driver.c | 101 ++++++++++++++++++++++++ input/common/hid/hid_device_driver.h | 9 +++ input/connect/connect_ps3.c | 5 +- input/connect/connect_ps4.c | 1 + input/connect/connect_wii.c | 1 + input/connect/connect_wiiugca.c | 1 + input/connect/connect_wiiupro.c | 1 + input/drivers_hid/btstack_hid.c | 7 +- input/drivers_hid/iohidmanager_hid.c | 8 +- input/drivers_hid/libusb_hid.c | 7 +- input/drivers_hid/null_hid.c | 5 +- input/drivers_hid/wiiusb_hid.c | 6 +- input/include/hid_driver.h | 63 +++++++++++++++ input/include/hid_types.h | 24 ++++++ input/input_driver.c | 13 ++++ input/input_driver.h | 32 +++----- wiiu/include/wiiu/pad_driver.h | 9 ++- wiiu/include/wiiu/syshid.h | 9 --- wiiu/input/hidpad_driver.c | 47 ++--------- wiiu/input/kpad_driver.c | 2 +- wiiu/input/pad_functions.c | 8 -- wiiu/input/wiiu_hid.c | 77 ++++++++++-------- wiiu/input/wiiu_hid.h | 1 + wiiu/input/wpad_driver.c | 2 +- 27 files changed, 471 insertions(+), 132 deletions(-) create mode 100644 input/include/hid_driver.h create mode 100644 input/include/hid_types.h diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 9af43ac1c6..569d4d7f79 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -16,12 +16,38 @@ #include "hid_device_driver.h" +struct ds3_instance { + hid_driver_t *driver; + void *handle; +}; + +static void *ds3_init(hid_driver_instance_t *hid_driver) +{ + return NULL; +} + +static void ds3_free(void *data) +{ + struct ds3_instance *instance = (struct ds3_instance *)data; + if(!instance) + return; + + free(instance); +} + +static void ds3_handle_packet(void *data, uint8_t *buffer, size_t size) +{ +} + static bool ds3_detect(uint16_t vendor_id, uint16_t product_id) { return vendor_id == VID_SONY && product_id == PID_SONY_DS3; } hid_device_t ds3_hid_device = { + ds3_init, + ds3_free, + ds3_handle_packet, ds3_detect, "Sony DualShock 3" }; diff --git a/input/common/hid/device_ds4.c b/input/common/hid/device_ds4.c index 7c90ebaf0a..6c8b77ac2f 100644 --- a/input/common/hid/device_ds4.c +++ b/input/common/hid/device_ds4.c @@ -16,12 +16,38 @@ #include "hid_device_driver.h" +struct ds4_instance { + hid_driver_t *driver; + void *handle; +}; + +static void *ds4_init(hid_driver_instance_t *hid_driver) +{ + return NULL; +} + +static void ds4_free(void *data) +{ + struct ds4_instance *instance = (struct ds4_instance *)data; + if(!instance) + return; + + free(instance); +} + +static void ds4_handle_packet(void *data, uint8_t *buffer, size_t size) +{ +} + static bool ds4_detect(uint16_t vendor_id, uint16_t product_id) { return vendor_id == VID_SONY && product_id == PID_SONY_DS4; } hid_device_t ds4_hid_device = { + ds4_init, + ds4_free, + ds4_handle_packet, ds4_detect, "Sony DualShock 4" }; diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index ec68aa897d..211f67dfbb 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -16,11 +16,123 @@ #include "hid_device_driver.h" +#ifdef WII +static uint8_t activation_packet[] = { 0x01, 0x13 }; +#else +static uint8_t activation_packet[] = { 0x13 }; +#endif + +#define GCA_PORT_INITIALIZING 0x00 +#define GCA_PORT_EMPTY 0x04 +#define GCA_PORT_CONNECTED 0x14 + +typedef struct wiiu_gca_instance { + hid_driver_instance_t *driver; + uint8_t device_state[37]; + joypad_connection_t *pads[4]; +} wiiu_gca_instance_t; + +static void update_pad_state(wiiu_gca_instance_t *instance); +static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance); + +extern pad_connection_interface_t wiiu_gca_pad_connection; + +static void *wiiu_gca_init(hid_driver_instance_t *driver) +{ + wiiu_gca_instance_t *instance = calloc(1, sizeof(wiiu_gca_instance_t)); + memset(instance, 0, sizeof(wiiu_gca_instance_t)); + instance->driver = driver; + + driver->hid_driver->send_control(driver->hid_data, activation_packet, sizeof(activation_packet)); + driver->hid_driver->read(driver->hid_data, instance->device_state, sizeof(instance->device_state)); + + return instance; +} + +static void wiiu_gca_free(void *data) { + wiiu_gca_instance_t *instance = (wiiu_gca_instance_t *)data; + if(instance) { + 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) + return; + + if(size > sizeof(instance->device_state)) + return; + + memcpy(instance->device_state, buffer, size); + update_pad_state(instance); +} + +static void update_pad_state(wiiu_gca_instance_t *instance) +{ + int i, pad; + + /* process each pad */ + for(i = 1; i < 37; i += 9) + { + pad = i / 9; + switch(instance->device_state[i]) + { + case GCA_PORT_INITIALIZING: + case GCA_PORT_EMPTY: + if(instance->pads[pad] != NULL) + { + /* TODO: free pad */ + instance->pads[pad] = NULL; + } + break; + case GCA_PORT_CONNECTED: + if(instance->pads[pad] == NULL) + { + instance->pads[pad] = register_pad(instance); + } + } + } +} + +static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance) { + int slot; + joypad_connection_t *result; + + slot = pad_connection_find_vacant_pad(instance->driver->pad_connection_list); + if(slot < 0) + return NULL; + + result = &(instance->driver->pad_connection_list[slot]); + result->iface = &wiiu_gca_pad_connection; + result->data = result->iface->init(instance, slot, instance->driver->hid_driver); + result->connected = true; + input_pad_connect(slot, instance->driver->pad_driver); + + return result; +} + static bool wiiu_gca_detect(uint16_t vendor_id, uint16_t product_id) { return vendor_id == VID_NINTENDO && product_id == PID_NINTENDO_GCA; } hid_device_t wiiu_gca_hid_device = { + wiiu_gca_init, + wiiu_gca_free, + wiiu_gca_handle_packet, wiiu_gca_detect, "Wii U Gamecube Adapter" }; + +pad_connection_interface_t wiiu_gca_pad_connection = { +/* + wiiu_gca_pad_init, + wiiu_gca_pad_deinit, + wiiu_gca_packet_handler, + wiiu_gca_set_rumble, + wiiu_gca_get_buttons, + wiiu_gca_get_axis, + wiiu_gca_get_name +*/ +}; diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index 0f049ca728..a3b861bf4d 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -16,6 +16,8 @@ #include "hid_device_driver.h" +hid_driver_instance_t hid_instance = {0}; + hid_device_t *hid_device_list[] = { &wiiu_gca_hid_device, &ds3_hid_device, @@ -34,3 +36,102 @@ hid_device_t *hid_device_driver_lookup(uint16_t vendor_id, uint16_t product_id) return NULL; } +void hid_pad_connect(hid_driver_instance_t *instance, int pad) +{ + if(!instance || !instance->pad_driver) + return; + + input_pad_connect(pad, instance->pad_driver); +} + +/** + * Fill in instance with data from initialized hid subsystem. + * + * @argument instance the hid_driver_instance_t struct to fill in + * @argument hid_driver the HID driver to initialize + * @argument pad_driver the gamepad driver to handle HID pads detected by the HID driver. + * + * @returns true if init is successful, false otherwise. + */ +bool hid_init(hid_driver_instance_t *instance, + hid_driver_t *hid_driver, + input_device_driver_t *pad_driver, + unsigned slots) +{ + if(!instance || !hid_driver || !pad_driver || slots > MAX_USERS) + return false; + + instance->hid_data = hid_driver->init(instance); + if(!instance->hid_data) + return false; + + instance->pad_connection_list = pad_connection_init(slots); + if(!instance->pad_connection_list) + { + hid_driver->free(instance->hid_data); + instance->hid_data = NULL; + return false; + } + + instance->max_slot = slots; + instance->hid_driver = hid_driver; + instance->pad_driver = pad_driver; + + return true; +} + +/** + * Tear down the HID system set up by hid_init() + * + * @argument instance the hid_driver_instance_t to tear down. + */ +void hid_deinit(hid_driver_instance_t *instance) +{ + if(!instance) + return; + + pad_connection_destroy(instance->pad_connection_list); + + if(instance->hid_driver && instance->hid_data) + { + instance->hid_driver->free(instance->hid_data); + } + + memset(instance, 0, sizeof(hid_driver_instance_t)); +} + +static void hid_device_log_buffer(uint8_t *data, uint32_t len) +{ +#if 0 + int i, offset; + int padding = len % 0x0F; + uint8_t buf[16]; + + RARCH_LOG("%d bytes read:\n", len); + + for(i = 0, offset = 0; i < len; i++) + { + buf[offset] = data[i]; + offset++; + if(offset == 16) + { + offset = 0; + RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], + buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); + } + } + + if(padding) + { + for(i = padding; i < 16; i++) + buf[i] = 0xff; + + RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], + buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); + } + + RARCH_LOG("=================================\n"); + #endif +} diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h index a3259aee52..8bb371f70e 100644 --- a/input/common/hid/hid_device_driver.h +++ b/input/common/hid/hid_device_driver.h @@ -19,8 +19,12 @@ #include "../../input_driver.h" #include "../../connect/joypad_connection.h" +#include "../../include/hid_driver.h" typedef struct hid_device { + void *(*init)(hid_driver_instance_t *driver); + void (*free)(void *data); + void (*handle_packet)(void *data, uint8_t *buffer, size_t size); bool (*detect)(uint16_t vid, uint16_t pid); const char *name; } hid_device_t; @@ -28,7 +32,12 @@ typedef struct hid_device { extern hid_device_t wiiu_gca_hid_device; extern hid_device_t ds3_hid_device; extern hid_device_t ds4_hid_device; +extern hid_driver_instance_t hid_instance; hid_device_t *hid_device_driver_lookup(uint16_t vendor_id, uint16_t product_id); +void hid_pad_connect(hid_driver_instance_t *instance, int pad); +bool hid_init(hid_driver_instance_t *instance, hid_driver_t *hid_driver, input_device_driver_t *pad_driver, unsigned slots); +void hid_deinit(hid_driver_instance_t *instance); + #endif /* HID_DEVICE_DRIVER__H */ diff --git a/input/connect/connect_ps3.c b/input/connect/connect_ps3.c index 61269a9e88..f77235cf80 100644 --- a/input/connect/connect_ps3.c +++ b/input/connect/connect_ps3.c @@ -21,10 +21,7 @@ #include #include "joypad_connection.h" #include "../input_defines.h" - -#ifdef WIIU -#include -#endif +#include "../common/hid/hid_device_driver.h" struct hidpad_ps3_data { diff --git a/input/connect/connect_ps4.c b/input/connect/connect_ps4.c index 0356a91537..f011bd3ab8 100644 --- a/input/connect/connect_ps4.c +++ b/input/connect/connect_ps4.c @@ -25,6 +25,7 @@ #include "joypad_connection.h" #include "../input_defines.h" #include "../../driver.h" +#include "../common/hid/hid_device_driver.h" enum connect_ps4_dpad_states { diff --git a/input/connect/connect_wii.c b/input/connect/connect_wii.c index f02e1735be..74865862aa 100644 --- a/input/connect/connect_wii.c +++ b/input/connect/connect_wii.c @@ -26,6 +26,7 @@ #include "joypad_connection.h" #include "../input_defines.h" +#include "../common/hid/hid_device_driver.h" /* wiimote state flags*/ #define WIIMOTE_STATE_DEV_FOUND 0x0001 diff --git a/input/connect/connect_wiiugca.c b/input/connect/connect_wiiugca.c index 7e49969fd2..3803488797 100644 --- a/input/connect/connect_wiiugca.c +++ b/input/connect/connect_wiiugca.c @@ -21,6 +21,7 @@ #include #include "joypad_connection.h" #include "../input_defines.h" +#include "../common/hid/hid_device_driver.h" struct hidpad_wiiugca_data { diff --git a/input/connect/connect_wiiupro.c b/input/connect/connect_wiiupro.c index 836f17856e..d2ad16a968 100644 --- a/input/connect/connect_wiiupro.c +++ b/input/connect/connect_wiiupro.c @@ -23,6 +23,7 @@ #include "joypad_connection.h" #include "../input_defines.h" #include "../../driver.h" +#include "../common/hid/hid_device_driver.h" struct wiiupro_buttons { diff --git a/input/drivers_hid/btstack_hid.c b/input/drivers_hid/btstack_hid.c index 1d277484aa..68f20ea666 100644 --- a/input/drivers_hid/btstack_hid.c +++ b/input/drivers_hid/btstack_hid.c @@ -1439,14 +1439,17 @@ static void btstack_hid_free(const void *data) free(hid); } -static void *btstack_hid_init(void) +static void *btstack_hid_init(joypad_connection_t *connections) { btstack_hid_t *hid = (btstack_hid_t*)calloc(1, sizeof(btstack_hid_t)); if (!hid) goto error; - hid->slots = pad_connection_init(MAX_USERS); + if(connections == NULL) + connections = pad_connection_init(MAX_USERS); + + hid->slots = connections; if (!hid->slots) goto error; diff --git a/input/drivers_hid/iohidmanager_hid.c b/input/drivers_hid/iohidmanager_hid.c index 9ad99ebe2f..ad60d4c969 100644 --- a/input/drivers_hid/iohidmanager_hid.c +++ b/input/drivers_hid/iohidmanager_hid.c @@ -854,14 +854,18 @@ static int iohidmanager_hid_manager_set_device_matching( return 0; } -static void *iohidmanager_hid_init(void) +static void *iohidmanager_hid_init(joypad_connection_t *connections) { iohidmanager_hid_t *hid_apple = (iohidmanager_hid_t*) calloc(1, sizeof(*hid_apple)); if (!hid_apple) goto error; - hid_apple->slots = pad_connection_init(MAX_USERS); + + if (connections == NULL) + connections = pad_connection_init(MAX_USERS); + + hid_apple->slots = connections; if (!hid_apple->slots) goto error; diff --git a/input/drivers_hid/libusb_hid.c b/input/drivers_hid/libusb_hid.c index 44580359fa..f06adb5366 100644 --- a/input/drivers_hid/libusb_hid.c +++ b/input/drivers_hid/libusb_hid.c @@ -546,7 +546,7 @@ static void poll_thread(void *data) } } -static void *libusb_hid_init(void) +static void *libusb_hid_init(joypad_connection_t *connections) { unsigned i, count; int ret; @@ -578,7 +578,10 @@ static void *libusb_hid_init(void) hid->can_hotplug = 0; #endif - hid->slots = pad_connection_init(MAX_USERS); + if (connections == NULL) + connections = pad_connection_init(MAX_USERS); + + hid->slots = connections; if (!hid->slots) goto error; diff --git a/input/drivers_hid/null_hid.c b/input/drivers_hid/null_hid.c index 70a34d4bf8..e7cf00b580 100644 --- a/input/drivers_hid/null_hid.c +++ b/input/drivers_hid/null_hid.c @@ -18,6 +18,7 @@ #include "../input_defines.h" #include "../input_driver.h" +#include "../include/hid_driver.h" typedef struct null_hid { @@ -75,8 +76,10 @@ static int16_t null_hid_joypad_axis(void *data, unsigned port, uint32_t joyaxis) return 0; } -static void *null_hid_init(void) +static void *null_hid_init(hid_driver_instance_t *instance) { + (void)instance; + return (null_hid_t*)calloc(1, sizeof(null_hid_t)); } diff --git a/input/drivers_hid/wiiusb_hid.c b/input/drivers_hid/wiiusb_hid.c index 397f0a0a64..6e3a768bca 100644 --- a/input/drivers_hid/wiiusb_hid.c +++ b/input/drivers_hid/wiiusb_hid.c @@ -574,15 +574,15 @@ static void wiiusb_hid_free(const void *data) free(hid); } -static void *wiiusb_hid_init(void) +static void *wiiusb_hid_init(joypad_connection_t *connections) { - joypad_connection_t *connections = NULL; wiiusb_hid_t *hid = (wiiusb_hid_t*)calloc(1, sizeof(*hid)); if (!hid) goto error; - connections = pad_connection_init(MAX_USERS); + if(connections == NULL) + connections = pad_connection_init(MAX_USERS); if (!connections) goto error; diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h new file mode 100644 index 0000000000..37ae190a51 --- /dev/null +++ b/input/include/hid_driver.h @@ -0,0 +1,63 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Andrés Suárez + * + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef HID_DRIVER_H__ +#define HID_DRIVER_H__ + +#include "../connect/joypad_connection.h" +#include "../input_driver.h" + +/* what is 1? */ +#define HID_REPORT_OUTPUT 2 +#define HID_REPORT_FEATURE 3 +/* are there more? */ + +/* + * This is the interface for the HID subsystem. + * + * The handle parameter is the pointer returned by init() and stores the implementation + * state data for the HID driver. + */ + +struct hid_driver +{ + void *(*init)(hid_driver_instance_t *); + bool (*query_pad)(void *handle, unsigned pad); + void (*free)(const void *handle); + bool (*button)(void *handle, unsigned pad, uint16_t button); + void (*get_buttons)(void *handle, unsigned pad, retro_bits_t *state); + int16_t (*axis)(void *handle, unsigned pad, uint32_t axis); + void (*poll)(void *handle); + bool (*set_rumble)(void *handle, unsigned pad, enum retro_rumble_effect effect, uint16_t); + const char *(*name)(void *handle, unsigned pad); + const char *ident; + void (*send_control)(void *handle, uint8_t *buf, size_t size); + int32_t (*set_report)(void *handle, uint8_t, uint8_t, void *data, uint32_t size); + int32_t (*set_idle)(void *handle, uint8_t amount); + int32_t (*set_protocol)(void *handle, uint8_t protocol); + int32_t (*read)(void *handle, void *buf, size_t size); +}; + +struct hid_driver_instance { + hid_driver_t *hid_driver; + void *hid_data; + input_device_driver_t *pad_driver; + joypad_connection_t *pad_connection_list; + unsigned max_slot; +}; + +#endif /* HID_DRIVER_H__ */ diff --git a/input/include/hid_types.h b/input/include/hid_types.h new file mode 100644 index 0000000000..28734e9dd8 --- /dev/null +++ b/input/include/hid_types.h @@ -0,0 +1,24 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Andrés Suárez + * + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef HID_TYPES_H__ +#define HID_TYPES_H__ + +typedef struct hid_driver hid_driver_t; +typedef struct hid_driver_instance hid_driver_instance_t; + +#endif /* HID_TYPES_H__ */ diff --git a/input/input_driver.c b/input/input_driver.c index 14ed1c17a9..882d33ca1b 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -1782,6 +1782,19 @@ bool input_mouse_button_raw(unsigned port, unsigned id) return false; } +void input_pad_connect(unsigned port, input_device_driver_t *driver) +{ + if(port >= MAX_USERS || !driver) + { + RARCH_ERR("[input]: input_pad_connect: bad parameters\n"); + return; + } + + if(!input_autoconfigure_connect(driver->name(port), NULL, driver->ident, + port, 0, 0)) + input_config_set_device_name(port, driver->name(port)); +} + /** * input_conv_analog_id_to_bind_id: * @idx : Analog key index. diff --git a/input/input_driver.h b/input/input_driver.h index 2ef47c7d24..b366413893 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -35,13 +35,12 @@ #include "input_defines.h" #include "../msg_hash.h" +#include "include/hid_types.h" RETRO_BEGIN_DECLS typedef struct rarch_joypad_driver input_device_driver_t; -typedef struct hid_driver hid_driver_t; - /* Keyboard line reader. Handles textual input in a direct fashion. */ typedef struct input_keyboard_line input_keyboard_line_t; @@ -181,25 +180,6 @@ struct rarch_joypad_driver const char *ident; }; -struct hid_driver -{ - void *(*init)(void); - bool (*query_pad)(void *, unsigned); - void (*free)(const void *); - bool (*button)(void *, unsigned, uint16_t); - void (*get_buttons)(void *, unsigned, retro_bits_t *); - int16_t (*axis)(void *, unsigned, uint32_t); - void (*poll)(void *); - bool (*set_rumble)(void *, unsigned, enum retro_rumble_effect, uint16_t); - const char *(*name)(void *, unsigned); - const char *ident; - void (*send_control)(void *data, uint8_t *buf, size_t size); - int32_t (*set_report)(void *, uint8_t, uint8_t, void *, uint32_t); - int32_t (*set_idle)(void *, uint8_t); - int32_t (*set_protocol)(void *, uint8_t); - -}; - /** * input_driver_find_handle: * @index : index of driver to get handle to. @@ -591,6 +571,15 @@ bool input_joypad_button_raw(const input_device_driver_t *driver, bool input_joypad_hat_raw(const input_device_driver_t *driver, unsigned joypad, unsigned hat_dir, unsigned hat); +/** + * input_pad_connect: + * @port : Joystick number. + * @driver : handle for joypad driver handling joystick's input + * + * Registers a newly connected pad with RetroArch. + **/ +void input_pad_connect(unsigned port, input_device_driver_t *driver); + /** * input_mouse_button_raw: * @port : Mouse number. @@ -848,7 +837,6 @@ extern hid_driver_t iohidmanager_hid; extern hid_driver_t btstack_hid; extern hid_driver_t libusb_hid; extern hid_driver_t wiiusb_hid; -extern hid_driver_t wiiu_hid; extern hid_driver_t null_hid; #endif diff --git a/wiiu/include/wiiu/pad_driver.h b/wiiu/include/wiiu/pad_driver.h index 8a93798de7..067bc34d67 100644 --- a/wiiu/include/wiiu/pad_driver.h +++ b/wiiu/include/wiiu/pad_driver.h @@ -32,8 +32,8 @@ #include "../../input/input_driver.h" #include "../../input/common/hid/hid_device_driver.h" -#include "../../input/connect/joypad_connection.h" #include "../../tasks/tasks_internal.h" +#include "../../input/connect/joypad_connection.h" #include "../../retroarch.h" #include "../../verbosity.h" #include "../../command.h" @@ -119,8 +119,8 @@ struct _wiiu_pad_functions { typedef struct wiiu_hid { /* used to register for HID notifications */ HIDClient *client; - /* list of HID pads */ - joypad_connection_t *connections; + /* pointer to HID driver state */ + hid_driver_instance_t *driver; /* size of connections list */ unsigned connections_size; /* thread state data for HID polling thread */ @@ -135,13 +135,14 @@ typedef struct wiiu_adapter wiiu_adapter_t; struct wiiu_adapter { wiiu_adapter_t *next; + hid_device_t *driver; + void *driver_handle; wiiu_hid_t *hid; uint8_t state; uint8_t *rx_buffer; int32_t rx_size; uint8_t *tx_buffer; int32_t tx_size; - int32_t slot; uint32_t handle; uint8_t interface_index; }; diff --git a/wiiu/include/wiiu/syshid.h b/wiiu/include/wiiu/syshid.h index 1f55718dd9..664e52eef6 100644 --- a/wiiu/include/wiiu/syshid.h +++ b/wiiu/include/wiiu/syshid.h @@ -1,15 +1,6 @@ #pragma once #include -/* - * Report types for the report_type parameter in HIDSetReport() - */ - -/* what is 1? */ -#define HID_REPORT_OUTPUT 2 -#define HID_REPORT_FEATURE 3 -/* are there more? */ - typedef struct { uint32_t handle; diff --git a/wiiu/input/hidpad_driver.c b/wiiu/input/hidpad_driver.c index 5cae6d710f..272bd2e7c0 100644 --- a/wiiu/input/hidpad_driver.c +++ b/wiiu/input/hidpad_driver.c @@ -15,6 +15,8 @@ */ #include +#include "../../input/include/hid_driver.h" +#include "../../input/common/hid/hid_device_driver.h" static bool hidpad_init(void *data); static bool hidpad_query_pad(unsigned pad); @@ -27,51 +29,25 @@ static const char *hidpad_name(unsigned pad); static bool ready = false; -static wiiu_hid_t *hid_data; -static hid_driver_t *hid_driver; - static unsigned to_slot(unsigned pad) { return pad - (WIIU_WIIMOTE_CHANNELS+1); } -const void *get_hid_data(void) +static bool init_hid_driver(void) { - return hid_data; -} - -static hid_driver_t *init_hid_driver(void) -{ - joypad_connection_t *connections = NULL; unsigned connections_size = MAX_USERS - (WIIU_WIIMOTE_CHANNELS+1); - hid_data = (wiiu_hid_t *)wiiu_hid.init(); - connections = pad_connection_init(connections_size); + memset(&hid_instance, 0, sizeof(hid_instance)); - if (!hid_data || !connections) - goto error; - - hid_data->connections = connections; - hid_data->connections_size = connections_size; - return &wiiu_hid; - -error: - if (connections) - free(connections); - if (hid_data) - { - wiiu_hid.free(hid_data); - hid_data = NULL; - } - return NULL; + return hid_init(&hid_instance, &wiiu_hid, &hidpad_driver, connections_size); } static bool hidpad_init(void *data) { (void *)data; - hid_driver = init_hid_driver(); - if (!hid_driver) + if(!init_hid_driver()) { RARCH_ERR("Failed to initialize HID driver.\n"); return false; @@ -92,16 +68,7 @@ static void hidpad_destroy(void) { ready = false; - if(hid_driver) { - hid_driver->free(hid_data); - hid_data = NULL; - hid_driver = NULL; - } - - if(hid_data) { - free(hid_data); - hid_data = NULL; - } + hid_deinit(&hid_instance); } static bool hidpad_button(unsigned pad, uint16_t button) diff --git a/wiiu/input/kpad_driver.c b/wiiu/input/kpad_driver.c index 48a7f428c3..51d203cec0 100644 --- a/wiiu/input/kpad_driver.c +++ b/wiiu/input/kpad_driver.c @@ -117,7 +117,7 @@ static void kpad_register(unsigned channel, uint8_t device_type) if (wiimotes[channel].type != device_type) { wiimotes[channel].type = device_type; - pad_functions.connect(to_retro_pad(channel), &kpad_driver); + input_pad_connect(to_retro_pad(channel), &kpad_driver); } } diff --git a/wiiu/input/pad_functions.c b/wiiu/input/pad_functions.c index fe352e5da4..132bffa146 100644 --- a/wiiu/input/pad_functions.c +++ b/wiiu/input/pad_functions.c @@ -88,16 +88,8 @@ void wiiu_pad_read_axis_data(uint32_t axis, axis_data *data) } } -void wiiu_pad_connect(unsigned pad, input_device_driver_t *driver) -{ - if(!input_autoconfigure_connect(driver->name(pad), NULL, driver->ident, - pad, VID_NONE, PID_NONE)) - input_config_set_device_name(pad, driver->name(pad)); -} - wiiu_pad_functions_t pad_functions = { wiiu_pad_get_axis_value, wiiu_pad_set_axis_value, wiiu_pad_read_axis_data, - wiiu_pad_connect }; diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index f2656a4cbb..cb09db3346 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -19,13 +19,15 @@ static wiiu_event_list events; static wiiu_adapter_list adapters; +static void log_buffer(uint8_t *data, uint32_t len); + static bool wiiu_hid_joypad_query(void *data, unsigned slot) { wiiu_hid_t *hid = (wiiu_hid_t *)data; - if (!hid) + if (!hid || !hid->driver) return false; - return slot < hid->connections_size; + return slot < hid->driver->max_slot; } static const char *wiiu_hid_joypad_name(void *data, unsigned slot) @@ -35,7 +37,7 @@ static const char *wiiu_hid_joypad_name(void *data, unsigned slot) wiiu_hid_t *hid = (wiiu_hid_t *)data; - return hid->connections[slot].iface->get_name(data); + return hid->driver->pad_connection_list[slot].iface->get_name(data); } static void wiiu_hid_joypad_get_buttons(void *data, unsigned port, retro_bits_t *state) @@ -75,7 +77,7 @@ static int16_t wiiu_hid_joypad_axis(void *data, unsigned port, uint32_t joyaxis) return 0; } -static void *wiiu_hid_init(void) +static void *wiiu_hid_init(hid_driver_instance_t *driver) { RARCH_LOG("[hid]: initializing HID subsystem\n"); wiiu_hid_t *hid = new_hid(); @@ -84,6 +86,8 @@ static void *wiiu_hid_init(void) if (!hid || !client) goto error; + hid->driver = driver; + wiiu_hid_init_lists(); start_polling_thread(hid); if (!hid->polling_thread) @@ -98,6 +102,7 @@ static void *wiiu_hid_init(void) error: RARCH_LOG("[hid]: initialization failed. cleaning up.\n"); + stop_polling_thread(hid); delete_hid(hid); delete_hidclient(client); @@ -197,6 +202,26 @@ static int32_t wiiu_hid_set_protocol(void *data, uint8_t protocol) NULL, NULL); } +static int32_t wiiu_hid_read(void *data, void *buffer, size_t size) +{ + wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; + + if(!adapter) + return -1; + + if(size > adapter->rx_size) + return -1; + +#if 1 + int32_t result = HIDRead(adapter->handle, buffer, size, NULL, NULL); + log_buffer(buffer, size); + return result; +#else + return HIDRead(adapter->handle, buffer, size, NULL, NULL); +#endif +} + + static void start_polling_thread(wiiu_hid_t *hid) { OSThreadAttributes attributes = OS_THREAD_ATTRIB_AFFINITY_CPU2; @@ -357,23 +382,12 @@ static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) } adapter->hid = hid; - adapter->slot = pad_connection_pad_init(hid->connections, - "hid", event->vendor_id, event->product_id, adapter, - &wiiu_hid); + adapter->driver = event->driver; - if(adapter->slot < 0) - { - RARCH_ERR("[hid]: No available slots.\n"); - goto error; - } - - RARCH_LOG("[hid]: got slot %d\n", adapter->slot); - - if(!pad_connection_has_interface(hid->connections, adapter->slot)) - { - RARCH_ERR("[hid]: Interface not found for HID device with vid=0x%04x pid=0x%04x\n", - event->vendor_id, event->product_id); - goto error; + adapter->driver_handle = adapter->driver->init(hid->driver); + if(adapter->driver_handle == NULL) { + RARCH_ERR("[hid]: Failed to initialize driver: %s\n", + adapter->driver->name); } RARCH_LOG("[hid]: adding to adapter list\n"); @@ -446,16 +460,6 @@ static void log_buffer(uint8_t *data, uint32_t len) } -static void wiiu_hid_do_read(wiiu_adapter_t *adapter, - uint8_t *data, uint32_t length) -{ -#if 0 - log_buffer(data, length); -#endif - - /* TODO: get this data to the connect_xxx driver somehow. */ -} - static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, uint8_t *buffer, uint32_t buffer_size, void *userdata) { @@ -468,12 +472,13 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, if(adapter->hid->polling_thread_quit) { - RARCH_LOG("Shutting down read loop for slot %d\n", adapter->slot); + RARCH_LOG("Shutting down read loop for device: %s\n", + adapter->driver->name); adapter->state = ADAPTER_STATE_DONE; return; } - wiiu_hid_do_read(adapter, buffer, buffer_size); + adapter->driver->handle_packet(adapter->driver_handle, buffer, buffer_size); adapter->state = ADAPTER_STATE_READING; HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, @@ -644,6 +649,11 @@ static void delete_adapter(wiiu_adapter_t *adapter) free(adapter->tx_buffer); adapter->tx_buffer = NULL; } + if(adapter->driver && adapter->driver_handle) { + adapter->driver->free(adapter->driver_handle); + adapter->driver_handle = NULL; + adapter->driver = NULL; + } free(adapter); } @@ -707,6 +717,7 @@ hid_driver_t wiiu_hid = { wiiu_hid_send_control, wiiu_hid_set_report, wiiu_hid_set_idle, - wiiu_hid_set_protocol + wiiu_hid_set_protocol, + wiiu_hid_read, }; diff --git a/wiiu/input/wiiu_hid.h b/wiiu/input/wiiu_hid.h index 1c2ede6f73..b1ce59a6c3 100644 --- a/wiiu/input/wiiu_hid.h +++ b/wiiu/input/wiiu_hid.h @@ -18,6 +18,7 @@ #define __WIIU_HID__H #include +#include "../../input/include/hid_driver.h" #define DEVICE_UNUSED 0 #define DEVICE_USED 1 diff --git a/wiiu/input/wpad_driver.c b/wiiu/input/wpad_driver.c index b707c63cb5..786f883cda 100644 --- a/wiiu/input/wpad_driver.c +++ b/wiiu/input/wpad_driver.c @@ -184,7 +184,7 @@ static void wpad_poll(void) static bool wpad_init(void *data) { - pad_functions.connect(PAD_GAMEPAD, &wpad_driver); + input_pad_connect(PAD_GAMEPAD, &wpad_driver); wpad_poll(); ready = true; From 4b9d5c0ab7f7ca07ea090e52a0500c5071dd1704 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 11 Mar 2018 22:08:06 -0700 Subject: [PATCH 04/31] Start implementing "detach" code path == DETAILS We're at a point where we need to do more than just clean up a local data structure, so I've started implementing the "detach" part of the code so that everything gets cleaned up properly. Also, added error handling inside the polling thread. == TESTING Have not tested yet. --- input/common/hid/device_wiiu_gca.c | 108 +++++++++++++++++------------ wiiu/input/wiiu_hid.c | 37 ++++++++++ wiiu/input/wiiu_hid.h | 1 + 3 files changed, 103 insertions(+), 43 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 211f67dfbb..7c8fa9296a 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -28,12 +28,14 @@ static uint8_t activation_packet[] = { 0x13 }; typedef struct wiiu_gca_instance { hid_driver_instance_t *driver; + bool online; uint8_t device_state[37]; joypad_connection_t *pads[4]; } wiiu_gca_instance_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); extern pad_connection_interface_t wiiu_gca_pad_connection; @@ -45,21 +47,29 @@ static void *wiiu_gca_init(hid_driver_instance_t *driver) driver->hid_driver->send_control(driver->hid_data, activation_packet, sizeof(activation_packet)); driver->hid_driver->read(driver->hid_data, instance->device_state, sizeof(instance->device_state)); + instance->online = true; return instance; } static void wiiu_gca_free(void *data) { - wiiu_gca_instance_t *instance = (wiiu_gca_instance_t *)data; - if(instance) { - free(instance); + wiiu_gca_instance_t *instance = (wiiu_gca_instance_t *)data; + int i; + + if(instance) { + instance->online = false; + + for(i = 0; i < 4; 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) + if(!instance || !instance->online) return; if(size > sizeof(instance->device_state)) @@ -71,58 +81,70 @@ static void wiiu_gca_handle_packet(void *data, uint8_t *buffer, size_t size) static void update_pad_state(wiiu_gca_instance_t *instance) { - int i, pad; + int i, pad; + if(!instance || !instance->online) + return; - /* process each pad */ - for(i = 1; i < 37; i += 9) - { - pad = i / 9; - switch(instance->device_state[i]) - { - case GCA_PORT_INITIALIZING: - case GCA_PORT_EMPTY: - if(instance->pads[pad] != NULL) - { - /* TODO: free pad */ - instance->pads[pad] = NULL; - } - break; - case GCA_PORT_CONNECTED: - if(instance->pads[pad] == NULL) - { - instance->pads[pad] = register_pad(instance); - } - } - } + /* process each pad */ + for(i = 1; i < 37; i += 9) + { + pad = i / 9; + switch(instance->device_state[i]) + { + case GCA_PORT_INITIALIZING: + case GCA_PORT_EMPTY: + if(instance->pads[pad] != NULL) + unregister_pad(instance, pad); + break; + case GCA_PORT_CONNECTED: + if(instance->pads[pad] == NULL) + instance->pads[pad] = register_pad(instance); + } + } } static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance) { - int slot; - joypad_connection_t *result; + int slot; + joypad_connection_t *result; - slot = pad_connection_find_vacant_pad(instance->driver->pad_connection_list); - if(slot < 0) - return NULL; + if(!instance || !instance->online) + return NULL; - result = &(instance->driver->pad_connection_list[slot]); - result->iface = &wiiu_gca_pad_connection; - result->data = result->iface->init(instance, slot, instance->driver->hid_driver); - result->connected = true; - input_pad_connect(slot, instance->driver->pad_driver); + slot = pad_connection_find_vacant_pad(instance->driver->pad_connection_list); + if(slot < 0) + return NULL; - return result; + result = &(instance->driver->pad_connection_list[slot]); + result->iface = &wiiu_gca_pad_connection; + result->data = result->iface->init(instance, slot, instance->driver->hid_driver); + result->connected = true; + input_pad_connect(slot, instance->driver->pad_driver); + + return result; +} + +static void unregister_pad(wiiu_gca_instance_t *instance, int slot) +{ + if(!instance || slot < 0 || slot >= 4 || instance->pads[slot] == NULL) + return; + + joypad_connection_t *pad = instance->pads[slot]; + instance->pads[slot] = NULL; + pad->iface->deinit(pad->data); + pad->data = NULL; + pad->connected = false; } static bool wiiu_gca_detect(uint16_t vendor_id, uint16_t product_id) { - return vendor_id == VID_NINTENDO && product_id == PID_NINTENDO_GCA; + return vendor_id == VID_NINTENDO && product_id == PID_NINTENDO_GCA; } hid_device_t wiiu_gca_hid_device = { - wiiu_gca_init, - wiiu_gca_free, - wiiu_gca_handle_packet, - wiiu_gca_detect, - "Wii U Gamecube Adapter" + wiiu_gca_init, + wiiu_gca_free, + wiiu_gca_handle_packet, + wiiu_gca_detect, + "Wii U Gamecube Adapter" }; pad_connection_interface_t wiiu_gca_pad_connection = { diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index cb09db3346..7a2cf113a4 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -329,6 +329,29 @@ static wiiu_attach_event *synchronized_get_events_list(void) return list; } +static wiiu_adapter_t *synchronized_remove_from_adapters_list(uint32_t handle) +{ + OSFastMutex_Lock(&(adapters.lock)); + wiiu_adapter_t *iterator, *prev = NULL; + + for(iterator = adapters.list; iterator != NULL; iterator = iterator->next) + { + if(iterator->handle == handle) + { + /* we're at the start of the list, so just re-assign head */ + if(prev == NULL) + adapters.list = iterator->next; + else + prev->next = iterator->next; + break; + } + prev = iterator; + } + OSFastMutex_Unlock(&(adapters.lock)); + + return iterator; +} + static void synchronized_add_to_adapters_list(wiiu_adapter_t *adapter) { OSFastMutex_Lock(&(adapters.lock)); @@ -368,6 +391,13 @@ error: static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event) { + wiiu_adapter_t *adapter = synchronized_remove_from_adapters_list(event->handle); + + if(adapter) { + adapter->driver->free(adapter->driver_handle); + adapter->driver_handle = NULL; + delete_adapter(adapter); + } } @@ -478,6 +508,13 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, return; } + if(error) + { + RARCH_ERR("Read failed with error 0x%08x\n", error); + adapter->state = ADAPTER_STATE_DONE; + return; + } + adapter->driver->handle_packet(adapter->driver_handle, buffer, buffer_size); adapter->state = ADAPTER_STATE_READING; diff --git a/wiiu/input/wiiu_hid.h b/wiiu/input/wiiu_hid.h index b1ce59a6c3..717980e7c8 100644 --- a/wiiu/input/wiiu_hid.h +++ b/wiiu/input/wiiu_hid.h @@ -48,6 +48,7 @@ static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list); static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event); static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event); static void synchronized_add_to_adapters_list(wiiu_adapter_t *adapter); +static wiiu_adapter_t *synchronized_remove_from_adapters_list(uint32_t handle); static void synchronized_add_event(wiiu_attach_event *event); static void wiiu_start_read_loop(wiiu_adapter_t *adapter); static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, From dc6f4c23ed26f5c010fcae9a15b5ba7f0dd521b5 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 11 Mar 2018 23:18:48 -0700 Subject: [PATCH 05/31] Rename hid_driver_instance members for clarity --- input/common/hid/device_wiiu_gca.c | 10 +++++----- input/common/hid/hid_device_driver.c | 20 ++++++++++---------- input/include/hid_driver.h | 6 +++--- wiiu/input/wiiu_hid.c | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 7c8fa9296a..ee721c3c7e 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -45,8 +45,8 @@ static void *wiiu_gca_init(hid_driver_instance_t *driver) memset(instance, 0, sizeof(wiiu_gca_instance_t)); instance->driver = driver; - driver->hid_driver->send_control(driver->hid_data, activation_packet, sizeof(activation_packet)); - driver->hid_driver->read(driver->hid_data, instance->device_state, sizeof(instance->device_state)); + driver->os_driver->send_control(driver->os_driver_data, activation_packet, sizeof(activation_packet)); + driver->os_driver->read(driver->os_driver_data, instance->device_state, sizeof(instance->device_state)); instance->online = true; return instance; @@ -110,13 +110,13 @@ static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance) { if(!instance || !instance->online) return NULL; - slot = pad_connection_find_vacant_pad(instance->driver->pad_connection_list); + slot = pad_connection_find_vacant_pad(instance->driver->pad_list); if(slot < 0) return NULL; - result = &(instance->driver->pad_connection_list[slot]); + result = &(instance->driver->pad_list[slot]); result->iface = &wiiu_gca_pad_connection; - result->data = result->iface->init(instance, slot, instance->driver->hid_driver); + result->data = result->iface->init(instance, slot, instance->driver->os_driver); result->connected = true; input_pad_connect(slot, instance->driver->pad_driver); diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index a3b861bf4d..e850188f07 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -61,20 +61,20 @@ bool hid_init(hid_driver_instance_t *instance, if(!instance || !hid_driver || !pad_driver || slots > MAX_USERS) return false; - instance->hid_data = hid_driver->init(instance); - if(!instance->hid_data) + instance->os_driver_data = hid_driver->init(instance); + if(!instance->os_driver_data) return false; - instance->pad_connection_list = pad_connection_init(slots); - if(!instance->pad_connection_list) + instance->pad_list = pad_connection_init(slots); + if(!instance->pad_list) { - hid_driver->free(instance->hid_data); - instance->hid_data = NULL; + hid_driver->free(instance->os_driver_data); + instance->os_driver_data = NULL; return false; } instance->max_slot = slots; - instance->hid_driver = hid_driver; + instance->os_driver = hid_driver; instance->pad_driver = pad_driver; return true; @@ -90,11 +90,11 @@ void hid_deinit(hid_driver_instance_t *instance) if(!instance) return; - pad_connection_destroy(instance->pad_connection_list); + pad_connection_destroy(instance->pad_list); - if(instance->hid_driver && instance->hid_data) + if(instance->os_driver && instance->os_driver_data) { - instance->hid_driver->free(instance->hid_data); + instance->os_driver->free(instance->os_driver_data); } memset(instance, 0, sizeof(hid_driver_instance_t)); diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 37ae190a51..59b5a62d28 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -53,10 +53,10 @@ struct hid_driver }; struct hid_driver_instance { - hid_driver_t *hid_driver; - void *hid_data; + hid_driver_t *os_driver; + void *os_driver_data; input_device_driver_t *pad_driver; - joypad_connection_t *pad_connection_list; + joypad_connection_t *pad_list; unsigned max_slot; }; diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 7a2cf113a4..8c82209704 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -37,7 +37,7 @@ static const char *wiiu_hid_joypad_name(void *data, unsigned slot) wiiu_hid_t *hid = (wiiu_hid_t *)data; - return hid->driver->pad_connection_list[slot].iface->get_name(data); + return hid->driver->pad_list[slot].iface->get_name(data); } static void wiiu_hid_joypad_get_buttons(void *data, unsigned port, retro_bits_t *state) From 180d6a28bfa3097bc24c7649afd2ca4ba7a11cfa Mon Sep 17 00:00:00 2001 From: gblues Date: Sat, 24 Mar 2018 22:35:22 -0700 Subject: [PATCH 06/31] Fix up HID device driver initialization == DETAILS Turns out the cause of the crash was a bad cast, resulting in a function call to nowhere. Also, I think the DSI exception handler only works on the primary core; when this was happening in the background thread, I got a black screen error instead. Next up: finishing up the GCA driver. --- input/common/hid/device_ds3.c | 2 +- input/common/hid/device_ds4.c | 2 +- input/common/hid/device_wiiu_gca.c | 30 ++++--- input/common/hid/hid_device_driver.h | 3 +- wiiu/input/hidpad_driver.c | 4 +- wiiu/input/wiiu_hid.c | 117 +++++++++++++++++++-------- wiiu/input/wiiu_hid.h | 7 +- 7 files changed, 113 insertions(+), 52 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 569d4d7f79..8b156d2ef5 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -21,7 +21,7 @@ struct ds3_instance { void *handle; }; -static void *ds3_init(hid_driver_instance_t *hid_driver) +static void *ds3_init(void *handle) { return NULL; } diff --git a/input/common/hid/device_ds4.c b/input/common/hid/device_ds4.c index 6c8b77ac2f..861de2751f 100644 --- a/input/common/hid/device_ds4.c +++ b/input/common/hid/device_ds4.c @@ -21,7 +21,7 @@ struct ds4_instance { void *handle; }; -static void *ds4_init(hid_driver_instance_t *hid_driver) +static void *ds4_init(void *handle) { return NULL; } diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index ee721c3c7e..960f2f3016 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -27,7 +27,7 @@ static uint8_t activation_packet[] = { 0x13 }; #define GCA_PORT_CONNECTED 0x14 typedef struct wiiu_gca_instance { - hid_driver_instance_t *driver; + void *handle; bool online; uint8_t device_state[37]; joypad_connection_t *pads[4]; @@ -39,17 +39,29 @@ static void unregister_pad(wiiu_gca_instance_t *instance, int slot); extern pad_connection_interface_t wiiu_gca_pad_connection; -static void *wiiu_gca_init(hid_driver_instance_t *driver) +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->driver = driver; + instance->handle = handle; - driver->os_driver->send_control(driver->os_driver_data, activation_packet, sizeof(activation_packet)); - driver->os_driver->read(driver->os_driver_data, instance->device_state, sizeof(instance->device_state)); + 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; + RARCH_LOG("[gca]: init done\n"); return instance; + + error: + RARCH_ERR("[gca]: init failed\n"); + if(instance) + free(instance); + return NULL; } static void wiiu_gca_free(void *data) { @@ -110,15 +122,15 @@ static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance) { if(!instance || !instance->online) return NULL; - slot = pad_connection_find_vacant_pad(instance->driver->pad_list); + slot = pad_connection_find_vacant_pad(hid_instance.pad_list); if(slot < 0) return NULL; - result = &(instance->driver->pad_list[slot]); + result = &(hid_instance.pad_list[slot]); result->iface = &wiiu_gca_pad_connection; - result->data = result->iface->init(instance, slot, instance->driver->os_driver); + result->data = result->iface->init(instance, slot, hid_instance.os_driver); result->connected = true; - input_pad_connect(slot, instance->driver->pad_driver); + input_pad_connect(slot, hid_instance.pad_driver); return result; } diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h index 8bb371f70e..8cd9f19944 100644 --- a/input/common/hid/hid_device_driver.h +++ b/input/common/hid/hid_device_driver.h @@ -20,9 +20,10 @@ #include "../../input_driver.h" #include "../../connect/joypad_connection.h" #include "../../include/hid_driver.h" +#include "../../../verbosity.h" typedef struct hid_device { - void *(*init)(hid_driver_instance_t *driver); + void *(*init)(void *handle); void (*free)(void *data); void (*handle_packet)(void *data, uint8_t *buffer, size_t size); bool (*detect)(uint16_t vid, uint16_t pid); diff --git a/wiiu/input/hidpad_driver.c b/wiiu/input/hidpad_driver.c index 272bd2e7c0..8991d156ba 100644 --- a/wiiu/input/hidpad_driver.c +++ b/wiiu/input/hidpad_driver.c @@ -108,10 +108,8 @@ static int16_t hidpad_axis(unsigned pad, uint32_t axis) static void hidpad_poll(void) { -#if 0 if (ready) - hid_driver->poll(hid_data); -#endif + hid_instance.os_driver->poll(hid_instance.os_driver_data); } static const char *hidpad_name(unsigned pad) diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 8c82209704..aa8b78d030 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -134,7 +134,11 @@ static void wiiu_hid_free(const void *data) static void wiiu_hid_poll(void *data) { - (void)data; + wiiu_hid_t *hid = (wiiu_hid_t *)data; + if(hid == NULL) + return; + + synchronized_process_adapters(hid); } static void wiiu_hid_send_control(void *data, uint8_t *buf, size_t size) @@ -310,6 +314,46 @@ static void log_device(HIDDevice *device) } +static uint8_t try_init_driver(wiiu_adapter_t *adapter) +{ + adapter->driver_handle = adapter->driver->init(adapter); + if(adapter->driver_handle == NULL) { + RARCH_ERR("[hid]: Failed to initialize driver: %s\n", + adapter->driver->name); + return ADAPTER_STATE_DONE; + } + + return ADAPTER_STATE_READY; +} + +static void synchronized_process_adapters(wiiu_hid_t *hid) +{ + wiiu_adapter_t *adapter = NULL; + + OSFastMutex_Lock(&(adapters.lock)); + for(adapter = adapters.list; adapter != NULL; adapter = adapter->next) + { + switch(adapter->state) + { + case ADAPTER_STATE_DONE: + break; + case ADAPTER_STATE_NEW: + adapter->state = try_init_driver(adapter); + break; + case ADAPTER_STATE_READY: + case ADAPTER_STATE_READING: +#if 0 + adapter->driver->poll(); +#endif + break; + default: + RARCH_ERR("[hid]: Invalid adapter state: %d\n", adapter->state); + break; + } + } + OSFastMutex_Unlock(&(adapters.lock)); +} + static void synchronized_add_event(wiiu_attach_event *event) { OSFastMutex_Lock(&(events.lock)); @@ -413,12 +457,7 @@ static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) adapter->hid = hid; adapter->driver = event->driver; - - adapter->driver_handle = adapter->driver->init(hid->driver); - if(adapter->driver_handle == NULL) { - RARCH_ERR("[hid]: Failed to initialize driver: %s\n", - adapter->driver->name); - } + adapter->state = ADAPTER_STATE_NEW; RARCH_LOG("[hid]: adding to adapter list\n"); synchronized_add_to_adapters_list(adapter); @@ -434,13 +473,11 @@ error: void wiiu_start_read_loop(wiiu_adapter_t *adapter) { - adapter->state = ADAPTER_STATE_READING; -#if 0 - RARCH_LOG("HIDRead(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", - adapter->handle, adapter->rx_buffer, adapter->rx_size, - wiiu_hid_read_loop_callback, adapter); -#endif - HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, wiiu_hid_read_loop_callback, adapter); + HIDRead(adapter->handle, + adapter->rx_buffer, + adapter->rx_size, + wiiu_hid_read_loop_callback, + adapter); } /** @@ -493,32 +530,42 @@ static void log_buffer(uint8_t *data, uint32_t len) static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, uint8_t *buffer, uint32_t buffer_size, void *userdata) { - wiiu_adapter_t *adapter = (wiiu_adapter_t *)userdata; - if(!adapter) - { - RARCH_ERR("read_loop_callback: bad userdata\n"); - return; - } + wiiu_adapter_t *adapter = (wiiu_adapter_t *)userdata; + if(!adapter) + { + RARCH_ERR("read_loop_callback: bad userdata\n"); + return; + } - if(adapter->hid->polling_thread_quit) - { - RARCH_LOG("Shutting down read loop for device: %s\n", + if(adapter->hid->polling_thread_quit) + { + RARCH_LOG("Shutting down read loop for device: %s\n", adapter->driver->name); - adapter->state = ADAPTER_STATE_DONE; - return; - } + adapter->state = ADAPTER_STATE_DONE; + } - if(error) - { - RARCH_ERR("Read failed with error 0x%08x\n", error); - adapter->state = ADAPTER_STATE_DONE; - return; - } + if(adapter->state == ADAPTER_STATE_READY || + adapter->state == ADAPTER_STATE_READING) { - adapter->driver->handle_packet(adapter->driver_handle, buffer, buffer_size); + adapter->state = ADAPTER_STATE_READING; - adapter->state = ADAPTER_STATE_READING; - HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, + if(error) + { + int16_t r1 = (error & 0x0000FFFF); + 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 + } + } + + /* this can also get set if something goes wrong in initialization */ + if(adapter->state == ADAPTER_STATE_DONE) + return; + + HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, wiiu_hid_read_loop_callback, adapter); } diff --git a/wiiu/input/wiiu_hid.h b/wiiu/input/wiiu_hid.h index 717980e7c8..59ad898fea 100644 --- a/wiiu/input/wiiu_hid.h +++ b/wiiu/input/wiiu_hid.h @@ -24,8 +24,10 @@ #define DEVICE_USED 1 #define ADAPTER_STATE_NEW 0 -#define ADAPTER_STATE_READING 1 -#define ADAPTER_STATE_DONE 2 +#define ADAPTER_STATE_READY 1 +#define ADAPTER_STATE_READING 2 +#define ADAPTER_STATE_DONE 3 + static void *alloc_zeroed(size_t alignment, size_t size); static OSThread *new_thread(void); @@ -47,6 +49,7 @@ static wiiu_attach_event *synchronized_get_events_list(void); static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list); static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event); static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event); +static void synchronized_process_adapters(wiiu_hid_t *hid); static void synchronized_add_to_adapters_list(wiiu_adapter_t *adapter); static wiiu_adapter_t *synchronized_remove_from_adapters_list(uint32_t handle); static void synchronized_add_event(wiiu_attach_event *event); From 8a4c5086fb20045b3e7a23b972b15fc9171da703 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 25 Mar 2018 22:59:30 -0700 Subject: [PATCH 07/31] 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. --- input/common/hid/device_wiiu_gca.c | 248 ++++++++++++++++++++++++----- input/drivers/wiiu_input.c | 4 + wiiu/input/wiiu_hid.c | 2 - 3 files changed, 213 insertions(+), 41 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 960f2f3016..79fb2ae59d 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with RetroArch. * If not, see . */ - +#include #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 -*/ }; diff --git a/input/drivers/wiiu_input.c b/input/drivers/wiiu_input.c index 5a188c1f21..869e8f9d1b 100644 --- a/input/drivers/wiiu_input.c +++ b/input/drivers/wiiu_input.c @@ -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 }; diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index aa8b78d030..1e4efb0049 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -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 } } From 6b43defc983b501e8be3ebe7290de67ebffdcaf4 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 25 Mar 2018 23:20:17 -0700 Subject: [PATCH 08/31] Less verbose logging --- wiiu/input/wiiu_hid.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 1e4efb0049..b9cc8c3af4 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -93,7 +93,6 @@ static void *wiiu_hid_init(hid_driver_instance_t *driver) if (!hid->polling_thread) goto error; - RARCH_LOG("[hid]: Registering HIDClient\n"); HIDAddClient(client, wiiu_attach_callback); hid->client = client; @@ -216,13 +215,7 @@ static int32_t wiiu_hid_read(void *data, void *buffer, size_t size) if(size > adapter->rx_size) return -1; -#if 1 - int32_t result = HIDRead(adapter->handle, buffer, size, NULL, NULL); - log_buffer(buffer, size); - return result; -#else return HIDRead(adapter->handle, buffer, size, NULL, NULL); -#endif } @@ -409,11 +402,10 @@ static int32_t wiiu_attach_callback(HIDClient *client, { wiiu_attach_event *event = NULL; - log_device(device); - switch(attach) { case HID_DEVICE_ATTACH: + log_device(device); case HID_DEVICE_DETACH: if (device) event = new_attach_event(device); @@ -459,10 +451,7 @@ static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) adapter->driver = event->driver; adapter->state = ADAPTER_STATE_NEW; - RARCH_LOG("[hid]: adding to adapter list\n"); synchronized_add_to_adapters_list(adapter); - - RARCH_LOG("[hid]: starting read loop\n"); wiiu_start_read_loop(adapter); return; From 1eea48d0c8ecfc3bd98b4246f3dccaaa5ec0b74a Mon Sep 17 00:00:00 2001 From: gblues Date: Mon, 26 Mar 2018 23:35:54 -0700 Subject: [PATCH 09/31] Fix crash on exit bug == DETAILS Turns out freeing memory that's already been freed is.. bad. Fix two double-free instances; one due to over-freeing and the other due to wrong order-of-operations causing a double free. Also updated logging a little. == TESTING The GC adapter still clobbers slot 0, but the "emergency exit" sequence works to quit RA cleanly. --- input/common/hid/device_wiiu_gca.c | 10 ++++++++++ input/common/hid/hid_device_driver.c | 12 +++++++++++- wiiu/input/wiiu_hid.c | 7 ++++--- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 79fb2ae59d..2cfb601771 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -169,12 +169,19 @@ static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port joypad_connection_t *result; if(!instance || !instance->online) + { + RARCH_ERR("[gca]: bad instance\n"); return NULL; + } slot = pad_connection_find_vacant_pad(hid_instance.pad_list); if(slot < 0) + { + RARCH_ERR("[gca]: failed to find a free slot\n"); return NULL; + } + RARCH_LOG("[gca]: registering pad in port %d to slot %d\n", port+1, slot); result = &(hid_instance.pad_list[slot]); result->iface = &wiiu_gca_pad_connection; result->data = result->iface->init(instance, slot, hid_instance.os_driver); @@ -237,7 +244,10 @@ static void wiiu_gca_pad_deinit(void *data) if(pad) { if(pad->name) + { free(pad->name); + pad->name = NULL; + } free(pad); } diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index e850188f07..13bbf89d40 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -58,13 +58,16 @@ bool hid_init(hid_driver_instance_t *instance, input_device_driver_t *pad_driver, unsigned slots) { + RARCH_LOG("[hid]: initializing instance with %d pad slots\n", slots); if(!instance || !hid_driver || !pad_driver || slots > MAX_USERS) return false; + RARCH_LOG("[hid]: initializing HID subsystem driver...\n"); instance->os_driver_data = hid_driver->init(instance); if(!instance->os_driver_data) return false; + RARCH_LOG("[hid]: initializing pad list...\n"); instance->pad_list = pad_connection_init(slots); if(!instance->pad_list) { @@ -77,6 +80,8 @@ bool hid_init(hid_driver_instance_t *instance, instance->os_driver = hid_driver; instance->pad_driver = pad_driver; + RARCH_LOG("[hid]: instance initialization complete.\n"); + return true; } @@ -90,13 +95,18 @@ void hid_deinit(hid_driver_instance_t *instance) if(!instance) return; - pad_connection_destroy(instance->pad_list); + RARCH_LOG("[hid]: destroying instance\n"); if(instance->os_driver && instance->os_driver_data) { + RARCH_LOG("[hid]: tearing down HID subsystem driver...\n"); instance->os_driver->free(instance->os_driver_data); } + RARCH_LOG("[hid]: destroying pad data...\n"); + pad_connection_destroy(instance->pad_list); + + RARCH_LOG("[hid]: wiping instance data...\n"); memset(instance, 0, sizeof(hid_driver_instance_t)); } diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index b9cc8c3af4..7bbca4987e 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -430,8 +430,7 @@ static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event) wiiu_adapter_t *adapter = synchronized_remove_from_adapters_list(event->handle); if(adapter) { - adapter->driver->free(adapter->driver_handle); - adapter->driver_handle = NULL; + RARCH_LOG("[hid]: freeing detached pad\n"); delete_adapter(adapter); } } @@ -580,8 +579,10 @@ static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack) * while we are holding the lock. */ if(incomplete == 0) { + RARCH_LOG("All in-flight reads complete.\n"); while(adapters.list != NULL) { + RARCH_LOG("[hid]: shutting down adapter..\n"); adapter = adapters.list; adapters.list = adapter->next; delete_adapter(adapter); @@ -599,7 +600,6 @@ static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack) } }while(incomplete); - RARCH_LOG("All in-flight reads complete.\n"); } static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list) @@ -725,6 +725,7 @@ static void delete_adapter(wiiu_adapter_t *adapter) adapter->driver_handle = NULL; adapter->driver = NULL; } + free(adapter); } From 89c1ba7929c78dfbf828a2d07e6c3d2d75fdacb0 Mon Sep 17 00:00:00 2001 From: gblues Date: Wed, 28 Mar 2018 00:02:09 -0700 Subject: [PATCH 10/31] Keep HID pads from clobbering gamepad/wiimotes == DETAILS Trying to do weird pad math just wasn't working so I bit the bullet and just let it allocate all 16 pads in the slot list, then just mark 0-4 as connected so that the slot allocator would start at 5. I can see it detect the pad, but no idea if it works. Out of time for today. --- input/common/hid/device_wiiu_gca.c | 41 ++++++------------------------ input/input_autodetect_builtin.c | 1 + wiiu/input/hidpad_driver.c | 26 ++++++++++--------- wiiu/input/wiiu_hid.c | 6 +---- 4 files changed, 24 insertions(+), 50 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 2cfb601771..6cda78cad2 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -40,14 +40,12 @@ typedef struct gca_pad_data 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, 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; @@ -91,10 +89,17 @@ 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) + { + RARCH_WARN("[gca]: instance null or not ready yet.\n"); return; + } if(size > sizeof(instance->device_state)) + { + RARCH_WARN("[gca]: packet size %d is too big for buffer of size %d\n", + size, sizeof(instance->device_state)); return; + } memcpy(instance->device_state, buffer, size); update_pad_state(instance); @@ -141,29 +146,6 @@ static void update_pad_state(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; @@ -185,7 +167,6 @@ static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port 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); @@ -243,12 +224,6 @@ static void wiiu_gca_pad_deinit(void *data) if(pad) { - if(pad->name) - { - free(pad->name); - pad->name = NULL; - } - free(pad); } } @@ -338,7 +313,7 @@ const char *wiiu_gca_get_name(void *data) { gca_pad_t *pad = (gca_pad_t *)data; - return pad->name; + return "GameCube Controller"; } pad_connection_interface_t wiiu_gca_pad_connection = { diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 0e76b04f4e..a6096f2d87 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -612,6 +612,7 @@ 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("GameCube Controller", "wiiu", WIIUINPUT_GAMEPAD_DEFAULT_BINDS), #endif #ifdef __CELLOS_LV2__ DECL_AUTOCONF_DEVICE("SixAxis Controller", "ps3", PS3INPUT_DEFAULT_BINDS), diff --git a/wiiu/input/hidpad_driver.c b/wiiu/input/hidpad_driver.c index 8991d156ba..8db27a66dc 100644 --- a/wiiu/input/hidpad_driver.c +++ b/wiiu/input/hidpad_driver.c @@ -29,23 +29,17 @@ static const char *hidpad_name(unsigned pad); static bool ready = false; -static unsigned to_slot(unsigned pad) -{ - return pad - (WIIU_WIIMOTE_CHANNELS+1); -} - static bool init_hid_driver(void) { - unsigned connections_size = MAX_USERS - (WIIU_WIIMOTE_CHANNELS+1); - memset(&hid_instance, 0, sizeof(hid_instance)); - return hid_init(&hid_instance, &wiiu_hid, &hidpad_driver, connections_size); + return hid_init(&hid_instance, &wiiu_hid, &hidpad_driver, MAX_USERS); } static bool hidpad_init(void *data) { (void *)data; + int i; if(!init_hid_driver()) { @@ -53,6 +47,14 @@ static bool hidpad_init(void *data) return false; } +/* hid_instance.pad_list[0].connected = true; */ + + for(i = 0; i < (WIIU_WIIMOTE_CHANNELS+1); i++) + { + hid_instance.pad_list[i].connected = true; + } + + hidpad_poll(); ready = true; @@ -77,7 +79,7 @@ static bool hidpad_button(unsigned pad, uint16_t button) return false; #if 0 - return hid_driver->button(hid_data, to_slot(pad), button); + return hid_driver->button(hid_data, pad, button); #else return false; #endif @@ -89,7 +91,7 @@ static void hidpad_get_buttons(unsigned pad, retro_bits_t *state) BIT256_CLEAR_ALL_PTR(state); #if 0 - hid_driver->get_buttons(hid_data, to_slot(pad), state); + hid_driver->get_buttons(hid_data, pad, state); #endif BIT256_CLEAR_ALL_PTR(state); } @@ -100,7 +102,7 @@ static int16_t hidpad_axis(unsigned pad, uint32_t axis) return 0; #if 0 - return hid_driver->axis(hid_data, to_slot(pad), axis); + return hid_driver->axis(hid_data, pad, axis); #else return 0; #endif @@ -120,7 +122,7 @@ static const char *hidpad_name(unsigned pad) #if 1 return PAD_NAME_HID; #else - return hid_driver->name(hid_data, to_slot(pad)); + return hid_driver->name(hid_data, pad); #endif } diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 7bbca4987e..d6a1a6c707 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -328,16 +328,12 @@ static void synchronized_process_adapters(wiiu_hid_t *hid) { switch(adapter->state) { - case ADAPTER_STATE_DONE: - break; case ADAPTER_STATE_NEW: adapter->state = try_init_driver(adapter); break; case ADAPTER_STATE_READY: case ADAPTER_STATE_READING: -#if 0 - adapter->driver->poll(); -#endif + case ADAPTER_STATE_DONE: break; default: RARCH_ERR("[hid]: Invalid adapter state: %d\n", adapter->state); From 5060c2aac473cb8b617b03d83033363f60d09c14 Mon Sep 17 00:00:00 2001 From: gblues Date: Thu, 29 Mar 2018 23:33:31 -0700 Subject: [PATCH 11/31] More fixes, GC pad kinda sorta works == DETAILS - Added a new method to the joypad_connection_t interface for getting a single button - wired everything into the hidpad driver - for testing purposes, hacking the top-level joypad driver so that kpad isn't used - add a new RARCH_LOG_BUFFER method to verbosity for logging the contents of a binary buffer (useful for writing/debugging pad drivers) - fix a few bugs in the wiiu GC pad driver The button mapping isn't quite right, and I'm not sure what's going wrong. --- input/common/hid/device_wiiu_gca.c | 48 +++++++++++-- input/connect/joypad_connection.h | 1 + input/drivers_joypad/wiiu_joypad.c | 9 +-- input/include/hid_driver.h | 13 ++++ input/input_autodetect_builtin.c | 14 ++++ verbosity.c | 31 ++++++++ verbosity.h | 11 +-- wiiu/input/hidpad_driver.c | 33 +++------ wiiu/input/wiiu_hid.c | 110 ++++++++++------------------- 9 files changed, 160 insertions(+), 110 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 6cda78cad2..7556305f6d 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -101,6 +101,8 @@ static void wiiu_gca_handle_packet(void *data, uint8_t *buffer, size_t size) return; } + //RARCH_LOG_BUFFER(buffer, size); + memcpy(instance->device_state, buffer, size); update_pad_state(instance); } @@ -239,6 +241,29 @@ static void wiiu_gca_get_buttons(void *data, retro_bits_t *state) } } +static void log_bitmask(uint32_t bits) +{ + char buf[33]; + int i; + + for(i = 0; i < 32; i++) + { + buf[i] = (bits & (1 << i)) ? '1' : '0'; + } + buf[32] = '\0'; + + RARCH_LOG("pressed_keys: %s\n", buf); +} + +/** + * The USB packet provides a 9-byte data packet for each pad. + * + * byte 0: connection status (0x14 = connected, 0x04 = disconnected) + * bytes 1-2: digital buttons + * bytes 3-4: left analog stick x/y + * bytes 5-6: right analog stick x/y + * bytes 7-8: L/R analog state (note that these have digital buttons too) + */ static void wiiu_gca_packet_handler(void *data, uint8_t *packet, uint16_t size) { gca_pad_t *pad = (gca_pad_t *)data; @@ -263,9 +288,13 @@ static void wiiu_gca_packet_handler(void *data, uint8_t *packet, uint16_t size) if(!pad || !packet || size > sizeof(pad->data)) return; +/* RARCH_LOG_BUFFER(packet, size); */ + memcpy(pad->data, packet, size); pad->buttons = 0; - pressed_keys = pad->data[3] | (pad->data[4] << 8); + pressed_keys = pad->data[1] | (pad->data[2] << 8); + + log_bitmask(pressed_keys); for(i = 0; i < 12; i++) { @@ -289,7 +318,7 @@ static int16_t wiiu_gca_get_axis(void *data, unsigned axis) if(!pad || axis >= 4) return 0; - val = pad->data[5+axis]; + val = pad->data[3+axis]; switch(axis) { @@ -309,13 +338,23 @@ static int16_t wiiu_gca_get_axis(void *data, unsigned axis) return val; } -const char *wiiu_gca_get_name(void *data) +static const char *wiiu_gca_get_name(void *data) { gca_pad_t *pad = (gca_pad_t *)data; return "GameCube Controller"; } +static bool wiiu_gca_button(void *data, uint16_t joykey) +{ + gca_pad_t *pad = (gca_pad_t *)data; + + if(!pad) + return false; + + return (pad->buttons & joykey); +} + pad_connection_interface_t wiiu_gca_pad_connection = { wiiu_gca_pad_init, wiiu_gca_pad_deinit, @@ -323,5 +362,6 @@ pad_connection_interface_t wiiu_gca_pad_connection = { wiiu_gca_set_rumble, wiiu_gca_get_buttons, wiiu_gca_get_axis, - wiiu_gca_get_name + wiiu_gca_get_name, + wiiu_gca_button }; diff --git a/input/connect/joypad_connection.h b/input/connect/joypad_connection.h index ec78b3c4df..e2f421dd45 100644 --- a/input/connect/joypad_connection.h +++ b/input/connect/joypad_connection.h @@ -61,6 +61,7 @@ typedef struct pad_connection_interface void (*get_buttons)(void *data, retro_bits_t *state); int16_t (*get_axis)(void *data, unsigned axis); const char* (*get_name)(void *data); + bool (*button)(void *data, uint16_t joykey); } pad_connection_interface_t; typedef struct joypad_connection joypad_connection_t; diff --git a/input/drivers_joypad/wiiu_joypad.c b/input/drivers_joypad/wiiu_joypad.c index 4ae4a4863a..aa9c3ab277 100644 --- a/input/drivers_joypad/wiiu_joypad.c +++ b/input/drivers_joypad/wiiu_joypad.c @@ -40,9 +40,10 @@ static input_device_driver_t *get_driver_for_pad(unsigned pad) { if(wpad_driver.query_pad(pad)) return &wpad_driver; +/* if(kpad_driver.query_pad(pad)) return &kpad_driver; - +*/ #ifdef WIIU_HID return &hidpad_driver; #else @@ -84,11 +85,7 @@ static bool wiiu_joypad_init(void* data) static bool wiiu_joypad_query_pad(unsigned pad) { -#ifdef WIIU_HID return ready && pad < MAX_USERS; -#else - return ready && pad < 5; -#endif } static void wiiu_joypad_destroy(void) @@ -138,7 +135,7 @@ static void wiiu_joypad_poll(void) static const char* wiiu_joypad_name(unsigned pad) { if(!wiiu_joypad_query_pad(pad)) - return "N/A"; + return "Snuffleupagus"; return pad_drivers[pad]->name(pad); } diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 59b5a62d28..1eee8a3f85 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -52,6 +52,19 @@ struct hid_driver int32_t (*read)(void *handle, void *buf, size_t size); }; +#define HID_GET_BUTTONS(pad, state) hid_instance.os_driver->get_buttons( \ + hid_instance.os_driver_data, pad, state) +#define HID_BUTTON(pad, key) hid_instance.os_driver->button( \ + hid_instance.os_driver_data, pad, key) +#define HID_AXIS(pad, axis) hid_instance.os_driver->axis( \ + hid_instance.os_driver_data, pad, axis) +#define HID_PAD_NAME(pad) hid_instance.os_driver->name( \ + hid_instance.os_driver_data, pad) +#define HID_POLL() hid_instance.os_driver->poll( \ + hid_instance.os_driver_data) + + + struct hid_driver_instance { hid_driver_t *os_driver; void *os_driver_data; diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index a6096f2d87..45bbed0775 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -228,6 +228,20 @@ DECL_AXIS(r_y_minus, +3) #ifdef WIIU +#define WIIUINPUT_GAMECUBE_DEFAULT_BINDS \ +DECL_BTN_EX(b, 0, "B") \ +DECL_BTN_EX(y, 1, "Y") \ +DECL_BTN_EX(select, 2, "Z") \ +DECL_BTN_EX(start, 3, "Start/Pause") \ +DECL_BTN_EX(up, 4, "D-Pad Up") \ +DECL_BTN_EX(down, 5, "D-Pad Down") \ +DECL_BTN_EX(left, 6, "D-Pad Left") \ +DECL_BTN_EX(right, 7, "D-Pad Right") \ +DECL_BTN_EX(a, 8, "A") \ +DECL_BTN_EX(x, 9, "X") \ +DECL_BTN_EX(l, 10, "L") \ +DECL_BTN_EX(r, 11, "R") + #define WIIUINPUT_GAMEPAD_DEFAULT_BINDS \ DECL_BTN_EX(menu_toggle, 1, "Home") \ DECL_BTN_EX(select, 2, "-") \ diff --git a/verbosity.c b/verbosity.c index ddb46512a9..ee6837132c 100644 --- a/verbosity.c +++ b/verbosity.c @@ -193,6 +193,37 @@ void RARCH_LOG_V(const char *tag, const char *fmt, va_list ap) #endif } +void RARCH_LOG_BUFFER(uint8_t *data, size_t size) +{ + int i, offset; + int padding = size % 16; + uint8_t buf[16]; + + RARCH_LOG("== %d-byte buffer ==================\n", size); + for(i = 0, offset = 0; i < size; i++) + { + buf[offset] = data[i]; + offset++; + + if(offset == 16) + { + offset = 0; + RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], + buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); + } + } + if(padding) + { + for(i = padding; i < 16; i++) + buf[i] = 0xff; + RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], + buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); + } + RARCH_LOG("==================================\n"); +} + void RARCH_LOG(const char *fmt, ...) { va_list ap; diff --git a/verbosity.h b/verbosity.h index 5f5cdcf30a..42ae964f58 100644 --- a/verbosity.h +++ b/verbosity.h @@ -86,7 +86,7 @@ void logger_send_v(const char *__format, va_list args); logger_send_v(fmt, vp); \ } while (0) -#else +#else /* IS_SALAMANDER */ #define RARCH_LOG(...) do { \ logger_send("" __VA_ARGS__); \ @@ -123,11 +123,14 @@ void logger_send_v(const char *__format, va_list args); logger_send("[OUTPUT] " tag); \ logger_send_v(fmt, vp); \ } while (0) - #endif -#else + +#define RARCH_LOG_BUFFER(...) do { } while(0) + +#else /* HAVE_LOGGER */ void RARCH_LOG_V(const char *tag, const char *fmt, va_list ap); void RARCH_LOG(const char *fmt, ...); +void RARCH_LOG_BUFFER(uint8_t *buffer, size_t size); void RARCH_LOG_OUTPUT(const char *msg, ...); void RARCH_WARN(const char *fmt, ...); void RARCH_ERR(const char *fmt, ...); @@ -135,7 +138,7 @@ void RARCH_ERR(const char *fmt, ...); #define RARCH_LOG_OUTPUT_V RARCH_LOG_V #define RARCH_WARN_V RARCH_LOG_V #define RARCH_ERR_V RARCH_LOG_V -#endif +#endif /* HAVE_LOGGER */ RETRO_END_DECLS diff --git a/wiiu/input/hidpad_driver.c b/wiiu/input/hidpad_driver.c index 8db27a66dc..97f05e9d06 100644 --- a/wiiu/input/hidpad_driver.c +++ b/wiiu/input/hidpad_driver.c @@ -47,13 +47,13 @@ static bool hidpad_init(void *data) return false; } -/* hid_instance.pad_list[0].connected = true; */ - + hid_instance.pad_list[0].connected = true; +/* for(i = 0; i < (WIIU_WIIMOTE_CHANNELS+1); i++) { hid_instance.pad_list[i].connected = true; } - +*/ hidpad_poll(); ready = true; @@ -63,7 +63,7 @@ static bool hidpad_init(void *data) static bool hidpad_query_pad(unsigned pad) { - return ready && (pad > WIIU_WIIMOTE_CHANNELS && pad < MAX_USERS); + return ready && pad < MAX_USERS; } static void hidpad_destroy(void) @@ -78,11 +78,7 @@ static bool hidpad_button(unsigned pad, uint16_t button) if (!hidpad_query_pad(pad)) return false; -#if 0 - return hid_driver->button(hid_data, pad, button); -#else - return false; -#endif + return HID_BUTTON(pad, button); } static void hidpad_get_buttons(unsigned pad, retro_bits_t *state) @@ -90,10 +86,7 @@ static void hidpad_get_buttons(unsigned pad, retro_bits_t *state) if (!hidpad_query_pad(pad)) BIT256_CLEAR_ALL_PTR(state); -#if 0 - hid_driver->get_buttons(hid_data, pad, state); -#endif - BIT256_CLEAR_ALL_PTR(state); + HID_GET_BUTTONS(pad, state); } static int16_t hidpad_axis(unsigned pad, uint32_t axis) @@ -101,17 +94,13 @@ static int16_t hidpad_axis(unsigned pad, uint32_t axis) if (!hidpad_query_pad(pad)); return 0; -#if 0 - return hid_driver->axis(hid_data, pad, axis); -#else - return 0; -#endif + return HID_AXIS(pad, axis); } static void hidpad_poll(void) { if (ready) - hid_instance.os_driver->poll(hid_instance.os_driver_data); + HID_POLL(); } static const char *hidpad_name(unsigned pad) @@ -119,11 +108,7 @@ static const char *hidpad_name(unsigned pad) if (!hidpad_query_pad(pad)) return "N/A"; -#if 1 - return PAD_NAME_HID; -#else - return hid_driver->name(hid_data, pad); -#endif + return HID_PAD_NAME(pad); } input_device_driver_t hidpad_driver = diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index d6a1a6c707..44c2822305 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -19,8 +19,6 @@ static wiiu_event_list events; static wiiu_adapter_list adapters; -static void log_buffer(uint8_t *data, uint32_t len); - static bool wiiu_hid_joypad_query(void *data, unsigned slot) { wiiu_hid_t *hid = (wiiu_hid_t *)data; @@ -30,51 +28,66 @@ static bool wiiu_hid_joypad_query(void *data, unsigned slot) return slot < hid->driver->max_slot; } -static const char *wiiu_hid_joypad_name(void *data, unsigned slot) +static joypad_connection_t *get_pad(wiiu_hid_t *hid, unsigned slot) { - if (!wiiu_hid_joypad_query(data, slot)) + if(!wiiu_hid_joypad_query(hid, slot)) return NULL; - wiiu_hid_t *hid = (wiiu_hid_t *)data; + joypad_connection_t *result = &(hid->driver->pad_list[slot]); + if(!result || !result->connected || !result->iface || !result->data) + return NULL; - return hid->driver->pad_list[slot].iface->get_name(data); + return result; } -static void wiiu_hid_joypad_get_buttons(void *data, unsigned port, retro_bits_t *state) +static const char *wiiu_hid_joypad_name(void *data, unsigned slot) { - (void)data; - (void)port; + joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot); - BIT256_CLEAR_ALL_PTR(state); + if(!pad) + return NULL; + + return pad->iface->get_name(pad->data); } -static bool wiiu_hid_joypad_button(void *data, unsigned port, uint16_t joykey) +static void wiiu_hid_joypad_get_buttons(void *data, unsigned slot, retro_bits_t *state) { - (void)data; - (void)port; - (void)joykey; + joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot); - return false; + if(pad) + pad->iface->get_buttons(pad->data, state); } -static bool wiiu_hid_joypad_rumble(void *data, unsigned pad, +static bool wiiu_hid_joypad_button(void *data, unsigned slot, uint16_t joykey) +{ + joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot); + + if(!pad) + return false; + + return pad->iface->button(pad->data, joykey); +} + +static bool wiiu_hid_joypad_rumble(void *data, unsigned slot, enum retro_rumble_effect effect, uint16_t strength) { - (void)data; - (void)pad; - (void)effect; - (void)strength; + joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot); + if(!pad) + return false; + + pad->iface->set_rumble(pad->data, effect, strength); return false; } -static int16_t wiiu_hid_joypad_axis(void *data, unsigned port, uint32_t joyaxis) +static int16_t wiiu_hid_joypad_axis(void *data, unsigned slot, uint32_t joyaxis) { - (void)data; - (void)port; - (void)joyaxis; + joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot); - return 0; + if(!pad) + return 0; + + return pad->iface->get_axis(pad->data, joyaxis); } static void *wiiu_hid_init(hid_driver_instance_t *driver) @@ -464,53 +477,6 @@ void wiiu_start_read_loop(wiiu_adapter_t *adapter) adapter); } -/** - * Takes a buffer and formats it for the log file, 16 bytes per line. - * - * When the end of the buffer is reached, it is padded out with 0xff. So e.g. - * a 5-byte buffer might look like: - * - * 5 bytes read fro HIDRead: - * 0102030405ffffff ffffffffffffffff - * ================================== - */ -static void log_buffer(uint8_t *data, uint32_t len) -{ - int i, o; - int padding = len % 16; - uint8_t buf[16]; - - (uint8_t *)data; - (uint32_t)len; - - RARCH_LOG("%d bytes read from HIDRead:\n", len); - - for(i = 0, o = 0; i < len; i++) - { - buf[o] = data[i]; - o++; - if(o == 16) - { - o = 0; - RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); - } - } - - if(padding) - { - for(i = padding; i < 16; i++) - buf[i] = 0xff; - - RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); - } - RARCH_LOG("==================================\n"); - -} - static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, uint8_t *buffer, uint32_t buffer_size, void *userdata) { From d65bd90e67f43ab66785f67d4a5f3c4412b569d1 Mon Sep 17 00:00:00 2001 From: gblues Date: Fri, 30 Mar 2018 18:57:34 -0700 Subject: [PATCH 12/31] Fix GC pad button mapping --- input/common/hid/device_wiiu_gca.c | 55 ++++++------------------------ input/input_autodetect_builtin.c | 34 +++++++++++------- 2 files changed, 31 insertions(+), 58 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 7556305f6d..1275c958d8 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -101,8 +101,6 @@ static void wiiu_gca_handle_packet(void *data, uint8_t *buffer, size_t size) return; } - //RARCH_LOG_BUFFER(buffer, size); - memcpy(instance->device_state, buffer, size); update_pad_state(instance); } @@ -165,7 +163,6 @@ static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port return NULL; } - RARCH_LOG("[gca]: registering pad in port %d to slot %d\n", port+1, slot); result = &(hid_instance.pad_list[slot]); result->iface = &wiiu_gca_pad_connection; result->data = result->iface->init(instance, slot, hid_instance.os_driver); @@ -184,6 +181,7 @@ static void unregister_pad(wiiu_gca_instance_t *instance, int slot) instance->pads[slot] = NULL; pad->iface->deinit(pad->data); pad->data = NULL; + pad->iface = NULL; pad->connected = false; } @@ -241,20 +239,6 @@ static void wiiu_gca_get_buttons(void *data, retro_bits_t *state) } } -static void log_bitmask(uint32_t bits) -{ - char buf[33]; - int i; - - for(i = 0; i < 32; i++) - { - buf[i] = (bits & (1 << i)) ? '1' : '0'; - } - buf[32] = '\0'; - - RARCH_LOG("pressed_keys: %s\n", buf); -} - /** * The USB packet provides a 9-byte data packet for each pad. * @@ -269,38 +253,11 @@ 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; -/* RARCH_LOG_BUFFER(packet, size); */ - memcpy(pad->data, packet, size); - pad->buttons = 0; - pressed_keys = pad->data[1] | (pad->data[2] << 8); - - log_bitmask(pressed_keys); - - for(i = 0; i < 12; i++) - { - pad->buttons |= (pressed_keys & (1 << i)) ? - (1 << button_mapping[i]) : 0; - } + pad->buttons = pad->data[1] | (pad->data[2] << 8); } static void wiiu_gca_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) @@ -345,6 +302,14 @@ static const char *wiiu_gca_get_name(void *data) return "GameCube Controller"; } +/** + * Button bitmask values: + * 0x0001 - A 0x0010 - left 0x0100 - Start/Pause + * 0x0002 - B 0x0020 - right 0x0200 - Z + * 0x0004 - X 0x0040 - down 0x0400 - R + * 0x0008 - Y 0x0080 - up 0x0800 - L + */ + static bool wiiu_gca_button(void *data, uint16_t joykey) { gca_pad_t *pad = (gca_pad_t *)data; diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 45bbed0775..75b9f0d3c6 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -229,18 +229,26 @@ DECL_AXIS(r_y_minus, +3) #ifdef WIIU #define WIIUINPUT_GAMECUBE_DEFAULT_BINDS \ -DECL_BTN_EX(b, 0, "B") \ -DECL_BTN_EX(y, 1, "Y") \ -DECL_BTN_EX(select, 2, "Z") \ -DECL_BTN_EX(start, 3, "Start/Pause") \ -DECL_BTN_EX(up, 4, "D-Pad Up") \ -DECL_BTN_EX(down, 5, "D-Pad Down") \ -DECL_BTN_EX(left, 6, "D-Pad Left") \ -DECL_BTN_EX(right, 7, "D-Pad Right") \ -DECL_BTN_EX(a, 8, "A") \ -DECL_BTN_EX(x, 9, "X") \ -DECL_BTN_EX(l, 10, "L") \ -DECL_BTN_EX(r, 11, "R") +DECL_BTN_EX(a, 0x0001, "A") \ +DECL_BTN_EX(b, 0x0002, "B") \ +DECL_BTN_EX(x, 0x0004, "X") \ +DECL_BTN_EX(y, 0x0008, "Y") \ +DECL_BTN_EX(select, 0x0200, "Z") \ +DECL_BTN_EX(start, 0x0100, "Start/Pause") \ +DECL_BTN_EX(l, 0x0800, "L Trigger") \ +DECL_BTN_EX(r, 0x0400, "R Trigger") \ +DECL_BTN_EX(left, 0x0010, "D-Pad Left") \ +DECL_BTN_EX(right, 0x0020, "D-Pad Right") \ +DECL_BTN_EX(down, 0x0040, "D-Pad Down") \ +DECL_BTN_EX(up, 0x0080, "D-Pad Up") \ +DECL_AXIS_EX(l_x_plus, +1, "Analog right") \ +DECL_AXIS_EX(l_x_minus, -1, "Analog left") \ +DECL_AXIS_EX(l_y_plus, +0, "Analog up") \ +DECL_AXIS_EX(l_y_minus, -0, "Analog down") \ +DECL_AXIS_EX(r_x_plus, +3, "C-stick right") \ +DECL_AXIS_EX(r_x_minus, -3, "C-stick left") \ +DECL_AXIS_EX(r_y_plus, +2, "C-stick up") \ +DECL_AXIS_EX(r_y_minus, -2, "C-stick down") #define WIIUINPUT_GAMEPAD_DEFAULT_BINDS \ DECL_BTN_EX(menu_toggle, 1, "Home") \ @@ -626,7 +634,7 @@ 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("GameCube Controller", "wiiu", WIIUINPUT_GAMEPAD_DEFAULT_BINDS), + DECL_AUTOCONF_DEVICE("GameCube Controller", "wiiu", WIIUINPUT_GAMECUBE_DEFAULT_BINDS), #endif #ifdef __CELLOS_LV2__ DECL_AUTOCONF_DEVICE("SixAxis Controller", "ps3", PS3INPUT_DEFAULT_BINDS), From 39e4167df65756591f3ab74b7c8bad854926fddd Mon Sep 17 00:00:00 2001 From: gblues Date: Fri, 30 Mar 2018 23:00:14 -0700 Subject: [PATCH 13/31] Start work on DualShock 3 driver == DETAILS The WiiU GC adapter is working! Next up: DualShock 3 I have the skeleton of the driver started, need to work out the activation packet. == TESTING The DS3 driver is broke as hell right now. --- input/common/hid/device_ds3.c | 114 +++++++++++++++++++++++---- input/common/hid/device_wiiu_gca.c | 5 +- input/common/hid/hid_device_driver.c | 21 ++++- input/common/hid/hid_device_driver.h | 3 +- 4 files changed, 121 insertions(+), 22 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 8b156d2ef5..3c1a805d60 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -16,38 +16,124 @@ #include "hid_device_driver.h" -struct ds3_instance { - hid_driver_t *driver; - void *handle; +#define DS3_ACTIVATION_REPORT_ID 0xf4 +#define DS3_RUMBLE_REPORT_ID 0x01 + +typedef struct ds3_instance { + void *handle; + joypad_connection_t *pad; +} ds3_instance_t; + +static uint8_t activation_packet[] = { + 0x42, 0x0c, 0x00, 0x00 }; +extern pad_connection_interface_t ds3_pad_connection; + static void *ds3_init(void *handle) { - return NULL; + ds3_instance_t *instance; + + instance = (ds3_instance_t *)calloc(1, sizeof(ds3_instance_t)); + if(!instance) + goto error; + + instance->handle = handle; + +/* TODO: do whatever is needed so that the read loop doesn't bomb out */ + + instance->pad = hid_pad_register(instance, &ds3_pad_connection); + if(!instance->pad) + goto error; + + return instance; + + error: + if(instance) + free(instance); + return NULL; } static void ds3_free(void *data) { - struct ds3_instance *instance = (struct ds3_instance *)data; - if(!instance) - return; + ds3_instance_t *instance = (ds3_instance_t *)data; - free(instance); + if(instance) + free(instance); } static void ds3_handle_packet(void *data, uint8_t *buffer, size_t size) { + ds3_instance_t *instance = (ds3_instance_t *)data; } static bool ds3_detect(uint16_t vendor_id, uint16_t product_id) { - return vendor_id == VID_SONY && product_id == PID_SONY_DS3; + return vendor_id == VID_SONY && product_id == PID_SONY_DS3; } hid_device_t ds3_hid_device = { - ds3_init, - ds3_free, - ds3_handle_packet, - ds3_detect, - "Sony DualShock 3" + ds3_init, + ds3_free, + ds3_handle_packet, + ds3_detect, + "Sony DualShock 3" +}; + +/** + * pad interface implementation + */ + +static void *ds3_pad_init(void *data, uint32_t slot, hid_driver_t *driver) +{ + return data; +} + +static void ds3_pad_deinit(void *data) +{ + ds3_instance_t *pad = (ds3_instance_t *)data; +} + +static void ds3_get_buttons(void *data, retro_bits_t *state) +{ + ds3_instance_t *pad = (ds3_instance_t *)data; +} + +static void ds3_packet_handler(void *data, uint8_t *packet, uint16_t size) +{ + ds3_instance_t *pad = (ds3_instance_t *)data; +} + +static void ds3_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) +{ + ds3_instance_t *pad = (ds3_instance_t *)data; +} + +static int16_t ds3_get_axis(void *data, unsigned axis) +{ + ds3_instance_t *pad = (ds3_instance_t *)data; + return 0; +} + +static const char *ds3_get_name(void *data) +{ + ds3_instance_t *pad = (ds3_instance_t *)data; + return "Sony DualShock 3"; +} + +static bool ds3_button(void *data, uint16_t joykey) +{ + ds3_instance_t *pad = (ds3_instance_t *)data; + return false; +} + +pad_connection_interface_t ds3_pad_connection = { + ds3_pad_init, + ds3_pad_deinit, + ds3_packet_handler, + ds3_set_rumble, + ds3_get_buttons, + ds3_get_axis, + ds3_get_name, + ds3_button }; diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 1275c958d8..1d50c513ee 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -44,7 +44,6 @@ typedef struct gca_pad_data static void update_pad_state(wiiu_gca_instance_t *instance); -static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port); static void unregister_pad(wiiu_gca_instance_t *instance, int port); extern pad_connection_interface_t wiiu_gca_pad_connection; @@ -131,7 +130,7 @@ static void update_pad_state(wiiu_gca_instance_t *instance) if(pad == NULL) { RARCH_LOG("[gca]: Gamepad at port %d connected.\n", port+1); - instance->pads[port] = register_pad(instance, port); + instance->pads[port] = hid_pad_register(instance, &wiiu_gca_pad_connection); pad = instance->pads[port]; if(pad == NULL) { @@ -146,6 +145,7 @@ static void update_pad_state(wiiu_gca_instance_t *instance) } } +/* static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port) { int slot; joypad_connection_t *result; @@ -171,6 +171,7 @@ static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port return result; } +*/ static void unregister_pad(wiiu_gca_instance_t *instance, int slot) { diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index 13bbf89d40..587f0dc33d 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -36,12 +36,25 @@ hid_device_t *hid_device_driver_lookup(uint16_t vendor_id, uint16_t product_id) return NULL; } -void hid_pad_connect(hid_driver_instance_t *instance, int pad) +joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface_t *iface) { - if(!instance || !instance->pad_driver) - return; + int slot; + joypad_connection_t *result; - input_pad_connect(pad, instance->pad_driver); + if(!pad_handle) + return NULL; + + slot = pad_connection_find_vacant_pad(hid_instance.pad_list); + if(slot < 0) + return NULL; + + result = &(hid_instance.pad_list[slot]); + result->iface = iface; + result->data = iface->init(pad_handle, slot, hid_instance.os_driver); + result->connected = true; + input_pad_connect(slot, hid_instance.pad_driver); + + return result; } /** diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h index 8cd9f19944..715fd7cfea 100644 --- a/input/common/hid/hid_device_driver.h +++ b/input/common/hid/hid_device_driver.h @@ -36,8 +36,7 @@ extern hid_device_t ds4_hid_device; extern hid_driver_instance_t hid_instance; hid_device_t *hid_device_driver_lookup(uint16_t vendor_id, uint16_t product_id); - -void hid_pad_connect(hid_driver_instance_t *instance, int pad); +joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface_t *iface); bool hid_init(hid_driver_instance_t *instance, hid_driver_t *hid_driver, input_device_driver_t *pad_driver, unsigned slots); void hid_deinit(hid_driver_instance_t *instance); From 2cf89feb868393a912549d8b37e2b7c17b5d2397 Mon Sep 17 00:00:00 2001 From: gblues Date: Sat, 31 Mar 2018 22:25:30 -0700 Subject: [PATCH 14/31] Code clean-up == DETAILS Now that I have a working implementation, it's time to tidy up a bit: - there was no need for the HID subsystem's object data to have a reference to the global hid state (since it's global), so removed it. - refactored the users of that member to use the global state, defining reusable macros. - reorganized the information in *.h files - removing the hid state also made the constructor changes to the hid driver unneeded, so I reverted those changes. == TESTING Confirmed clean build. Haven't tested the build yet to make sure everything still works, though. --- input/common/hid/hid_device_driver.c | 38 +----- input/drivers_hid/btstack_hid.c | 7 +- input/drivers_hid/iohidmanager_hid.c | 7 +- input/drivers_hid/libusb_hid.c | 7 +- input/drivers_hid/null_hid.c | 4 +- input/drivers_hid/wiiusb_hid.c | 6 +- input/drivers_joypad/wiiu_joypad.c | 8 +- input/include/hid_driver.h | 4 +- input/input_autodetect_builtin.c | 2 +- wiiu/include/wiiu/pad_driver.h | 186 --------------------------- wiiu/include/wiiu/pad_strings.h | 32 +++++ wiiu/input/hidpad_driver.c | 5 +- wiiu/input/kpad_driver.c | 2 +- wiiu/input/pad_functions.c | 2 +- wiiu/input/wiiu_hid.c | 10 +- wiiu/input/wiiu_hid.h | 69 +++++++++- wiiu/input/wiiu_hid_types.h | 28 ++++ wiiu/input/wiiu_input.h | 72 +++++++++++ wiiu/input/wpad_driver.c | 4 +- 19 files changed, 229 insertions(+), 264 deletions(-) delete mode 100644 wiiu/include/wiiu/pad_driver.h create mode 100644 wiiu/include/wiiu/pad_strings.h create mode 100644 wiiu/input/wiiu_hid_types.h create mode 100644 wiiu/input/wiiu_input.h diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index 587f0dc33d..3792e2c737 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -76,7 +76,7 @@ bool hid_init(hid_driver_instance_t *instance, return false; RARCH_LOG("[hid]: initializing HID subsystem driver...\n"); - instance->os_driver_data = hid_driver->init(instance); + instance->os_driver_data = hid_driver->init(); if(!instance->os_driver_data) return false; @@ -122,39 +122,3 @@ void hid_deinit(hid_driver_instance_t *instance) RARCH_LOG("[hid]: wiping instance data...\n"); memset(instance, 0, sizeof(hid_driver_instance_t)); } - -static void hid_device_log_buffer(uint8_t *data, uint32_t len) -{ -#if 0 - int i, offset; - int padding = len % 0x0F; - uint8_t buf[16]; - - RARCH_LOG("%d bytes read:\n", len); - - for(i = 0, offset = 0; i < len; i++) - { - buf[offset] = data[i]; - offset++; - if(offset == 16) - { - offset = 0; - RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); - } - } - - if(padding) - { - for(i = padding; i < 16; i++) - buf[i] = 0xff; - - RARCH_LOG("%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); - } - - RARCH_LOG("=================================\n"); - #endif -} diff --git a/input/drivers_hid/btstack_hid.c b/input/drivers_hid/btstack_hid.c index 68f20ea666..1d277484aa 100644 --- a/input/drivers_hid/btstack_hid.c +++ b/input/drivers_hid/btstack_hid.c @@ -1439,17 +1439,14 @@ static void btstack_hid_free(const void *data) free(hid); } -static void *btstack_hid_init(joypad_connection_t *connections) +static void *btstack_hid_init(void) { btstack_hid_t *hid = (btstack_hid_t*)calloc(1, sizeof(btstack_hid_t)); if (!hid) goto error; - if(connections == NULL) - connections = pad_connection_init(MAX_USERS); - - hid->slots = connections; + hid->slots = pad_connection_init(MAX_USERS); if (!hid->slots) goto error; diff --git a/input/drivers_hid/iohidmanager_hid.c b/input/drivers_hid/iohidmanager_hid.c index ad60d4c969..faaf84eceb 100644 --- a/input/drivers_hid/iohidmanager_hid.c +++ b/input/drivers_hid/iohidmanager_hid.c @@ -854,7 +854,7 @@ static int iohidmanager_hid_manager_set_device_matching( return 0; } -static void *iohidmanager_hid_init(joypad_connection_t *connections) +static void *iohidmanager_hid_init(void) { iohidmanager_hid_t *hid_apple = (iohidmanager_hid_t*) calloc(1, sizeof(*hid_apple)); @@ -862,10 +862,7 @@ static void *iohidmanager_hid_init(joypad_connection_t *connections) if (!hid_apple) goto error; - if (connections == NULL) - connections = pad_connection_init(MAX_USERS); - - hid_apple->slots = connections; + hid_apple->slots = pad_connection_init(MAX_USERS); if (!hid_apple->slots) goto error; diff --git a/input/drivers_hid/libusb_hid.c b/input/drivers_hid/libusb_hid.c index f06adb5366..44580359fa 100644 --- a/input/drivers_hid/libusb_hid.c +++ b/input/drivers_hid/libusb_hid.c @@ -546,7 +546,7 @@ static void poll_thread(void *data) } } -static void *libusb_hid_init(joypad_connection_t *connections) +static void *libusb_hid_init(void) { unsigned i, count; int ret; @@ -578,10 +578,7 @@ static void *libusb_hid_init(joypad_connection_t *connections) hid->can_hotplug = 0; #endif - if (connections == NULL) - connections = pad_connection_init(MAX_USERS); - - hid->slots = connections; + hid->slots = pad_connection_init(MAX_USERS); if (!hid->slots) goto error; diff --git a/input/drivers_hid/null_hid.c b/input/drivers_hid/null_hid.c index e7cf00b580..125ac54739 100644 --- a/input/drivers_hid/null_hid.c +++ b/input/drivers_hid/null_hid.c @@ -76,10 +76,8 @@ static int16_t null_hid_joypad_axis(void *data, unsigned port, uint32_t joyaxis) return 0; } -static void *null_hid_init(hid_driver_instance_t *instance) +static void *null_hid_init(void) { - (void)instance; - return (null_hid_t*)calloc(1, sizeof(null_hid_t)); } diff --git a/input/drivers_hid/wiiusb_hid.c b/input/drivers_hid/wiiusb_hid.c index 6e3a768bca..397f0a0a64 100644 --- a/input/drivers_hid/wiiusb_hid.c +++ b/input/drivers_hid/wiiusb_hid.c @@ -574,15 +574,15 @@ static void wiiusb_hid_free(const void *data) free(hid); } -static void *wiiusb_hid_init(joypad_connection_t *connections) +static void *wiiusb_hid_init(void) { + joypad_connection_t *connections = NULL; wiiusb_hid_t *hid = (wiiusb_hid_t*)calloc(1, sizeof(*hid)); if (!hid) goto error; - if(connections == NULL) - connections = pad_connection_init(MAX_USERS); + connections = pad_connection_init(MAX_USERS); if (!connections) goto error; diff --git a/input/drivers_joypad/wiiu_joypad.c b/input/drivers_joypad/wiiu_joypad.c index aa9c3ab277..dc0ab8fe94 100644 --- a/input/drivers_joypad/wiiu_joypad.c +++ b/input/drivers_joypad/wiiu_joypad.c @@ -14,7 +14,7 @@ * If not, see . */ -#include +#include "../../wiiu/input/wiiu_input.h" #include "wiiu_dbg.h" @@ -40,10 +40,10 @@ static input_device_driver_t *get_driver_for_pad(unsigned pad) { if(wpad_driver.query_pad(pad)) return &wpad_driver; -/* + if(kpad_driver.query_pad(pad)) return &kpad_driver; -*/ + #ifdef WIIU_HID return &hidpad_driver; #else @@ -135,7 +135,7 @@ static void wiiu_joypad_poll(void) static const char* wiiu_joypad_name(unsigned pad) { if(!wiiu_joypad_query_pad(pad)) - return "Snuffleupagus"; + return "N/A"; return pad_drivers[pad]->name(pad); } diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 1eee8a3f85..619f491688 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -35,7 +35,7 @@ struct hid_driver { - void *(*init)(hid_driver_instance_t *); + void *(*init)(void); bool (*query_pad)(void *handle, unsigned pad); void (*free)(const void *handle); bool (*button)(void *handle, unsigned pad, uint16_t button); @@ -62,6 +62,8 @@ struct hid_driver hid_instance.os_driver_data, pad) #define HID_POLL() hid_instance.os_driver->poll( \ hid_instance.os_driver_data) +#define HID_MAX_SLOT() hid_instance.max_slot +#define HID_PAD_CONNECTION_PTR(slot) &(hid_instance.pad_list[(slot)]) diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 75b9f0d3c6..2a237e8831 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -29,7 +29,7 @@ #endif #ifdef WIIU -#include +#include #endif #define DECL_BTN(btn, bind) "input_" #btn "_btn = " #bind "\n" diff --git a/wiiu/include/wiiu/pad_driver.h b/wiiu/include/wiiu/pad_driver.h deleted file mode 100644 index 067bc34d67..0000000000 --- a/wiiu/include/wiiu/pad_driver.h +++ /dev/null @@ -1,186 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2014-2017 - Ali Bouhlel - * 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. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __PAD_DRIVER__H -#define __PAD_DRIVER__H - -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif /* HAVE_CONFIG_H */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../input/input_driver.h" -#include "../../input/common/hid/hid_device_driver.h" -#include "../../tasks/tasks_internal.h" -#include "../../input/connect/joypad_connection.h" -#include "../../retroarch.h" -#include "../../verbosity.h" -#include "../../command.h" -#include "../../gfx/video_driver.h" - -/** - * Magic button sequence that triggers an exit. Useful for if the visuals are - * corrupted, but won't work in the case of a hard lock. - */ -#define PANIC_BUTTON_MASK (VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_STICK_L) - -/** - * Applies a standard transform to the Wii U gamepad's analog stick. - * No idea where 0x7ff0 comes from. - */ - -#define WIIU_ANALOG_FACTOR 0x7ff0 -#define WIIU_READ_STICK(stick) ((stick) * WIIU_ANALOG_FACTOR) - -/** - * the wiimote driver uses these to delimit which pads correspond to the - * wiimotes. - */ -#define PAD_GAMEPAD 0 -#define WIIU_WIIMOTE_CHANNELS 4 - -/** - * These are used by the wiimote driver to identify the wiimote configuration - * attached to the channel. - */ -/* wiimote with Wii U Pro controller */ -#define WIIMOTE_TYPE_PRO 0x1f -/* wiimote with Classic Controller */ -#define WIIMOTE_TYPE_CLASSIC 0x02 -/* wiimote with nunchuk */ -#define WIIMOTE_TYPE_NUNCHUK 0x01 -/* wiimote plus (no accessory attached) */ -#define WIIMOTE_TYPE_WIIPLUS 0x00 -/* wiimote not attached on this channel */ -#define WIIMOTE_TYPE_NONE 0xFD - -/** - * These are used to map pad names to controller mappings. You can - * change these relatively free-form. - */ - -#define PAD_NAME_WIIU_GAMEPAD "WiiU Gamepad" -#define PAD_NAME_WIIU_PRO "WiiU Pro Controller" -#define PAD_NAME_WIIMOTE "Wiimote Controller" -#define PAD_NAME_NUNCHUK "Wiimote+Nunchuk Controller" -#define PAD_NAME_CLASSIC "Classic Controller" -#define PAD_NAME_HID "HID Controller" - -/** - * The Wii U gamepad and wiimotes have 3 sets of x/y axes. The third - * is used by the gamepad for the touchpad driver; the wiimotes is - * currently unimplemented, but could be used for future IR pointer - * support. - */ -#define WIIU_DEVICE_INDEX_TOUCHPAD 2 - -typedef struct _axis_data axis_data; - -struct _axis_data { - int32_t axis; - bool is_negative; -}; - -typedef struct _wiiu_pad_functions wiiu_pad_functions_t; - -struct _wiiu_pad_functions { - int16_t (*get_axis_value)(int32_t axis, int16_t state[3][2], bool is_negative); - void (*set_axis_value)(int16_t state[3][2], int16_t left_x, int16_t left_y, - int16_t right_x, int16_t right_y, int16_t touch_x, int16_t touch_y); - void (*read_axis_data)(uint32_t axis, axis_data *data); - void (*connect)(unsigned pad, input_device_driver_t *driver); -}; - -/** - * HID driver data structures - */ - -typedef struct wiiu_hid { - /* used to register for HID notifications */ - HIDClient *client; - /* pointer to HID driver state */ - hid_driver_instance_t *driver; - /* size of connections list */ - unsigned connections_size; - /* thread state data for HID polling thread */ - OSThread *polling_thread; - /* stack space for polling thread */ - void *polling_thread_stack; - /* watch variable to tell the polling thread to terminate */ - volatile bool polling_thread_quit; -} wiiu_hid_t; - -typedef struct wiiu_adapter wiiu_adapter_t; - -struct wiiu_adapter { - wiiu_adapter_t *next; - hid_device_t *driver; - void *driver_handle; - wiiu_hid_t *hid; - uint8_t state; - uint8_t *rx_buffer; - int32_t rx_size; - uint8_t *tx_buffer; - int32_t tx_size; - uint32_t handle; - uint8_t interface_index; -}; - -typedef struct wiiu_attach wiiu_attach_event; - -struct wiiu_attach { - wiiu_attach_event *next; - hid_device_t *driver; - uint32_t type; - uint32_t handle; - uint16_t vendor_id; - uint16_t product_id; - uint8_t interface_index; - uint8_t is_keyboard; - uint8_t is_mouse; - uint16_t max_packet_size_rx; - uint16_t max_packet_size_tx; -}; - -typedef struct _wiiu_event_list wiiu_event_list; -typedef struct _wiiu_adapter_list wiiu_adapter_list; - -struct _wiiu_event_list { - OSFastMutex lock; - wiiu_attach_event *list; -}; - -struct _wiiu_adapter_list { - OSFastMutex lock; - wiiu_adapter_t *list; -}; - -extern wiiu_pad_functions_t pad_functions; -extern input_device_driver_t wiiu_joypad; -extern input_device_driver_t wpad_driver; -extern input_device_driver_t kpad_driver; -extern input_device_driver_t hidpad_driver; -extern hid_driver_t wiiu_hid; - -#endif /* __PAD_DRIVER__H */ diff --git a/wiiu/include/wiiu/pad_strings.h b/wiiu/include/wiiu/pad_strings.h new file mode 100644 index 0000000000..e28a9036e6 --- /dev/null +++ b/wiiu/include/wiiu/pad_strings.h @@ -0,0 +1,32 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2014-2017 - Ali Bouhlel + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __PAD_DRIVER__H +#define __PAD_DRIVER__H + +/** + * These are used to map pad names to controller mappings. You can + * change these relatively free-form. + */ + +#define PAD_NAME_WIIU_GAMEPAD "WiiU Gamepad" +#define PAD_NAME_WIIU_PRO "WiiU Pro Controller" +#define PAD_NAME_WIIMOTE "Wiimote Controller" +#define PAD_NAME_NUNCHUK "Wiimote+Nunchuk Controller" +#define PAD_NAME_CLASSIC "Classic Controller" +#define PAD_NAME_HID "HID Controller" + +#endif /* __PAD_DRIVER__H */ diff --git a/wiiu/input/hidpad_driver.c b/wiiu/input/hidpad_driver.c index 97f05e9d06..896ba4b2d4 100644 --- a/wiiu/input/hidpad_driver.c +++ b/wiiu/input/hidpad_driver.c @@ -14,9 +14,8 @@ * If not, see . */ -#include -#include "../../input/include/hid_driver.h" -#include "../../input/common/hid/hid_device_driver.h" +#include "wiiu_input.h" +#include "wiiu_hid.h" static bool hidpad_init(void *data); static bool hidpad_query_pad(unsigned pad); diff --git a/wiiu/input/kpad_driver.c b/wiiu/input/kpad_driver.c index 51d203cec0..faebe1143e 100644 --- a/wiiu/input/kpad_driver.c +++ b/wiiu/input/kpad_driver.c @@ -20,7 +20,7 @@ * controllers. */ -#include +#include "wiiu_input.h" static bool kpad_init(void *data); static bool kpad_query_pad(unsigned pad); diff --git a/wiiu/input/pad_functions.c b/wiiu/input/pad_functions.c index 132bffa146..ad2c383090 100644 --- a/wiiu/input/pad_functions.c +++ b/wiiu/input/pad_functions.c @@ -14,7 +14,7 @@ * If not, see . */ -#include +#include "wiiu_input.h" enum wiiu_pad_axes { AXIS_LEFT_ANALOG_X, diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 44c2822305..b289f648f4 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -22,10 +22,10 @@ static wiiu_adapter_list adapters; static bool wiiu_hid_joypad_query(void *data, unsigned slot) { wiiu_hid_t *hid = (wiiu_hid_t *)data; - if (!hid || !hid->driver) + if (!hid) return false; - return slot < hid->driver->max_slot; + return slot < HID_MAX_SLOT(); } static joypad_connection_t *get_pad(wiiu_hid_t *hid, unsigned slot) @@ -33,7 +33,7 @@ static joypad_connection_t *get_pad(wiiu_hid_t *hid, unsigned slot) if(!wiiu_hid_joypad_query(hid, slot)) return NULL; - joypad_connection_t *result = &(hid->driver->pad_list[slot]); + joypad_connection_t *result = HID_PAD_CONNECTION_PTR(slot); if(!result || !result->connected || !result->iface || !result->data) return NULL; @@ -90,7 +90,7 @@ static int16_t wiiu_hid_joypad_axis(void *data, unsigned slot, uint32_t joyaxis) return pad->iface->get_axis(pad->data, joyaxis); } -static void *wiiu_hid_init(hid_driver_instance_t *driver) +static void *wiiu_hid_init(void) { RARCH_LOG("[hid]: initializing HID subsystem\n"); wiiu_hid_t *hid = new_hid(); @@ -99,8 +99,6 @@ static void *wiiu_hid_init(hid_driver_instance_t *driver) if (!hid || !client) goto error; - hid->driver = driver; - wiiu_hid_init_lists(); start_polling_thread(hid); if (!hid->polling_thread) diff --git a/wiiu/input/wiiu_hid.h b/wiiu/input/wiiu_hid.h index 59ad898fea..892e1d3151 100644 --- a/wiiu/input/wiiu_hid.h +++ b/wiiu/input/wiiu_hid.h @@ -17,8 +17,9 @@ #ifndef __WIIU_HID__H #define __WIIU_HID__H -#include -#include "../../input/include/hid_driver.h" +#include "wiiu_hid_types.h" + +#include "wiiu_input.h" #define DEVICE_UNUSED 0 #define DEVICE_USED 1 @@ -28,6 +29,70 @@ #define ADAPTER_STATE_READING 2 #define ADAPTER_STATE_DONE 3 +struct wiiu_hid { + /* used to register for HID notifications */ + HIDClient *client; + /* thread state data for the HID input polling thread */ + OSThread *polling_thread; + /* stack space for polling thread */ + void *polling_thread_stack; + /* watch variable for telling the polling thread to terminate */ + volatile bool polling_thread_quit; +}; + +/** + * Each HID device attached to the WiiU gets its own adapter, which + * connects the HID subsystem with the HID device driver. + */ +struct wiiu_adapter { + wiiu_adapter_t *next; + hid_device_t *driver; + void *driver_handle; + wiiu_hid_t *hid; + uint8_t state; + uint8_t *rx_buffer; + int32_t rx_size; + uint8_t *tx_buffer; + int32_t tx_size; + uint32_t handle; + uint8_t interface_index; +}; + +/** + * When a HID device is connected, the OS generates an attach + * event; the attach event handler translate them into these + * structures. + */ +struct wiiu_attach { + wiiu_attach_event *next; + hid_device_t *driver; + uint32_t type; + uint32_t handle; + uint16_t vendor_id; + uint16_t product_id; + uint8_t interface_index; + uint8_t is_keyboard; + uint8_t is_mouse; + uint16_t max_packet_size_rx; + uint16_t max_packet_size_tx; +}; + +struct _wiiu_event_list { + OSFastMutex lock; + wiiu_attach_event *list; +}; + +struct _wiiu_adapter_list { + OSFastMutex lock; + wiiu_adapter_t *list; +}; + +extern wiiu_pad_functions_t pad_functions; +extern input_device_driver_t wiiu_joypad; +extern input_device_driver_t wpad_driver; +extern input_device_driver_t kpad_driver; +extern input_device_driver_t hidpad_driver; +extern hid_driver_t wiiu_hid; static void *alloc_zeroed(size_t alignment, size_t size); static OSThread *new_thread(void); diff --git a/wiiu/input/wiiu_hid_types.h b/wiiu/input/wiiu_hid_types.h new file mode 100644 index 0000000000..59eaabaddf --- /dev/null +++ b/wiiu/input/wiiu_hid_types.h @@ -0,0 +1,28 @@ +/* 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __WIIU_HID_TYPES__H +#define __WIIU_HID_TYPES__H + +typedef struct wiiu_hid wiiu_hid_t; +typedef struct wiiu_adapter wiiu_adapter_t; +typedef struct wiiu_attach wiiu_attach_event; +typedef struct _wiiu_event_list wiiu_event_list; +typedef struct _wiiu_adapter_list wiiu_adapter_list; +typedef struct _axis_data axis_data; +typedef struct _wiiu_pad_functions wiiu_pad_functions_t; + +#endif /* __WIIU_HID_TYPES__H */ diff --git a/wiiu/input/wiiu_input.h b/wiiu/input/wiiu_input.h new file mode 100644 index 0000000000..16509b47f2 --- /dev/null +++ b/wiiu/input/wiiu_input.h @@ -0,0 +1,72 @@ +/* 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __WIIU_INPUT__H +#define __WIIU_INPUT__H + +#include "wiiu_hid_types.h" + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../input/input_driver.h" +#include "../../input/common/hid/hid_device_driver.h" +#include "../../tasks/tasks_internal.h" +#include "../../input/connect/joypad_connection.h" +#include "../../retroarch.h" +#include "../../verbosity.h" +#include "../../command.h" +#include "../../gfx/video_driver.h" +#include "wiiu_hid.h" + +#define WIIMOTE_TYPE_WIIPLUS 0x00 +#define WIIMOTE_TYPE_NUNCHUK 0x01 +#define WIIMOTE_TYPE_CLASSIC 0x02 +#define WIIMOTE_TYPE_PRO 0x1f +#define WIIMOTE_TYPE_NONE 0xfd + +#define WIIU_DEVICE_INDEX_TOUCHPAD 2 + +#define PAD_GAMEPAD 0 +#define WIIU_WIIMOTE_CHANNELS 4 + +#define WIIU_ANALOG_FACTOR 0x7ff0 +#define WIIU_READ_STICK(stick) ((stick) * WIIU_ANALOG_FACTOR) + +struct _axis_data { + int32_t axis; + bool is_negative; +}; + +struct _wiiu_pad_functions { + int16_t (*get_axis_value)(int32_t axis, int16_t state[3][2], bool is_negative); + void (*set_axis_value)(int16_t state[3][2], int16_t left_x, int16_t left_y, + int16_t right_x, int16_t right_y, int16_t touch_x, int16_t touch_y); + void (*read_axis_data)(uint32_t axis, axis_data *data); + void (*connect)(unsigned pad, input_device_driver_t *driver); +}; + +#endif /* __WIIU_INPUT__H */ diff --git a/wiiu/input/wpad_driver.c b/wiiu/input/wpad_driver.c index 786f883cda..5cac0c5bff 100644 --- a/wiiu/input/wpad_driver.c +++ b/wiiu/input/wpad_driver.c @@ -21,7 +21,9 @@ * - For HID controllers, see hid_driver.c */ -#include +#include "wiiu_input.h" + +#define PANIC_BUTTON_MASK (VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_STICK_L) static bool ready = false; static uint64_t button_state = 0; From 9bc5a15c2de83e40ac339685906b9e742ae2b7f0 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 1 Apr 2018 18:52:26 -0700 Subject: [PATCH 15/31] Enable pads to register in any order == DETAILS Whereas the last commit had a hack (that disabled the wiimote driver in the process), this has.. well, a *different* hack that allows pads to register in any order. Note that due to the initialization routines, the gamepad will still likely always get slot 0. Not sure if this can be overridden via config or not. == TESTING Tested locally with GC adapter --- input/common/hid/hid_device_driver.c | 23 ++++++-- input/drivers_joypad/wiiu_joypad.c | 79 +++++++++++----------------- input/include/gamepad.h | 27 ++++++++++ input/include/hid_driver.h | 4 +- input/input_driver.c | 18 +++++++ input/input_driver.h | 23 ++++---- input/input_types.h | 26 +++++++++ wiiu/input/hidpad_driver.c | 10 ---- wiiu/input/kpad_driver.c | 68 ++++++++++++++++++------ wiiu/input/wpad_driver.c | 9 +++- 10 files changed, 193 insertions(+), 94 deletions(-) create mode 100644 input/include/gamepad.h create mode 100644 input/input_types.h diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index 3792e2c737..ee0ef38a58 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -57,6 +57,24 @@ joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface return result; } +static bool init_pad_list(hid_driver_instance_t *instance, unsigned slots) +{ + if(!instance || slots > MAX_USERS) + return false; + + if(instance->pad_list) + return true; + + RARCH_LOG("[hid]: initializing pad list...\n"); + instance->pad_list = pad_connection_init(slots); + if(!instance->pad_list) + return false; + + instance->max_slot = slots; + + return true; +} + /** * Fill in instance with data from initialized hid subsystem. * @@ -80,16 +98,13 @@ bool hid_init(hid_driver_instance_t *instance, if(!instance->os_driver_data) return false; - RARCH_LOG("[hid]: initializing pad list...\n"); - instance->pad_list = pad_connection_init(slots); - if(!instance->pad_list) + if(!init_pad_list(instance, slots)) { hid_driver->free(instance->os_driver_data); instance->os_driver_data = NULL; return false; } - instance->max_slot = slots; instance->os_driver = hid_driver; instance->pad_driver = pad_driver; diff --git a/input/drivers_joypad/wiiu_joypad.c b/input/drivers_joypad/wiiu_joypad.c index dc0ab8fe94..b4725a9d4d 100644 --- a/input/drivers_joypad/wiiu_joypad.c +++ b/input/drivers_joypad/wiiu_joypad.c @@ -19,6 +19,8 @@ #include "wiiu_dbg.h" static input_device_driver_t *pad_drivers[MAX_USERS]; +extern pad_connection_listener_t wiiu_pad_connection_listener; + static bool ready = false; @@ -31,61 +33,30 @@ static int16_t wiiu_joypad_axis(unsigned pad, uint32_t axis); static void wiiu_joypad_poll(void); static const char *wiiu_joypad_name(unsigned pad); -/** - * Translates a pad to its appropriate driver. - * Note that this is a helper for build_pad_map and shouldn't be - * used directly. - */ -static input_device_driver_t *get_driver_for_pad(unsigned pad) -{ - if(wpad_driver.query_pad(pad)) - return &wpad_driver; - - if(kpad_driver.query_pad(pad)) - return &kpad_driver; - -#ifdef WIIU_HID - return &hidpad_driver; -#else - return NULL; -#endif -} - -/** - * Populates the pad_driver array. We do this once at init time so - * that lookups at runtime are constant time. - */ -static void build_pad_map(void) -{ - unsigned i; - - for(i = 0; i < MAX_USERS; i++) - { - pad_drivers[i] = get_driver_for_pad(i); - } -} - static bool wiiu_joypad_init(void* data) { - /* the sub-drivers have to init first, otherwise - * build_pad_map will fail (because all lookups will return false). */ - wpad_driver.init(data); - kpad_driver.init(data); + set_connection_listener(&wiiu_pad_connection_listener); + hid_instance.pad_list = pad_connection_init(MAX_USERS); + hid_instance.max_slot = MAX_USERS; + + wpad_driver.init(data); + kpad_driver.init(data); #ifdef WIIU_HID - hidpad_driver.init(data); + hidpad_driver.init(data); #endif - build_pad_map(); + ready = true; + (void)data; - ready = true; - (void)data; - - return true; + return true; } static bool wiiu_joypad_query_pad(unsigned pad) { - return ready && pad < MAX_USERS; + return ready && + pad < MAX_USERS && + pad_drivers[pad] != NULL && + pad_drivers[pad]->query_pad(pad); } static void wiiu_joypad_destroy(void) @@ -134,10 +105,17 @@ static void wiiu_joypad_poll(void) static const char* wiiu_joypad_name(unsigned pad) { - if(!wiiu_joypad_query_pad(pad)) - return "N/A"; + if(!wiiu_joypad_query_pad(pad)) + return "N/A"; - return pad_drivers[pad]->name(pad); + return pad_drivers[pad]->name(pad); +} + +static void wiiu_joypad_connection_listener(unsigned pad, + input_device_driver_t *driver) +{ + if(pad < MAX_USERS) + pad_drivers[pad] = driver; } input_device_driver_t wiiu_joypad = @@ -153,3 +131,8 @@ input_device_driver_t wiiu_joypad = wiiu_joypad_name, "wiiu", }; + +pad_connection_listener_t wiiu_pad_connection_listener = +{ + wiiu_joypad_connection_listener +}; diff --git a/input/include/gamepad.h b/input/include/gamepad.h new file mode 100644 index 0000000000..8acb9027d1 --- /dev/null +++ b/input/include/gamepad.h @@ -0,0 +1,27 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Andrés Suárez + * + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef GAMEPAD_H__ +#define GAMEPAD_H__ + +#include "../input_driver.h" + +typedef struct pad_connection_listener_interface { + void (*connected)(unsigned port, input_device_driver_t *driver); +} pad_connection_listener_t; + +#endif /* GAMEPAD_H__ */ diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 619f491688..654c3849ea 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -58,8 +58,8 @@ struct hid_driver hid_instance.os_driver_data, pad, key) #define HID_AXIS(pad, axis) hid_instance.os_driver->axis( \ hid_instance.os_driver_data, pad, axis) -#define HID_PAD_NAME(pad) hid_instance.os_driver->name( \ - hid_instance.os_driver_data, pad) +#define HID_PAD_NAME(pad) \ + hid_instance.os_driver->name(hid_instance.os_driver_data, pad) #define HID_POLL() hid_instance.os_driver->poll( \ hid_instance.os_driver_data) #define HID_MAX_SLOT() hid_instance.max_slot diff --git a/input/input_driver.c b/input/input_driver.c index 882d33ca1b..78d50590d1 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -60,6 +60,22 @@ #include "../verbosity.h" #include "../tasks/tasks_internal.h" #include "../command.h" +#include "include/gamepad.h" + +static pad_connection_listener_t *pad_connection_listener = NULL; + +void set_connection_listener(pad_connection_listener_t *listener) +{ + pad_connection_listener = listener; +} + +void fire_connection_listener(unsigned port, input_device_driver_t *driver) +{ + if(!pad_connection_listener) + return; + + pad_connection_listener->connected(port, driver); +} static const input_driver_t *input_drivers[] = { #ifdef __CELLOS_LV2__ @@ -1790,6 +1806,8 @@ void input_pad_connect(unsigned port, input_device_driver_t *driver) return; } + fire_connection_listener(port, driver); + if(!input_autoconfigure_connect(driver->name(port), NULL, driver->ident, port, 0, 0)) input_config_set_device_name(port, driver->name(port)); diff --git a/input/input_driver.h b/input/input_driver.h index b366413893..67a42fecc8 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -22,6 +22,8 @@ #include #include +#include "input_types.h" + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -36,14 +38,10 @@ #include "../msg_hash.h" #include "include/hid_types.h" +#include "include/gamepad.h" RETRO_BEGIN_DECLS -typedef struct rarch_joypad_driver input_device_driver_t; - -/* Keyboard line reader. Handles textual input in a direct fashion. */ -typedef struct input_keyboard_line input_keyboard_line_t; - enum input_device_type { INPUT_DEVICE_TYPE_NONE = 0, @@ -120,14 +118,14 @@ struct retro_keybind char *joyaxis_label; }; -typedef struct rarch_joypad_info +struct rarch_joypad_info { uint16_t joy_idx; const struct retro_keybind *auto_binds; float axis_threshold; -} rarch_joypad_info_t; +}; -typedef struct input_driver +struct input_driver { /* Inits input driver. */ @@ -163,7 +161,7 @@ typedef struct input_driver const input_device_driver_t *(*get_sec_joypad_driver)(void *data); bool (*keyboard_mapping_is_blocked)(void *data); void (*keyboard_mapping_set_block)(void *data, bool value); -} input_driver_t; +}; struct rarch_joypad_driver { @@ -657,11 +655,11 @@ typedef void (*input_keyboard_line_complete_t)(void *userdata, typedef bool (*input_keyboard_press_t)(void *userdata, unsigned code); -typedef struct input_keyboard_ctx_wait +struct input_keyboard_ctx_wait { void *userdata; input_keyboard_press_t cb; -} input_keyboard_ctx_wait_t; +}; /** * input_keyboard_event: @@ -789,6 +787,9 @@ uint16_t input_config_get_vid(unsigned port); void input_config_reset(void); +void set_connection_listener(pad_connection_listener_t *listener); +void fire_connection_listener(unsigned port, input_device_driver_t *driver); + extern input_device_driver_t dinput_joypad; extern input_device_driver_t linuxraw_joypad; extern input_device_driver_t parport_joypad; diff --git a/input/input_types.h b/input/input_types.h new file mode 100644 index 0000000000..4c36861866 --- /dev/null +++ b/input/input_types.h @@ -0,0 +1,26 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __INPUT_TYPES__H +#define __INPUT_TYPES__H + +typedef struct rarch_joypad_driver input_device_driver_t; +typedef struct input_keyboard_line input_keyboard_line_t; +typedef struct rarch_joypad_info rarch_joypad_info_t; +typedef struct input_driver input_driver_t; +typedef struct input_keyboard_ctx_wait input_keyboard_ctx_wait_t; + +#endif /* __INPUT_TYPES__H */ diff --git a/wiiu/input/hidpad_driver.c b/wiiu/input/hidpad_driver.c index 896ba4b2d4..8b1f1adeae 100644 --- a/wiiu/input/hidpad_driver.c +++ b/wiiu/input/hidpad_driver.c @@ -30,8 +30,6 @@ static bool ready = false; static bool init_hid_driver(void) { - memset(&hid_instance, 0, sizeof(hid_instance)); - return hid_init(&hid_instance, &wiiu_hid, &hidpad_driver, MAX_USERS); } @@ -46,14 +44,6 @@ static bool hidpad_init(void *data) return false; } - hid_instance.pad_list[0].connected = true; -/* - for(i = 0; i < (WIIU_WIIMOTE_CHANNELS+1); i++) - { - hid_instance.pad_list[i].connected = true; - } -*/ - hidpad_poll(); ready = true; diff --git a/wiiu/input/kpad_driver.c b/wiiu/input/kpad_driver.c index faebe1143e..006a180d97 100644 --- a/wiiu/input/kpad_driver.c +++ b/wiiu/input/kpad_driver.c @@ -52,17 +52,30 @@ wiimote_state wiimotes[WIIU_WIIMOTE_CHANNELS] = { { 0, {{0,0},{0,0},{0,0}}, WIIMOTE_TYPE_NONE }, }; -static unsigned to_wiimote_channel(unsigned pad) -{ - if (pad == PAD_GAMEPAD || pad > WIIU_WIIMOTE_CHANNELS) - return 0xffffffff; +static int channel_slot_map[] = { -1, -1, -1, -1 }; - return pad-1; +static int to_wiimote_channel(unsigned pad) +{ + int i; + + for(i = 0; i < WIIU_WIIMOTE_CHANNELS; i++) + if(channel_slot_map[i] == pad) + return i; + + return -1; } -static unsigned to_retro_pad(unsigned channel) +static int get_slot_for_channel(unsigned channel) { - return channel+1; + int slot = pad_connection_find_vacant_pad(hid_instance.pad_list); + if(slot >= 0) + { + RARCH_LOG("[kpad]: got slot %d\n", slot); + channel_slot_map[channel] = slot; + hid_instance.pad_list[slot].connected = true; + } + + return slot; } static bool kpad_init(void *data) @@ -75,7 +88,7 @@ static bool kpad_init(void *data) static bool kpad_query_pad(unsigned pad) { - return ready && pad <= WIIU_WIIMOTE_CHANNELS && pad > PAD_GAMEPAD; + return ready && pad < MAX_USERS; } static void kpad_destroy(void) @@ -88,27 +101,34 @@ static bool kpad_button(unsigned pad, uint16_t button_bit) if (!kpad_query_pad(pad)) return false; - return wiimotes[to_wiimote_channel(pad)].button_state + int channel = to_wiimote_channel(pad); + if(channel < 0) + return false; + + return wiimotes[channel].button_state & (UINT64_C(1) << button_bit); } static void kpad_get_buttons(unsigned pad, retro_bits_t *state) { - if (!kpad_query_pad(pad)) + int channel = to_wiimote_channel(pad); + + if (!kpad_query_pad(pad) || channel < 0) BIT256_CLEAR_ALL_PTR(state); else - BITS_COPY16_PTR(state, wiimotes[to_wiimote_channel(pad)].button_state); + BITS_COPY16_PTR(state, wiimotes[channel].button_state); } static int16_t kpad_axis(unsigned pad, uint32_t axis) { + int channel = to_wiimote_channel(pad); axis_data data; - if (!kpad_query_pad(pad) || axis == AXIS_NONE) + if (!kpad_query_pad(pad) || channel < 0 || axis == AXIS_NONE) return 0; pad_functions.read_axis_data(axis, &data); return pad_functions.get_axis_value(data.axis, - wiimotes[to_wiimote_channel(pad)].analog_state, + wiimotes[channel].analog_state, data.is_negative); } @@ -116,8 +136,15 @@ static void kpad_register(unsigned channel, uint8_t device_type) { if (wiimotes[channel].type != device_type) { + int slot = get_slot_for_channel(channel); + if(slot < 0) + { + RARCH_ERR("Couldn't get a slot for this remote.\n"); + return; + } + wiimotes[channel].type = device_type; - input_pad_connect(to_retro_pad(channel), &kpad_driver); + input_pad_connect(slot, &kpad_driver); } } @@ -173,6 +200,13 @@ static void kpad_poll(void) result = KPADRead(channel, &kpad, 1); if (result == 0) { + int slot = channel_slot_map[channel]; + + if(slot > 0) + { + hid_instance.pad_list[slot].connected = false; + channel_slot_map[channel] = -1; + } continue; } @@ -182,11 +216,11 @@ static void kpad_poll(void) static const char *kpad_name(unsigned pad) { - pad = to_wiimote_channel(pad); - if (pad >= WIIU_WIIMOTE_CHANNELS) + int channel = to_wiimote_channel(pad); + if (channel < 0) return "unknown"; - switch(wiimotes[pad].type) + switch(wiimotes[channel].type) { case WIIMOTE_TYPE_PRO: return PAD_NAME_WIIU_PRO; diff --git a/wiiu/input/wpad_driver.c b/wiiu/input/wpad_driver.c index 5cac0c5bff..c66fb066f2 100644 --- a/wiiu/input/wpad_driver.c +++ b/wiiu/input/wpad_driver.c @@ -186,7 +186,12 @@ static void wpad_poll(void) static bool wpad_init(void *data) { - input_pad_connect(PAD_GAMEPAD, &wpad_driver); + int slot = pad_connection_find_vacant_pad(hid_instance.pad_list); + if(slot < 0) + return false; + + hid_instance.pad_list[slot].connected = true; + input_pad_connect(slot, &wpad_driver); wpad_poll(); ready = true; @@ -195,7 +200,7 @@ static bool wpad_init(void *data) static bool wpad_query_pad(unsigned pad) { - return ready && pad == PAD_GAMEPAD; + return ready && pad < MAX_USERS; } static void wpad_destroy(void) From af08e5015ad4ad18d7c4c370385a60a16ac3e335 Mon Sep 17 00:00:00 2001 From: gblues Date: Mon, 2 Apr 2018 23:16:49 -0700 Subject: [PATCH 16/31] More work on Dual Shock 3 driver == DETAILS - update to not try starting the read loop until after the device is successfully initialized - add new HID wrapper macros needed by ds3 driver - add some debug logging to help with troubleshooting - add button map for DS3 == TESTING Tested with local build. DS3 init is not working. --- input/common/hid/device_ds3.c | 168 ++++++++++++++++++++++++++- input/common/hid/hid_device_driver.c | 3 + input/include/hid_driver.h | 6 + input/input_autodetect_builtin.c | 1 + wiiu/input/wiiu_hid.c | 17 ++- 5 files changed, 190 insertions(+), 5 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 3c1a805d60..7ff4ae307b 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -22,33 +22,158 @@ typedef struct ds3_instance { void *handle; joypad_connection_t *pad; + int slot; + bool led_set; + uint32_t buttons; + uint16_t motors[2]; + uint8_t data[64]; } ds3_instance_t; static uint8_t activation_packet[] = { +#if defined(IOS) + 0x53, 0xF4, +#elif defined(HAVE_WIIUSB_HID) + 0x02, +#endif 0x42, 0x0c, 0x00, 0x00 }; +#if defined(WIIU) +#define PACKET_OFFSET 2 +#elif defined(HAVE_WIIUSB_HID) +#define PACKET_OFFSET 1 +#else +#define PACKET_OFFSET 0 +#endif + +#define LED_OFFSET 11 +#define MOTOR1_OFFSET 4 +#define MOTOR2_OFFSET 6 + +static uint8_t control_packet[] = { + 0x52, 0x01, + 0x00, 0xff, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; + +static int control_packet_size = sizeof(control_packet); + extern pad_connection_interface_t ds3_pad_connection; +static void print_error(const char *fmt, int32_t errcode) +{ + int16_t err1, err2; + + err1 = errcode & 0x0000ffff; + err2 = ((errcode & 0xffff0000) >> 16); + + RARCH_ERR(fmt, err1, err2); +} + +static uint32_t send_activation_packet(ds3_instance_t *instance) +{ + uint32_t result; +#if defined(WIIU) + result = HID_SET_REPORT(instance->handle, + HID_REPORT_FEATURE, + DS3_ACTIVATION_REPORT_ID, + activation_packet, + sizeof(activation_packet)); +#else + HID_SEND_CONTROL(instance->handle, + activation_packet, sizeof(activation_packet)); +#endif + if(result) + print_error("[ds3]: activation packet failed (%d:%d)\n", result); + return result; +} + +static uint32_t set_protocol(ds3_instance_t *instance, int protocol) +{ + uint32_t result = 0; +#if defined(WIIU) + result = HID_SET_PROTOCOL(1); + if(result) + print_error("[ds3]: set protocol failed (%d:%d)\n", result); + +#endif + return result; +} + +static uint32_t send_control_packet(ds3_instance_t *instance) +{ + uint8_t packet_buffer[control_packet_size]; + uint32_t result = 0; + memcpy(packet_buffer, control_packet, control_packet_size); + + packet_buffer[LED_OFFSET] = 0; + if(instance->pad) { + packet_buffer[LED_OFFSET] = 1 << ((instance->slot % 4) + 1); + } + packet_buffer[MOTOR1_OFFSET] = instance->motors[1] >> 8; + packet_buffer[MOTOR2_OFFSET] = instance->motors[0] >> 8; + +#if defined(HAVE_WIIUSB_HID) + packet_buffer[1] = 0x03; +#endif + +#if defined(WIIU) + result = HID_SET_REPORT(instance->handle, + HID_REPORT_OUTPUT, + DS3_RUMBLE_REPORT_ID, + packet_buffer+PACKET_OFFSET, + control_packet_size-PACKET_OFFSET); + if(result) + print_error("[ds3]: send control packet failed: (%d:%d)\n", result); +#else + HID_SEND_CONTROL(instance->handle, + packet_buffer+PACKET_OFFSET, + control_packet_size-PACKET_OFFSET); +#endif /* WIIU */ + return result; +} + static void *ds3_init(void *handle) { ds3_instance_t *instance; - + int errors = 0; + RARCH_LOG("[ds3]: init\n"); instance = (ds3_instance_t *)calloc(1, sizeof(ds3_instance_t)); if(!instance) goto error; instance->handle = handle; -/* TODO: do whatever is needed so that the read loop doesn't bomb out */ + RARCH_LOG("[ds3]: sending activation packet\n"); + if(send_activation_packet(instance)) + errors++; + RARCH_LOG("[ds3]: setting protocol\n"); + if(set_protocol(instance, 1)) + errors++; + RARCH_LOG("[ds3]: sending control packet\n"); + if(send_control_packet(instance)) + errors++; + + if(errors) + goto error; instance->pad = hid_pad_register(instance, &ds3_pad_connection); if(!instance->pad) goto error; + RARCH_LOG("[ds3]: init complete.\n"); return instance; error: + RARCH_ERR("[ds3]: init failed.\n"); if(instance) free(instance); return NULL; @@ -62,9 +187,14 @@ static void ds3_free(void *data) free(instance); } -static void ds3_handle_packet(void *data, uint8_t *buffer, size_t size) +static void ds3_handle_packet(void *data, uint8_t *packet, size_t size) { ds3_instance_t *instance = (ds3_instance_t *)data; + + if(!instance || !instance->pad) + return; + + instance->pad->iface->packet_handler(data, packet, size); } static bool ds3_detect(uint16_t vendor_id, uint16_t product_id) @@ -86,6 +216,9 @@ hid_device_t ds3_hid_device = { static void *ds3_pad_init(void *data, uint32_t slot, hid_driver_t *driver) { + ds3_instance_t *pad = (ds3_instance_t *)data; + pad->slot = slot; + return data; } @@ -97,11 +230,38 @@ static void ds3_pad_deinit(void *data) static void ds3_get_buttons(void *data, retro_bits_t *state) { ds3_instance_t *pad = (ds3_instance_t *)data; + + if(pad) + { + BITS_COPY16_PTR(state, pad->buttons); + + if(pad->buttons & 0x10000) + BIT256_SET_PTR(state, RARCH_MENU_TOGGLE); + } else { + BIT256_CLEAR_ALL_PTR(state); + } } static void ds3_packet_handler(void *data, uint8_t *packet, uint16_t size) { - ds3_instance_t *pad = (ds3_instance_t *)data; + ds3_instance_t *instance = (ds3_instance_t *)data; + RARCH_LOG_BUFFER(packet, size); + + if(!instance->led_set) + { + send_activation_packet(instance); + instance->led_set = true; + } + + if(size > control_packet_size) + { + RARCH_ERR("[ds3]: Expecting packet to be %d but was %d\n", + control_packet_size, size); + return; + } + + memcpy(instance->data, packet, size); + instance->buttons = 0; } static void ds3_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index ee0ef38a58..37bc4feaa8 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -46,7 +46,10 @@ joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface slot = pad_connection_find_vacant_pad(hid_instance.pad_list); if(slot < 0) + { + RARCH_ERR("[hid]: failed to find a vacant pad.\n"); return NULL; + } result = &(hid_instance.pad_list[slot]); result->iface = iface; diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 654c3849ea..577dbb093a 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -60,6 +60,12 @@ struct hid_driver hid_instance.os_driver_data, pad, axis) #define HID_PAD_NAME(pad) \ hid_instance.os_driver->name(hid_instance.os_driver_data, pad) +#define HID_SET_PROTOCOL(protocol) \ + hid_instance.os_driver->set_protocol(hid_instance.os_driver_data, protocol) +#define HID_SET_REPORT(pad, rpttype, rptid, data, len) \ + hid_instance.os_driver->set_report(pad, rpttype, rptid, data, len) +#define HID_SEND_CONTROL(pad, data, len) \ + hid_instance.os_driver->send_control(pad, data, len) #define HID_POLL() hid_instance.os_driver->poll( \ hid_instance.os_driver_data) #define HID_MAX_SLOT() hid_instance.max_slot diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 2a237e8831..77a09e0487 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -635,6 +635,7 @@ const char* const input_builtin_autoconfs[] = 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("GameCube Controller", "wiiu", WIIUINPUT_GAMECUBE_DEFAULT_BINDS), + DECL_AUTOCONF_DEVICE("Sony DualShock 3", "wiiu", PS3INPUT_DEFAULT_BINDS), #endif #ifdef __CELLOS_LV2__ DECL_AUTOCONF_DEVICE("SixAxis Controller", "ps3", PS3INPUT_DEFAULT_BINDS), diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index b289f648f4..eaa9210e68 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -458,7 +458,6 @@ static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) adapter->state = ADAPTER_STATE_NEW; synchronized_add_to_adapters_list(adapter); - wiiu_start_read_loop(adapter); return; @@ -580,6 +579,21 @@ static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list) } } +static void wiiu_handle_ready_adapters(wiiu_hid_t *hid) +{ + wiiu_adapter_t *it; + OSFastMutex_Lock(&(adapters.lock)); + + for(it = adapters.list; it != NULL; it = it->next) + { + if(it->state == ADAPTER_STATE_READY) + wiiu_start_read_loop(it); + } + + OSFastMutex_Unlock(&(adapters.lock)); + +} + static int wiiu_hid_polling_thread(int argc, const char **argv) { wiiu_hid_t *hid = (wiiu_hid_t *)argv; @@ -590,6 +604,7 @@ static int wiiu_hid_polling_thread(int argc, const char **argv) while(!hid->polling_thread_quit) { wiiu_handle_attach_events(hid, synchronized_get_events_list()); + wiiu_handle_ready_adapters(hid); usleep(10000); i += 10000; if(i >= (1000 * 1000 * 3)) From 4433cbebc6c9ec8db9561c5e227cdf916d430efe Mon Sep 17 00:00:00 2001 From: gblues Date: Thu, 5 Apr 2018 23:03:38 -0700 Subject: [PATCH 17/31] Get digital inputs for Sony DualShock 3 working == DETAILS - fix the bitshift math - read the right bytes out of the ds3 data packet - remove verbose logging in critical path - stop caring about errors in the hid read loop -- seems to just be benign "device not ready" -- or at least, that's what I'm assuming given that the read eventually succeeds. == TESTING Played Mario 3 with the DS3 with no issues. --- input/common/hid/device_ds3.c | 84 +++++++++++++++++++++++++------- input/include/hid_driver.h | 4 +- input/input_autodetect_builtin.c | 21 +++++++- wiiu/input/wiiu_hid.c | 74 ++++++++++++++++------------ wiiu/input/wiiu_hid.h | 6 +++ 5 files changed, 137 insertions(+), 52 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 7ff4ae307b..0bda535d41 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -78,9 +78,11 @@ static void print_error(const char *fmt, int32_t errcode) RARCH_ERR(fmt, err1, err2); } -static uint32_t send_activation_packet(ds3_instance_t *instance) +static void update_pad_state(ds3_instance_t *instance); + +static int32_t send_activation_packet(ds3_instance_t *instance) { - uint32_t result; + int32_t result; #if defined(WIIU) result = HID_SET_REPORT(instance->handle, HID_REPORT_FEATURE, @@ -91,8 +93,9 @@ static uint32_t send_activation_packet(ds3_instance_t *instance) HID_SEND_CONTROL(instance->handle, activation_packet, sizeof(activation_packet)); #endif - if(result) + if(result < 0) print_error("[ds3]: activation packet failed (%d:%d)\n", result); + return result; } @@ -100,18 +103,18 @@ static uint32_t set_protocol(ds3_instance_t *instance, int protocol) { uint32_t result = 0; #if defined(WIIU) - result = HID_SET_PROTOCOL(1); + result = HID_SET_PROTOCOL(instance->handle, 1); if(result) print_error("[ds3]: set protocol failed (%d:%d)\n", result); - #endif + return result; } -static uint32_t send_control_packet(ds3_instance_t *instance) +static int32_t send_control_packet(ds3_instance_t *instance) { uint8_t packet_buffer[control_packet_size]; - uint32_t result = 0; + int32_t result = 0; memcpy(packet_buffer, control_packet, control_packet_size); packet_buffer[LED_OFFSET] = 0; @@ -131,7 +134,7 @@ static uint32_t send_control_packet(ds3_instance_t *instance) DS3_RUMBLE_REPORT_ID, packet_buffer+PACKET_OFFSET, control_packet_size-PACKET_OFFSET); - if(result) + if(result < 0) print_error("[ds3]: send control packet failed: (%d:%d)\n", result); #else HID_SEND_CONTROL(instance->handle, @@ -152,14 +155,18 @@ static void *ds3_init(void *handle) instance->handle = handle; - RARCH_LOG("[ds3]: sending activation packet\n"); - if(send_activation_packet(instance)) - errors++; +/* maybe not necessary? */ +/* RARCH_LOG("[ds3]: setting protocol\n"); if(set_protocol(instance, 1)) errors++; +*/ RARCH_LOG("[ds3]: sending control packet\n"); - if(send_control_packet(instance)) + if(send_control_packet(instance) < 0) + errors++; + + RARCH_LOG("[ds3]: sending activation packet\n"); + if(send_activation_packet(instance) < 0) errors++; if(errors) @@ -245,11 +252,10 @@ static void ds3_get_buttons(void *data, retro_bits_t *state) static void ds3_packet_handler(void *data, uint8_t *packet, uint16_t size) { ds3_instance_t *instance = (ds3_instance_t *)data; - RARCH_LOG_BUFFER(packet, size); - if(!instance->led_set) + if(instance->pad && !instance->led_set) { - send_activation_packet(instance); + send_control_packet(instance); instance->led_set = true; } @@ -261,7 +267,41 @@ static void ds3_packet_handler(void *data, uint8_t *packet, uint16_t size) } memcpy(instance->data, packet, size); + update_pad_state(instance); +} + +static void update_pad_state(ds3_instance_t *instance) +{ + uint32_t i, pressed_keys; + + static const uint32_t button_mapping[17] = + { + RETRO_DEVICE_ID_JOYPAD_SELECT, + RETRO_DEVICE_ID_JOYPAD_L3, + RETRO_DEVICE_ID_JOYPAD_R3, + RETRO_DEVICE_ID_JOYPAD_START, + RETRO_DEVICE_ID_JOYPAD_UP, + RETRO_DEVICE_ID_JOYPAD_RIGHT, + RETRO_DEVICE_ID_JOYPAD_DOWN, + RETRO_DEVICE_ID_JOYPAD_LEFT, + RETRO_DEVICE_ID_JOYPAD_L2, + RETRO_DEVICE_ID_JOYPAD_R2, + RETRO_DEVICE_ID_JOYPAD_L, + RETRO_DEVICE_ID_JOYPAD_R, + RETRO_DEVICE_ID_JOYPAD_X, + RETRO_DEVICE_ID_JOYPAD_A, + RETRO_DEVICE_ID_JOYPAD_B, + RETRO_DEVICE_ID_JOYPAD_Y, + 16 /* PS button */ + }; + instance->buttons = 0; + + pressed_keys = instance->data[2]|(instance->data[3] << 8)|((instance->data[4] & 0x01) << 16); + + for(i = 0; i < 17; i++) + instance->buttons |= (pressed_keys & (1 << i)) ? + (1 << button_mapping[i]) : 0; } static void ds3_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) @@ -272,7 +312,14 @@ static void ds3_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t static int16_t ds3_get_axis(void *data, unsigned axis) { ds3_instance_t *pad = (ds3_instance_t *)data; - return 0; + int16_t val; + + if(!pad || axis >= 4) + return 0; + + val = (pad->data[6+axis] << 8) - 0x8000; +// val = (pad->data[7+axis] << 8) - 0x8000; + return (val > 0x1000 || val < -0x1000) ? 0 : val; } static const char *ds3_get_name(void *data) @@ -284,7 +331,10 @@ static const char *ds3_get_name(void *data) static bool ds3_button(void *data, uint16_t joykey) { ds3_instance_t *pad = (ds3_instance_t *)data; - return false; + if(!pad || joykey > 31) + return false; + + return pad->buttons & (1 << joykey); } pad_connection_interface_t ds3_pad_connection = { diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 577dbb093a..5b75c785bb 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -60,8 +60,8 @@ struct hid_driver hid_instance.os_driver_data, pad, axis) #define HID_PAD_NAME(pad) \ hid_instance.os_driver->name(hid_instance.os_driver_data, pad) -#define HID_SET_PROTOCOL(protocol) \ - hid_instance.os_driver->set_protocol(hid_instance.os_driver_data, protocol) +#define HID_SET_PROTOCOL(pad, protocol) \ + hid_instance.os_driver->set_protocol(pad, protocol) #define HID_SET_REPORT(pad, rpttype, rptid, data, len) \ hid_instance.os_driver->set_report(pad, rpttype, rptid, data, len) #define HID_SEND_CONTROL(pad, data, len) \ diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 77a09e0487..8b37d0828d 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -250,6 +250,25 @@ DECL_AXIS_EX(r_x_minus, -3, "C-stick left") \ DECL_AXIS_EX(r_y_plus, +2, "C-stick up") \ DECL_AXIS_EX(r_y_minus, -2, "C-stick down") +#define WIIUINPUT_DS3_DEFAULT_BINDS \ +DECL_BTN_EX(menu_toggle, 16, "Playstation") \ +DECL_BTN_EX(select, 2, "Select") \ +DECL_BTN_EX(start, 3, "Start") \ +DECL_BTN_EX(a, 8, "Circle") \ +DECL_BTN_EX(y, 1, "Triangle") \ +DECL_BTN_EX(b, 0, "Cross") \ +DECL_BTN_EX(x, 9, "Square") \ +DECL_BTN_EX(r, 11, "R1") \ +DECL_BTN_EX(l, 10, "L1") \ +DECL_BTN_EX(r2, 13, "R2") \ +DECL_BTN_EX(l2, 12, "L2") \ +DECL_BTN_EX(up, 4, "D-Pad Up") \ +DECL_BTN_EX(down, 5, "D-Pad Down") \ +DECL_BTN_EX(left, 6, "D-Pad left") \ +DECL_BTN_EX(right, 7, "D-Pad Right") \ +DECL_BTN_EX(r3, 15, "R3") \ +DECL_BTN_EX(l3, 14, "L3") + #define WIIUINPUT_GAMEPAD_DEFAULT_BINDS \ DECL_BTN_EX(menu_toggle, 1, "Home") \ DECL_BTN_EX(select, 2, "-") \ @@ -635,7 +654,7 @@ const char* const input_builtin_autoconfs[] = 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("GameCube Controller", "wiiu", WIIUINPUT_GAMECUBE_DEFAULT_BINDS), - DECL_AUTOCONF_DEVICE("Sony DualShock 3", "wiiu", PS3INPUT_DEFAULT_BINDS), + DECL_AUTOCONF_DEVICE("Sony DualShock 3", "wiiu", WIIUINPUT_DS3_DEFAULT_BINDS), #endif #ifdef __CELLOS_LV2__ DECL_AUTOCONF_DEVICE("SixAxis Controller", "ps3", PS3INPUT_DEFAULT_BINDS), diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index eaa9210e68..63c9317430 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -181,14 +181,17 @@ static int32_t wiiu_hid_set_report(void *data, uint8_t report_type, uint8_t report_id, void *report_data, uint32_t report_length) { wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; - if (!adapter) + if (!adapter || report_length > adapter->tx_size) return -1; + memset(adapter->tx_buffer, 0, adapter->tx_size); + memcpy(adapter->tx_buffer, report_data, report_length); + return HIDSetReport(adapter->handle, report_type, report_id, - report_data, - report_length, + adapter->tx_buffer, + adapter->tx_size, NULL, NULL); } @@ -333,10 +336,14 @@ static uint8_t try_init_driver(wiiu_adapter_t *adapter) static void synchronized_process_adapters(wiiu_hid_t *hid) { wiiu_adapter_t *adapter = NULL; + wiiu_adapter_t *prev = NULL, *adapter_next = NULL; + bool keep_prev = false; OSFastMutex_Lock(&(adapters.lock)); - for(adapter = adapters.list; adapter != NULL; adapter = adapter->next) + for(adapter = adapters.list; adapter != NULL; adapter = adapter_next) { + adapter_next = adapter->next; + switch(adapter->state) { case ADAPTER_STATE_NEW: @@ -346,10 +353,24 @@ static void synchronized_process_adapters(wiiu_hid_t *hid) case ADAPTER_STATE_READING: case ADAPTER_STATE_DONE: break; + case ADAPTER_STATE_GC: + /* remove from the list */ + if(prev == NULL) + adapters.list = adapter->next; + else + prev->next = adapter->next; + + /* 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: RARCH_ERR("[hid]: Invalid adapter state: %d\n", adapter->state); break; } + prev = keep_prev ? prev : adapter; + keep_prev = false; } OSFastMutex_Unlock(&(adapters.lock)); } @@ -373,23 +394,15 @@ static wiiu_attach_event *synchronized_get_events_list(void) return list; } -static wiiu_adapter_t *synchronized_remove_from_adapters_list(uint32_t handle) +static wiiu_adapter_t *synchronized_lookup_adapter(uint32_t handle) { OSFastMutex_Lock(&(adapters.lock)); - wiiu_adapter_t *iterator, *prev = NULL; + wiiu_adapter_t *iterator; for(iterator = adapters.list; iterator != NULL; iterator = iterator->next) { if(iterator->handle == handle) - { - /* we're at the start of the list, so just re-assign head */ - if(prev == NULL) - adapters.list = iterator->next; - else - prev->next = iterator->next; break; - } - prev = iterator; } OSFastMutex_Unlock(&(adapters.lock)); @@ -434,12 +447,13 @@ error: static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event) { - wiiu_adapter_t *adapter = synchronized_remove_from_adapters_list(event->handle); + wiiu_adapter_t *adapter = synchronized_lookup_adapter(event->handle); - if(adapter) { - RARCH_LOG("[hid]: freeing detached pad\n"); - delete_adapter(adapter); - } + /* this will signal the read loop to stop for this adapter + * the read loop method will update this to ADAPTER_STATE_GC + * so the adapter poll method can clean it up. */ + if(adapter) + adapter->state = ADAPTER_STATE_DONE; } @@ -495,20 +509,21 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, adapter->state == ADAPTER_STATE_READING) { adapter->state = ADAPTER_STATE_READING; - - if(error) - { - int16_t r1 = (error & 0x0000FFFF); - int16_t r2 = ((error & 0xFFFF0000) >> 16); - RARCH_ERR("[hid]: read failed: %08x (%d:%d)\n", error, r2, r1); - } else { - adapter->driver->handle_packet(adapter->driver_handle, buffer, buffer_size); + /* "error" usually is something benign like "device not ready", at + * least from my own experiments. Just ignore the error and retry + * the read. */ + if(error == 0) { + adapter->driver->handle_packet(adapter->driver_handle, + buffer, buffer_size); } } /* this can also get set if something goes wrong in initialization */ if(adapter->state == ADAPTER_STATE_DONE) + { + adapter->state = ADAPTER_STATE_GC; return; + } HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, wiiu_hid_read_loop_callback, adapter); @@ -597,7 +612,6 @@ static void wiiu_handle_ready_adapters(wiiu_hid_t *hid) static int wiiu_hid_polling_thread(int argc, const char **argv) { wiiu_hid_t *hid = (wiiu_hid_t *)argv; - int i = 0; RARCH_LOG("[hid]: polling thread is starting\n"); @@ -606,9 +620,6 @@ static int wiiu_hid_polling_thread(int argc, const char **argv) wiiu_handle_attach_events(hid, synchronized_get_events_list()); wiiu_handle_ready_adapters(hid); usleep(10000); - i += 10000; - if(i >= (1000 * 1000 * 3)) - i = 0; } RARCH_LOG("[hid]: polling thread is stopping\n"); @@ -713,7 +724,6 @@ static wiiu_attach_event *new_attach_event(HIDDevice *device) device->vid, device->pid); return NULL; } - RARCH_LOG("[hid]: Found HID device driver: %s\n", driver->name); wiiu_attach_event *event = alloc_zeroed(4, sizeof(wiiu_attach_event)); if(!event) return NULL; diff --git a/wiiu/input/wiiu_hid.h b/wiiu/input/wiiu_hid.h index 892e1d3151..2a060d8dd2 100644 --- a/wiiu/input/wiiu_hid.h +++ b/wiiu/input/wiiu_hid.h @@ -24,10 +24,16 @@ #define DEVICE_UNUSED 0 #define DEVICE_USED 1 +/* Adapter has been detected and needs to be initialized */ #define ADAPTER_STATE_NEW 0 +/* Adapter has been initialized successfully */ #define ADAPTER_STATE_READY 1 +/* The read loop has been started */ #define ADAPTER_STATE_READING 2 +/* The read loop is shutting down */ #define ADAPTER_STATE_DONE 3 +/* The read loop has fully stopped and the adapter can be freed */ +#define ADAPTER_STATE_GC 4 struct wiiu_hid { /* used to register for HID notifications */ From dca36ebaf8101865bcaf4496d23d2d21a15df616 Mon Sep 17 00:00:00 2001 From: gblues Date: Sat, 14 Apr 2018 01:26:26 -0700 Subject: [PATCH 18/31] Add small snippet for atomic value swapping Fortunately, the gcc port implements the builtins and, from basic testing, they seem to work. This is only really useful on Wii U--other platforms have more robust atomic operations, or aren't using gcc to build. --- Makefile.wiiu | 4 +- input/common/hid/device_null.c | 211 +++++++++++++++++++++++++++++++++ wiiu/include/wiiu/os/atomic.h | 14 +++ wiiu/system/atomic.c | 36 ++++++ 4 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 input/common/hid/device_null.c create mode 100644 wiiu/include/wiiu/os/atomic.h create mode 100644 wiiu/system/atomic.c diff --git a/Makefile.wiiu b/Makefile.wiiu index 798028e5de..823233215e 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -32,6 +32,7 @@ OBJ += wiiu/input/wpad_driver.o OBJ += wiiu/input/kpad_driver.o OBJ += wiiu/input/pad_functions.o OBJ += wiiu/system/memory.o +OBJ += wiiu/system/atomic.o OBJ += wiiu/system/exception_handler.o OBJ += wiiu/fs/sd_fat_devoptab.o OBJ += wiiu/fs/fs_utils.o @@ -60,7 +61,8 @@ ifeq ($(WIIU_HID),1) input/common/hid/hid_device_driver.o \ input/common/hid/device_wiiu_gca.o \ input/common/hid/device_ds3.o \ - input/common/hid/device_ds4.o + input/common/hid/device_ds4.o \ + input/common/hid/device_null.o endif ifeq ($(SALAMANDER_BUILD),1) diff --git a/input/common/hid/device_null.c b/input/common/hid/device_null.c new file mode 100644 index 0000000000..18628859f5 --- /dev/null +++ b/input/common/hid/device_null.c @@ -0,0 +1,211 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "hid_device_driver.h" + +extern pad_connection_interface_t null_pad_connection; + +/* + * This is the instance data structure for the pad you are implementing. + * This is a good starting point, but you can add/remove things as makes + * sense for the pad you're writing for. The pointer to this structure + * will be passed in as a void pointer to the methods you implement below. + */ +typedef struct null_instance { + void *handle; /* a handle to the HID subsystem adapter */ + joypad_connection_t *pad; /* a pointer to the joypad connection you assign + in init() */ + int slot; /* which slot does this pad occupy? */ + uint32_t buttons; /* a bitmap of the digital buttons for the pad */ + uint16_t motors[2]; /* rumble strength, if appropriate */ + uint8_t data[64]; /* a buffer large enough to hold the device's + max rx packet */ +} null_instance_t; + +/** + * Use the HID_ macros (see input/include/hid_driver.h) to send data packets + * to the device. When this method returns, the device needs to be in a state + * where we can read data packets from the device. So, if there's any + * activation packets (see the ds3 and Wii U GameCube adapter drivers for + * examples), send them here. + * + * While you *can* allocate the retro pad here, it isn't mandatory (see + * the Wii U GC adapter). + * + * If initialization fails, return NULL. + */ +static void *null_init(void *handle) +{ + null_instance_t *instance; + instance = (null_instance_t *)calloc(1, sizeof(null_instance_t)); + if(!instance) + goto error; + + memset(instance, 0, sizeof(null_instance_t)); + instance->handle = handle; + instance->pad = hid_pad_register(instance, &null_pad_connection); + if(!instance->pad) + goto error; + + RARCH_LOG("[null]: init complete.\n"); + return instance; + + error: + RARCH_ERR("[null]: init failed.\n"); + if(instance) + free(instance); + + return NULL; +} + +/* + * Gets called when the pad is disconnected. It must clean up any memory + * allocated and used by the instance data. + */ +static void null_free(void *data) +{ + null_instance_t *instance = (null_instance_t *)data; + + if(instance) + free(instance); +} + +/** + * Handle a single packet from the device. + * For most pads you'd just forward it onto the pad driver (see below). + * A more complicated example is in the Wii U GC adapter driver. + */ +static void null_handle_packet(void *data, uint8_t *buffer, size_t size) +{ + null_instance_t *instance = (null_instance_t *)data; + + if(instance && instance->pad) + instance->pad->iface->packet_handler(instance->pad->data, buffer, size); +} + +/** + * Return true if the passed in VID and PID are supported by the driver. + */ +static bool null_detect(uint16_t vendor_id, uint16_t product_id) +{ + return vendor_id == VID_NONE && product_id == PID_NONE; +} + +/** + * Assign function pointers to the driver structure. + */ +hid_device_t null_hid_device = { + null_init, + null_free, + null_handle_packet, + null_detect, + "Null HID device" +}; + +/** + * This is called via hid_pad_register(). In the common case where the + * device only controls one pad, you can simply return the data parameter. + * But if you need to track multiple pads attached to the same HID device + * (see: Wii U GC adapter), you can allocate that memory here. + */ +static void *null_pad_init(void *data, uint32_t slot, hid_driver_t *driver) +{ + null_instance_t *instance = (null_instance_t *)data; + + if(!instance) + return NULL; + + instance->slot = slot; + return instance; +} + +/** + * If you allocate any memory in null_pad_init() above, de-allocate it here. + */ +static void null_pad_deinit(void *data) +{ +} + +/** + * Translate the button data from the pad into the retro_bits_t format + * that RetroArch can use. + */ +static void null_get_buttons(void *data, retro_bits_t *state) +{ + null_instance_t *instance = (null_instance_t *)data; + if(!instance) + return; + + /* TODO: get buttons */ +} + +/** + * Handle a single packet for the pad. + */ +static void null_packet_handler(void *data, uint8_t *packet, uint16_t size) +{ + null_instance_t *instance = (null_instance_t *)data; + if(!instance) + return; + + RARCH_LOG_BUFFER(packet, size); +} + +/** + * If the pad doesn't support rumble, then this can just be a no-op. + */ +static void null_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) +{ +} + +/** + * Read analog sticks. If the pad doesn't have any analog axis, just return 0 here. + */ +static int16_t null_get_axis(void *data, unsigned axis) +{ + return 0; +} + +/** + * The name the pad will show up as in the UI, also used to auto-assign + * buttons in input/input_autodetect_builtin.c + */ +static const char *null_get_name(void *data) +{ + return "Null HID Pad"; +} + +/** + * Read the state of a single button. + */ +static bool null_button(void *data, uint16_t joykey) +{ + return false; +} + +/** + * Fill in the joypad interface + */ +pad_connection_interface_t null_pad_connection = { + null_pad_init, + null_pad_deinit, + null_packet_handler, + null_set_rumble, + null_get_buttons, + null_get_axis, + null_get_name, + null_button +}; diff --git a/wiiu/include/wiiu/os/atomic.h b/wiiu/include/wiiu/os/atomic.h new file mode 100644 index 0000000000..a5e5dfbcf4 --- /dev/null +++ b/wiiu/include/wiiu/os/atomic.h @@ -0,0 +1,14 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t SwapAtomic8(uint8_t *ptr, uint8_t value); +uint16_t SwapAtomic16(uint16_t *ptr, uint16_t value); +uint32_t SwapAtomic32(uint32_t *ptr, uint32_t value); + +#ifdef __cplusplus +} +#endif diff --git a/wiiu/system/atomic.c b/wiiu/system/atomic.c new file mode 100644 index 0000000000..ec16f75876 --- /dev/null +++ b/wiiu/system/atomic.c @@ -0,0 +1,36 @@ +/* devkitPPC is missing a few functions that are kinda needed for some cores. + * This should add them back in. + */ + +#include + +/** + * Performs an atomic swap of a single piece of data. In each function, + * value is written to ptr, and the previous value is returned. + * + * From GCC docs: + * + * "This builtin is not a full barrier, but rather a *release* barrier. This + * means that references after the builtin cannot move to (or be speculated + * to) before the builtin, but previous memory stores may not be globally + * visible yet, and previous memory loads may not yet be satisfied." + * + * https://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Atomic-Builtins.html + * + * This builtin seems to be implemented in the Wii U GCC toolchain. But since + * this is GCC-specific, I'm not going to put it into a more general-use + * location. + */ +uint8_t SwapAtomic8(uint8_t *ptr, uint8_t value) +{ + return __sync_lock_test_and_set(ptr, value); +} +uint16_t SwapAtomic16(uint16_t *ptr, uint16_t value) +{ + return __sync_lock_test_and_set(ptr, value); +} +uint32_t SwapAtomic32(uint32_t *ptr, uint32_t value) +{ + return __sync_lock_test_and_set(ptr, value); +} + From 97e09d179f53472e89b28382324dfe5000088c52 Mon Sep 17 00:00:00 2001 From: gblues Date: Sat, 14 Apr 2018 13:30:34 -0700 Subject: [PATCH 19/31] Fix deadlocks when device is unplugged == DETAILS TIL that it's bad to call synchronization code from callbacks. To avoid that, I made the following changes: - Implemented an atomic swap (see previous commit) to avoid explicit locking when working with the event list - ensure locks are only acquired in either the main thread or the I/O polling thread - use an explicit polling loop; we still use async reads, but the read doesn't immediately re-invoke itself. - remove the sleep in the polling thread. - remove unnecessary locking in the thread cleanup call--verified that the list can't be modified while it is being executed. == TESTING I tested locally, and was able to disconnect/reconnect USB devices several times without the worker thread getting deadlocked. --- input/common/hid/device_ds3.c | 6 +- input/common/hid/device_ds4.c | 117 ++++++++++++++++-- input/common/hid/hid_device_driver.c | 2 +- wiiu/input/wiiu_hid.c | 172 ++++++++++++++++----------- wiiu/input/wiiu_hid.h | 1 + 5 files changed, 216 insertions(+), 82 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 0bda535d41..e06b0a6c6f 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -153,14 +153,16 @@ static void *ds3_init(void *handle) if(!instance) goto error; + memset(instance, 0, sizeof(ds3_instance_t)); instance->handle = handle; -/* maybe not necessary? */ -/* RARCH_LOG("[ds3]: setting protocol\n"); +/* if(set_protocol(instance, 1)) errors++; */ + set_protocol(instance, 1); + RARCH_LOG("[ds3]: sending control packet\n"); if(send_control_packet(instance) < 0) errors++; diff --git a/input/common/hid/device_ds4.c b/input/common/hid/device_ds4.c index 861de2751f..ce17221b35 100644 --- a/input/common/hid/device_ds4.c +++ b/input/common/hid/device_ds4.c @@ -16,27 +16,63 @@ #include "hid_device_driver.h" -struct ds4_instance { - hid_driver_t *driver; - void *handle; -}; +extern pad_connection_interface_t ds4_pad_connection; +typedef struct ds4_instance { + void *handle; + joypad_connection_t *pad; + int slot; + uint32_t buttons; + uint16_t motors[2]; + uint8_t data[64]; +} ds4_instance_t; + +/** + * I'm leaving this code in here for posterity, and because maybe it can + * be used on other platforms. But using the DS4 on the Wii U directly is + * impossible because it doesn't generate a HID event. Which makes me think + * it's not a HID device at all--at least, not over USB. + * + * I imagine it might be useful in Bluetooth mode, though. + */ static void *ds4_init(void *handle) { - return NULL; + ds4_instance_t *instance; + instance = (ds4_instance_t *)calloc(1, sizeof(ds4_instance_t)); + if(!instance) + goto error; + + memset(instance, 0, sizeof(ds4_instance_t)); + instance->handle = handle; + instance->pad = hid_pad_register(instance, &ds4_pad_connection); + if(!instance->pad) + goto error; + + RARCH_LOG("[ds4]: init complete.\n"); + return instance; + + error: + RARCH_ERR("[ds4]: init failed.\n"); + if(instance) + free(instance); + + return NULL; } static void ds4_free(void *data) { - struct ds4_instance *instance = (struct ds4_instance *)data; - if(!instance) - return; + ds4_instance_t *instance = (ds4_instance_t *)data; - free(instance); + if(instance) + free(instance); } static void ds4_handle_packet(void *data, uint8_t *buffer, size_t size) { + ds4_instance_t *instance = (ds4_instance_t *)data; + + if(instance && instance->pad) + instance->pad->iface->packet_handler(instance->pad->data, buffer, size); } static bool ds4_detect(uint16_t vendor_id, uint16_t product_id) @@ -51,3 +87,66 @@ hid_device_t ds4_hid_device = { ds4_detect, "Sony DualShock 4" }; + +static void *ds4_pad_init(void *data, uint32_t slot, hid_driver_t *driver) +{ + ds4_instance_t *instance = (ds4_instance_t *)data; + + if(!instance) + return NULL; + + instance->slot = slot; + return instance; +} + +static void ds4_pad_deinit(void *data) +{ +} + +static void ds4_get_buttons(void *data, retro_bits_t *state) +{ + ds4_instance_t *instance = (ds4_instance_t *)data; + if(!instance) + return; + + /* TODO: get buttons */ +} + +static void ds4_packet_handler(void *data, uint8_t *packet, uint16_t size) +{ + ds4_instance_t *instance = (ds4_instance_t *)data; + if(!instance) + return; + + RARCH_LOG_BUFFER(packet, size); +} + +static void ds4_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) +{ +} + +static int16_t ds4_get_axis(void *data, unsigned axis) +{ + return 0; +} + +static const char *ds4_get_name(void *data) +{ + return "Sony DualShock 4"; +} + +static bool ds4_button(void *data, uint16_t joykey) +{ + return false; +} + +pad_connection_interface_t ds4_pad_connection = { + ds4_pad_init, + ds4_pad_deinit, + ds4_packet_handler, + ds4_set_rumble, + ds4_get_buttons, + ds4_get_axis, + ds4_get_name, + ds4_button +}; diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index 37bc4feaa8..b38bdd9067 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -21,7 +21,7 @@ hid_driver_instance_t hid_instance = {0}; hid_device_t *hid_device_list[] = { &wiiu_gca_hid_device, &ds3_hid_device, - &ds4_hid_device, +/* &ds4_hid_device, */ NULL /* must be last entry in list */ }; diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 63c9317430..8990d9ce44 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -15,6 +15,7 @@ */ #include "wiiu_hid.h" +#include static wiiu_event_list events; static wiiu_adapter_list adapters; @@ -377,21 +378,17 @@ static void synchronized_process_adapters(wiiu_hid_t *hid) static void synchronized_add_event(wiiu_attach_event *event) { - OSFastMutex_Lock(&(events.lock)); - event->next = events.list; - events.list = event; - OSFastMutex_Unlock(&(events.lock)); + wiiu_attach_event *head = (wiiu_attach_event *)SwapAtomic32((uint32_t *)&events.list, 0); + + event->next = head; + head = event; + + SwapAtomic32((uint32_t *)&events.list, (uint32_t)head); } static wiiu_attach_event *synchronized_get_events_list(void) { - wiiu_attach_event *list; - OSFastMutex_Lock(&(events.lock)); - list = events.list; - events.list = NULL; - OSFastMutex_Unlock(&(events.lock)); - - return list; + return (wiiu_attach_event *)SwapAtomic32((uint32_t *)&events.list, 0); } static wiiu_adapter_t *synchronized_lookup_adapter(uint32_t handle) @@ -422,24 +419,24 @@ static int32_t wiiu_attach_callback(HIDClient *client, { wiiu_attach_event *event = NULL; - switch(attach) - { - case HID_DEVICE_ATTACH: - log_device(device); - case HID_DEVICE_DETACH: - if (device) - event = new_attach_event(device); - - if(!event) - goto error; - - event->type = attach; - synchronized_add_event(event); - return DEVICE_USED; - default: - break; + if(attach) { + RARCH_LOG("[hid]: Device attach event generated.\n"); + log_device(device); + } else { + RARCH_LOG("[hid]: Device detach event generated.\n"); } + if (device) + event = new_attach_event(device); + + if(!event) + goto error; + + event->type = attach; + synchronized_add_event(event); + + return DEVICE_USED; + error: delete_attach_event(event); return DEVICE_UNUSED; @@ -453,7 +450,7 @@ static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event) * the read loop method will update this to ADAPTER_STATE_GC * so the adapter poll method can clean it up. */ if(adapter) - adapter->state = ADAPTER_STATE_DONE; + adapter->connected = false; } @@ -479,15 +476,6 @@ error: delete_adapter(adapter); } -void wiiu_start_read_loop(wiiu_adapter_t *adapter) -{ - HIDRead(adapter->handle, - adapter->rx_buffer, - adapter->rx_size, - wiiu_hid_read_loop_callback, - adapter); -} - static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, uint8_t *buffer, uint32_t buffer_size, void *userdata) { @@ -498,17 +486,49 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, return; } - if(adapter->hid->polling_thread_quit) + if(error < 0) { - RARCH_LOG("Shutting down read loop for device: %s\n", - adapter->driver->name); - adapter->state = ADAPTER_STATE_DONE; + int16_t hid_error_code = error & 0xffff; + switch(hid_error_code) + { + case -100: + RARCH_ERR("[hid]: Invalid RM command (%s)\n", adapter->driver->name); + break; + case -102: + RARCH_ERR("[hid]: Invalid IOCTL command (%s)\n", adapter->driver->name); + break; + case -103: + RARCH_ERR("[hid]: bad vector count (%s)\n", adapter->driver->name); + break; + case -104: + RARCH_ERR("[hid]: invalid memory bank (%s)\n", adapter->driver->name); + break; + case -105: + RARCH_ERR("[hid]: invalid memory alignment (%s)\n", adapter->driver->name); + break; + case -106: + RARCH_ERR("[hid]: invalid data size (%s)\n", adapter->driver->name); + break; + case -107: + RARCH_ERR("[hid]: request cancelled (%s)\n", adapter->driver->name); + break; + case -108: + RARCH_ERR("[hid]: request timed out (%s)\n", adapter->driver->name); + break; + case -109: + RARCH_ERR("[hid]: request aborted (%s)\n", adapter->driver->name); + break; + case -110: + RARCH_ERR("[hid]: client priority error (%s)\n", adapter->driver->name); + break; + case -111: + RARCH_ERR("[hid]: invalid device handle (%s)\n", adapter->driver->name); + break; + } } - if(adapter->state == ADAPTER_STATE_READY || - adapter->state == ADAPTER_STATE_READING) { - - adapter->state = ADAPTER_STATE_READING; + if(adapter->state == ADAPTER_STATE_READING) { + adapter->state = ADAPTER_STATE_READY; /* "error" usually is something benign like "device not ready", at * least from my own experiments. Just ignore the error and retry * the read. */ @@ -517,16 +537,6 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, buffer, buffer_size); } } - - /* this can also get set if something goes wrong in initialization */ - if(adapter->state == ADAPTER_STATE_DONE) - { - adapter->state = ADAPTER_STATE_GC; - return; - } - - HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, - wiiu_hid_read_loop_callback, adapter); } /** @@ -540,17 +550,18 @@ static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack) RARCH_LOG("Waiting for in-flight reads to finish.\n"); + /* We don't need to protect the adapter list here because nothing else + will access it during this method (the HID system is shut down, and + the only other access is the polling thread that just stopped */ do { - OSFastMutex_Lock(&(adapters.lock)); incomplete = 0; for(adapter = adapters.list; adapter != NULL; adapter = adapter->next) { if(adapter->state == ADAPTER_STATE_READING) incomplete++; } - /* We are clear for shutdown. Clean up the list - * while we are holding the lock. */ + if(incomplete == 0) { RARCH_LOG("All in-flight reads complete.\n"); @@ -562,7 +573,6 @@ static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack) delete_adapter(adapter); } } - OSFastMutex_Unlock(&(adapters.lock)); if(incomplete) usleep(5000); @@ -572,8 +582,7 @@ static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack) RARCH_WARN("[hid]: timed out waiting for in-flight read to finish.\n"); incomplete = 0; } - }while(incomplete); - + } while(incomplete); } static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list) @@ -594,7 +603,7 @@ static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list) } } -static void wiiu_handle_ready_adapters(wiiu_hid_t *hid) +static void wiiu_poll_adapters(wiiu_hid_t *hid) { wiiu_adapter_t *it; OSFastMutex_Lock(&(adapters.lock)); @@ -602,11 +611,25 @@ static void wiiu_handle_ready_adapters(wiiu_hid_t *hid) for(it = adapters.list; it != NULL; it = it->next) { if(it->state == ADAPTER_STATE_READY) - wiiu_start_read_loop(it); + { + if(it->connected) + { + it->state = ADAPTER_STATE_READING; + HIDRead(it->handle, + it->rx_buffer, + it->rx_size, + wiiu_hid_read_loop_callback, + it); + } else { + it->state = ADAPTER_STATE_DONE; + } + } + + if(it->state == ADAPTER_STATE_DONE) + it->state = ADAPTER_STATE_GC; } OSFastMutex_Unlock(&(adapters.lock)); - } static int wiiu_hid_polling_thread(int argc, const char **argv) @@ -618,8 +641,7 @@ static int wiiu_hid_polling_thread(int argc, const char **argv) while(!hid->polling_thread_quit) { wiiu_handle_attach_events(hid, synchronized_get_events_list()); - wiiu_handle_ready_adapters(hid); - usleep(10000); + wiiu_poll_adapters(hid); } RARCH_LOG("[hid]: polling thread is stopping\n"); @@ -674,6 +696,17 @@ static void delete_hidclient(HIDClient *client) free(client); } +static void init_cachealigned_buffer(int32_t min_size, uint8_t **out_buf_ptr, int32_t *actual_size) +{ + int cacheblocks = (min_size < 32) ? 1 : min_size / 32; + if(min_size > 32 && min_size % 32 != 0) + cacheblocks++; + + *actual_size = 32 * cacheblocks; + + *out_buf_ptr = alloc_zeroed(32, *actual_size); +} + static wiiu_adapter_t *new_adapter(wiiu_attach_event *event) { wiiu_adapter_t *adapter = alloc_zeroed(32, sizeof(wiiu_adapter_t)); @@ -683,10 +716,9 @@ static wiiu_adapter_t *new_adapter(wiiu_attach_event *event) adapter->handle = event->handle; adapter->interface_index = event->interface_index; - adapter->rx_size = event->max_packet_size_rx; - adapter->rx_buffer = alloc_zeroed(32, adapter->rx_size); - adapter->tx_size = event->max_packet_size_tx; - adapter->tx_buffer = alloc_zeroed(32, adapter->tx_size); + init_cachealigned_buffer(event->max_packet_size_rx, &adapter->rx_buffer, &adapter->rx_size); + init_cachealigned_buffer(event->max_packet_size_tx, &adapter->tx_buffer, &adapter->tx_size); + adapter->connected = true; return adapter; } diff --git a/wiiu/input/wiiu_hid.h b/wiiu/input/wiiu_hid.h index 2a060d8dd2..0c96c9599c 100644 --- a/wiiu/input/wiiu_hid.h +++ b/wiiu/input/wiiu_hid.h @@ -62,6 +62,7 @@ struct wiiu_adapter { int32_t tx_size; uint32_t handle; uint8_t interface_index; + bool connected; }; /** From 6ab91a422eef83ee014e14bc9511e92b4acba02e Mon Sep 17 00:00:00 2001 From: gblues Date: Sat, 14 Apr 2018 14:34:13 -0700 Subject: [PATCH 20/31] Small cleanup to adapt to upstream code changes retro_bits_t turned into input_bits_t and there were parts of my code that needed to update. == TESTING No idea if upstream changes broke anything, but it compiles cleanly now. --- input/common/hid/device_ds3.c | 2 +- input/common/hid/device_ds4.c | 2 +- input/common/hid/device_null.c | 4 ++-- input/common/hid/device_wiiu_gca.c | 2 +- input/include/hid_driver.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index e06b0a6c6f..365d945b2e 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -236,7 +236,7 @@ static void ds3_pad_deinit(void *data) ds3_instance_t *pad = (ds3_instance_t *)data; } -static void ds3_get_buttons(void *data, retro_bits_t *state) +static void ds3_get_buttons(void *data, input_bits_t *state) { ds3_instance_t *pad = (ds3_instance_t *)data; diff --git a/input/common/hid/device_ds4.c b/input/common/hid/device_ds4.c index ce17221b35..b334a13233 100644 --- a/input/common/hid/device_ds4.c +++ b/input/common/hid/device_ds4.c @@ -103,7 +103,7 @@ static void ds4_pad_deinit(void *data) { } -static void ds4_get_buttons(void *data, retro_bits_t *state) +static void ds4_get_buttons(void *data, input_bits_t *state) { ds4_instance_t *instance = (ds4_instance_t *)data; if(!instance) diff --git a/input/common/hid/device_null.c b/input/common/hid/device_null.c index 18628859f5..96d99f5f74 100644 --- a/input/common/hid/device_null.c +++ b/input/common/hid/device_null.c @@ -140,10 +140,10 @@ static void null_pad_deinit(void *data) } /** - * Translate the button data from the pad into the retro_bits_t format + * Translate the button data from the pad into the input_bits_t format * that RetroArch can use. */ -static void null_get_buttons(void *data, retro_bits_t *state) +static void null_get_buttons(void *data, input_bits_t *state) { null_instance_t *instance = (null_instance_t *)data; if(!instance) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 1d50c513ee..5e3968f757 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -229,7 +229,7 @@ static void wiiu_gca_pad_deinit(void *data) } } -static void wiiu_gca_get_buttons(void *data, retro_bits_t *state) +static void wiiu_gca_get_buttons(void *data, input_bits_t *state) { gca_pad_t *pad = (gca_pad_t *)data; if(pad) diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 5b75c785bb..02b6529f63 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -39,7 +39,7 @@ struct hid_driver bool (*query_pad)(void *handle, unsigned pad); void (*free)(const void *handle); bool (*button)(void *handle, unsigned pad, uint16_t button); - void (*get_buttons)(void *handle, unsigned pad, retro_bits_t *state); + void (*get_buttons)(void *handle, unsigned pad, input_bits_t *state); int16_t (*axis)(void *handle, unsigned pad, uint32_t axis); void (*poll)(void *handle); bool (*set_rumble)(void *handle, unsigned pad, enum retro_rumble_effect effect, uint16_t); From 4cd301bd929c765b968ce45b95bd749cce4b442d Mon Sep 17 00:00:00 2001 From: gblues Date: Sat, 14 Apr 2018 21:30:44 -0700 Subject: [PATCH 21/31] Add pad unregistration == DETAILS I think this will fix the problem with duplicate pads--pads weren't properly de-initializing and registering as disconnected. When a pad is disconnected, the slot should properly release now. --- input/common/hid/device_ds3.c | 4 +++- input/common/hid/device_ds4.c | 4 +++- input/common/hid/device_null.c | 4 +++- input/common/hid/device_wiiu_gca.c | 34 ++-------------------------- input/common/hid/hid_device_driver.c | 14 ++++++++++++ input/common/hid/hid_device_driver.h | 1 + 6 files changed, 26 insertions(+), 35 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 365d945b2e..bd4d6a1ad4 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -192,8 +192,10 @@ static void ds3_free(void *data) { ds3_instance_t *instance = (ds3_instance_t *)data; - if(instance) + if(instance) { + hid_pad_deregister(instance->pad); free(instance); + } } static void ds3_handle_packet(void *data, uint8_t *packet, size_t size) diff --git a/input/common/hid/device_ds4.c b/input/common/hid/device_ds4.c index b334a13233..af923cee13 100644 --- a/input/common/hid/device_ds4.c +++ b/input/common/hid/device_ds4.c @@ -63,8 +63,10 @@ static void ds4_free(void *data) { ds4_instance_t *instance = (ds4_instance_t *)data; - if(instance) + if(instance) { + hid_pad_deregister(instance->pad); free(instance); + } } static void ds4_handle_packet(void *data, uint8_t *buffer, size_t size) diff --git a/input/common/hid/device_null.c b/input/common/hid/device_null.c index 96d99f5f74..783c615924 100644 --- a/input/common/hid/device_null.c +++ b/input/common/hid/device_null.c @@ -79,8 +79,10 @@ static void null_free(void *data) { null_instance_t *instance = (null_instance_t *)data; - if(instance) + if(instance) { + hid_pad_deregister(instance->pad); free(instance); + } } /** diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 5e3968f757..9e09598022 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -145,34 +145,6 @@ static void update_pad_state(wiiu_gca_instance_t *instance) } } -/* -static joypad_connection_t *register_pad(wiiu_gca_instance_t *instance, int port) { - int slot; - joypad_connection_t *result; - - if(!instance || !instance->online) - { - RARCH_ERR("[gca]: bad instance\n"); - return NULL; - } - - slot = pad_connection_find_vacant_pad(hid_instance.pad_list); - if(slot < 0) - { - RARCH_ERR("[gca]: failed to find a free slot\n"); - return NULL; - } - - result = &(hid_instance.pad_list[slot]); - result->iface = &wiiu_gca_pad_connection; - result->data = result->iface->init(instance, slot, hid_instance.os_driver); - result->connected = true; - input_pad_connect(slot, hid_instance.pad_driver); - - return result; -} -*/ - static void unregister_pad(wiiu_gca_instance_t *instance, int slot) { if(!instance || slot < 0 || slot >= 4 || instance->pads[slot] == NULL) @@ -180,10 +152,8 @@ static void unregister_pad(wiiu_gca_instance_t *instance, int slot) joypad_connection_t *pad = instance->pads[slot]; instance->pads[slot] = NULL; - pad->iface->deinit(pad->data); - pad->data = NULL; - pad->iface = NULL; - pad->connected = false; + + hid_pad_deregister(pad); } static bool wiiu_gca_detect(uint16_t vendor_id, uint16_t product_id) { diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index b38bdd9067..ccab2dc569 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -60,6 +60,20 @@ joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface return result; } +void hid_pad_deregister(joypad_connection_t *pad) +{ + if(!pad) + return; + + if(pad->data) { + pad->iface->deinit(pad->data); + pad->data = NULL; + } + + pad->iface = NULL; + pad->connected = false; +} + static bool init_pad_list(hid_driver_instance_t *instance, unsigned slots) { if(!instance || slots > MAX_USERS) diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h index 715fd7cfea..18a8f45479 100644 --- a/input/common/hid/hid_device_driver.h +++ b/input/common/hid/hid_device_driver.h @@ -37,6 +37,7 @@ extern hid_driver_instance_t hid_instance; hid_device_t *hid_device_driver_lookup(uint16_t vendor_id, uint16_t product_id); joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface_t *iface); +void hid_pad_deregister(joypad_connection_t *pad); bool hid_init(hid_driver_instance_t *instance, hid_driver_t *hid_driver, input_device_driver_t *pad_driver, unsigned slots); void hid_deinit(hid_driver_instance_t *instance); From 6eebbe42133ce6ff9fd1c2c52a2fb077fe6d50e3 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 15 Apr 2018 00:04:49 -0700 Subject: [PATCH 22/31] Build fix for PC == DETAILS Hooray for conditional compile directives. Moving things around broke things in unexpected ways on non-WiiU builds. Well, not *completely* unexpected. But still. Changes: - Move some typedefs around to avoid circular include dependencies - Include the file where the HID driver definition got moved to == TESTING - verified build for Wii U still runs successfully - did a local build without any errors (some weird warnings, but since they happen in code I didn't change, I'm assuming they're pre-existing?) --- input/connect/joypad_connection.h | 2 -- input/input_driver.h | 17 ++++------------- input/input_types.h | 5 +++++ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/input/connect/joypad_connection.h b/input/connect/joypad_connection.h index bb1b12158a..62a454609a 100644 --- a/input/connect/joypad_connection.h +++ b/input/connect/joypad_connection.h @@ -64,8 +64,6 @@ typedef struct pad_connection_interface bool (*button)(void *data, uint16_t joykey); } pad_connection_interface_t; -typedef struct joypad_connection joypad_connection_t; - extern pad_connection_interface_t pad_connection_wii; extern pad_connection_interface_t pad_connection_wiiupro; extern pad_connection_interface_t pad_connection_ps3; diff --git a/input/input_driver.h b/input/input_driver.h index 1fe417bd78..f47e8830eb 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -38,23 +38,11 @@ #include "../msg_hash.h" #include "include/hid_types.h" +#include "include/hid_driver.h" #include "include/gamepad.h" RETRO_BEGIN_DECLS -typedef struct -{ - uint32_t data[8]; - uint16_t analogs[8]; -} input_bits_t; - -typedef struct rarch_joypad_driver input_device_driver_t; - -typedef struct hid_driver hid_driver_t; - -/* Keyboard line reader. Handles textual input in a direct fashion. */ -typedef struct input_keyboard_line input_keyboard_line_t; - enum input_device_type { INPUT_DEVICE_TYPE_NONE = 0, @@ -621,6 +609,9 @@ const char *input_joypad_name(const input_device_driver_t *driver, bool input_config_get_bind_idx(unsigned port, unsigned *joy_idx_real); #ifdef HAVE_HID + +#include "include/hid_driver.h" + /** * hid_driver_find_handle: * @index : index of driver to get handle to. diff --git a/input/input_types.h b/input/input_types.h index 4c36861866..0c1e2edcf1 100644 --- a/input/input_types.h +++ b/input/input_types.h @@ -22,5 +22,10 @@ typedef struct input_keyboard_line input_keyboard_line_t; typedef struct rarch_joypad_info rarch_joypad_info_t; typedef struct input_driver input_driver_t; typedef struct input_keyboard_ctx_wait input_keyboard_ctx_wait_t; +typedef struct { + uint32_t data[8]; + uint16_t analogs[8]; +} input_bits_t; +typedef struct joypad_connection joypad_connection_t; #endif /* __INPUT_TYPES__H */ From 53738e4a0d5c7d0a74a4d330596c651790134c57 Mon Sep 17 00:00:00 2001 From: gblues Date: Wed, 18 Apr 2018 23:12:45 -0700 Subject: [PATCH 23/31] Allow Wii U GCA to work without 2nd cable attached === DETAILS So, the GCA has 2 USB connections; one is the data connection, and the second is used to drive rumble. Due to a driver bug, if the second cable wasn't attached, the pads wouldn't get detected. I fixed that bug. --- input/common/hid/device_wiiu_gca.c | 45 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 9e09598022..fe27e764f5 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -23,8 +23,9 @@ static uint8_t activation_packet[] = { 0x13 }; #endif #define GCA_PORT_INITIALIZING 0x00 -#define GCA_PORT_EMPTY 0x04 -#define GCA_PORT_CONNECTED 0x14 +#define GCA_PORT_POWERED 0x04 +#define GCA_PORT_CONNECTED 0x10 + typedef struct wiiu_gca_instance { void *handle; @@ -107,40 +108,41 @@ static void wiiu_gca_handle_packet(void *data, uint8_t *buffer, size_t size) static void update_pad_state(wiiu_gca_instance_t *instance) { int i, port; + unsigned char port_connected; + if(!instance || !instance->online) return; joypad_connection_t *pad; /* process each pad */ + //RARCH_LOG_BUFFER(instance->device_state, 37); for(i = 1; i < 37; i += 9) { port = i / 9; pad = instance->pads[port]; - switch(instance->device_state[i]) + port_connected = instance->device_state[i] & GCA_PORT_CONNECTED; + + if(port_connected) { - case GCA_PORT_INITIALIZING: - case GCA_PORT_EMPTY: - if(pad != NULL) { - RARCH_LOG("[gca]: Gamepad at port %d disconnected.\n", port+1); - unregister_pad(instance, port); - } - break; - case GCA_PORT_CONNECTED: + if(pad == NULL) + { + RARCH_LOG("[gca]: Gamepad at port %d connected.\n", port+1); + instance->pads[port] = hid_pad_register(instance, &wiiu_gca_pad_connection); + pad = instance->pads[port]; if(pad == NULL) { - RARCH_LOG("[gca]: Gamepad at port %d connected.\n", port+1); - instance->pads[port] = hid_pad_register(instance, &wiiu_gca_pad_connection); - pad = instance->pads[port]; - if(pad == NULL) - { - RARCH_ERR("[gca]: Failed to register pad.\n"); - break; - } + RARCH_ERR("[gca]: Failed to register pad.\n"); + break; } + } - pad->iface->packet_handler(pad->data, &instance->device_state[i], 9); - break; + pad->iface->packet_handler(pad->data, &instance->device_state[i], 9); + } else { + if(pad != NULL) { + RARCH_LOG("[gca]: Gamepad at port %d disconnected.\n", port+1); + unregister_pad(instance, port); + } } } } @@ -263,6 +265,7 @@ static int16_t wiiu_gca_get_axis(void *data, unsigned axis) if(val > 0x1000 || val < -0x1000) return 0; +// RARCH_LOG("[gca]: reading axis %d: %04x\n", axis, val); return val; } From 0c92fab0b9c5abf4df09493a7506027ab304aa9f Mon Sep 17 00:00:00 2001 From: gblues Date: Fri, 20 Apr 2018 00:00:33 -0700 Subject: [PATCH 24/31] Fix GameCube button detection This should fix the issue where R/L buttons didn't register when doing input detection. This also brings the GC pad in line with the rest of the gamepads in input_autodetect_builtin.c. Also fixed a really stupid bug that was part of why analog inputs aren't being read. Analog still isn't working, mind, but it's a lot closer to working now that it's actually getting down into the pad driver level! --- input/common/hid/device_wiiu_gca.c | 53 +++++++++++++++++++++++++++--- input/input_autodetect_builtin.c | 24 +++++++------- wiiu/input/hidpad_driver.c | 4 +-- 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index fe27e764f5..ab113494c4 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -212,6 +212,38 @@ static void wiiu_gca_get_buttons(void *data, input_bits_t *state) } } +static void update_buttons(gca_pad_t *pad) +{ + 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) + 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; +} + + /** * The USB packet provides a 9-byte data packet for each pad. * @@ -230,9 +262,11 @@ static void wiiu_gca_packet_handler(void *data, uint8_t *packet, uint16_t size) return; memcpy(pad->data, packet, size); - pad->buttons = pad->data[1] | (pad->data[2] << 8); + update_buttons(pad); } + + static void wiiu_gca_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) { (void)data; @@ -240,8 +274,19 @@ static void wiiu_gca_set_rumble(void *data, enum retro_rumble_effect effect, uin (void)strength; } +static unsigned decode_axis(unsigned axis) +{ + unsigned positive = AXIS_POS_GET(axis); + unsigned negative = AXIS_NEG_GET(axis); + RARCH_LOG("[gca]: positive: %ud negative: %ud\n", positive, negative); + + return positive >= 4 ? negative : positive; +} + static int16_t wiiu_gca_get_axis(void *data, unsigned axis) { + axis = decode_axis(axis); + RARCH_LOG("[gca]: decoded axis: %d\n", axis); int16_t val; gca_pad_t *pad = (gca_pad_t *)data; @@ -265,7 +310,7 @@ static int16_t wiiu_gca_get_axis(void *data, unsigned axis) if(val > 0x1000 || val < -0x1000) return 0; -// RARCH_LOG("[gca]: reading axis %d: %04x\n", axis, val); + RARCH_LOG("[gca]: reading axis %d: %04x\n", axis, val); return val; } @@ -288,10 +333,10 @@ static bool wiiu_gca_button(void *data, uint16_t joykey) { gca_pad_t *pad = (gca_pad_t *)data; - if(!pad) + if(!pad || joykey > 31) return false; - return (pad->buttons & joykey); + return pad->buttons & (1 << joykey); } pad_connection_interface_t wiiu_gca_pad_connection = { diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 8b37d0828d..72909ebb8e 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -229,18 +229,18 @@ DECL_AXIS(r_y_minus, +3) #ifdef WIIU #define WIIUINPUT_GAMECUBE_DEFAULT_BINDS \ -DECL_BTN_EX(a, 0x0001, "A") \ -DECL_BTN_EX(b, 0x0002, "B") \ -DECL_BTN_EX(x, 0x0004, "X") \ -DECL_BTN_EX(y, 0x0008, "Y") \ -DECL_BTN_EX(select, 0x0200, "Z") \ -DECL_BTN_EX(start, 0x0100, "Start/Pause") \ -DECL_BTN_EX(l, 0x0800, "L Trigger") \ -DECL_BTN_EX(r, 0x0400, "R Trigger") \ -DECL_BTN_EX(left, 0x0010, "D-Pad Left") \ -DECL_BTN_EX(right, 0x0020, "D-Pad Right") \ -DECL_BTN_EX(down, 0x0040, "D-Pad Down") \ -DECL_BTN_EX(up, 0x0080, "D-Pad Up") \ +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, +1, "Analog right") \ DECL_AXIS_EX(l_x_minus, -1, "Analog left") \ DECL_AXIS_EX(l_y_plus, +0, "Analog up") \ diff --git a/wiiu/input/hidpad_driver.c b/wiiu/input/hidpad_driver.c index 9c0889b177..03efe64d5c 100644 --- a/wiiu/input/hidpad_driver.c +++ b/wiiu/input/hidpad_driver.c @@ -80,8 +80,8 @@ static void hidpad_get_buttons(unsigned pad, input_bits_t *state) static int16_t hidpad_axis(unsigned pad, uint32_t axis) { - if (!hidpad_query_pad(pad)); - return 0; + if (!hidpad_query_pad(pad)) + return 0; return HID_AXIS(pad, axis); } From ef3674485978d3dda99a7c753c18a5d84adf4998 Mon Sep 17 00:00:00 2001 From: gblues Date: Fri, 20 Apr 2018 13:03:53 -0700 Subject: [PATCH 25/31] Start implementing fall-back to async read == DETAILS The Wii U GC adapter doesn't seem to like doing async reads if it is connected via a USB hub. It seems to be device-specific, though, because my DS3 works just fine through the same hub. I tried creating a fallback to synchronous reads, but it resulted in a hard lock of the system. So, for the time being, it's going to be a known limitation. Might be solved by using a powered USB hub. Learned that the cache alignment is 64, not 32, so the alignment math has been updated. Thanks, @aliaspider for that info. --- wiiu/input/wiiu_hid.c | 147 +++++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 65 deletions(-) diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index 8a0d2fe53a..962e9323d8 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -20,6 +20,8 @@ static wiiu_event_list events; static wiiu_adapter_list adapters; +static void report_hid_error(const char *msg, wiiu_adapter_t *adapter, int32_t error); + static bool wiiu_hid_joypad_query(void *data, unsigned slot) { wiiu_hid_t *hid = (wiiu_hid_t *)data; @@ -222,15 +224,20 @@ static int32_t wiiu_hid_set_protocol(void *data, uint8_t protocol) static int32_t wiiu_hid_read(void *data, void *buffer, size_t size) { - wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; + wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; + int32_t result; - if(!adapter) - return -1; + if(!adapter) + return -1; - if(size > adapter->rx_size) - return -1; + if(size > adapter->rx_size) + return -1; - return HIDRead(adapter->handle, buffer, size, NULL, NULL); + result = HIDRead(adapter->handle, buffer, size, NULL, NULL); + if(result < 0) + report_hid_error("read failed", adapter, result); + + return result; } @@ -488,50 +495,12 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, if(error < 0) { - int16_t hid_error_code = error & 0xffff; - switch(hid_error_code) - { - case -100: - RARCH_ERR("[hid]: Invalid RM command (%s)\n", adapter->driver->name); - break; - case -102: - RARCH_ERR("[hid]: Invalid IOCTL command (%s)\n", adapter->driver->name); - break; - case -103: - RARCH_ERR("[hid]: bad vector count (%s)\n", adapter->driver->name); - break; - case -104: - RARCH_ERR("[hid]: invalid memory bank (%s)\n", adapter->driver->name); - break; - case -105: - RARCH_ERR("[hid]: invalid memory alignment (%s)\n", adapter->driver->name); - break; - case -106: - RARCH_ERR("[hid]: invalid data size (%s)\n", adapter->driver->name); - break; - case -107: - RARCH_ERR("[hid]: request cancelled (%s)\n", adapter->driver->name); - break; - case -108: - RARCH_ERR("[hid]: request timed out (%s)\n", adapter->driver->name); - break; - case -109: - RARCH_ERR("[hid]: request aborted (%s)\n", adapter->driver->name); - break; - case -110: - RARCH_ERR("[hid]: client priority error (%s)\n", adapter->driver->name); - break; - case -111: - RARCH_ERR("[hid]: invalid device handle (%s)\n", adapter->driver->name); - break; - } + report_hid_error("async read failed", adapter, error); } if(adapter->state == ADAPTER_STATE_READING) { adapter->state = ADAPTER_STATE_READY; - /* "error" usually is something benign like "device not ready", at - * least from my own experiments. Just ignore the error and retry - * the read. */ + if(error == 0) { adapter->driver->handle_packet(adapter->driver_handle, buffer, buffer_size); @@ -539,6 +508,58 @@ static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, } } +static void report_hid_error(const char *msg, wiiu_adapter_t *adapter, int32_t error) +{ + if(error >= 0) + return; + + int16_t hid_error_code = error & 0xffff; + int16_t error_category = (error >> 16) & 0xffff; + const char *device = (adapter && adapter->driver) ? adapter->driver->name : "unknown"; + + switch(hid_error_code) + { + case -100: + RARCH_ERR("[hid]: Invalid RM command (%s)\n", device); + break; + case -102: + RARCH_ERR("[hid]: Invalid IOCTL command (%s)\n", device); + break; + case -103: + RARCH_ERR("[hid]: bad vector count (%s)\n", device); + break; + case -104: + RARCH_ERR("[hid]: invalid memory bank (%s)\n", device); + break; + case -105: + RARCH_ERR("[hid]: invalid memory alignment (%s)\n", device); + break; + case -106: + RARCH_ERR("[hid]: invalid data size (%s)\n", device); + break; + case -107: + RARCH_ERR("[hid]: request cancelled (%s)\n", device); + break; + case -108: + RARCH_ERR("[hid]: request timed out (%s)\n", device); + break; + case -109: + RARCH_ERR("[hid]: request aborted (%s)\n", device); + break; + case -110: + RARCH_ERR("[hid]: client priority error (%s)\n", device); + break; + case -111: + RARCH_ERR("[hid]: invalid device handle (%s)\n", device); + break; +#if 0 + default: + RARCH_ERR("[hid]: Unknown error (%d:%d: %s)\n", + error_category, hid_error_code, device); +#endif + } +} + /** * Block until all the HIDRead() calls have returned. */ @@ -603,6 +624,18 @@ static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list) } } +static void wiiu_poll_adapter(wiiu_adapter_t *adapter) +{ + if(!adapter->connected) { + adapter->state = ADAPTER_STATE_DONE; + return; + } + + adapter->state = ADAPTER_STATE_READING; + HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, + wiiu_hid_read_loop_callback, adapter); +} + static void wiiu_poll_adapters(wiiu_hid_t *hid) { wiiu_adapter_t *it; @@ -611,19 +644,7 @@ static void wiiu_poll_adapters(wiiu_hid_t *hid) for(it = adapters.list; it != NULL; it = it->next) { if(it->state == ADAPTER_STATE_READY) - { - if(it->connected) - { - it->state = ADAPTER_STATE_READING; - HIDRead(it->handle, - it->rx_buffer, - it->rx_size, - wiiu_hid_read_loop_callback, - it); - } else { - it->state = ADAPTER_STATE_DONE; - } - } + wiiu_poll_adapter(it); if(it->state == ADAPTER_STATE_DONE) it->state = ADAPTER_STATE_GC; @@ -698,13 +719,9 @@ static void delete_hidclient(HIDClient *client) static void init_cachealigned_buffer(int32_t min_size, uint8_t **out_buf_ptr, int32_t *actual_size) { - int cacheblocks = (min_size < 32) ? 1 : min_size / 32; - if(min_size > 32 && min_size % 32 != 0) - cacheblocks++; + *actual_size = (min_size + 0x3f) & ~0x3f; - *actual_size = 32 * cacheblocks; - - *out_buf_ptr = alloc_zeroed(32, *actual_size); + *out_buf_ptr = alloc_zeroed(64, *actual_size); } static wiiu_adapter_t *new_adapter(wiiu_attach_event *event) From ed742c48e0840b40a2ab65d3b8073ce1354879d2 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 22 Apr 2018 17:34:20 -0700 Subject: [PATCH 26/31] Fix hotplugging == DETAILS So, it turns out that there *is* a autoconfig disconnect handler. Took digging through tasks/task_autodetect.c to find it! So, I added a call to the handler when the pad gets disconnected. This seems to solve the problem of the pad not disappearing from the menu. (At the very least, the user's pad index reverts to "none" which is still an improvement) == TESTING Tested manually, made sure it didn't crash or leak slots. --- input/common/hid/device_ds3.c | 3 +++ input/common/hid/device_wiiu_gca.c | 14 ++++++-------- input/common/hid/hid_device_driver.h | 1 + 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index bd4d6a1ad4..d21788e624 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -236,6 +236,9 @@ static void *ds3_pad_init(void *data, uint32_t slot, hid_driver_t *driver) static void ds3_pad_deinit(void *data) { ds3_instance_t *pad = (ds3_instance_t *)data; + if(pad) { + input_autoconfigure_disconnect(pad->slot, ds3_pad_connection.get_name(pad)); + } } static void ds3_get_buttons(void *data, input_bits_t *state) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index ab113494c4..2b8eecc046 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -193,12 +193,13 @@ static void *wiiu_gca_pad_init(void *data, uint32_t slot, hid_driver_t *driver) static void wiiu_gca_pad_deinit(void *data) { - gca_pad_t *pad = (gca_pad_t *)data; + gca_pad_t *pad = (gca_pad_t *)data; - if(pad) - { - free(pad); - } + if(pad) + { + input_autoconfigure_disconnect(pad->slot, wiiu_gca_pad_connection.get_name(pad)); + free(pad); + } } static void wiiu_gca_get_buttons(void *data, input_bits_t *state) @@ -278,7 +279,6 @@ static unsigned decode_axis(unsigned axis) { unsigned positive = AXIS_POS_GET(axis); unsigned negative = AXIS_NEG_GET(axis); - RARCH_LOG("[gca]: positive: %ud negative: %ud\n", positive, negative); return positive >= 4 ? negative : positive; } @@ -286,7 +286,6 @@ static unsigned decode_axis(unsigned axis) static int16_t wiiu_gca_get_axis(void *data, unsigned axis) { axis = decode_axis(axis); - RARCH_LOG("[gca]: decoded axis: %d\n", axis); int16_t val; gca_pad_t *pad = (gca_pad_t *)data; @@ -310,7 +309,6 @@ static int16_t wiiu_gca_get_axis(void *data, unsigned axis) if(val > 0x1000 || val < -0x1000) return 0; - RARCH_LOG("[gca]: reading axis %d: %04x\n", axis, val); return val; } diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h index 18a8f45479..57cd9f6e40 100644 --- a/input/common/hid/hid_device_driver.h +++ b/input/common/hid/hid_device_driver.h @@ -21,6 +21,7 @@ #include "../../connect/joypad_connection.h" #include "../../include/hid_driver.h" #include "../../../verbosity.h" +#include "../../../tasks/tasks_internal.h" typedef struct hid_device { void *(*init)(void *handle); From f7135bcee6df2da937d065c50970eaf470bdbfaf Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 22 Apr 2018 23:47:07 -0700 Subject: [PATCH 27/31] Fix analog reading on GCA == DETAILS After a little trial and error, I got analog input working for the Wii U GC adapter. DS3 might work, but it's untested. --- input/common/hid/device_ds3.c | 8 ++-- input/common/hid/device_null.c | 8 +++- input/common/hid/device_wiiu_gca.c | 75 ++++++++++++++++++------------ 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index d21788e624..1c87ec6595 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -324,9 +324,11 @@ static int16_t ds3_get_axis(void *data, unsigned axis) if(!pad || axis >= 4) return 0; - val = (pad->data[6+axis] << 8) - 0x8000; -// val = (pad->data[7+axis] << 8) - 0x8000; - return (val > 0x1000 || val < -0x1000) ? 0 : val; + val = pad->data[6+axis]; + // val = pad->data[7+axis]; + val = (val - 128) * 256; + + return val; } static const char *ds3_get_name(void *data) diff --git a/input/common/hid/device_null.c b/input/common/hid/device_null.c index 783c615924..f5676c87b7 100644 --- a/input/common/hid/device_null.c +++ b/input/common/hid/device_null.c @@ -174,7 +174,13 @@ static void null_set_rumble(void *data, enum retro_rumble_effect effect, uint16_ } /** - * Read analog sticks. If the pad doesn't have any analog axis, just return 0 here. + * Read analog sticks. + * If the pad doesn't have any analog axis, just return 0 here. + * + * The return value must conform to the following characteristics: + * - (0, 0) is center + * - (-32768,-32768) is top-left + * - (32767,32767) is bottom-right */ static int16_t null_get_axis(void *data, unsigned axis) { diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 2b8eecc046..7e82dda288 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -15,6 +15,7 @@ */ #include #include "hid_device_driver.h" +#include "../../../wiiu/input/wiiu_hid.h" #ifdef WII static uint8_t activation_packet[] = { 0x01, 0x13 }; @@ -41,6 +42,7 @@ typedef struct gca_pad_data uint8_t data[9]; // pad data uint32_t slot; // slot this pad occupies uint32_t buttons; // digital button state + int16_t analog_state[3][2]; // analog state } gca_pad_t; @@ -244,6 +246,43 @@ static void update_buttons(gca_pad_t *pad) (1 << button_mapping[i]) : 0; } +#if 0 +const char *axes[] = { + "left x", + "left y", + "right x", + "right y" +}; +#endif + +static void update_analog_state(gca_pad_t *pad) +{ + int pad_axis; + int16_t interpolated; + int16_t stage1, stage2; + unsigned stick, axis; + uint8_t val; + + /* 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_state[stick][axis] = interpolated; +#if 0 + RARCH_LOG("%s: %d\n", axes[pad_axis], interpolated); +#endif + } +} + /** * The USB packet provides a 9-byte data packet for each pad. @@ -264,6 +303,7 @@ static void wiiu_gca_packet_handler(void *data, uint8_t *packet, uint16_t size) memcpy(pad->data, packet, size); update_buttons(pad); + update_analog_state(pad); } @@ -275,41 +315,18 @@ static void wiiu_gca_set_rumble(void *data, enum retro_rumble_effect effect, uin (void)strength; } -static unsigned decode_axis(unsigned axis) -{ - unsigned positive = AXIS_POS_GET(axis); - unsigned negative = AXIS_NEG_GET(axis); - - return positive >= 4 ? negative : positive; -} - static int16_t wiiu_gca_get_axis(void *data, unsigned axis) { - axis = decode_axis(axis); - int16_t val; + axis_data axis_data; + gca_pad_t *pad = (gca_pad_t *)data; - if(!pad || axis >= 4) + pad_functions.read_axis_data(axis, &axis_data); + + if(!pad || axis_data.axis >= 4) return 0; - val = pad->data[3+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; + return pad_functions.get_axis_value(axis_data.axis, pad->analog_state, axis_data.is_negative); } static const char *wiiu_gca_get_name(void *data) From 1d84c0eca122334fbafa52e2dbd41b3a7a9327c0 Mon Sep 17 00:00:00 2001 From: gblues Date: Mon, 23 Apr 2018 23:22:27 -0700 Subject: [PATCH 28/31] Fix analog for DS3, plus some cleanups == DETAILS - DS3 analog wasn't working mainly because I forgot to actually declare the axes in input/input_autoconfig.c when declaring the pad. Whoops. - I also moved the axis decoding logic to a more central place, because it clearly is not Wii U specific. - Removed some dead commented-out code == TESTING Can use analog inputs on both GCA and DS3. Tested in Mario 3 on Nestopia core. Haven't tested with any actual analog games, but I did confirm via logging that the correct ranges are produced. --- Makefile.common | 1 + Makefile.wiiu | 9 ----- input/common/hid/device_ds3.c | 52 +++++++++++++--------------- input/common/hid/device_wiiu_gca.c | 7 ++-- input/common/hid/hid_device_driver.h | 1 + input/include/gamepad.h | 12 +++++-- input/input_autodetect_builtin.c | 11 +++++- input/input_types.h | 1 + wiiu/input/pad_functions.c | 15 +------- wiiu/input/wiiu_hid_types.h | 1 - wiiu/input/wiiu_input.h | 6 +--- 11 files changed, 52 insertions(+), 64 deletions(-) diff --git a/Makefile.common b/Makefile.common index 3743a0c805..98e00bd34d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -198,6 +198,7 @@ OBJ += frontend/frontend.o \ $(LIBRETRO_COMM_DIR)/hash/rhash.o \ audio/audio_driver.o \ $(LIBRETRO_COMM_DIR)/audio/audio_mixer.o \ + input/common/input_common.o \ input/input_driver.o \ input/input_mapper.o \ led/led_driver.o \ diff --git a/Makefile.wiiu b/Makefile.wiiu index 519da84341..59b35b388b 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -50,15 +50,6 @@ ifeq ($(WIIU_HID),1) OBJ += wiiu/input/hidpad_driver.o OBJ += wiiu/input/wiiu_hid.o OBJ += input/connect/joypad_connection.o \ - input/connect/connect_ps2adapter.o \ - input/connect/connect_psxadapter.o \ - input/connect/connect_ps3.o \ - input/connect/connect_ps4.o \ - input/connect/connect_wii.o \ - input/connect/connect_nesusb.o \ - input/connect/connect_snesusb.o \ - input/connect/connect_wiiupro.o \ - input/connect/connect_wiiugca.o \ input/common/hid/hid_device_driver.o \ input/common/hid/device_wiiu_gca.o \ input/common/hid/device_ds3.o \ diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 1c87ec6595..4b26cd5634 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -25,6 +25,7 @@ typedef struct ds3_instance { int slot; bool led_set; uint32_t buttons; + int16_t analog_state[3][2]; uint16_t motors[2]; uint8_t data[64]; } ds3_instance_t; @@ -68,17 +69,8 @@ static int control_packet_size = sizeof(control_packet); extern pad_connection_interface_t ds3_pad_connection; -static void print_error(const char *fmt, int32_t errcode) -{ - int16_t err1, err2; - - err1 = errcode & 0x0000ffff; - err2 = ((errcode & 0xffff0000) >> 16); - - RARCH_ERR(fmt, err1, err2); -} - static void update_pad_state(ds3_instance_t *instance); +static void update_analog_state(ds3_instance_t *instance); static int32_t send_activation_packet(ds3_instance_t *instance) { @@ -93,8 +85,6 @@ static int32_t send_activation_packet(ds3_instance_t *instance) HID_SEND_CONTROL(instance->handle, activation_packet, sizeof(activation_packet)); #endif - if(result < 0) - print_error("[ds3]: activation packet failed (%d:%d)\n", result); return result; } @@ -104,8 +94,6 @@ static uint32_t set_protocol(ds3_instance_t *instance, int protocol) uint32_t result = 0; #if defined(WIIU) result = HID_SET_PROTOCOL(instance->handle, 1); - if(result) - print_error("[ds3]: set protocol failed (%d:%d)\n", result); #endif return result; @@ -134,8 +122,6 @@ static int32_t send_control_packet(ds3_instance_t *instance) DS3_RUMBLE_REPORT_ID, packet_buffer+PACKET_OFFSET, control_packet_size-PACKET_OFFSET); - if(result < 0) - print_error("[ds3]: send control packet failed: (%d:%d)\n", result); #else HID_SEND_CONTROL(instance->handle, packet_buffer+PACKET_OFFSET, @@ -157,10 +143,8 @@ static void *ds3_init(void *handle) instance->handle = handle; RARCH_LOG("[ds3]: setting protocol\n"); -/* - if(set_protocol(instance, 1)) - errors++; -*/ + + /* this might fail, but we don't care. */ set_protocol(instance, 1); RARCH_LOG("[ds3]: sending control packet\n"); @@ -275,6 +259,22 @@ static void ds3_packet_handler(void *data, uint8_t *packet, uint16_t size) memcpy(instance->data, packet, size); update_pad_state(instance); + update_analog_state(instance); +} + +static void update_analog_state(ds3_instance_t *instance) +{ + int pad_axis; + int16_t interpolated; + unsigned stick, axis; + + for(pad_axis = 0; pad_axis < 4; pad_axis++) + { + axis = pad_axis % 2 ? 0 : 1; + stick = pad_axis / 2; + interpolated = instance->data[6+pad_axis]; + instance->analog_state[stick][axis] = (interpolated - 128) * 256; + } } static void update_pad_state(ds3_instance_t *instance) @@ -318,17 +318,15 @@ static void ds3_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t static int16_t ds3_get_axis(void *data, unsigned axis) { + axis_data axis_data; ds3_instance_t *pad = (ds3_instance_t *)data; - int16_t val; - if(!pad || axis >= 4) + gamepad_read_axis_data(axis, &axis_data); + + if(!pad || axis_data.axis >= 4) return 0; - val = pad->data[6+axis]; - // val = pad->data[7+axis]; - val = (val - 128) * 256; - - return val; + return gamepad_get_axis_value(pad->analog_state, &axis_data); } static const char *ds3_get_name(void *data) diff --git a/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c index 7e82dda288..1a26800041 100644 --- a/input/common/hid/device_wiiu_gca.c +++ b/input/common/hid/device_wiiu_gca.c @@ -15,7 +15,6 @@ */ #include #include "hid_device_driver.h" -#include "../../../wiiu/input/wiiu_hid.h" #ifdef WII static uint8_t activation_packet[] = { 0x01, 0x13 }; @@ -259,9 +258,7 @@ static void update_analog_state(gca_pad_t *pad) { int pad_axis; int16_t interpolated; - int16_t stage1, stage2; unsigned stick, axis; - uint8_t val; /* 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 @@ -321,12 +318,12 @@ static int16_t wiiu_gca_get_axis(void *data, unsigned axis) gca_pad_t *pad = (gca_pad_t *)data; - pad_functions.read_axis_data(axis, &axis_data); + gamepad_read_axis_data(axis, &axis_data); if(!pad || axis_data.axis >= 4) return 0; - return pad_functions.get_axis_value(axis_data.axis, pad->analog_state, axis_data.is_negative); + return gamepad_get_axis_value(pad->analog_state, &axis_data); } static const char *wiiu_gca_get_name(void *data) diff --git a/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h index 57cd9f6e40..8e764f0f78 100644 --- a/input/common/hid/hid_device_driver.h +++ b/input/common/hid/hid_device_driver.h @@ -20,6 +20,7 @@ #include "../../input_driver.h" #include "../../connect/joypad_connection.h" #include "../../include/hid_driver.h" +#include "../../include/gamepad.h" #include "../../../verbosity.h" #include "../../../tasks/tasks_internal.h" diff --git a/input/include/gamepad.h b/input/include/gamepad.h index 8acb9027d1..d895b55f25 100644 --- a/input/include/gamepad.h +++ b/input/include/gamepad.h @@ -20,8 +20,16 @@ #include "../input_driver.h" -typedef struct pad_connection_listener_interface { +struct pad_connection_listener_interface { void (*connected)(unsigned port, input_device_driver_t *driver); -} pad_connection_listener_t; +}; + +typedef struct _axis_data { + int32_t axis; + bool is_negative; +} axis_data; + +void gamepad_read_axis_data(uint32_t axis, axis_data *data); +int16_t gamepad_get_axis_value(int16_t state[3][2], axis_data *data); #endif /* GAMEPAD_H__ */ diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 72909ebb8e..db3443cd45 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -267,7 +267,16 @@ DECL_BTN_EX(down, 5, "D-Pad Down") \ DECL_BTN_EX(left, 6, "D-Pad left") \ DECL_BTN_EX(right, 7, "D-Pad Right") \ DECL_BTN_EX(r3, 15, "R3") \ -DECL_BTN_EX(l3, 14, "L3") +DECL_BTN_EX(l3, 14, "L3") \ +DECL_AXIS_EX(l_x_plus, +1, "L Analog right") \ +DECL_AXIS_EX(l_x_minus, -1, "L Analog left") \ +DECL_AXIS_EX(l_y_plus, +0, "L Analog up") \ +DECL_AXIS_EX(l_y_minus, -0, "L Analog down") \ +DECL_AXIS_EX(r_x_plus, +3, "R Analog right") \ +DECL_AXIS_EX(r_x_minus, -3, "R Analog left") \ +DECL_AXIS_EX(r_y_plus, +2, "R Analog up") \ +DECL_AXIS_EX(r_y_minus, -2, "R Analog down") + #define WIIUINPUT_GAMEPAD_DEFAULT_BINDS \ DECL_BTN_EX(menu_toggle, 1, "Home") \ diff --git a/input/input_types.h b/input/input_types.h index 0c1e2edcf1..0bc64d8c42 100644 --- a/input/input_types.h +++ b/input/input_types.h @@ -27,5 +27,6 @@ typedef struct { uint16_t analogs[8]; } input_bits_t; typedef struct joypad_connection joypad_connection_t; +typedef struct pad_connection_listener_interface pad_connection_listener_t; #endif /* __INPUT_TYPES__H */ diff --git a/wiiu/input/pad_functions.c b/wiiu/input/pad_functions.c index ad2c383090..5aefbaf23c 100644 --- a/wiiu/input/pad_functions.c +++ b/wiiu/input/pad_functions.c @@ -75,21 +75,8 @@ void wiiu_pad_set_axis_value(int16_t state[3][2], int16_t left_x, int16_t left_y state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_Y] = touch_y; } - -void wiiu_pad_read_axis_data(uint32_t axis, axis_data *data) -{ - data->axis = AXIS_POS_GET(axis); - data->is_negative = false; - - if(data->axis >= AXIS_INVALID) - { - data->axis = AXIS_NEG_GET(axis); - data->is_negative = true; - } -} - wiiu_pad_functions_t pad_functions = { wiiu_pad_get_axis_value, wiiu_pad_set_axis_value, - wiiu_pad_read_axis_data, + gamepad_read_axis_data, }; diff --git a/wiiu/input/wiiu_hid_types.h b/wiiu/input/wiiu_hid_types.h index 59eaabaddf..b73fcf3a6d 100644 --- a/wiiu/input/wiiu_hid_types.h +++ b/wiiu/input/wiiu_hid_types.h @@ -22,7 +22,6 @@ typedef struct wiiu_adapter wiiu_adapter_t; typedef struct wiiu_attach wiiu_attach_event; typedef struct _wiiu_event_list wiiu_event_list; typedef struct _wiiu_adapter_list wiiu_adapter_list; -typedef struct _axis_data axis_data; typedef struct _wiiu_pad_functions wiiu_pad_functions_t; #endif /* __WIIU_HID_TYPES__H */ diff --git a/wiiu/input/wiiu_input.h b/wiiu/input/wiiu_input.h index 16509b47f2..37416bc7e6 100644 --- a/wiiu/input/wiiu_input.h +++ b/wiiu/input/wiiu_input.h @@ -18,6 +18,7 @@ #define __WIIU_INPUT__H #include "wiiu_hid_types.h" +#include "../../input/include/gamepad.h" #ifdef HAVE_CONFIG_H #include "../../config.h" @@ -56,11 +57,6 @@ #define WIIU_ANALOG_FACTOR 0x7ff0 #define WIIU_READ_STICK(stick) ((stick) * WIIU_ANALOG_FACTOR) -struct _axis_data { - int32_t axis; - bool is_negative; -}; - struct _wiiu_pad_functions { int16_t (*get_axis_value)(int32_t axis, int16_t state[3][2], bool is_negative); void (*set_axis_value)(int16_t state[3][2], int16_t left_x, int16_t left_y, From f6b33b1d30d42c9ff69a7ec700d0afa4b8d4b353 Mon Sep 17 00:00:00 2001 From: gblues Date: Tue, 24 Apr 2018 06:37:02 -0700 Subject: [PATCH 29/31] missing file --- input/common/input_common.c | 78 +++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 input/common/input_common.c diff --git a/input/common/input_common.c b/input/common/input_common.c new file mode 100644 index 0000000000..4f6e656363 --- /dev/null +++ b/input/common/input_common.c @@ -0,0 +1,78 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "../include/gamepad.h" + +enum pad_axes { + AXIS_LEFT_ANALOG_X, + AXIS_LEFT_ANALOG_Y, + AXIS_RIGHT_ANALOG_X, + AXIS_RIGHT_ANALOG_Y, + AXIS_INVALID +}; + +static int16_t clamp_axis(int16_t value, bool is_negative) +{ + if(is_negative && value > 0) + return 0; + if(!is_negative && value < 0) + return 0; + + return value; +} + +void gamepad_read_axis_data(uint32_t axis, axis_data *data) +{ + if(!data) + return; + + data->axis = AXIS_POS_GET(axis); + data->is_negative = false; + + if(data->axis >= AXIS_INVALID) + { + data->axis = AXIS_NEG_GET(axis); + data->is_negative = true; + } +} + +int16_t gamepad_get_axis_value(int16_t state[3][2], axis_data *data) +{ + int16_t value = 0; + + if(!data) + return 0; + + switch(data->axis) + { + case AXIS_LEFT_ANALOG_X: + value = state[RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X]; + break; + case AXIS_LEFT_ANALOG_Y: + value = state[RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y]; + break; + case AXIS_RIGHT_ANALOG_X: + value = state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X]; + break; + case AXIS_RIGHT_ANALOG_Y: + value = state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y]; + break; + } + + return clamp_axis(value, data->is_negative); +} + + From f33fa3d566105b157b272e0369a7ff82a000598c Mon Sep 17 00:00:00 2001 From: gblues Date: Tue, 24 Apr 2018 21:20:08 -0700 Subject: [PATCH 30/31] Fix pad leak in kpad (wiimote) driver == DETAILS This is the wiimote version of the same bug I previously fixed in the HID driver, where disconnected pads didn't actually invoke the unregister task. This has an extra wrinkle, in that we *also* need to invoke the unregister task when the wiimote device changes (e.g. user plugs in a nunchuk or classic controller). Now, there's still the problem of the "disconnect" detection being broken; so a consequence of this commit is OSD spam. However, the actual wiimote input is processed successfully and there's no noticeable issues in the pad handling. == TESTING Using Mario 3, I played a level in which I started as bare wiimote, then hot-plugged the nunchuk, and the input switched automatically. At the end of the level, I hot-unplugged the nunchuk and it automatically reverted to horizontal layout; and the pad remained 100% responsive the entire time. --- wiiu/input/kpad_driver.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/wiiu/input/kpad_driver.c b/wiiu/input/kpad_driver.c index 8453e597f4..c958e43bb4 100644 --- a/wiiu/input/kpad_driver.c +++ b/wiiu/input/kpad_driver.c @@ -30,6 +30,7 @@ static void kpad_get_buttons(unsigned pad, input_bits_t *state); static int16_t kpad_axis(unsigned pad, uint32_t axis); static void kpad_poll(void); static const char *kpad_name(unsigned pad); +static void kpad_deregister(unsigned channel); typedef struct _wiimote_state wiimote_state; @@ -136,7 +137,11 @@ static void kpad_register(unsigned channel, uint8_t device_type) { if (wiimotes[channel].type != device_type) { - int slot = get_slot_for_channel(channel); + int slot; + + kpad_deregister(channel); + slot = get_slot_for_channel(channel); + if(slot < 0) { RARCH_ERR("Couldn't get a slot for this remote.\n"); @@ -188,6 +193,19 @@ static void kpad_poll_one_channel(unsigned channel, KPADData *kpad) } } +static void kpad_deregister(unsigned channel) +{ + int slot = channel_slot_map[channel]; + + if(slot >= 0) + { + input_autoconfigure_disconnect(slot, kpad_driver.name(slot)); + wiimotes[channel].type = WIIMOTE_TYPE_NONE; + hid_instance.pad_list[slot].connected = false; + channel_slot_map[channel] = -1; + } +} + static void kpad_poll(void) { unsigned channel; @@ -200,13 +218,7 @@ static void kpad_poll(void) result = KPADRead(channel, &kpad, 1); if (result == 0) { - int slot = channel_slot_map[channel]; - - if(slot > 0) - { - hid_instance.pad_list[slot].connected = false; - channel_slot_map[channel] = -1; - } + kpad_deregister(channel); continue; } From 07864aebb4e2873c10678835f06574cd70d9f815 Mon Sep 17 00:00:00 2001 From: gblues Date: Tue, 24 Apr 2018 21:46:42 -0700 Subject: [PATCH 31/31] Add fault-tolerance to kpad driver == DETAILS So, the KPadRead function will sometimes return 0, but this doesn't mean the wiimote is actually disconnected. It's usually something transient, like the BT chip has nothing to send or whatever. I don't know. So, I added a buffer so that it won't disconnect the pad without 5 consecutive 0-reads. This is a temporary hack; a proper solution will use the Wii U's callback mechanisms to do wiimote detection. But that's a separate project. This at least prevents OSD spam. == TESTING Tested locally. Verified that connecting/disconnecting nunchuk during play still works properly. --- wiiu/input/kpad_driver.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/wiiu/input/kpad_driver.c b/wiiu/input/kpad_driver.c index c958e43bb4..a3c7078357 100644 --- a/wiiu/input/kpad_driver.c +++ b/wiiu/input/kpad_driver.c @@ -206,6 +206,8 @@ static void kpad_deregister(unsigned channel) } } +static int poll_failures[WIIU_WIIMOTE_CHANNELS] = { 0, 0, 0, 0 }; + static void kpad_poll(void) { unsigned channel; @@ -217,10 +219,16 @@ static void kpad_poll(void) memset(&kpad, 0, sizeof(kpad)); result = KPADRead(channel, &kpad, 1); + /* this is a hack to prevent spurious disconnects */ + /* TODO: use KPADSetConnectCallback and use callbacks to detect */ + /* pad disconnects properly. */ if (result == 0) { - kpad_deregister(channel); + poll_failures[channel]++; + if(poll_failures[channel] > 5) + kpad_deregister(channel); continue; } + poll_failures[channel] = 0; kpad_poll_one_channel(channel, &kpad); }