Add Retrode support (Thanks revvv!)

This commit is contained in:
Daryl Borth 2019-08-05 18:22:54 -06:00
parent 637f4b42cc
commit 4c15d55247
4 changed files with 149 additions and 0 deletions

View File

@ -18,6 +18,7 @@ Wii homebrew is WiiBrew (www.wiibrew.org).
* Based on Snes9x 1.58 (with faster Blargg S-SMP module) * Based on Snes9x 1.58 (with faster Blargg S-SMP module)
* Wiimote, Nunchuk, Classic, Wii U Pro, and Gamecube controller support * Wiimote, Nunchuk, Classic, Wii U Pro, and Gamecube controller support
* Wii U GamePad support (requires homebrew injection into Wii U VC title) * Wii U GamePad support (requires homebrew injection into Wii U VC title)
* Retrode support for up to 4 players
* SNES Superscope, Mouse, Justifier support * SNES Superscope, Mouse, Justifier support
* Cheat support * Cheat support
* Satellaview (BS-X) support * Satellaview (BS-X) support
@ -34,6 +35,10 @@ Wii homebrew is WiiBrew (www.wiibrew.org).
| UPDATE HISTORY | | UPDATE HISTORY |
•˜———–—––-- - —————————––––– ———–—––-- - —————————––––– ———–—––-- - ————————• •˜———–—––-- - —————————––––– ———–—––-- - —————————––––– ———–—––-- - ————————•
[4.4.4]
* Added retrode support (thanks revvv!)
[4.4.3 - April 13, 2019] [4.4.3 - April 13, 2019]
* Game-specific fixes (Chou Aniki, Rendering Rangers R2, Tenshi no Uta, Circuit USA) * Game-specific fixes (Chou Aniki, Rendering Rangers R2, Tenshi no Uta, Circuit USA)

View File

@ -35,6 +35,10 @@
#include "snes9x/memmap.h" #include "snes9x/memmap.h"
#include "snes9x/controls.h" #include "snes9x/controls.h"
#ifdef HW_RVL
#include "utils/retrode.h"
#endif
#define ANALOG_SENSITIVITY 30 #define ANALOG_SENSITIVITY 30
int rumbleRequest[4] = {0,0,0,0}; int rumbleRequest[4] = {0,0,0,0};
@ -243,6 +247,7 @@ UpdatePads()
{ {
#ifdef HW_RVL #ifdef HW_RVL
WiiDRC_ScanPads(); WiiDRC_ScanPads();
Retrode_ScanPads();
WPAD_ScanPads(); WPAD_ScanPads();
#endif #endif
@ -442,6 +447,8 @@ static void decodepad (int chan)
s16 wiidrc_ax = userInput[chan].wiidrcdata.stickX; s16 wiidrc_ax = userInput[chan].wiidrcdata.stickX;
s16 wiidrc_ay = userInput[chan].wiidrcdata.stickY; s16 wiidrc_ay = userInput[chan].wiidrcdata.stickY;
u32 wiidrcp = userInput[chan].wiidrcdata.btns_h; u32 wiidrcp = userInput[chan].wiidrcdata.btns_h;
jp |= Retrode_ButtonsHeld(chan);
#endif #endif
/*** /***

122
source/utils/retrode.c Normal file
View File

@ -0,0 +1,122 @@
#ifdef HW_RVL
#include <gccore.h>
static bool retrodeSetup = false;
static s32 deviceIdRetrode = 0;
static u8 endpointRetrode = 0;
static u8 bMaxPacketSizeRetrode = 0;
static u32 jpRetrode[4];
static bool isRetrodeGamepad(usb_devdesc devdesc)
{
if (devdesc.idVendor != 0x0403 || devdesc.idProduct != 0x97C1 ||
devdesc.configurations == NULL || devdesc.configurations->interfaces == NULL ||
devdesc.configurations->interfaces->endpoints == NULL)
{
return false;
}
return devdesc.configurations->interfaces->bInterfaceSubClass == 0;
}
static u8 getEndpoint(usb_devdesc devdesc)
{
if (devdesc.configurations == NULL || devdesc.configurations->interfaces == NULL ||
devdesc.configurations->interfaces->endpoints == NULL)
{
return -1;
}
return devdesc.configurations->interfaces->endpoints->bEndpointAddress;
}
static void openRetrode()
{
usb_device_entry dev_entry[8];
u8 dev_count;
if (USB_GetDeviceList(dev_entry, 8, USB_CLASS_HID, &dev_count) < 0)
{
return;
}
// Retrode has two entries in USB_GetDeviceList(), one for gamepads and one for SNES mouse
for (int i = 0; i < dev_count; ++i)
{
s32 fd;
if (USB_OpenDevice(dev_entry[i].device_id, dev_entry[i].vid, dev_entry[i].pid, &fd) < 0)
{
continue;
}
usb_devdesc devdesc;
if (USB_GetDescriptors(fd, &devdesc) < 0 || !isRetrodeGamepad(devdesc))
{
USB_CloseDevice(&fd);
continue;
}
deviceIdRetrode = fd;
endpointRetrode = getEndpoint(devdesc);
bMaxPacketSizeRetrode = devdesc.bMaxPacketSize0;
}
}
void Retrode_ScanPads()
{
if(!retrodeSetup)
{
retrodeSetup = true;
openRetrode();
}
if (deviceIdRetrode == 0)
{
return;
}
uint8_t ATTRIBUTE_ALIGN(32) buf[bMaxPacketSizeRetrode];
if (USB_ReadIntrMsg(deviceIdRetrode, endpointRetrode, sizeof(buf), buf) != 5)
{
return;
}
// buf[0] contains the port returned
// you have to make 4 calls to get the status, even if you are only interested in one port
// because it is not sure which port is returned first
// 1 = left SNES
// 2 = right SNES
// 3 = left Genesis/MD
// 4 = right Genesis/MD
// Retrode gamepad endpoint returns 5 bytes with gamepad events
u32 jp12 = 0;
jp12 |= ((buf[2] & 0x9C) == 0x9C) ? PAD_BUTTON_UP : 0;
jp12 |= ((buf[2] & 0x64) == 0x64) ? PAD_BUTTON_DOWN : 0;
jp12 |= ((buf[1] & 0x9C) == 0x9C) ? PAD_BUTTON_LEFT : 0;
jp12 |= ((buf[1] & 0x64) == 0x64) ? PAD_BUTTON_RIGHT : 0;
jp12 |= (buf[3] & 0x10) ? PAD_BUTTON_A : 0;
jp12 |= (buf[3] & 0x01) ? PAD_BUTTON_B : 0;
jp12 |= (buf[3] & 0x20) ? PAD_BUTTON_X : 0;
jp12 |= (buf[3] & 0x02) ? PAD_BUTTON_Y : 0;
jp12 |= (buf[3] & 0x40) ? PAD_TRIGGER_L : 0;
jp12 |= (buf[3] & 0x80) ? PAD_TRIGGER_R : 0;
jp12 |= (buf[3] & 0x08) ? PAD_BUTTON_START : 0;
jp12 |= (buf[3] & 0x04) ? PAD_TRIGGER_Z : 0; // SNES select button maps to Z
// Required, otherwise if the returned port isn't the one we are looking for, jp will be set to zero,
// and held buttons are not possible w/o saving the state.
jpRetrode[buf[0] - 1] = jp12;
}
u32 Retrode_ButtonsHeld(int chan)
{
if (deviceIdRetrode == 0)
{
return 0;
}
return jpRetrode[chan];
}
#endif

15
source/utils/retrode.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _RETRODE_H_
#define _RETRODE_H_
#ifdef __cplusplus
extern "C" {
#endif
bool Retrode_ScanPads();
u32 Retrode_ButtonsHeld(int chan);
#ifdef __cplusplus
}
#endif
#endif