diff --git a/Makefile.common b/Makefile.common
index dc96774b20..e5924dd99f 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 b3f57e8918..59b35b388b 100644
--- a/Makefile.wiiu
+++ b/Makefile.wiiu
@@ -6,8 +6,8 @@ DEBUG = 0
GRIFFIN_BUILD = 0
SALAMANDER_BUILD = 0
WHOLE_ARCHIVE_LINK = 0
+WIIU_HID = 1
HAVE_RUNAHEAD = 1
-WIIU_HID = 0
WIIU_LOG_RPX = 0
BUILD_DIR = objs/wiiu
PC_DEVELOPMENT_IP_ADDRESS ?=
@@ -33,6 +33,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
@@ -49,15 +50,11 @@ 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 \
+ input/common/hid/device_ds4.o \
+ input/common/hid/device_null.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..4b26cd5634
--- /dev/null
+++ b/input/common/hid/device_ds3.c
@@ -0,0 +1,356 @@
+/* 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"
+
+#define DS3_ACTIVATION_REPORT_ID 0xf4
+#define DS3_RUMBLE_REPORT_ID 0x01
+
+typedef struct ds3_instance {
+ void *handle;
+ joypad_connection_t *pad;
+ 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;
+
+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 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)
+{
+ int32_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
+
+ return result;
+}
+
+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);
+#endif
+
+ return result;
+}
+
+static int32_t send_control_packet(ds3_instance_t *instance)
+{
+ uint8_t packet_buffer[control_packet_size];
+ int32_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);
+#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;
+
+ memset(instance, 0, sizeof(ds3_instance_t));
+ instance->handle = handle;
+
+ RARCH_LOG("[ds3]: setting protocol\n");
+
+ /* this might fail, but we don't care. */
+ set_protocol(instance, 1);
+
+ RARCH_LOG("[ds3]: sending control packet\n");
+ if(send_control_packet(instance) < 0)
+ errors++;
+
+ RARCH_LOG("[ds3]: sending activation packet\n");
+ if(send_activation_packet(instance) < 0)
+ 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;
+}
+
+static void ds3_free(void *data)
+{
+ ds3_instance_t *instance = (ds3_instance_t *)data;
+
+ if(instance) {
+ hid_pad_deregister(instance->pad);
+ free(instance);
+ }
+}
+
+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)
+{
+ 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"
+};
+
+/**
+ * pad interface implementation
+ */
+
+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;
+}
+
+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)
+{
+ 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 *instance = (ds3_instance_t *)data;
+
+ if(instance->pad && !instance->led_set)
+ {
+ send_control_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);
+ 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)
+{
+ 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)
+{
+ ds3_instance_t *pad = (ds3_instance_t *)data;
+}
+
+static int16_t ds3_get_axis(void *data, unsigned axis)
+{
+ axis_data axis_data;
+ ds3_instance_t *pad = (ds3_instance_t *)data;
+
+ gamepad_read_axis_data(axis, &axis_data);
+
+ if(!pad || axis_data.axis >= 4)
+ return 0;
+
+ return gamepad_get_axis_value(pad->analog_state, &axis_data);
+}
+
+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;
+ if(!pad || joykey > 31)
+ return false;
+
+ return pad->buttons & (1 << joykey);
+}
+
+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_ds4.c b/input/common/hid/device_ds4.c
new file mode 100644
index 0000000000..af923cee13
--- /dev/null
+++ b/input/common/hid/device_ds4.c
@@ -0,0 +1,154 @@
+/* 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 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)
+{
+ 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)
+{
+ ds4_instance_t *instance = (ds4_instance_t *)data;
+
+ if(instance) {
+ hid_pad_deregister(instance->pad);
+ 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)
+{
+ 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"
+};
+
+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, input_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/device_null.c b/input/common/hid/device_null.c
new file mode 100644
index 0000000000..f5676c87b7
--- /dev/null
+++ b/input/common/hid/device_null.c
@@ -0,0 +1,219 @@
+/* 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) {
+ hid_pad_deregister(instance->pad);
+ 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 input_bits_t format
+ * that RetroArch can use.
+ */
+static void null_get_buttons(void *data, input_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.
+ *
+ * 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)
+{
+ 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/input/common/hid/device_wiiu_gca.c b/input/common/hid/device_wiiu_gca.c
new file mode 100644
index 0000000000..1a26800041
--- /dev/null
+++ b/input/common/hid/device_wiiu_gca.c
@@ -0,0 +1,363 @@
+/* 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 "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_POWERED 0x04
+#define GCA_PORT_CONNECTED 0x10
+
+
+typedef struct wiiu_gca_instance {
+ void *handle;
+ bool online;
+ uint8_t device_state[37];
+ 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
+ int16_t analog_state[3][2]; // analog state
+} gca_pad_t;
+
+
+static void update_pad_state(wiiu_gca_instance_t *instance);
+static void unregister_pad(wiiu_gca_instance_t *instance, 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;
+ memset(instance, 0, sizeof(wiiu_gca_instance_t));
+ instance->handle = handle;
+
+ 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;
+
+ error:
+ RARCH_ERR("[gca]: init failed\n");
+ if(instance)
+ free(instance);
+ return NULL;
+}
+
+static void wiiu_gca_free(void *data) {
+ 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 || !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);
+}
+
+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];
+
+ port_connected = instance->device_state[i] & GCA_PORT_CONNECTED;
+
+ if(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_ERR("[gca]: Failed to register pad.\n");
+ 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);
+ }
+ }
+ }
+}
+
+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;
+
+ hid_pad_deregister(pad);
+}
+
+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 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)
+ {
+ 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)
+{
+ gca_pad_t *pad = (gca_pad_t *)data;
+ if(pad)
+ {
+ BITS_COPY16_PTR(state, pad->buttons);
+ } else {
+ BIT256_CLEAR_ALL_PTR(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;
+}
+
+#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;
+ unsigned stick, axis;
+
+ /* GameCube analog axis are 8-bit unsigned, where 128/128 is center.
+ * So, we subtract 128 to get a signed, 0-based value and then mulitply
+ * by 256 to get the 16-bit range RetroArch expects. */
+ for(pad_axis = 0; pad_axis < 4; pad_axis++)
+ {
+ axis = pad_axis % 2 ? 0 : 1;
+ stick = pad_axis / 2;
+ interpolated = pad->data[3 + pad_axis];
+ /* libretro requires "up" to be negative, so we invert the y axis */
+ interpolated = (axis) ?
+ ((interpolated - 128) * 256) :
+ ((interpolated - 128) * -256);
+
+ pad->analog_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.
+ *
+ * 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;
+ uint32_t i, pressed_keys;
+
+ if(!pad || !packet || size > sizeof(pad->data))
+ return;
+
+ memcpy(pad->data, packet, size);
+ update_buttons(pad);
+ update_analog_state(pad);
+}
+
+
+
+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)
+{
+ axis_data axis_data;
+
+ gca_pad_t *pad = (gca_pad_t *)data;
+
+ gamepad_read_axis_data(axis, &axis_data);
+
+ if(!pad || axis_data.axis >= 4)
+ return 0;
+
+ return gamepad_get_axis_value(pad->analog_state, &axis_data);
+}
+
+static const char *wiiu_gca_get_name(void *data)
+{
+ gca_pad_t *pad = (gca_pad_t *)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;
+
+ if(!pad || joykey > 31)
+ return false;
+
+ return pad->buttons & (1 << joykey);
+}
+
+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,
+ wiiu_gca_button
+};
diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c
new file mode 100644
index 0000000000..ccab2dc569
--- /dev/null
+++ b/input/common/hid/hid_device_driver.c
@@ -0,0 +1,156 @@
+/* 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_driver_instance_t hid_instance = {0};
+
+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;
+}
+
+joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface_t *iface)
+{
+ int slot;
+ joypad_connection_t *result;
+
+ if(!pad_handle)
+ return NULL;
+
+ 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;
+ result->data = iface->init(pad_handle, slot, hid_instance.os_driver);
+ result->connected = true;
+ input_pad_connect(slot, hid_instance.pad_driver);
+
+ 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)
+ 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.
+ *
+ * @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)
+{
+ 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();
+ if(!instance->os_driver_data)
+ return false;
+
+ if(!init_pad_list(instance, slots))
+ {
+ hid_driver->free(instance->os_driver_data);
+ instance->os_driver_data = NULL;
+ return false;
+ }
+
+ instance->os_driver = hid_driver;
+ instance->pad_driver = pad_driver;
+
+ RARCH_LOG("[hid]: instance initialization complete.\n");
+
+ 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;
+
+ 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/input/common/hid/hid_device_driver.h b/input/common/hid/hid_device_driver.h
new file mode 100644
index 0000000000..8e764f0f78
--- /dev/null
+++ b/input/common/hid/hid_device_driver.h
@@ -0,0 +1,46 @@
+/* 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"
+#include "../../connect/joypad_connection.h"
+#include "../../include/hid_driver.h"
+#include "../../include/gamepad.h"
+#include "../../../verbosity.h"
+#include "../../../tasks/tasks_internal.h"
+
+typedef struct hid_device {
+ 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);
+ const char *name;
+} 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;
+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);
+
+#endif /* HID_DEVICE_DRIVER__H */
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);
+}
+
+
diff --git a/input/connect/connect_ps3.c b/input/connect/connect_ps3.c
index 5625ee09d1..52d0032ecd 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 1de5d8d056..f33844e6b1 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 be27bfcfef..2008be9ecc 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 8283f2ac9d..357e479b58 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 dd9751114c..a6194fb922 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/connect/joypad_connection.h b/input/connect/joypad_connection.h
index 67bc34bcb9..62a454609a 100644
--- a/input/connect/joypad_connection.h
+++ b/input/connect/joypad_connection.h
@@ -61,10 +61,9 @@ typedef struct pad_connection_interface
void (*get_buttons)(void *data, input_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;
-
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/drivers/wiiu_input.c b/input/drivers/wiiu_input.c
index 35ae955f68..ba00ed971a 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/input/drivers_hid/null_hid.c b/input/drivers_hid/null_hid.c
index 85056ecbb1..44d1cc397b 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
{
diff --git a/input/drivers_joypad/wiiu_joypad.c b/input/drivers_joypad/wiiu_joypad.c
index 1f1b476439..5728a90c6d 100644
--- a/input/drivers_joypad/wiiu_joypad.c
+++ b/input/drivers_joypad/wiiu_joypad.c
@@ -14,11 +14,13 @@
* If not, see .
*/
-#include
+#include "../../wiiu/input/wiiu_input.h"
#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,64 +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)
{
-#ifdef WIIU_HID
- return ready && pad < MAX_USERS;
-#else
- return ready && pad < 5;
-#endif
+ return ready &&
+ pad < MAX_USERS &&
+ pad_drivers[pad] != NULL &&
+ pad_drivers[pad]->query_pad(pad);
}
static void wiiu_joypad_destroy(void)
@@ -137,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 =
@@ -156,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..d895b55f25
--- /dev/null
+++ b/input/include/gamepad.h
@@ -0,0 +1,35 @@
+/* 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"
+
+struct pad_connection_listener_interface {
+ void (*connected)(unsigned port, input_device_driver_t *driver);
+};
+
+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/include/hid_driver.h b/input/include/hid_driver.h
new file mode 100644
index 0000000000..02b6529f63
--- /dev/null
+++ b/input/include/hid_driver.h
@@ -0,0 +1,84 @@
+/* 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)(void);
+ 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, 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);
+ 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);
+};
+
+#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_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) \
+ 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
+#define HID_PAD_CONNECTION_PTR(slot) &(hid_instance.pad_list[(slot)])
+
+
+
+struct hid_driver_instance {
+ hid_driver_t *os_driver;
+ void *os_driver_data;
+ input_device_driver_t *pad_driver;
+ joypad_connection_t *pad_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_autodetect_builtin.c b/input/input_autodetect_builtin.c
index 0e76b04f4e..db3443cd45 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"
@@ -228,6 +228,56 @@ DECL_AXIS(r_y_minus, +3)
#ifdef WIIU
+#define WIIUINPUT_GAMECUBE_DEFAULT_BINDS \
+DECL_BTN_EX(a, 8, "A") \
+DECL_BTN_EX(b, 0, "B") \
+DECL_BTN_EX(x, 9, "X") \
+DECL_BTN_EX(y, 1, "Y") \
+DECL_BTN_EX(left, 6, "D-Pad Left") \
+DECL_BTN_EX(right, 7, "D-Pad Right") \
+DECL_BTN_EX(down, 5, "D-Pad Down") \
+DECL_BTN_EX(up, 4, "D-Pad Up") \
+DECL_BTN_EX(start, 3, "Start/Pause") \
+DECL_BTN_EX(select, 2, "Z") \
+DECL_BTN_EX(r, 10, "R Trigger") \
+DECL_BTN_EX(l, 11, "L Trigger") \
+DECL_AXIS_EX(l_x_plus, +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_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") \
+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") \
DECL_BTN_EX(select, 2, "-") \
@@ -612,6 +662,8 @@ const char* const input_builtin_autoconfs[] =
DECL_AUTOCONF_DEVICE(PAD_NAME_NUNCHUK, "wiiu", WIIUINPUT_NUNCHUK_DEFAULT_BINDS),
DECL_AUTOCONF_DEVICE(PAD_NAME_CLASSIC, "wiiu", WIIUINPUT_CLASSIC_CONTROLLER_DEFAULT_BINDS),
DECL_AUTOCONF_DEVICE(PAD_NAME_HID, "wiiu", WIIUINPUT_GAMEPAD_DEFAULT_BINDS),
+ DECL_AUTOCONF_DEVICE("GameCube Controller", "wiiu", WIIUINPUT_GAMECUBE_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/input/input_driver.c b/input/input_driver.c
index 2f5255285b..742b34b1b9 100644
--- a/input/input_driver.c
+++ b/input/input_driver.c
@@ -58,6 +58,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__
@@ -1819,6 +1835,21 @@ 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;
+ }
+
+ 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));
+}
+
/**
* input_conv_analog_id_to_bind_id:
* @idx : Analog key index.
diff --git a/input/input_driver.h b/input/input_driver.h
index 6ffc894387..f47e8830eb 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
@@ -35,22 +37,12 @@
#include "input_defines.h"
#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,
@@ -127,14 +119,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.
*/
@@ -170,7 +162,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
{
@@ -187,25 +179,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, input_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.
@@ -599,6 +572,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.
@@ -627,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.
@@ -676,11 +661,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:
@@ -808,6 +793,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;
@@ -856,7 +844,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/input/input_types.h b/input/input_types.h
new file mode 100644
index 0000000000..0bc64d8c42
--- /dev/null
+++ b/input/input_types.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 __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;
+typedef struct {
+ uint32_t data[8];
+ 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/verbosity.c b/verbosity.c
index 1465b59a4c..4fc7686f50 100644
--- a/verbosity.c
+++ b/verbosity.c
@@ -188,6 +188,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/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/include/wiiu/pad_driver.h b/wiiu/include/wiiu/pad_driver.h
deleted file mode 100644
index 376b899f43..0000000000
--- a/wiiu/include/wiiu/pad_driver.h
+++ /dev/null
@@ -1,183 +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/connect/joypad_connection.h"
-#include "../../tasks/tasks_internal.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;
- /* list of HID pads */
- joypad_connection_t *connections;
- /* 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;
- 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;
-};
-
-typedef struct wiiu_attach wiiu_attach_event;
-
-struct wiiu_attach {
- wiiu_attach_event *next;
- 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/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 9bcbc8f3d0..03efe64d5c 100644
--- a/wiiu/input/hidpad_driver.c
+++ b/wiiu/input/hidpad_driver.c
@@ -14,7 +14,8 @@
* If not, see .
*/
-#include
+#include "wiiu_input.h"
+#include "wiiu_hid.h"
static bool hidpad_init(void *data);
static bool hidpad_query_pad(unsigned pad);
@@ -27,51 +28,17 @@ 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)
+static bool init_hid_driver(void)
{
- return pad - (WIIU_WIIMOTE_CHANNELS+1);
-}
-
-const void *get_hid_data(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);
-
- 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, MAX_USERS);
}
static bool hidpad_init(void *data)
{
(void *)data;
+ int i;
- hid_driver = init_hid_driver();
- if (!hid_driver)
+ if(!init_hid_driver())
{
RARCH_ERR("Failed to initialize HID driver.\n");
return false;
@@ -85,23 +52,14 @@ 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)
{
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)
@@ -109,11 +67,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, to_slot(pad), button);
-#else
- return false;
-#endif
+ return HID_BUTTON(pad, button);
}
static void hidpad_get_buttons(unsigned pad, input_bits_t *state)
@@ -121,30 +75,21 @@ static void hidpad_get_buttons(unsigned pad, input_bits_t *state)
if (!hidpad_query_pad(pad))
BIT256_CLEAR_ALL_PTR(state);
-#if 0
- hid_driver->get_buttons(hid_data, to_slot(pad), state);
-#endif
- BIT256_CLEAR_ALL_PTR(state);
+ HID_GET_BUTTONS(pad, 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;
-#if 0
- return hid_driver->axis(hid_data, to_slot(pad), axis);
-#else
- return 0;
-#endif
+ return HID_AXIS(pad, axis);
}
static void hidpad_poll(void)
{
-#if 0
if (ready)
- hid_driver->poll(hid_data);
-#endif
+ HID_POLL();
}
static const char *hidpad_name(unsigned pad)
@@ -152,11 +97,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, to_slot(pad));
-#endif
+ return HID_PAD_NAME(pad);
}
input_device_driver_t hidpad_driver =
diff --git a/wiiu/input/kpad_driver.c b/wiiu/input/kpad_driver.c
index de6efe7f64..a3c7078357 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);
@@ -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;
@@ -52,17 +53,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 +89,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 +102,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, input_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 +137,19 @@ static void kpad_register(unsigned channel, uint8_t device_type)
{
if (wiimotes[channel].type != device_type)
{
+ 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");
+ return;
+ }
+
wiimotes[channel].type = device_type;
- pad_functions.connect(to_retro_pad(channel), &kpad_driver);
+ input_pad_connect(slot, &kpad_driver);
}
}
@@ -161,6 +193,21 @@ 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 int poll_failures[WIIU_WIIMOTE_CHANNELS] = { 0, 0, 0, 0 };
+
static void kpad_poll(void)
{
unsigned channel;
@@ -172,9 +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) {
+ poll_failures[channel]++;
+ if(poll_failures[channel] > 5)
+ kpad_deregister(channel);
continue;
}
+ poll_failures[channel] = 0;
kpad_poll_one_channel(channel, &kpad);
}
@@ -182,11 +236,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/pad_functions.c b/wiiu/input/pad_functions.c
index fe352e5da4..5aefbaf23c 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,
@@ -75,29 +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;
- }
-}
-
-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
+ gamepad_read_axis_data,
};
diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c
index d0becc716e..962e9323d8 100644
--- a/wiiu/input/wiiu_hid.c
+++ b/wiiu/input/wiiu_hid.c
@@ -15,65 +15,82 @@
*/
#include "wiiu_hid.h"
+#include
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;
if (!hid)
return false;
- return slot < hid->connections_size;
+ return slot < HID_MAX_SLOT();
+}
+
+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_PAD_CONNECTION_PTR(slot);
+ if(!result || !result->connected || !result->iface || !result->data)
+ return NULL;
+
+ return result;
}
static const char *wiiu_hid_joypad_name(void *data, unsigned slot)
{
- if (!wiiu_hid_joypad_query(data, slot))
+ joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot);
+
+ if(!pad)
return NULL;
- wiiu_hid_t *hid = (wiiu_hid_t *)data;
-
- return hid->connections[slot].iface->get_name(data);
+ return pad->iface->get_name(pad->data);
}
-static void wiiu_hid_joypad_get_buttons(void *data, unsigned port,
- input_bits_t *state)
+static void wiiu_hid_joypad_get_buttons(void *data, unsigned slot, input_bits_t *state)
{
- (void)data;
- (void)port;
+ joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot);
- BIT256_CLEAR_ALL_PTR(state);
+ if(pad)
+ pad->iface->get_buttons(pad->data, state);
}
-static bool wiiu_hid_joypad_button(void *data, unsigned port, uint16_t joykey)
+static bool wiiu_hid_joypad_button(void *data, unsigned slot, uint16_t joykey)
{
- (void)data;
- (void)port;
- (void)joykey;
+ joypad_connection_t *pad = get_pad((wiiu_hid_t *)data, slot);
- return false;
+ if(!pad)
+ return false;
+
+ return pad->iface->button(pad->data, joykey);
}
-static bool wiiu_hid_joypad_rumble(void *data, unsigned pad,
+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(void)
@@ -90,7 +107,6 @@ static void *wiiu_hid_init(void)
if (!hid->polling_thread)
goto error;
- RARCH_LOG("[hid]: Registering HIDClient\n");
HIDAddClient(client, wiiu_attach_callback);
hid->client = client;
@@ -99,6 +115,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);
@@ -130,7 +147,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)
@@ -163,14 +184,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);
}
@@ -198,6 +222,25 @@ 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;
+ int32_t result;
+
+ if(!adapter)
+ return -1;
+
+ if(size > adapter->rx_size)
+ return -1;
+
+ result = HIDRead(adapter->handle, buffer, size, NULL, NULL);
+ if(result < 0)
+ report_hid_error("read failed", adapter, result);
+
+ return result;
+}
+
+
static void start_polling_thread(wiiu_hid_t *hid)
{
OSThreadAttributes attributes = OS_THREAD_ATTRIB_AFFINITY_CPU2;
@@ -286,23 +329,88 @@ 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;
+ 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)
+ {
+ adapter_next = adapter->next;
+
+ switch(adapter->state)
+ {
+ case ADAPTER_STATE_NEW:
+ adapter->state = try_init_driver(adapter);
+ break;
+ case ADAPTER_STATE_READY:
+ 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));
+}
+
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 (wiiu_attach_event *)SwapAtomic32((uint32_t *)&events.list, 0);
+}
- return list;
+static wiiu_adapter_t *synchronized_lookup_adapter(uint32_t handle)
+{
+ OSFastMutex_Lock(&(adapters.lock));
+ wiiu_adapter_t *iterator;
+
+ for(iterator = adapters.list; iterator != NULL; iterator = iterator->next)
+ {
+ if(iterator->handle == handle)
+ break;
+ }
+ OSFastMutex_Unlock(&(adapters.lock));
+
+ return iterator;
}
static void synchronized_add_to_adapters_list(wiiu_adapter_t *adapter)
@@ -318,25 +426,24 @@ static int32_t wiiu_attach_callback(HIDClient *client,
{
wiiu_attach_event *event = NULL;
- log_device(device);
-
- switch(attach)
- {
- case HID_DEVICE_ATTACH:
- 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;
@@ -344,6 +451,13 @@ error:
static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event)
{
+ wiiu_adapter_t *adapter = synchronized_lookup_adapter(event->handle);
+
+ /* 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->connected = false;
}
@@ -358,127 +472,92 @@ 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;
+ adapter->state = ADAPTER_STATE_NEW;
- 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;
- }
-
- 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;
error:
delete_adapter(adapter);
}
-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);
-}
-
-/**
- * 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_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)
{
- 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 slot %d\n", adapter->slot);
- adapter->state = ADAPTER_STATE_DONE;
- return;
- }
+ if(error < 0)
+ {
+ report_hid_error("async read failed", adapter, error);
+ }
- wiiu_hid_do_read(adapter, buffer, buffer_size);
+ if(adapter->state == ADAPTER_STATE_READING) {
+ adapter->state = ADAPTER_STATE_READY;
- adapter->state = ADAPTER_STATE_READING;
- HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size,
- wiiu_hid_read_loop_callback, adapter);
+ if(error == 0) {
+ adapter->driver->handle_packet(adapter->driver_handle,
+ buffer, buffer_size);
+ }
+ }
+}
+
+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
+ }
}
/**
@@ -492,27 +571,29 @@ 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");
while(adapters.list != NULL)
{
+ RARCH_LOG("[hid]: shutting down adapter..\n");
adapter = adapters.list;
adapters.list = adapter->next;
delete_adapter(adapter);
}
}
- OSFastMutex_Unlock(&(adapters.lock));
if(incomplete)
usleep(5000);
@@ -522,9 +603,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);
-
- RARCH_LOG("All in-flight reads complete.\n");
+ } while(incomplete);
}
static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list)
@@ -545,20 +624,45 @@ 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;
+ OSFastMutex_Lock(&(adapters.lock));
+
+ for(it = adapters.list; it != NULL; it = it->next)
+ {
+ if(it->state == ADAPTER_STATE_READY)
+ wiiu_poll_adapter(it);
+
+ 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)
{
wiiu_hid_t *hid = (wiiu_hid_t *)argv;
- int i = 0;
RARCH_LOG("[hid]: polling thread is starting\n");
while(!hid->polling_thread_quit)
{
wiiu_handle_attach_events(hid, synchronized_get_events_list());
- usleep(10000);
- i += 10000;
- if(i >= (1000 * 1000 * 3))
- i = 0;
+ wiiu_poll_adapters(hid);
}
RARCH_LOG("[hid]: polling thread is stopping\n");
@@ -613,6 +717,13 @@ 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)
+{
+ *actual_size = (min_size + 0x3f) & ~0x3f;
+
+ *out_buf_ptr = alloc_zeroed(64, *actual_size);
+}
+
static wiiu_adapter_t *new_adapter(wiiu_attach_event *event)
{
wiiu_adapter_t *adapter = alloc_zeroed(32, sizeof(wiiu_adapter_t));
@@ -622,10 +733,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;
}
@@ -645,15 +755,29 @@ 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);
}
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;
@@ -699,6 +823,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..0c96c9599c 100644
--- a/wiiu/input/wiiu_hid.h
+++ b/wiiu/input/wiiu_hid.h
@@ -17,14 +17,89 @@
#ifndef __WIIU_HID__H
#define __WIIU_HID__H
-#include
+#include "wiiu_hid_types.h"
+
+#include "wiiu_input.h"
#define DEVICE_UNUSED 0
#define DEVICE_USED 1
+/* Adapter has been detected and needs to be initialized */
#define ADAPTER_STATE_NEW 0
-#define ADAPTER_STATE_READING 1
-#define ADAPTER_STATE_DONE 2
+/* 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 */
+ 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;
+ bool connected;
+};
+
+/**
+ * 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);
@@ -46,7 +121,9 @@ 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);
static void wiiu_start_read_loop(wiiu_adapter_t *adapter);
static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error,
diff --git a/wiiu/input/wiiu_hid_types.h b/wiiu/input/wiiu_hid_types.h
new file mode 100644
index 0000000000..b73fcf3a6d
--- /dev/null
+++ b/wiiu/input/wiiu_hid_types.h
@@ -0,0 +1,27 @@
+/* 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 _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..37416bc7e6
--- /dev/null
+++ b/wiiu/input/wiiu_input.h
@@ -0,0 +1,68 @@
+/* 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"
+#include "../../input/include/gamepad.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 _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 9dd778e19a..4933a2dc3e 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;
@@ -184,7 +186,12 @@ static void wpad_poll(void)
static bool wpad_init(void *data)
{
- pad_functions.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;
@@ -193,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)
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);
+}
+