1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-08 12:15:49 +00:00

Merge pull request #6580 from gblues/gblues/hid

Working HID driver for Wii U [TESTING NEEDED]
This commit is contained in:
Twinaphex 2018-04-25 23:10:39 +02:00 committed by GitHub
commit 6ac4032735
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 2407 additions and 605 deletions

View File

@ -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 \

View File

@ -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)

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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
};

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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
};

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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
};

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#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
};

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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));
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 */

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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);
}

View File

@ -21,10 +21,7 @@
#include <boolean.h>
#include "joypad_connection.h"
#include "../input_defines.h"
#ifdef WIIU
#include <wiiu/syshid.h>
#endif
#include "../common/hid/hid_device_driver.h"
struct hidpad_ps3_data
{

View File

@ -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
{

View File

@ -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

View File

@ -21,6 +21,7 @@
#include <boolean.h>
#include "joypad_connection.h"
#include "../input_defines.h"
#include "../common/hid/hid_device_driver.h"
struct hidpad_wiiugca_data
{

View File

@ -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
{

View File

@ -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;

View File

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

View File

@ -18,6 +18,7 @@
#include "../input_defines.h"
#include "../input_driver.h"
#include "../include/hid_driver.h"
typedef struct null_hid
{

View File

@ -14,11 +14,13 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <wiiu/pad_driver.h>
#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
};

35
input/include/gamepad.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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__ */

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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__ */

24
input/include/hid_types.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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__ */

View File

@ -29,7 +29,7 @@
#endif
#ifdef WIIU
#include <wiiu/pad_driver.h>
#include <wiiu/pad_strings.h>
#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),

View File

@ -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.

View File

@ -22,6 +22,8 @@
#include <stddef.h>
#include <sys/types.h>
#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

32
input/input_types.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 */

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,14 @@
#pragma once
#include <wiiu/types.h>
#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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef __PAD_DRIVER__H
#define __PAD_DRIVER__H
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <wiiu/os.h>
#include <wiiu/syshid.h>
#include <wiiu/vpad.h>
#include <wiiu/kpad.h>
#include <string.h>
#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 */

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 */

View File

@ -1,15 +1,6 @@
#pragma once
#include <wiiu/types.h>
/*
* 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;

View File

@ -14,7 +14,8 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <wiiu/pad_driver.h>
#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 =

View File

@ -20,7 +20,7 @@
* controllers.
*/
#include <wiiu/pad_driver.h>
#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;

View File

@ -14,7 +14,7 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <wiiu/pad_driver.h>
#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,
};

View File

@ -15,65 +15,82 @@
*/
#include "wiiu_hid.h"
#include <wiiu/os/atomic.h>
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,
};

View File

@ -17,14 +17,89 @@
#ifndef __WIIU_HID__H
#define __WIIU_HID__H
#include <wiiu/pad_driver.h>
#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,

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 */

68
wiiu/input/wiiu_input.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <string.h>
#include <malloc.h>
#include <unistd.h>
#include <wiiu/os.h>
#include <wiiu/syshid.h>
#include <wiiu/vpad.h>
#include <wiiu/kpad.h>
#include <wiiu/pad_strings.h>
#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 */

View File

@ -21,7 +21,9 @@
* - For HID controllers, see hid_driver.c
*/
#include <wiiu/pad_driver.h>
#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)

36
wiiu/system/atomic.c Normal file
View File

@ -0,0 +1,36 @@
/* devkitPPC is missing a few functions that are kinda needed for some cores.
* This should add them back in.
*/
#include <wiiu/os/atomic.h>
/**
* 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);
}