mirror of
https://github.com/libretro/RetroArch
synced 2025-02-02 14:54:10 +00:00
(GX) Refactor of the Wii USB HID support. Now it's working!
In order to have a controller working you need: 1) Have a matching HID autoconfig file in autoconfig/hid for your controller. 2) Create a "connect" driver for the pad in "input/connect" folder (source code of RA). 3) Once you are in RA, change the joystick driver to HID and restart. 4) You may be now able to use you USB HID compatible pad in RA. I included some "connect" drivers as an example. It also need to include them for compilation.
This commit is contained in:
parent
deb3c73ae0
commit
bca4ccb155
@ -416,6 +416,11 @@ INPUT (HID)
|
||||
#include "../input/connect/connect_ps4.c"
|
||||
#include "../input/connect/connect_wii.c"
|
||||
#include "../input/connect/connect_wiiupro.c"
|
||||
#ifdef HAVE_WIIUSB_HID
|
||||
#include "../input/connect/connect_snesusb.c"
|
||||
#include "../input/connect/connect_nesusb.c"
|
||||
#include "../input/connect/connect_wiiugca.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*============================================================
|
||||
|
146
input/connect/connect_nesusb.c
Normal file
146
input/connect/connect_nesusb.c
Normal file
@ -0,0 +1,146 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013-2014 - Jason Fetters
|
||||
* Copyright (C) 2011-2016 - 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include "joypad_connection.h"
|
||||
|
||||
struct hidpad_nesusb_data
|
||||
{
|
||||
struct pad_connection* connection;
|
||||
uint8_t data[64];
|
||||
uint32_t slot;
|
||||
uint64_t buttons;
|
||||
};
|
||||
|
||||
static void* hidpad_nesusb_init(void *data, uint32_t slot, send_control_t ptr)
|
||||
{
|
||||
struct pad_connection* connection = (struct pad_connection*)data;
|
||||
struct hidpad_nesusb_data* device = (struct hidpad_nesusb_data*)
|
||||
calloc(1, sizeof(struct hidpad_nesusb_data));
|
||||
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
if (!connection)
|
||||
{
|
||||
free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device->connection = connection;
|
||||
device->slot = slot;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void hidpad_nesusb_deinit(void *data)
|
||||
{
|
||||
struct hidpad_nesusb_data *device = (struct hidpad_nesusb_data*)data;
|
||||
|
||||
if (device)
|
||||
free(device);
|
||||
}
|
||||
|
||||
static uint64_t hidpad_nesusb_get_buttons(void *data)
|
||||
{
|
||||
struct hidpad_nesusb_data *device = (struct hidpad_nesusb_data*)data;
|
||||
if (!device)
|
||||
return 0;
|
||||
return device->buttons;
|
||||
}
|
||||
|
||||
static int16_t hidpad_nesusb_get_axis(void *data, unsigned axis)
|
||||
{
|
||||
int val;
|
||||
struct hidpad_nesusb_data *device = (struct hidpad_nesusb_data*)data;
|
||||
|
||||
if (!device || axis >= 2)
|
||||
return 0;
|
||||
|
||||
val = device->data[4 + axis];
|
||||
val = (val << 8) - 0x8000;
|
||||
|
||||
return (abs(val) > 0x1000) ? val : 0;
|
||||
}
|
||||
|
||||
static void hidpad_nesusb_packet_handler(void *data, uint8_t *packet, uint16_t size)
|
||||
{
|
||||
uint32_t i, pressed_keys;
|
||||
static const uint32_t button_mapping[17] =
|
||||
{
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
RETRO_DEVICE_ID_JOYPAD_SELECT,
|
||||
RETRO_DEVICE_ID_JOYPAD_START,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
RETRO_DEVICE_ID_JOYPAD_B,
|
||||
RETRO_DEVICE_ID_JOYPAD_A,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
16, /* HOME BUTTON when pressing SELECT+START */
|
||||
};
|
||||
struct hidpad_nesusb_data *device = (struct hidpad_nesusb_data*)data;
|
||||
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
memcpy(device->data, packet, size);
|
||||
|
||||
device->buttons = 0;
|
||||
|
||||
pressed_keys = device->data[7] | (device->data[6] << 8) |
|
||||
(((device->data[7] & 0x30) == 0x30) ? (1 << 16) : 0); /* SELECT+START=HOME */
|
||||
|
||||
for (i = 0; i < 17; i ++)
|
||||
if (button_mapping[i] != NO_BTN)
|
||||
device->buttons |= (pressed_keys & (1 << i)) ? (UINT64_C(1) << button_mapping[i]) : 0;
|
||||
}
|
||||
|
||||
static void hidpad_nesusb_set_rumble(void *data,
|
||||
enum retro_rumble_effect effect, uint16_t strength)
|
||||
{
|
||||
(void)data;
|
||||
(void)effect;
|
||||
(void)strength;
|
||||
}
|
||||
|
||||
const char * hidpad_nesusb_get_name(void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* For now we return a single static name */
|
||||
return "Generic NES USB Controller";
|
||||
}
|
||||
|
||||
pad_connection_interface_t pad_connection_nesusb = {
|
||||
hidpad_nesusb_init,
|
||||
hidpad_nesusb_deinit,
|
||||
hidpad_nesusb_packet_handler,
|
||||
hidpad_nesusb_set_rumble,
|
||||
hidpad_nesusb_get_buttons,
|
||||
hidpad_nesusb_get_axis,
|
||||
hidpad_nesusb_get_name,
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013-2014 - Jason Fetters
|
||||
* Copyright (C) 2011-2016 - 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.
|
||||
@ -51,13 +51,20 @@ static void hidpad_ps3_send_control(struct hidpad_ps3_data* device)
|
||||
report_buffer[11] = 1 << ((device->slot % 4) + 1);
|
||||
report_buffer[4] = device->motors[1] >> 8;
|
||||
report_buffer[6] = device->motors[0] >> 8;
|
||||
|
||||
#ifdef HAVE_WIIUSB_HID
|
||||
report_buffer[1] = 0x03; /* send control message type */
|
||||
device->send_control(device->connection, &report_buffer[1], sizeof(report_buffer)-1);
|
||||
#else
|
||||
device->send_control(device->connection, report_buffer, sizeof(report_buffer));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void* hidpad_ps3_init(void *data, uint32_t slot, send_control_t ptr)
|
||||
{
|
||||
#ifdef IOS
|
||||
#ifdef HAVE_WIIUSB_HID
|
||||
/* Special command to enable Sixaxis, first byte defines the message type */
|
||||
static uint8_t magic_data[] = {0x02, 0x42, 0x0c, 0x00, 0x00};
|
||||
#elif defined(IOS)
|
||||
/* Magic packet to start reports. */
|
||||
static uint8_t magic_data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
|
||||
#endif
|
||||
@ -74,17 +81,18 @@ static void* hidpad_ps3_init(void *data, uint32_t slot, send_control_t ptr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device->connection = connection;
|
||||
device->connection = connection;
|
||||
device->slot = slot;
|
||||
device->send_control = ptr;
|
||||
|
||||
#ifdef IOS
|
||||
device->send_control(device->connection, magic_data, 6);
|
||||
#if defined(IOS) || defined(HAVE_WIIUSB_HID)
|
||||
device->send_control(device->connection, magic_data, sizeof(magic_data));
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_WIIUSB_HID
|
||||
/* Without this, the digital buttons won't be reported. */
|
||||
hidpad_ps3_send_control(device);
|
||||
|
||||
#endif
|
||||
return device;
|
||||
}
|
||||
|
||||
@ -180,6 +188,13 @@ static void hidpad_ps3_set_rumble(void *data,
|
||||
hidpad_ps3_send_control(device);
|
||||
}
|
||||
|
||||
const char * hidpad_ps3_get_name(void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* For now we return a single static name */
|
||||
return "PLAYSTATION(R)3 Controller";
|
||||
}
|
||||
|
||||
pad_connection_interface_t pad_connection_ps3 = {
|
||||
hidpad_ps3_init,
|
||||
hidpad_ps3_deinit,
|
||||
@ -187,4 +202,5 @@ pad_connection_interface_t pad_connection_ps3 = {
|
||||
hidpad_ps3_set_rumble,
|
||||
hidpad_ps3_get_buttons,
|
||||
hidpad_ps3_get_axis,
|
||||
hidpad_ps3_get_name,
|
||||
};
|
||||
|
@ -264,4 +264,5 @@ pad_connection_interface_t pad_connection_ps4 = {
|
||||
hidpad_ps4_set_rumble,
|
||||
hidpad_ps4_get_buttons,
|
||||
hidpad_ps4_get_axis,
|
||||
NULL,
|
||||
};
|
||||
|
146
input/connect/connect_snesusb.c
Normal file
146
input/connect/connect_snesusb.c
Normal file
@ -0,0 +1,146 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013-2014 - Jason Fetters
|
||||
* Copyright (C) 2011-2016 - 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include "joypad_connection.h"
|
||||
|
||||
struct hidpad_snesusb_data
|
||||
{
|
||||
struct pad_connection* connection;
|
||||
uint8_t data[64];
|
||||
uint32_t slot;
|
||||
uint64_t buttons;
|
||||
};
|
||||
|
||||
static void* hidpad_snesusb_init(void *data, uint32_t slot, send_control_t ptr)
|
||||
{
|
||||
struct pad_connection* connection = (struct pad_connection*)data;
|
||||
struct hidpad_snesusb_data* device = (struct hidpad_snesusb_data*)
|
||||
calloc(1, sizeof(struct hidpad_snesusb_data));
|
||||
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
if (!connection)
|
||||
{
|
||||
free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device->connection = connection;
|
||||
device->slot = slot;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void hidpad_snesusb_deinit(void *data)
|
||||
{
|
||||
struct hidpad_snesusb_data *device = (struct hidpad_snesusb_data*)data;
|
||||
|
||||
if (device)
|
||||
free(device);
|
||||
}
|
||||
|
||||
static uint64_t hidpad_snesusb_get_buttons(void *data)
|
||||
{
|
||||
struct hidpad_snesusb_data *device = (struct hidpad_snesusb_data*)data;
|
||||
if (!device)
|
||||
return 0;
|
||||
return device->buttons;
|
||||
}
|
||||
|
||||
static int16_t hidpad_snesusb_get_axis(void *data, unsigned axis)
|
||||
{
|
||||
int val;
|
||||
struct hidpad_snesusb_data *device = (struct hidpad_snesusb_data*)data;
|
||||
|
||||
if (!device || axis >= 2)
|
||||
return 0;
|
||||
|
||||
val = device->data[1 + axis];
|
||||
val = (val << 8) - 0x8000;
|
||||
|
||||
return (abs(val) > 0x1000) ? val : 0;
|
||||
}
|
||||
|
||||
static void hidpad_snesusb_packet_handler(void *data, uint8_t *packet, uint16_t size)
|
||||
{
|
||||
uint32_t i, pressed_keys;
|
||||
static const uint32_t button_mapping[17] =
|
||||
{
|
||||
RETRO_DEVICE_ID_JOYPAD_L,
|
||||
RETRO_DEVICE_ID_JOYPAD_R,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
RETRO_DEVICE_ID_JOYPAD_SELECT,
|
||||
RETRO_DEVICE_ID_JOYPAD_START,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
NO_BTN,
|
||||
RETRO_DEVICE_ID_JOYPAD_X,
|
||||
RETRO_DEVICE_ID_JOYPAD_A,
|
||||
RETRO_DEVICE_ID_JOYPAD_B,
|
||||
RETRO_DEVICE_ID_JOYPAD_Y,
|
||||
16, /* HOME BUTTON when pressing SELECT+START */
|
||||
};
|
||||
struct hidpad_snesusb_data *device = (struct hidpad_snesusb_data*)data;
|
||||
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
memcpy(device->data, packet, size);
|
||||
|
||||
device->buttons = 0;
|
||||
|
||||
pressed_keys = device->data[7] | (device->data[6] << 8) |
|
||||
(((device->data[7] & 0x30) == 0x30) ? (1 << 16) : 0); /* SELECT+START = MENU TOGGLE */
|
||||
|
||||
for (i = 0; i < 17; i ++)
|
||||
if (button_mapping[i] != NO_BTN)
|
||||
device->buttons |= (pressed_keys & (1 << i)) ? (UINT64_C(1) << button_mapping[i]) : 0;
|
||||
}
|
||||
|
||||
static void hidpad_snesusb_set_rumble(void *data,
|
||||
enum retro_rumble_effect effect, uint16_t strength)
|
||||
{
|
||||
(void)data;
|
||||
(void)effect;
|
||||
(void)strength;
|
||||
}
|
||||
|
||||
const char * hidpad_snesusb_get_name(void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* For now we return a single static name */
|
||||
return "Generic SNES USB Controller";
|
||||
}
|
||||
|
||||
pad_connection_interface_t pad_connection_snesusb = {
|
||||
hidpad_snesusb_init,
|
||||
hidpad_snesusb_deinit,
|
||||
hidpad_snesusb_packet_handler,
|
||||
hidpad_snesusb_set_rumble,
|
||||
hidpad_snesusb_get_buttons,
|
||||
hidpad_snesusb_get_axis,
|
||||
hidpad_snesusb_get_name,
|
||||
};
|
@ -724,4 +724,5 @@ pad_connection_interface_t pad_connection_wii = {
|
||||
hidpad_wii_set_rumble,
|
||||
hidpad_wii_get_buttons,
|
||||
hidpad_wii_get_axis,
|
||||
NULL,
|
||||
};
|
||||
|
148
input/connect/connect_wiiugca.c
Normal file
148
input/connect/connect_wiiugca.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013-2014 - Jason Fetters
|
||||
* Copyright (C) 2011-2016 - 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include "joypad_connection.h"
|
||||
|
||||
struct hidpad_wiiugca_data
|
||||
{
|
||||
struct pad_connection* connection;
|
||||
send_control_t send_control;
|
||||
uint8_t data[64];
|
||||
uint32_t slot;
|
||||
uint64_t buttons;
|
||||
};
|
||||
|
||||
static void* hidpad_wiiugca_init(void *data, uint32_t slot, send_control_t ptr)
|
||||
{
|
||||
static uint8_t magic_data[] = {0x01, 0x13}; /* Special command to enable reading */
|
||||
struct pad_connection* connection = (struct pad_connection*)data;
|
||||
struct hidpad_wiiugca_data* device = (struct hidpad_wiiugca_data*)
|
||||
calloc(1, sizeof(struct hidpad_wiiugca_data));
|
||||
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
if (!connection)
|
||||
{
|
||||
free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device->connection = connection;
|
||||
device->slot = slot;
|
||||
device->send_control = ptr;
|
||||
device->send_control(device->connection, magic_data, sizeof(magic_data));
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void hidpad_wiiugca_deinit(void *data)
|
||||
{
|
||||
struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data;
|
||||
|
||||
if (device)
|
||||
free(device);
|
||||
}
|
||||
|
||||
static uint64_t hidpad_wiiugca_get_buttons(void *data)
|
||||
{
|
||||
struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data;
|
||||
if (!device)
|
||||
return 0;
|
||||
return device->buttons;
|
||||
}
|
||||
|
||||
static int16_t hidpad_wiiugca_get_axis(void *data, unsigned axis)
|
||||
{
|
||||
int val;
|
||||
struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data;
|
||||
|
||||
if (!device || axis >= 4)
|
||||
return 0;
|
||||
|
||||
val = device->data[5 + axis];
|
||||
|
||||
if (axis % 2) /* the Y axis is inverted */
|
||||
val = 0x8000 - (val << 8);
|
||||
else
|
||||
val = (val << 8) - 0x8000;
|
||||
|
||||
return (abs(val) > 0x1000) ? val : 0;
|
||||
}
|
||||
|
||||
static void hidpad_wiiugca_packet_handler(void *data, uint8_t *packet, uint16_t size)
|
||||
{
|
||||
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,
|
||||
};
|
||||
struct hidpad_wiiugca_data *device = (struct hidpad_wiiugca_data*)data;
|
||||
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
memcpy(device->data, packet, size);
|
||||
|
||||
device->buttons = 0;
|
||||
|
||||
pressed_keys = device->data[3] | (device->data[4] << 8);
|
||||
|
||||
for (i = 0; i < 12; i ++)
|
||||
device->buttons |= (pressed_keys & (1 << i)) ?
|
||||
(1 << button_mapping[i]) : 0;
|
||||
}
|
||||
|
||||
static void hidpad_wiiugca_set_rumble(void *data,
|
||||
enum retro_rumble_effect effect, uint16_t strength)
|
||||
{
|
||||
(void)data;
|
||||
(void)effect;
|
||||
(void)strength;
|
||||
}
|
||||
|
||||
const char * hidpad_wiiugca_get_name(void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* For now we return a single static name */
|
||||
return "Wii U GC Controller Adapter";
|
||||
}
|
||||
|
||||
pad_connection_interface_t pad_connection_wiiugca = {
|
||||
hidpad_wiiugca_init,
|
||||
hidpad_wiiugca_deinit,
|
||||
hidpad_wiiugca_packet_handler,
|
||||
hidpad_wiiugca_set_rumble,
|
||||
hidpad_wiiugca_get_buttons,
|
||||
hidpad_wiiugca_get_axis,
|
||||
hidpad_wiiugca_get_name,
|
||||
};
|
@ -242,4 +242,5 @@ pad_connection_interface_t pad_connection_wiiupro = {
|
||||
hidpad_wiiupro_set_rumble,
|
||||
hidpad_wiiupro_get_buttons,
|
||||
hidpad_wiiupro_get_axis,
|
||||
NULL,
|
||||
};
|
||||
|
@ -81,7 +81,12 @@ int32_t pad_connection_pad_init(joypad_connection_t *joyconn,
|
||||
{ "Nintendo RVL-CNT-01-UC", 1406, 816, &pad_connection_wiiupro },
|
||||
{ "Wireless Controller", 1356, 1476, &pad_connection_ps4 },
|
||||
{ "PLAYSTATION(R)3 Controller", 1356, 616, &pad_connection_ps3 },
|
||||
{ "PLAYSTATION(R)3 Controller", 787, 8406, &pad_connection_ps3 },
|
||||
{ "PLAYSTATION(R)3 Controller", 787, 8406, &pad_connection_ps3 },
|
||||
#ifdef HAVE_WIIUSB_HID
|
||||
{ "Generic SNES USB Controller", 2079, 58369, &pad_connection_snesusb },
|
||||
{ "Generic NES USB Controller", 121, 17, &pad_connection_nesusb },
|
||||
{ "Wii U GC Controller Adapter", 1406, 823, &pad_connection_wiiugca },
|
||||
#endif
|
||||
{ 0, 0}
|
||||
};
|
||||
joypad_connection_t *s = NULL;
|
||||
@ -91,7 +96,7 @@ int32_t pad_connection_pad_init(joypad_connection_t *joyconn,
|
||||
return -1;
|
||||
|
||||
s = &joyconn[pad];
|
||||
|
||||
|
||||
if (s)
|
||||
{
|
||||
unsigned i;
|
||||
@ -177,6 +182,8 @@ void pad_connection_destroy(joypad_connection_t *joyconn)
|
||||
|
||||
for (i = 0; i < MAX_USERS; i ++)
|
||||
pad_connection_pad_deinit(&joyconn[i], i);
|
||||
|
||||
free(joyconn);
|
||||
}
|
||||
|
||||
bool pad_connection_rumble(joypad_connection_t *joyconn,
|
||||
@ -190,3 +197,10 @@ bool pad_connection_rumble(joypad_connection_t *joyconn,
|
||||
joyconn->iface->set_rumble(joyconn->data, effect, strength);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* pad_connection_get_name(joypad_connection_t *joyconn, unsigned pad)
|
||||
{
|
||||
if (!joyconn->iface || !joyconn->iface->get_name)
|
||||
return NULL;
|
||||
return joyconn->iface->get_name(joyconn->data);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013-2014 - Jason Fetters
|
||||
* Copyright (C) 2011-2016 - 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.
|
||||
@ -33,13 +33,14 @@ struct joypad_connection
|
||||
|
||||
typedef struct pad_connection_interface
|
||||
{
|
||||
void* (*init)(void *data, uint32_t slot, send_control_t ptr);
|
||||
void (*deinit)(void* device);
|
||||
void (*packet_handler)(void* device, uint8_t *packet, uint16_t size);
|
||||
void (*set_rumble)(void* device, enum retro_rumble_effect effect,
|
||||
uint16_t strength);
|
||||
uint64_t (*get_buttons)(void *data);
|
||||
int16_t (*get_axis)(void *data, unsigned axis);
|
||||
void* (*init)(void *data, uint32_t slot, send_control_t ptr);
|
||||
void (*deinit)(void* device);
|
||||
void (*packet_handler)(void* device, uint8_t *packet, uint16_t size);
|
||||
void (*set_rumble)(void* device, enum retro_rumble_effect effect,
|
||||
uint16_t strength);
|
||||
uint64_t (*get_buttons)(void *data);
|
||||
int16_t (*get_axis)(void *data, unsigned axis);
|
||||
const char* (*get_name)(void *data);
|
||||
} pad_connection_interface_t;
|
||||
|
||||
typedef struct joypad_connection joypad_connection_t;
|
||||
@ -48,6 +49,11 @@ extern pad_connection_interface_t pad_connection_wii;
|
||||
extern pad_connection_interface_t pad_connection_wiiupro;
|
||||
extern pad_connection_interface_t pad_connection_ps3;
|
||||
extern pad_connection_interface_t pad_connection_ps4;
|
||||
#ifdef HAVE_WIIUSB_HID
|
||||
extern pad_connection_interface_t pad_connection_snesusb;
|
||||
extern pad_connection_interface_t pad_connection_nesusb;
|
||||
extern pad_connection_interface_t pad_connection_wiiugca;
|
||||
#endif
|
||||
|
||||
int32_t pad_connection_pad_init(joypad_connection_t *joyconn,
|
||||
const char* name, uint16_t vid, uint16_t pid,
|
||||
@ -80,4 +86,7 @@ int pad_connection_find_vacant_pad(joypad_connection_t *joyconn);
|
||||
bool pad_connection_rumble(joypad_connection_t *s,
|
||||
unsigned pad, enum retro_rumble_effect effect, uint16_t strength);
|
||||
|
||||
const char* pad_connection_get_name(joypad_connection_t *joyconn,
|
||||
unsigned idx);
|
||||
|
||||
#endif
|
||||
|
@ -14,110 +14,107 @@
|
||||
*/
|
||||
|
||||
#include <gccore.h>
|
||||
|
||||
#include <rthreads/rthreads.h>
|
||||
#include <compat/strl.h>
|
||||
#include <queues/fifo_buffer.h>
|
||||
|
||||
#include "../connect/joypad_connection.h"
|
||||
#include "../input_autodetect.h"
|
||||
#include "../input_hid_driver.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
#define WIIUSB_SC_NONE 0
|
||||
#define WIIUSB_SC_INTMSG 1
|
||||
#define WIIUSB_SC_CTRLMSG 2
|
||||
#define WIIUSB_SC_CTRLMSG2 3
|
||||
|
||||
typedef struct wiiusb_hid
|
||||
{
|
||||
joypad_connection_t *slots;
|
||||
int hp; /* wiiusb_hotplug_callback_handle is just int */
|
||||
int quit;
|
||||
joypad_connection_t *connections;
|
||||
struct wiiusb_adapter *adapters_head;
|
||||
|
||||
sthread_t *poll_thread;
|
||||
volatile bool poll_thread_quit;
|
||||
|
||||
bool device_detected; /* helps on knowing if a new device has been inserted */
|
||||
bool removal_cb; /* helps on detecting that a device has just been removed */
|
||||
bool manual_removal;
|
||||
} wiiusb_hid_t;
|
||||
|
||||
struct wiiusb_adapter
|
||||
{
|
||||
wiiusb_hid_t *hid;
|
||||
volatile bool quitting;
|
||||
usb_device_entry device;
|
||||
int handle;
|
||||
int interface_number;
|
||||
int endpoint_in;
|
||||
int endpoint_out;
|
||||
int endpoint_in_max_size;
|
||||
int endpoint_out_max_size;
|
||||
struct wiiusb_adapter *next;
|
||||
|
||||
uint8_t manufacturer_name[255];
|
||||
uint8_t name[255];
|
||||
bool busy;
|
||||
int32_t device_id;
|
||||
int32_t handle;
|
||||
int32_t endpoint_in;
|
||||
int32_t endpoint_out;
|
||||
int32_t endpoint_in_max_size;
|
||||
int32_t endpoint_out_max_size;
|
||||
|
||||
int32_t slot;
|
||||
uint8_t *data;
|
||||
|
||||
int slot;
|
||||
|
||||
sthread_t *thread;
|
||||
slock_t *send_control_lock;
|
||||
fifo_buffer_t *send_control_buffer;
|
||||
struct wiiusb_adapter *next;
|
||||
uint8_t send_control_type;
|
||||
uint8_t *send_control_buffer;
|
||||
uint32_t send_control_size;
|
||||
};
|
||||
|
||||
static struct wiiusb_adapter adapters;
|
||||
|
||||
static void adapter_thread(void *data)
|
||||
static void wiiusb_hid_process_control_message(struct wiiusb_adapter* adapter)
|
||||
{
|
||||
int32_t r;
|
||||
switch (adapter->send_control_type)
|
||||
{
|
||||
case WIIUSB_SC_INTMSG:
|
||||
do { r = USB_WriteIntrMsg(adapter->handle, adapter->endpoint_out, adapter->send_control_size, adapter->send_control_buffer);
|
||||
} while (r < 0);
|
||||
break;
|
||||
case WIIUSB_SC_CTRLMSG:
|
||||
do { r = USB_WriteCtrlMsg(adapter->handle, USB_REQTYPE_INTERFACE_SET, USB_REQ_SETREPORT, (USB_REPTYPE_FEATURE<<8) | 0xf4, 0x0, adapter->send_control_size, adapter->send_control_buffer);
|
||||
} while (r < 0);
|
||||
break;
|
||||
case WIIUSB_SC_CTRLMSG2:
|
||||
do { r = USB_WriteCtrlMsg(adapter->handle, USB_REQTYPE_INTERFACE_SET, USB_REQ_SETREPORT, (USB_REPTYPE_OUTPUT<<8) | 0x01, 0x0, adapter->send_control_size, adapter->send_control_buffer);
|
||||
} while (r < 0);
|
||||
break;
|
||||
/*default: any other case we do nothing */
|
||||
}
|
||||
/* Reset the control type */
|
||||
adapter->send_control_type = WIIUSB_SC_NONE;
|
||||
}
|
||||
|
||||
static int32_t wiiusb_hid_read_cb(int32_t size, void *data)
|
||||
{
|
||||
uint8_t __attribute__((aligned(32))) send_command_buf[4096];
|
||||
struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)data;
|
||||
wiiusb_hid_t *hid = adapter ? adapter->hid : NULL;
|
||||
|
||||
if (!adapter)
|
||||
return;
|
||||
if (hid && hid->connections && size > 0)
|
||||
pad_connection_packet(&hid->connections[adapter->slot], adapter->slot, adapter->data-1, size+1);
|
||||
|
||||
while (!adapter->quitting)
|
||||
{
|
||||
size_t send_command_size;
|
||||
int size = 0;
|
||||
if (adapter)
|
||||
adapter->busy = false;
|
||||
|
||||
slock_lock(adapter->send_control_lock);
|
||||
|
||||
if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size))
|
||||
{
|
||||
fifo_read(adapter->send_control_buffer, &send_command_size, sizeof(send_command_size));
|
||||
if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size))
|
||||
{
|
||||
fifo_read(adapter->send_control_buffer, send_command_buf, send_command_size);
|
||||
USB_WriteIntrMsg(adapter->handle, adapter->endpoint_out, send_command_size, send_command_buf);
|
||||
}
|
||||
}
|
||||
slock_unlock(adapter->send_control_lock);
|
||||
|
||||
size = USB_ReadIntrMsg(adapter->handle, adapter->endpoint_in, adapter->endpoint_in_max_size, &adapter->data[0]);
|
||||
/* RARCH_LOG("%p USB_ReadIntrMsg(%i, %i, %i, %p): %i\n", &adapter->data[0],
|
||||
adapter->handle, adapter->endpoint_in, adapter->endpoint_in_max_size, &adapter->data[0],
|
||||
size); */
|
||||
|
||||
//RARCH_LOG("%03i %03i %03i %03i\n", adapter->data[0], adapter->data[1], adapter->data[2], adapter->data[3], adapter->data[4]);
|
||||
//memmove(&adapter->data[1], &adapter->data[0], 2048);
|
||||
|
||||
if (adapter && hid && hid->slots && size)
|
||||
pad_connection_packet(&hid->slots[adapter->slot], adapter->slot,
|
||||
adapter->data - 1, size+1);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static void wiiusb_hid_device_send_control(void *data,
|
||||
uint8_t* data_buf, size_t size)
|
||||
{
|
||||
uint8_t control_type;
|
||||
struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)data;
|
||||
|
||||
if (!adapter)
|
||||
if (!adapter || !data_buf || !adapter->send_control_buffer)
|
||||
return;
|
||||
|
||||
slock_lock(adapter->send_control_lock);
|
||||
|
||||
if (fifo_write_avail(adapter->send_control_buffer) >= size + sizeof(size))
|
||||
{
|
||||
fifo_write(adapter->send_control_buffer, &size, sizeof(size));
|
||||
fifo_write(adapter->send_control_buffer, data_buf, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_WARN("adapter write buffer is full, cannot write send control\n");
|
||||
}
|
||||
slock_unlock(adapter->send_control_lock);
|
||||
/* first byte contains the type of control to use
|
||||
* which can be NONE, INT_MSG, CTRL_MSG, CTRL_MSG2 */
|
||||
control_type = data_buf[0];
|
||||
/* decrement size by one as we are getting rid of first byte */
|
||||
adapter->send_control_size = size - 1;
|
||||
/* increase the buffer address so we access the actual data */
|
||||
data_buf++;
|
||||
memcpy(adapter->send_control_buffer, data_buf, adapter->send_control_size);
|
||||
/* Activate it so it can be processed in the adapter thread */
|
||||
adapter->send_control_type = control_type;
|
||||
}
|
||||
|
||||
static void wiiusb_hid_device_add_autodetect(unsigned idx,
|
||||
@ -125,6 +122,7 @@ static void wiiusb_hid_device_add_autodetect(unsigned idx,
|
||||
uint16_t dev_vid, uint16_t dev_pid)
|
||||
{
|
||||
autoconfig_params_t params = {{0}};
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
params.idx = idx;
|
||||
params.vid = dev_vid;
|
||||
@ -133,6 +131,9 @@ static void wiiusb_hid_device_add_autodetect(unsigned idx,
|
||||
strlcpy(params.name, device_name, sizeof(params.name));
|
||||
strlcpy(params.driver, driver_name, sizeof(params.driver));
|
||||
|
||||
strlcpy(settings->input.device_names[idx], device_name,
|
||||
sizeof(settings->input.device_names[idx]));
|
||||
|
||||
input_config_autoconfigure_joypad(¶ms);
|
||||
}
|
||||
|
||||
@ -148,30 +149,23 @@ static void wiiusb_get_description(usb_device_entry *device,
|
||||
for (i = 0; i < (int)config->bNumInterfaces; i++)
|
||||
{
|
||||
const usb_interfacedesc *inter = &config->interfaces[i];
|
||||
#if 0
|
||||
if (inter->bInterfaceClass == USB_CLASS_HID)
|
||||
#endif
|
||||
for(k = 0; k < (int)inter->bNumEndpoints; k++)
|
||||
{
|
||||
adapter->interface_number = (int)inter->bInterfaceNumber;
|
||||
|
||||
for(k = 0; k < (int)inter->bNumEndpoints; k++)
|
||||
const usb_endpointdesc *epdesc = &inter->endpoints[k];
|
||||
bool is_int = (epdesc->bmAttributes & 0x03) == USB_ENDPOINT_INTERRUPT;
|
||||
bool is_out = (epdesc->bEndpointAddress & 0x80) == USB_ENDPOINT_OUT;
|
||||
bool is_in = (epdesc->bEndpointAddress & 0x80) == USB_ENDPOINT_IN;
|
||||
if (is_int)
|
||||
{
|
||||
const usb_endpointdesc *epdesc = &inter->endpoints[k];
|
||||
bool is_int = (epdesc->bmAttributes & 0x03) == USB_ENDPOINT_INTERRUPT;
|
||||
bool is_out = (epdesc->bEndpointAddress & 0x80) == USB_ENDPOINT_OUT;
|
||||
bool is_in = (epdesc->bEndpointAddress & 0x80) == USB_ENDPOINT_IN;
|
||||
if (is_int)
|
||||
if (is_in)
|
||||
{
|
||||
if (is_in)
|
||||
{
|
||||
adapter->endpoint_in = epdesc->bEndpointAddress;
|
||||
adapter->endpoint_in_max_size = epdesc->wMaxPacketSize;
|
||||
}
|
||||
if (is_out)
|
||||
{
|
||||
adapter->endpoint_out = epdesc->bEndpointAddress;
|
||||
adapter->endpoint_out_max_size = epdesc->wMaxPacketSize;
|
||||
}
|
||||
adapter->endpoint_in = epdesc->bEndpointAddress;
|
||||
adapter->endpoint_in_max_size = epdesc->wMaxPacketSize;
|
||||
}
|
||||
if (is_out)
|
||||
{
|
||||
adapter->endpoint_out = epdesc->bEndpointAddress;
|
||||
adapter->endpoint_out_max_size = epdesc->wMaxPacketSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,67 +174,91 @@ static void wiiusb_get_description(usb_device_entry *device,
|
||||
}
|
||||
}
|
||||
|
||||
static int remove_adapter(void *data, usb_device_entry *dev)
|
||||
static const char *wiiusb_hid_joypad_name(void *data, unsigned pad)
|
||||
{
|
||||
struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)&adapters;
|
||||
struct wiiusb_hid *hid = (struct wiiusb_hid*)data;
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
if (pad >= MAX_USERS)
|
||||
return NULL;
|
||||
|
||||
while (adapter->next == NULL)
|
||||
return -1;
|
||||
if (hid)
|
||||
return pad_connection_get_name(&hid->connections[pad], pad);
|
||||
|
||||
if (&adapter->next->device == dev)
|
||||
{
|
||||
struct wiiusb_adapter *new_next = NULL;
|
||||
const char *name = (const char*)adapter->next->name;
|
||||
|
||||
input_config_autoconfigure_disconnect(adapter->slot, name);
|
||||
|
||||
adapter->next->quitting = true;
|
||||
sthread_join(adapter->next->thread);
|
||||
|
||||
pad_connection_pad_deinit(&hid->slots[adapter->slot], adapter->slot);
|
||||
|
||||
slock_free(adapter->send_control_lock);
|
||||
fifo_free(adapter->send_control_buffer);
|
||||
|
||||
free(adapter->data);
|
||||
|
||||
USB_CloseDevice(&adapter->next->handle);
|
||||
|
||||
new_next = adapter->next->next;
|
||||
free(adapter->next);
|
||||
adapter->next = new_next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
adapter = adapter->next;
|
||||
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int wiiusb_hid_removalnotify_cb(int result, void *usrdata)
|
||||
static int32_t wiiusb_hid_release_adapter(struct wiiusb_adapter *adapter)
|
||||
{
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)usrdata;
|
||||
wiiusb_hid_t *hid;
|
||||
const char *name;
|
||||
|
||||
if (!hid)
|
||||
if (!adapter)
|
||||
return -1;
|
||||
|
||||
hid = adapter->hid;
|
||||
name = wiiusb_hid_joypad_name(hid, adapter->slot);
|
||||
input_config_autoconfigure_disconnect(adapter->slot, name);
|
||||
pad_connection_pad_deinit(&hid->connections[adapter->slot], adapter->slot);
|
||||
|
||||
free(adapter->send_control_buffer);
|
||||
free(adapter->data);
|
||||
free(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_adapter(void *data, usb_device_entry *dev)
|
||||
static int wiiusb_hid_remove_adapter(struct wiiusb_adapter *adapter)
|
||||
{
|
||||
if (!adapter)
|
||||
return -1;
|
||||
|
||||
if (adapter->handle > 0) {
|
||||
USB_CloseDevice(&adapter->handle);
|
||||
}
|
||||
|
||||
wiiusb_hid_release_adapter(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wiiusb_hid_removal_cb(int result, void *usrdata)
|
||||
{
|
||||
struct wiiusb_adapter *adapter = (struct wiiusb_adapter *)usrdata;
|
||||
wiiusb_hid_t *hid = adapter ? adapter->hid : NULL;
|
||||
struct wiiusb_adapter *temp = hid ? hid->adapters_head : NULL;
|
||||
|
||||
if (!adapter || !hid || !temp || hid->manual_removal)
|
||||
return -1;
|
||||
|
||||
if (temp == adapter)
|
||||
hid->adapters_head = adapter->next;
|
||||
else
|
||||
while (temp->next)
|
||||
{
|
||||
if (temp->next == adapter)
|
||||
{
|
||||
temp->next = adapter->next;
|
||||
break;
|
||||
}
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
/* get rid of the adapter */
|
||||
wiiusb_hid_release_adapter(adapter);
|
||||
|
||||
/* notify that we pass thru the removal callback */
|
||||
hid->removal_cb = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wiiusb_hid_add_adapter(void *data, usb_device_entry *dev)
|
||||
{
|
||||
int rc;
|
||||
usb_devdesc desc;
|
||||
const char *device_name = NULL;
|
||||
struct wiiusb_adapter *old_head = NULL;
|
||||
struct wiiusb_hid *hid = (struct wiiusb_hid*)data;
|
||||
struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)
|
||||
calloc(1, sizeof(struct wiiusb_adapter));
|
||||
|
||||
(void)rc;
|
||||
|
||||
if (!adapter)
|
||||
return -1;
|
||||
|
||||
@ -254,16 +272,15 @@ static int add_adapter(void *data, usb_device_entry *dev)
|
||||
if (USB_OpenDevice(dev->device_id, dev->vid, dev->pid, &adapter->handle) < 0)
|
||||
{
|
||||
RARCH_ERR("Error opening device 0x%p (VID/PID: %04x:%04x).\n",
|
||||
(void*)&adapter->device, dev->vid, dev->pid);
|
||||
dev->device_id, dev->vid, dev->pid);
|
||||
free(adapter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
adapter->device = *dev;
|
||||
adapter->device_id = dev->device_id;
|
||||
|
||||
USB_GetDescriptors(adapter->handle, &desc);
|
||||
|
||||
wiiusb_get_description(&adapter->device, adapter, &desc);
|
||||
wiiusb_get_description(dev, adapter, &desc);
|
||||
|
||||
if (adapter->endpoint_in == 0)
|
||||
{
|
||||
@ -271,84 +288,54 @@ static int add_adapter(void *data, usb_device_entry *dev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (desc.iManufacturer)
|
||||
{
|
||||
USB_GetAsciiString(adapter->handle, desc.iManufacturer, 0,
|
||||
sizeof(adapter->manufacturer_name), adapter->manufacturer_name);
|
||||
#if 0
|
||||
RARCH_ERR(" Adapter Manufacturer name: %s\n", adapter->manufacturer_name);
|
||||
#endif
|
||||
}
|
||||
/* Allocate mem for the send control buffer, 32bit aligned */
|
||||
adapter->send_control_type = WIIUSB_SC_NONE;
|
||||
adapter->send_control_buffer = memalign(32, 128);
|
||||
|
||||
if (desc.iProduct)
|
||||
{
|
||||
USB_GetAsciiString(adapter->handle, desc.iProduct, 0,
|
||||
sizeof(adapter->name), adapter->name);
|
||||
#if 0
|
||||
RARCH_ERR(" Adapter name: %s\n", adapter->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
device_name = (const char *)adapter->name;
|
||||
|
||||
adapter->send_control_lock = slock_new();
|
||||
adapter->send_control_buffer = fifo_new(4096);
|
||||
|
||||
if (!adapter->send_control_lock || !adapter->send_control_buffer)
|
||||
if (!adapter->send_control_buffer)
|
||||
{
|
||||
RARCH_ERR("Error creating send control buffer.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
adapter->slot = pad_connection_pad_init(hid->slots,
|
||||
device_name, desc.idVendor, desc.idProduct,
|
||||
/* Sent the pad name as dummy, we don't know the
|
||||
* control name until we get its interface */
|
||||
adapter->slot = pad_connection_pad_init(hid->connections,
|
||||
"hid", desc.idVendor, desc.idProduct,
|
||||
adapter, &wiiusb_hid_device_send_control);
|
||||
|
||||
if (adapter->slot == -1)
|
||||
goto error;
|
||||
|
||||
if (!pad_connection_has_interface(hid->slots, adapter->slot))
|
||||
if (!pad_connection_has_interface(hid->connections, adapter->slot))
|
||||
{
|
||||
RARCH_ERR(" Interface not found (%s).\n", adapter->name);
|
||||
RARCH_ERR(" Interface not found.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
RARCH_LOG("Interface found: [%s].\n", adapter->name);
|
||||
adapter->data = memalign(32, 128);
|
||||
adapter->hid = hid;
|
||||
adapter->next = hid->adapters_head;
|
||||
hid->adapters_head = adapter;
|
||||
|
||||
/* Get the name from the interface */
|
||||
device_name = wiiusb_hid_joypad_name(hid, adapter->slot);
|
||||
RARCH_LOG("Interface found: [%s].\n", device_name);
|
||||
|
||||
RARCH_LOG("Device 0x%p attached (VID/PID: %04x:%04x).\n",
|
||||
adapter->device, desc.idVendor, desc.idProduct);
|
||||
adapter->device_id, desc.idVendor, desc.idProduct);
|
||||
|
||||
wiiusb_hid_device_add_autodetect(adapter->slot,
|
||||
device_name, wiiusb_hid.ident, desc.idVendor, desc.idProduct);
|
||||
|
||||
adapter->hid = hid;
|
||||
adapter->thread = sthread_create(adapter_thread, adapter);
|
||||
|
||||
if (!adapter->thread)
|
||||
{
|
||||
RARCH_ERR("Error initializing adapter thread.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
adapter->data = memalign(32, 2048);
|
||||
|
||||
old_head = adapters.next;
|
||||
adapters.next = adapter;
|
||||
adapter->next = old_head;
|
||||
|
||||
USB_FreeDescriptors(&desc);
|
||||
|
||||
USB_DeviceRemovalNotifyAsync(adapter->handle, wiiusb_hid_removalnotify_cb, (void *)hid);
|
||||
USB_DeviceRemovalNotifyAsync(adapter->handle, wiiusb_hid_removal_cb, adapter);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (adapter->thread)
|
||||
sthread_join(adapter->thread);
|
||||
if (adapter->send_control_lock)
|
||||
slock_free(adapter->send_control_lock);
|
||||
if (adapter->send_control_buffer)
|
||||
fifo_free(adapter->send_control_buffer);
|
||||
free(adapter->send_control_buffer);
|
||||
if (adapter)
|
||||
free(adapter);
|
||||
USB_FreeDescriptors(&desc);
|
||||
@ -356,23 +343,112 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int wiiusb_hid_changenotify_cb(int result, void *usrdata)
|
||||
static bool wiiusb_hid_new_device(wiiusb_hid_t *hid, int32_t id) {
|
||||
struct wiiusb_adapter *temp;
|
||||
|
||||
if(!hid)
|
||||
return false; /* false, so we do not proceed to add it */
|
||||
|
||||
temp = hid->adapters_head;
|
||||
while (temp)
|
||||
{
|
||||
if (temp->device_id == id)
|
||||
return false;
|
||||
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void wiiusb_hid_scan_for_devices(wiiusb_hid_t *hid)
|
||||
{
|
||||
unsigned i;
|
||||
u8 count;
|
||||
usb_device_entry *dev_entries;
|
||||
|
||||
dev_entries = (usb_device_entry *)calloc(MAX_USERS, sizeof(*dev_entries));
|
||||
|
||||
if (!dev_entries)
|
||||
goto error;
|
||||
|
||||
if (USB_GetDeviceList(dev_entries, MAX_USERS, USB_CLASS_HID, &count) < 0)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
/* first check the device is not already in our list */
|
||||
if (!wiiusb_hid_new_device(hid, dev_entries[i].device_id))
|
||||
continue;
|
||||
|
||||
if (dev_entries[i].vid > 0 && dev_entries[i].pid > 0)
|
||||
wiiusb_hid_add_adapter(hid, &dev_entries[i]);
|
||||
}
|
||||
|
||||
error:
|
||||
if (dev_entries)
|
||||
free(dev_entries);
|
||||
}
|
||||
|
||||
static void wiiusb_hid_poll_thread(void *data)
|
||||
{
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
struct wiiusb_adapter *adapter;
|
||||
|
||||
if (!hid)
|
||||
return;
|
||||
|
||||
while (!hid->poll_thread_quit)
|
||||
{
|
||||
|
||||
/* first check for new devices */
|
||||
if (hid->device_detected)
|
||||
{
|
||||
/* turn off the detection flag */
|
||||
hid->device_detected = false;
|
||||
/* search for new pads and add them as needed */
|
||||
wiiusb_hid_scan_for_devices(hid);
|
||||
}
|
||||
|
||||
/* process each active adapter */
|
||||
for (adapter=hid->adapters_head; adapter; adapter=adapter->next)
|
||||
{
|
||||
if (!adapter->busy)
|
||||
{
|
||||
/* lock itself while writing or reading */
|
||||
adapter->busy = true;
|
||||
|
||||
if (adapter->send_control_type)
|
||||
wiiusb_hid_process_control_message(adapter);
|
||||
|
||||
USB_ReadIntrMsgAsync(adapter->handle, adapter->endpoint_in, adapter->endpoint_in_max_size,
|
||||
adapter->data, wiiusb_hid_read_cb, adapter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait 10 milliseconds to process again */
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
static int wiiusb_hid_change_cb(int result, void *usrdata)
|
||||
{
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)usrdata;
|
||||
|
||||
if (!hid)
|
||||
return -1;
|
||||
|
||||
/* usb_device_entry entries[8];
|
||||
u8 cnt = 0;
|
||||
if (!hid->removal_cb)
|
||||
{
|
||||
/* As it's not coming from the removal callback
|
||||
then we detected a new device being inserted */
|
||||
hid->device_detected = true;
|
||||
}
|
||||
else
|
||||
hid->removal_cb = false;
|
||||
|
||||
USB_GetDeviceList(entries, 8, USB_CLASS_HID, &cnt);
|
||||
|
||||
add_adapter((void *)hid, &entries[0]); */
|
||||
|
||||
// RARCH_LOG("Wii USB hid change notify callback\n");
|
||||
|
||||
USB_DeviceChangeNotifyAsync(USB_CLASS_HID, wiiusb_hid_changenotify_cb, usrdata);
|
||||
/* Re-submit the change alert */
|
||||
USB_DeviceChangeNotifyAsync(USB_CLASS_HID, wiiusb_hid_change_cb, usrdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -382,20 +458,11 @@ static bool wiiusb_hid_joypad_query(void *data, unsigned pad)
|
||||
return pad < MAX_USERS;
|
||||
}
|
||||
|
||||
static const char *wiiusb_hid_joypad_name(void *data, unsigned pad)
|
||||
{
|
||||
/* TODO/FIXME - implement properly */
|
||||
if (pad >= MAX_USERS)
|
||||
return NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t wiiusb_hid_joypad_get_buttons(void *data, unsigned port)
|
||||
{
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
if (hid)
|
||||
return pad_connection_get_buttons(&hid->slots[port], port);
|
||||
return pad_connection_get_buttons(&hid->connections[port], port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -413,30 +480,33 @@ static bool wiiusb_hid_joypad_button(void *data, unsigned port, uint16_t joykey)
|
||||
/* Check the button. */
|
||||
if ((port < MAX_USERS) && (joykey < 32))
|
||||
return ((buttons & (1 << joykey)) != 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool wiiusb_hid_joypad_rumble(void *data, unsigned pad,
|
||||
enum retro_rumble_effect effect, uint16_t strength)
|
||||
{
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
|
||||
if (!hid)
|
||||
return false;
|
||||
return pad_connection_rumble(&hid->slots[pad], pad, effect, strength);
|
||||
|
||||
return pad_connection_rumble(&hid->connections[pad], pad, effect, strength);
|
||||
}
|
||||
|
||||
static int16_t wiiusb_hid_joypad_axis(void *data,
|
||||
unsigned port, uint32_t joyaxis)
|
||||
{
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
int16_t val = 0;
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
int16_t val = 0;
|
||||
|
||||
if (joyaxis == AXIS_NONE)
|
||||
return 0;
|
||||
|
||||
if (AXIS_NEG_GET(joyaxis) < 4)
|
||||
{
|
||||
val = pad_connection_get_axis(&hid->slots[port],
|
||||
val = pad_connection_get_axis(&hid->connections[port],
|
||||
port, AXIS_NEG_GET(joyaxis));
|
||||
|
||||
if (val >= 0)
|
||||
@ -444,7 +514,7 @@ static int16_t wiiusb_hid_joypad_axis(void *data,
|
||||
}
|
||||
else if(AXIS_POS_GET(joyaxis) < 4)
|
||||
{
|
||||
val = pad_connection_get_axis(&hid->slots[port],
|
||||
val = pad_connection_get_axis(&hid->connections[port],
|
||||
port, AXIS_POS_GET(joyaxis));
|
||||
|
||||
if (val <= 0)
|
||||
@ -457,58 +527,57 @@ static int16_t wiiusb_hid_joypad_axis(void *data,
|
||||
static void wiiusb_hid_free(void *data)
|
||||
{
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
|
||||
struct wiiusb_adapter *adapter, *next_adapter;
|
||||
|
||||
while (adapters.next)
|
||||
if (remove_adapter(hid, &adapters.next->device) == -1)
|
||||
RARCH_ERR("could not remove device %p\n",
|
||||
adapters.next->device);
|
||||
if (!hid)
|
||||
return;
|
||||
|
||||
pad_connection_destroy(hid->slots);
|
||||
hid->poll_thread_quit = true;
|
||||
sthread_join(hid->poll_thread);
|
||||
|
||||
// wiiusb_hotplug_deregister_callback(hid->ctx, hid->hp);
|
||||
hid->manual_removal = TRUE;
|
||||
/* remove each of the adapters */
|
||||
for (adapter = hid->adapters_head; adapter; adapter = next_adapter)
|
||||
{
|
||||
next_adapter = adapter->next;
|
||||
wiiusb_hid_remove_adapter(adapter);
|
||||
}
|
||||
|
||||
if (hid)
|
||||
free(hid);
|
||||
pad_connection_destroy(hid->connections);
|
||||
|
||||
free(hid);
|
||||
}
|
||||
|
||||
static void *wiiusb_hid_init(void)
|
||||
{
|
||||
unsigned i;
|
||||
u8 count;
|
||||
int ret;
|
||||
usb_device_entry *dev_entries;
|
||||
wiiusb_hid_t *hid = (wiiusb_hid_t*)calloc(1, sizeof(*hid));
|
||||
|
||||
(void)ret;
|
||||
|
||||
if (!hid)
|
||||
goto error;
|
||||
|
||||
hid->slots = pad_connection_init(MAX_USERS);
|
||||
hid->connections = pad_connection_init(MAX_USERS);
|
||||
|
||||
if (!hid->slots)
|
||||
if (!hid->connections)
|
||||
goto error;
|
||||
|
||||
dev_entries = (usb_device_entry *)calloc(MAX_USERS, sizeof(*dev_entries));
|
||||
/* Init hid values */
|
||||
hid->adapters_head = NULL;
|
||||
hid->removal_cb = FALSE;
|
||||
hid->manual_removal = FALSE;
|
||||
hid->poll_thread_quit = FALSE;
|
||||
/* we set it initially to TRUE so we force
|
||||
* to add the already connected pads */
|
||||
hid->device_detected = TRUE;
|
||||
|
||||
if (!dev_entries)
|
||||
goto error;
|
||||
hid->poll_thread = sthread_create(wiiusb_hid_poll_thread, hid);
|
||||
|
||||
if (USB_GetDeviceList(dev_entries, MAX_USERS, USB_CLASS_HID, &count) < 0)
|
||||
if (!hid->poll_thread)
|
||||
{
|
||||
free(dev_entries);
|
||||
RARCH_ERR("Error initializing poll thread.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (dev_entries[i].vid > 0 && dev_entries[i].pid > 0)
|
||||
add_adapter(hid, &dev_entries[i]);
|
||||
}
|
||||
|
||||
free(dev_entries);
|
||||
|
||||
USB_DeviceChangeNotifyAsync(USB_CLASS_HID, wiiusb_hid_changenotify_cb, (void *)hid);
|
||||
USB_DeviceChangeNotifyAsync(USB_CLASS_HID, wiiusb_hid_change_cb, (void *)hid);
|
||||
|
||||
return hid;
|
||||
|
||||
@ -517,7 +586,6 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void wiiusb_hid_poll(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
Loading…
x
Reference in New Issue
Block a user