From 7f19659d0618226fb4dfc795ae795f9bb32755d0 Mon Sep 17 00:00:00 2001 From: Mike Parks Date: Sat, 16 Dec 2023 11:05:02 -0800 Subject: [PATCH] Additional/mini console input modes (#643) * Initial implementation of mini console USB input modes. First mode: Neo Geo Mini * Added Sega Genesis/MD Mini input mode. * Updated MDMini enum to use value 6 * Added support for PC Engine/Turbografx 16 Mini Pad. * Implemented PS Classic input type. Astro City and Egret II Minis are WIP. * Removed leftover serial debugging lines. * Implemented Egret II Gamepad input type. * Fully implemented Astro City based on GEN/MD similarities assumption. Redefined platform button mask defines to better align with platform button layout instead of user controller. * Fixed issue with Select and Start being reversed on PS Classic mode * Added display labels for minicon modes * Original Xbox controller implementation based on xid_driver from Ryzee119/ogx360_t4 * Added "OGXBOX" label to Display status * Fixed descriptor header dependencies causing builds to fail * Included license to xid_driver --- headers/gamepad.h | 15 + headers/gamepad/GamepadDescriptors.h | 139 +++++++ headers/gamepad/GamepadState.h | 28 ++ .../gamepad/descriptors/AstroDescriptors.h | 187 ++++++++++ .../gamepad/descriptors/EgretDescriptors.h | 166 +++++++++ .../gamepad/descriptors/MDMiniDescriptors.h | 178 +++++++++ .../gamepad/descriptors/NeogeoDescriptors.h | 265 +++++++++++++ .../gamepad/descriptors/PCEngineDescriptors.h | 187 ++++++++++ .../descriptors/PSClassicDescriptors.h | 147 ++++++++ .../descriptors/XboxOriginalDescriptors.h | 23 ++ headers/gp2040.h | 9 +- lib/TinyUSB_Gamepad/CMakeLists.txt | 6 + lib/TinyUSB_Gamepad/src/hid_driver.h | 6 + lib/TinyUSB_Gamepad/src/tusb_driver.cpp | 59 ++- lib/TinyUSB_Gamepad/src/usb_descriptors.cpp | 61 ++- lib/TinyUSB_Gamepad/src/xid_driver/LICENSE | 21 ++ lib/TinyUSB_Gamepad/src/xid_driver/xid.c | 257 +++++++++++++ lib/TinyUSB_Gamepad/src/xid_driver/xid.h | 53 +++ .../src/xid_driver/xid_driver.c | 6 + .../src/xid_driver/xid_driver.h | 87 +++++ .../src/xid_driver/xid_gamepad.c | 33 ++ .../src/xid_driver/xid_gamepad.h | 94 +++++ .../src/xid_driver/xid_remote.c | 47 +++ .../src/xid_driver/xid_remote.h | 77 ++++ .../src/xid_driver/xid_steelbattalion.c | 33 ++ .../src/xid_driver/xid_steelbattalion.h | 155 ++++++++ proto/enums.proto | 7 + src/addons/i2cdisplay.cpp | 7 + src/gamepad.cpp | 349 +++++++++++++++++- src/gamepad/GamepadDescriptors.cpp | 139 +++++++ src/gp2040.cpp | 36 ++ www/src/Locales/en/SettingsPage.jsx | 9 +- www/src/Pages/SettingsPage.jsx | 14 + 33 files changed, 2895 insertions(+), 5 deletions(-) create mode 100644 headers/gamepad/descriptors/AstroDescriptors.h create mode 100644 headers/gamepad/descriptors/EgretDescriptors.h create mode 100644 headers/gamepad/descriptors/MDMiniDescriptors.h create mode 100644 headers/gamepad/descriptors/NeogeoDescriptors.h create mode 100644 headers/gamepad/descriptors/PCEngineDescriptors.h create mode 100644 headers/gamepad/descriptors/PSClassicDescriptors.h create mode 100644 headers/gamepad/descriptors/XboxOriginalDescriptors.h create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/LICENSE create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid.c create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid.h create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.c create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.h create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.c create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.h create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.c create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.h create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.c create mode 100644 lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.h diff --git a/headers/gamepad.h b/headers/gamepad.h index 4c19b2fc3..6393f1c6d 100644 --- a/headers/gamepad.h +++ b/headers/gamepad.h @@ -13,6 +13,13 @@ #include "gamepad/descriptors/XInputDescriptors.h" #include "gamepad/descriptors/KeyboardDescriptors.h" #include "gamepad/descriptors/PS4Descriptors.h" +#include "gamepad/descriptors/NeogeoDescriptors.h" +#include "gamepad/descriptors/MDMiniDescriptors.h" +#include "gamepad/descriptors/PCEngineDescriptors.h" +#include "gamepad/descriptors/EgretDescriptors.h" +#include "gamepad/descriptors/AstroDescriptors.h" +#include "gamepad/descriptors/PSClassicDescriptors.h" +#include "gamepad/descriptors/XboxOriginalDescriptors.h" #include "pico/stdlib.h" @@ -72,6 +79,13 @@ class Gamepad { XInputReport *getXInputReport(); KeyboardReport *getKeyboardReport(); PS4Report *getPS4Report(); + NeogeoReport *getNeogeoReport(); + MDMiniReport *getMDMiniReport(); + PCEngineReport *getPCEngineReport(); + EgretReport *getEgretReport(); + AstroReport *getAstroReport(); + PSClassicReport *getPSClassicReport(); + XboxOriginalReport *getXboxOriginalReport(); /** * @brief Check for a button press. Used by `pressed[Button]` helper methods. @@ -163,6 +177,7 @@ class Gamepad { return (options.socdMode == SOCD_MODE_BYPASS && (options.inputMode == INPUT_MODE_HID || options.inputMode == INPUT_MODE_SWITCH || + options.inputMode == INPUT_MODE_NEOGEO || options.inputMode == INPUT_MODE_PS4)) ? SOCD_MODE_NEUTRAL : options.socdMode; }; diff --git a/headers/gamepad/GamepadDescriptors.h b/headers/gamepad/GamepadDescriptors.h index 944b3faa6..454f6559a 100644 --- a/headers/gamepad/GamepadDescriptors.h +++ b/headers/gamepad/GamepadDescriptors.h @@ -12,6 +12,13 @@ #include "descriptors/XInputDescriptors.h" #include "descriptors/KeyboardDescriptors.h" #include "descriptors/PS4Descriptors.h" +#include "descriptors/NeogeoDescriptors.h" +#include "descriptors/MDMiniDescriptors.h" +#include "descriptors/PCEngineDescriptors.h" +#include "descriptors/EgretDescriptors.h" +#include "descriptors/AstroDescriptors.h" +#include "descriptors/PSClassicDescriptors.h" +#include "descriptors/XboxOriginalDescriptors.h" #include "enums.pb.h" @@ -38,6 +45,34 @@ static const uint8_t *getConfigurationDescriptor(uint16_t *size, InputMode mode) *size = sizeof(ps4_configuration_descriptor); return ps4_configuration_descriptor; + case INPUT_MODE_NEOGEO: + *size = sizeof(neogeo_configuration_descriptor); + return neogeo_configuration_descriptor; + + case INPUT_MODE_MDMINI: + *size = sizeof(mdmini_configuration_descriptor); + return mdmini_configuration_descriptor; + + case INPUT_MODE_PCEMINI: + *size = sizeof(pcengine_configuration_descriptor); + return pcengine_configuration_descriptor; + + case INPUT_MODE_EGRET: + *size = sizeof(egret_configuration_descriptor); + return egret_configuration_descriptor; + + case INPUT_MODE_ASTRO: + *size = sizeof(astro_configuration_descriptor); + return astro_configuration_descriptor; + + case INPUT_MODE_PSCLASSIC: + *size = sizeof(psclassic_configuration_descriptor); + return psclassic_configuration_descriptor; + + case INPUT_MODE_XBOXORIGINAL: + *size = sizeof(xboxoriginal_configuration_descriptor); + return xboxoriginal_configuration_descriptor; + default: *size = sizeof(hid_configuration_descriptor); return hid_configuration_descriptor; @@ -64,6 +99,34 @@ static const uint8_t *getDeviceDescriptor(uint16_t *size, InputMode mode) *size = sizeof(ps4_device_descriptor); return ps4_device_descriptor; + case INPUT_MODE_NEOGEO: + *size = sizeof(neogeo_device_descriptor); + return neogeo_device_descriptor; + + case INPUT_MODE_MDMINI: + *size = sizeof(mdmini_device_descriptor); + return mdmini_device_descriptor; + + case INPUT_MODE_PCEMINI: + *size = sizeof(pcengine_device_descriptor); + return pcengine_device_descriptor; + + case INPUT_MODE_EGRET: + *size = sizeof(egret_device_descriptor); + return egret_device_descriptor; + + case INPUT_MODE_ASTRO: + *size = sizeof(astro_device_descriptor); + return astro_device_descriptor; + + case INPUT_MODE_PSCLASSIC: + *size = sizeof(psclassic_device_descriptor); + return psclassic_device_descriptor; + + case INPUT_MODE_XBOXORIGINAL: + *size = sizeof(xboxoriginal_device_descriptor); + return xboxoriginal_device_descriptor; + default: *size = sizeof(hid_device_descriptor); return hid_device_descriptor; @@ -86,6 +149,30 @@ static const uint8_t *getHIDDescriptor(uint16_t *size, InputMode mode) *size = sizeof(ps4_hid_descriptor); return ps4_hid_descriptor; + case INPUT_MODE_NEOGEO: + *size = sizeof(neogeo_hid_descriptor); + return neogeo_hid_descriptor; + + case INPUT_MODE_MDMINI: + *size = sizeof(mdmini_hid_descriptor); + return mdmini_hid_descriptor; + + case INPUT_MODE_PCEMINI: + *size = sizeof(pcengine_hid_descriptor); + return pcengine_hid_descriptor; + + case INPUT_MODE_EGRET: + *size = sizeof(egret_hid_descriptor); + return egret_hid_descriptor; + + case INPUT_MODE_ASTRO: + *size = sizeof(astro_hid_descriptor); + return astro_hid_descriptor; + + case INPUT_MODE_PSCLASSIC: + *size = sizeof(psclassic_hid_descriptor); + return psclassic_hid_descriptor; + default: *size = sizeof(hid_hid_descriptor); return hid_hid_descriptor; @@ -108,6 +195,30 @@ static const uint8_t *getHIDReport(uint16_t *size, InputMode mode) *size = sizeof(ps4_report_descriptor); return ps4_report_descriptor; + case INPUT_MODE_NEOGEO: + *size = sizeof(neogeo_report_descriptor); + return neogeo_report_descriptor; + + case INPUT_MODE_MDMINI: + *size = sizeof(mdmini_report_descriptor); + return mdmini_report_descriptor; + + case INPUT_MODE_PCEMINI: + *size = sizeof(pcengine_report_descriptor); + return pcengine_report_descriptor; + + case INPUT_MODE_EGRET: + *size = sizeof(egret_report_descriptor); + return egret_report_descriptor; + + case INPUT_MODE_ASTRO: + *size = sizeof(astro_report_descriptor); + return astro_report_descriptor; + + case INPUT_MODE_PSCLASSIC: + *size = sizeof(psclassic_report_descriptor); + return psclassic_report_descriptor; + default: *size = sizeof(hid_report_descriptor); return hid_report_descriptor; @@ -171,6 +282,34 @@ static const uint16_t *getStringDescriptor(uint16_t *size, InputMode mode, uint8 str = (char *)ps4_string_descriptors[index]; break; + case INPUT_MODE_NEOGEO: + str = (char *)neogeo_string_descriptors[index]; + break; + + case INPUT_MODE_MDMINI: + str = (char *)mdmini_string_descriptors[index]; + break; + + case INPUT_MODE_PCEMINI: + str = (char *)pcengine_string_descriptors[index]; + break; + + case INPUT_MODE_EGRET: + str = (char *)egret_string_descriptors[index]; + break; + + case INPUT_MODE_ASTRO: + str = (char *)astro_string_descriptors[index]; + break; + + case INPUT_MODE_PSCLASSIC: + str = (char *)psclassic_string_descriptors[index]; + break; + + case INPUT_MODE_XBOXORIGINAL: + str = (char *)xboxoriginal_string_descriptors[index]; + break; + default: str = (char *)hid_string_descriptors[index]; break; diff --git a/headers/gamepad/GamepadState.h b/headers/gamepad/GamepadState.h index 69fdcd5ee..bfd0a56ae 100644 --- a/headers/gamepad/GamepadState.h +++ b/headers/gamepad/GamepadState.h @@ -15,6 +15,13 @@ using namespace std; #include "gamepad/descriptors/SwitchDescriptors.h" #include "gamepad/descriptors/XInputDescriptors.h" #include "gamepad/descriptors/PS4Descriptors.h" +#include "gamepad/descriptors/NeogeoDescriptors.h" +#include "gamepad/descriptors/MDMiniDescriptors.h" +#include "gamepad/descriptors/PCEngineDescriptors.h" +#include "gamepad/descriptors/EgretDescriptors.h" +#include "gamepad/descriptors/AstroDescriptors.h" +#include "gamepad/descriptors/PSClassicDescriptors.h" +#include "gamepad/descriptors/XboxOriginalDescriptors.h" #define GAMEPAD_BUTTON_COUNT 14 @@ -148,6 +155,27 @@ inline uint16_t GetJoystickMidValue(uint8_t mode) { case INPUT_MODE_PS4: return PS4_JOYSTICK_MID << 8; + case INPUT_MODE_NEOGEO: + return NEOGEO_JOYSTICK_MID << 8; + + case INPUT_MODE_MDMINI: + return GAMEPAD_JOYSTICK_MID; + + case INPUT_MODE_PCEMINI: + return GAMEPAD_JOYSTICK_MID; + + case INPUT_MODE_EGRET: + return GAMEPAD_JOYSTICK_MID; + + case INPUT_MODE_ASTRO: + return GAMEPAD_JOYSTICK_MID; + + case INPUT_MODE_PSCLASSIC: + return GAMEPAD_JOYSTICK_MID; + + case INPUT_MODE_XBOXORIGINAL: + return GAMEPAD_JOYSTICK_MID; + default: return GAMEPAD_JOYSTICK_MID; } diff --git a/headers/gamepad/descriptors/AstroDescriptors.h b/headers/gamepad/descriptors/AstroDescriptors.h new file mode 100644 index 000000000..34db54c53 --- /dev/null +++ b/headers/gamepad/descriptors/AstroDescriptors.h @@ -0,0 +1,187 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) + */ + +#pragma once + +#include + +#define ASTRO_ENDPOINT_SIZE 64 + +// HAT report (4 bits) +#define ASTRO_HAT_UP 0x00 +#define ASTRO_HAT_UPRIGHT 0x01 +#define ASTRO_HAT_RIGHT 0x02 +#define ASTRO_HAT_DOWNRIGHT 0x03 +#define ASTRO_HAT_DOWN 0x04 +#define ASTRO_HAT_DOWNLEFT 0x05 +#define ASTRO_HAT_LEFT 0x06 +#define ASTRO_HAT_UPLEFT 0x07 +#define ASTRO_HAT_NOTHING 0x08 + +// Buttons (16 bits) +#define ASTRO_MASK_A 0x0080 +#define ASTRO_MASK_B 0x0010 +#define ASTRO_MASK_C 0x0100 +#define ASTRO_MASK_D 0x0040 +#define ASTRO_MASK_E 0x0020 +#define ASTRO_MASK_F 0x0200 +#define ASTRO_MASK_CREDIT 0x1000 +#define ASTRO_MASK_START 0x2000 + +// Switch analog sticks only report 8 bits +#define ASTRO_JOYSTICK_MIN 0x00 +//#define ASTRO_JOYSTICK_MID 0x80 +#define ASTRO_JOYSTICK_MID 0x7F +#define ASTRO_JOYSTICK_MAX 0xFF + +typedef struct __attribute((packed, aligned(1))) +{ + uint8_t id; + uint8_t notuse1; + uint8_t notuse2; + uint8_t lx; + uint8_t ly; + uint16_t buttons; + uint8_t notuse3; +} AstroReport; + +static const uint8_t astro_string_language[] = { 0x09, 0x04 }; +static const uint8_t astro_string_manufacturer[] = ""; +static const uint8_t astro_string_product[] = "6B Controller"; +static const uint8_t astro_string_version[] = "1.0"; + +static const uint8_t *astro_string_descriptors[] __attribute__((unused)) = +{ + astro_string_language, + astro_string_manufacturer, + astro_string_product, + astro_string_version +}; + +static const uint8_t astro_device_descriptor[] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0x00, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + 0xA3, 0x0C, // idVendor 0x0CA3 "Sega Corp." + 0x27, 0x00, // idProduct 0x0027 + 0x07, 0x02, // bcdDevice + 0x00, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +static const uint8_t astro_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x65, 0x00, // wDescriptorLength[0] 101 +}; + +static const uint8_t astro_configuration_descriptor[] = +{ + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x29, 0x00, // wTotalLength 41 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0x80, // bmAttributes + 0x32, // bMaxPower 100mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x65, 0x00, // wDescriptorLength[0] 101 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x02, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x0A, // bInterval 10 (unit depends on device speed) + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x0A, // bInterval 10 (unit depends on device speed) +}; + +static const uint8_t astro_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x30, // Usage (X) + 0x09, 0x30, // Usage (X) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x00, // Usage (Undefined) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0A, // Report Count (10) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0A, // Usage Maximum (0x0A) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0A, // Report Count (10) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x09, 0x02, // Usage (0x02) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection +}; \ No newline at end of file diff --git a/headers/gamepad/descriptors/EgretDescriptors.h b/headers/gamepad/descriptors/EgretDescriptors.h new file mode 100644 index 000000000..78f152ff1 --- /dev/null +++ b/headers/gamepad/descriptors/EgretDescriptors.h @@ -0,0 +1,166 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) + */ + +#pragma once + +#include + +#define EGRET_ENDPOINT_SIZE 64 + +// HAT report (4 bits) +#define EGRET_HAT_UP 0x00 +#define EGRET_HAT_UPRIGHT 0x01 +#define EGRET_HAT_RIGHT 0x02 +#define EGRET_HAT_DOWNRIGHT 0x03 +#define EGRET_HAT_DOWN 0x04 +#define EGRET_HAT_DOWNLEFT 0x05 +#define EGRET_HAT_LEFT 0x06 +#define EGRET_HAT_UPLEFT 0x07 +#define EGRET_HAT_NOTHING 0x08 + +// Button report (16 bits) +#define EGRET_MASK_A (1U << 4) +#define EGRET_MASK_B (1U << 2) +#define EGRET_MASK_C (1U << 1) +#define EGRET_MASK_D (1U << 8) +#define EGRET_MASK_E (1U << 3) +#define EGRET_MASK_F (1U << 0) +#define EGRET_MASK_START (1U << 6) +#define EGRET_MASK_CREDIT (1U << 7) +#define EGRET_MASK_MENU (1U << 9) + +// Switch analog sticks only report 8 bits +#define EGRET_JOYSTICK_MIN 0x00 +//#define EGRET_JOYSTICK_MID 0x80 +#define EGRET_JOYSTICK_MID 0x7F +#define EGRET_JOYSTICK_MAX 0xFF + +typedef struct __attribute((packed, aligned(1))) +{ + uint16_t buttons; + uint8_t lx; + uint8_t ly; +} EgretReport; + +typedef struct +{ + uint16_t buttons; + uint8_t lx; + uint8_t ly; +} EgretOutReport; + +static const uint8_t egret_string_language[] = { 0x09, 0x04 }; +static const uint8_t egret_string_manufacturer[] = ""; +static const uint8_t egret_string_product[] = "TAITO USB Control Pad"; +static const uint8_t egret_string_version[] = "1.0"; + +static const uint8_t *egret_string_descriptors[] __attribute__((unused)) = +{ + egret_string_language, + egret_string_manufacturer, + egret_string_product, + egret_string_version +}; + +static const uint8_t egret_device_descriptor[] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0x00, // bDeviceClass (Use class information in the Interface Descriptors) + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + 0xE4, 0x0A, // idVendor 0x0AE4 + 0x02, 0x07, // idProduct 0x0702 + 0x01, 0x00, // bcdDevice 0.01 + 0x00, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +static const uint8_t egret_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x31, 0x00, // wDescriptorLength[0] 49 +}; + +static const uint8_t egret_configuration_descriptor[] = +{ + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x29, 0x00, // wTotalLength 41 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0x80, // bmAttributes + 0xFA, // bMaxPower 500mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x31, 0x00, // wDescriptorLength[0] 49 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x02, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x0A, // bInterval 10 (unit depends on device speed) + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x0A, // bInterval 10 (unit depends on device speed) +}; + +static const uint8_t egret_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0C, // Usage Maximum (0x0C) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x04, // Report Count (4) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x75, 0x08, // Report Size (8) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection +}; \ No newline at end of file diff --git a/headers/gamepad/descriptors/MDMiniDescriptors.h b/headers/gamepad/descriptors/MDMiniDescriptors.h new file mode 100644 index 000000000..fe8c38c8f --- /dev/null +++ b/headers/gamepad/descriptors/MDMiniDescriptors.h @@ -0,0 +1,178 @@ +/*. + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2022 Ann(@alirin222) + */ + +#pragma once + +#include + +#define MDMINI_ENDPOINT_SIZE 64 + +// HAT1 report (8 bits) +#define MDMINI_MASK_LEFT 0x00 +#define MDMINI_MASK_RIGHT 0xff + +// HAT2 report (8 bits) +#define MDMINI_MASK_UP 0x00 +#define MDMINI_MASK_DOWN 0xff + +// Buttons (16 bits) +#define MDMINI_MASK_A 0x0040 +#define MDMINI_MASK_B 0x0020 +#define MDMINI_MASK_C 0x0200 +#define MDMINI_MASK_X 0x0080 +#define MDMINI_MASK_Y 0x0010 +#define MDMINI_MASK_Z 0x0100 +#define MDMINI_MASK_MODE 0x1000 +#define MDMINI_MASK_START 0x2000 + +typedef struct __attribute((packed, aligned(1))) +{ + uint8_t id; + uint8_t notuse1; + uint8_t notuse2; + uint8_t lx; + uint8_t ly; + uint16_t buttons; + uint8_t notuse3; +} MDMiniReport; + +static const uint8_t mdmini_string_language[] = { 0x09, 0x04 }; +static const uint8_t mdmini_string_manfacturer[] = "SEGA CORP."; +static const uint8_t mdmini_string_product[] = "MEGA DRIVE mini GAMEPAD"; +static const uint8_t mdmini_string_version[] = "1.0"; + +static const uint8_t *mdmini_string_descriptors[] __attribute__((unused)) = +{ + mdmini_string_language, + mdmini_string_manfacturer, + mdmini_string_product, + mdmini_string_version +}; + +static const uint8_t mdmini_device_descriptor[] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0x00, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + 0xA3, 0x0C, // idVendor 0x0CA3 "Sega Corp." + 0x24, 0x00, // idProduct 0x0024 + 0x07, 0x02, // bcdDevice + 0x00, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +static const uint8_t mdmini_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x65, 0x00, // wDescriptorLength[0] 101 +}; + +static const uint8_t mdmini_configuration_descriptor[] = +{ + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x29, 0x00, // wTotalLength 41 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0x80, // bmAttributes + 0x32, // bMaxPower 100mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x65, 0x00, // wDescriptorLength[0] 101 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x02, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x0A, // bInterval 10 (unit depends on device speed) + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x0A, // bInterval 10 (unit depends on device speed) +}; + +static const uint8_t mdmini_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x30, // Usage (X) + 0x09, 0x30, // Usage (X) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x00, // Usage (Undefined) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0A, // Report Count (10) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0A, // Usage Maximum (0x0A) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0A, // Report Count (10) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x09, 0x02, // Usage (0x02) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection +}; \ No newline at end of file diff --git a/headers/gamepad/descriptors/NeogeoDescriptors.h b/headers/gamepad/descriptors/NeogeoDescriptors.h new file mode 100644 index 000000000..c82ccd5a2 --- /dev/null +++ b/headers/gamepad/descriptors/NeogeoDescriptors.h @@ -0,0 +1,265 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) + */ + +#pragma once + +#include + +#define NEOGEO_ENDPOINT_SIZE 64 + +// HAT report (4 bits) +#define NEOGEO_HAT_UP 0x00 +#define NEOGEO_HAT_UPRIGHT 0x01 +#define NEOGEO_HAT_RIGHT 0x02 +#define NEOGEO_HAT_DOWNRIGHT 0x03 +#define NEOGEO_HAT_DOWN 0x04 +#define NEOGEO_HAT_DOWNLEFT 0x05 +#define NEOGEO_HAT_LEFT 0x06 +#define NEOGEO_HAT_UPLEFT 0x07 +#define NEOGEO_HAT_NOTHING 0x0f + +// Button report (16 bits) +#define NEOGEO_MASK_A (1U << 0) +#define NEOGEO_MASK_B (1U << 1) +#define NEOGEO_MASK_C (1U << 3) +#define NEOGEO_MASK_D (1U << 4) +#define NEOGEO_MASK_SELECT (1U << 11) +#define NEOGEO_MASK_START (1U << 10) + +#define NEOGEO_JOYSTICK_MID 0x7f + +typedef struct __attribute((packed, aligned(1))) +{ + uint16_t buttons; + uint8_t hat; + uint8_t const0; + uint8_t const1; + uint8_t const2; + uint8_t const3; + uint8_t const4; + uint8_t const5; + uint8_t const6; + uint8_t const7; + uint8_t const8; + uint8_t const9; + uint8_t const10; + uint8_t const11; + uint8_t const12; + uint8_t const13; + uint8_t const14; + uint8_t const15; + uint8_t const16; + uint8_t const17; +} NeogeoReport; + +typedef struct +{ + uint16_t buttons; + uint8_t hat; + uint8_t const0; + uint8_t const1; + uint8_t const2; + uint8_t const3; + uint8_t const4; + uint8_t const5; + uint8_t const6; + uint8_t const7; + uint8_t const8; + uint8_t const9; + uint8_t const10; + uint8_t const11; + uint8_t const12; + uint8_t const13; + uint8_t const14; + uint8_t const15; + uint8_t const16; + uint8_t const17; +} NeogeoOutReport; + +static const uint8_t neogeo_string_language[] = { 0x09, 0x04 }; +static const uint8_t neogeo_string_manufacturer[] = { 0x4a, 0x4a }; +static const uint8_t neogeo_string_product[] = { }; +static const uint8_t neogeo_string_version[] = { 0x20, 0x31, 0x2e, 0x31, 0x30 }; + +static const uint8_t *neogeo_string_descriptors[] __attribute__((unused)) = +{ + neogeo_string_language, + neogeo_string_manufacturer, + neogeo_string_product, + neogeo_string_version +}; + +static const uint8_t neogeo_device_descriptor[] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x10, 0x01, // bcdUSB 1.10 + 0x00, // bDeviceClass (Use class information in the Interface Descriptors) + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + 0xBC, 0x20, // idVendor 0x20BC + 0x00, 0x55, // idProduct 0x5500 + 0x00, 0x02, // bcdDevice 4.00 + 0x01, // iManufacturer (String Index) + 0x00, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +static const uint8_t neogeo_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x56, 0x00 // wDescriptorLength[0] 86 +}; + +static const uint8_t neogeo_configuration_descriptor[] = +{ + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x42, 0x00, // wTotalLength 66 + 0x02, // bNumInterfaces 2 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0x80, // bmAttributes + 0xFA, // bMaxPower 500mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x96, 0x00, // wDescriptorLength[0] 150 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x02, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x01, // bInterval 10 (unit depends on device speed) + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x01, // bInterval 10 (unit depends on device speed) + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x01, // bInterfaceNumber 1 + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints 1 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x65, 0x00, // wDescriptorLength[0] 101 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x83, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x01, // bInterval 10 (unit depends on device speed) +}; + +static const uint8_t neogeo_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0F, // Report Count (15) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0F, // Usage Maximum (0x0F) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x02, // Usage Page (Sim Ctrls) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x09, 0xC5, // Usage (Brake) + 0x09, 0xC4, // Usage (Accelerator) + 0x95, 0x02, // Report Count (2) + 0x75, 0x08, // Report Size (8) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x46, 0xFF, 0x03, // Physical Maximum (1023) + 0x09, 0x20, // Usage (0x20) + 0x09, 0x21, // Usage (0x21) + 0x09, 0x22, // Usage (0x22) + 0x09, 0x23, // Usage (0x23) + 0x09, 0x24, // Usage (0x24) + 0x09, 0x25, // Usage (0x25) + 0x75, 0x10, // Report Size (16) + 0x95, 0x06, // Report Count (6) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x08, // Usage Page (LEDs) + 0x09, 0x43, // Usage (Slow Blink On Time) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) + 0x09, 0x44, // Usage (Slow Blink Off Time) + 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) + 0x09, 0x45, // Usage (Fast Blink On Time) + 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) + 0x09, 0x46, // Usage (Fast Blink Off Time) + 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) + 0xC0, // End Collection +}; \ No newline at end of file diff --git a/headers/gamepad/descriptors/PCEngineDescriptors.h b/headers/gamepad/descriptors/PCEngineDescriptors.h new file mode 100644 index 000000000..a2ca80253 --- /dev/null +++ b/headers/gamepad/descriptors/PCEngineDescriptors.h @@ -0,0 +1,187 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) + */ + +#pragma once + +#include + +#define PCENGINE_ENDPOINT_SIZE 64 + +// HAT report (4 bits) +#define PCENGINE_HAT_UP 0x00 +#define PCENGINE_HAT_UPRIGHT 0x01 +#define PCENGINE_HAT_RIGHT 0x02 +#define PCENGINE_HAT_DOWNRIGHT 0x03 +#define PCENGINE_HAT_DOWN 0x04 +#define PCENGINE_HAT_DOWNLEFT 0x05 +#define PCENGINE_HAT_LEFT 0x06 +#define PCENGINE_HAT_UPLEFT 0x07 +#define PCENGINE_HAT_NOTHING 0x0f + +// Button report (16 bits) +#define PCENGINE_MASK_1 (1U << 1) +#define PCENGINE_MASK_2 (1U << 2) +#define PCENGINE_MASK_SELECT (1U << 8) +#define PCENGINE_MASK_RUN (1U << 9) + + +#define PCENGINE_JOYSTICK_MID 0x7f + +typedef struct __attribute((packed, aligned(1))) +{ + uint16_t buttons; + uint8_t hat; + uint8_t const0; + uint8_t const1; + uint8_t const2; + uint8_t const3; + uint8_t const4; +} PCEngineReport; + +typedef struct +{ + uint16_t buttons; + uint8_t hat; + uint8_t const0; + uint8_t const1; + uint8_t const2; + uint8_t const3; + uint8_t const4; +} PCEngineOutReport; + +static const uint8_t pcengine_string_language[] = { 0x09, 0x04 }; +static const uint8_t pcengine_string_manufacturer[] = "HORI CO.,LTD."; +static const uint8_t pcengine_string_product[] = "PCEngine PAD"; +static const uint8_t pcengine_string_version[] = "1.0"; + +static const uint8_t *pcengine_string_descriptors[] __attribute__((unused)) = +{ + pcengine_string_language, + pcengine_string_manufacturer, + pcengine_string_product, + pcengine_string_version +}; + +static const uint8_t pcengine_device_descriptor[] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0x00, // bDeviceClass (Use class information in the Interface Descriptors) + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + 0x0D, 0x0F, // idVendor 0x0F0D + 0x38, 0x01, // idProduct 0x0138 + 0x09, 0x01, // bcdDevice 2.09 + 0x01, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +static const uint8_t pcengine_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x56, 0x00 // wDescriptorLength[0] 86 +}; + +static const uint8_t pcengine_configuration_descriptor[] = +{ + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x29, 0x00, // wTotalLength 41 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0x80, // bmAttributes + 0x32, // bMaxPower 100mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x5E, 0x00, // wDescriptorLength[0] 94 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x02, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x05, // bInterval 5 (unit depends on device speed) + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x05, // bInterval 5 (unit depends on device speed) +}; + +static const uint8_t pcengine_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0E, // Report Count (14) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0E, // Usage Maximum (0x0E) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x02, // Report Count (2) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x0A, 0x4F, 0x48, // Usage (0x484F) + 0x75, 0x08, // Report Size (8) + 0x95, 0x08, // Report Count (8) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x0A, 0x4F, 0x48, // Usage (0x484F) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection +}; diff --git a/headers/gamepad/descriptors/PSClassicDescriptors.h b/headers/gamepad/descriptors/PSClassicDescriptors.h new file mode 100644 index 000000000..c84ff0a50 --- /dev/null +++ b/headers/gamepad/descriptors/PSClassicDescriptors.h @@ -0,0 +1,147 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) + */ + +#pragma once + +#include + +#define PSCLASSIC_ENDPOINT_SIZE 64 + +// Button report (16 bits) +#define PSCLASSIC_MASK_TRIANGLE (1U << 0) +#define PSCLASSIC_MASK_CIRCLE (1U << 1) +#define PSCLASSIC_MASK_CROSS (1U << 2) +#define PSCLASSIC_MASK_SQUARE (1U << 3) +#define PSCLASSIC_MASK_L2 (1U << 4) +#define PSCLASSIC_MASK_R2 (1U << 5) +#define PSCLASSIC_MASK_L1 (1U << 6) +#define PSCLASSIC_MASK_R1 (1U << 7) +#define PSCLASSIC_MASK_START (1U << 8) +#define PSCLASSIC_MASK_SELECT (1U << 9) + +#define PSCLASSIC_MASK_UP_LEFT 0x0000 +#define PSCLASSIC_MASK_UP 0x0400 +#define PSCLASSIC_MASK_UP_RIGHT 0x0800 +#define PSCLASSIC_MASK_LEFT 0x1000 +#define PSCLASSIC_MASK_CENTER 0x1400 +#define PSCLASSIC_MASK_RIGHT 0x1800 +#define PSCLASSIC_MASK_DOWN_LEFT 0x2000 +#define PSCLASSIC_MASK_DOWN 0x2400 +#define PSCLASSIC_MASK_DOWN_RIGHT 0x2800 + +#define PSCLASSIC_JOYSTICK_MID 0x7f + +typedef struct __attribute((packed, aligned(1))) +{ + uint16_t buttons; // 10 buttons (1 bit each) +} PSClassicReport; + +static const uint8_t psclassic_string_language[] = { 0x09, 0x04 }; +static const uint8_t psclassic_string_manufacturer[] = "Sony Interactive Entertainment"; +static const uint8_t psclassic_string_product[] = "Controller"; +static const uint8_t psclassic_string_version[] = { }; + +static const uint8_t *psclassic_string_descriptors[] __attribute__((unused)) = +{ + psclassic_string_language, + psclassic_string_manufacturer, + psclassic_string_product, + psclassic_string_version +}; + +static const uint8_t psclassic_device_descriptor[] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0x00, // bDeviceClass (Use class information in the Interface Descriptors) + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + 0x4C, 0x05, // idVendor 0x054C + 0xDA, 0x0C, // idProduct 0x0CDA + 0x00, 0x01, // bcdDevice 2.00 + 0x01, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +static const uint8_t psclassic_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x31, 0x00, // wDescriptorLength[0] 49 +}; + +static const uint8_t psclassic_configuration_descriptor[] = +{ + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x22, 0x00, // wTotalLength 34 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0xA0, // bmAttributes Remote Wakeup + 0x32, // bMaxPower 100mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints 1 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x31, 0x00, // wDescriptorLength[0] 49 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x0A, // bInterval 10 (unit depends on device speed) +}; + +static const uint8_t psclassic_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0A, // Report Count (10) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0A, // Usage Maximum (0x0A) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x02, // Logical Maximum (2) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x02, // Physical Maximum (2) + 0x75, 0x02, // Report Size (2) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection +}; \ No newline at end of file diff --git a/headers/gamepad/descriptors/XboxOriginalDescriptors.h b/headers/gamepad/descriptors/XboxOriginalDescriptors.h new file mode 100644 index 000000000..cf02232db --- /dev/null +++ b/headers/gamepad/descriptors/XboxOriginalDescriptors.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "xid_driver.h" + +#define XboxOriginalReport USB_XboxGamepad_InReport_t + +static const uint8_t xboxoriginal_string_language[] = { 0x09, 0x04 }; +static const uint8_t xboxoriginal_string_manufacturer[] = ""; +static const uint8_t xboxoriginal_string_product[] = ""; +static const uint8_t xboxoriginal_string_version[] = "1.0"; + +static const uint8_t *xboxoriginal_string_descriptors[] __attribute__((unused)) = +{ + xboxoriginal_string_language, + xboxoriginal_string_manufacturer, + xboxoriginal_string_product, + xboxoriginal_string_version +}; + +static const uint8_t *xboxoriginal_device_descriptor = (const uint8_t*)&XID_DESC_DEVICE; + +static const uint8_t *xboxoriginal_configuration_descriptor = (const uint8_t*)&XID_DESC_CONFIGURATION; \ No newline at end of file diff --git a/headers/gp2040.h b/headers/gp2040.h index 29bbb7a06..8661fc92c 100644 --- a/headers/gp2040.h +++ b/headers/gp2040.h @@ -47,7 +47,14 @@ class GP2040 { SET_INPUT_MODE_SWITCH, SET_INPUT_MODE_XINPUT, SET_INPUT_MODE_KEYBOARD, - SET_INPUT_MODE_PS4 + SET_INPUT_MODE_PS4, + SET_INPUT_MODE_NEOGEO, + SET_INPUT_MODE_MDMINI, + SET_INPUT_MODE_PCEMINI, + SET_INPUT_MODE_EGRET, + SET_INPUT_MODE_ASTRO, + SET_INPUT_MODE_PSCLASSIC, + SET_INPUT_MODE_XBOXORIGINAL }; BootAction getBootAction(); diff --git a/lib/TinyUSB_Gamepad/CMakeLists.txt b/lib/TinyUSB_Gamepad/CMakeLists.txt index 70be7fb9a..2f2d81fdd 100644 --- a/lib/TinyUSB_Gamepad/CMakeLists.txt +++ b/lib/TinyUSB_Gamepad/CMakeLists.txt @@ -8,10 +8,16 @@ src/tusb_driver.cpp src/usb_descriptors.cpp src/xinput_driver.cpp src/ps4_driver.cpp +src/xid_driver/xid_driver.c +src/xid_driver/xid.c +src/xid_driver/xid_gamepad.c +src/xid_driver/xid_remote.c +src/xid_driver/xid_steelbattalion.c ${PROTO_OUTPUT_DIR}/enums.pb.h ) target_include_directories(TinyUSB_Gamepad PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src +${CMAKE_CURRENT_SOURCE_DIR}/src/xid_driver ${CMAKE_SOURCE_DIR}/headers ${CMAKE_SOURCE_DIR}/lib/CRC32/src ${CMAKE_SOURCE_DIR}/lib/mbedtls/include diff --git a/lib/TinyUSB_Gamepad/src/hid_driver.h b/lib/TinyUSB_Gamepad/src/hid_driver.h index c268150c6..1486bb82b 100644 --- a/lib/TinyUSB_Gamepad/src/hid_driver.h +++ b/lib/TinyUSB_Gamepad/src/hid_driver.h @@ -8,6 +8,12 @@ #include "device/usbd_pvt.h" #include "gamepad/descriptors/HIDDescriptors.h" #include "gamepad/descriptors/SwitchDescriptors.h" +#include "gamepad/descriptors/NeogeoDescriptors.h" +#include "gamepad/descriptors/MDMiniDescriptors.h" +#include "gamepad/descriptors/PCEngineDescriptors.h" +#include "gamepad/descriptors/EgretDescriptors.h" +#include "gamepad/descriptors/AstroDescriptors.h" +#include "gamepad/descriptors/PSClassicDescriptors.h" extern const usbd_class_driver_t hid_driver; diff --git a/lib/TinyUSB_Gamepad/src/tusb_driver.cpp b/lib/TinyUSB_Gamepad/src/tusb_driver.cpp index 395c19cb9..e16ed4966 100644 --- a/lib/TinyUSB_Gamepad/src/tusb_driver.cpp +++ b/lib/TinyUSB_Gamepad/src/tusb_driver.cpp @@ -17,6 +17,7 @@ #include "hid_driver.h" #include "xinput_driver.h" #include "ps4_driver.h" +#include "xid_driver/xid_driver.h" UsbMode usb_mode = USB_MODE_HID; InputMode input_mode = INPUT_MODE_XINPUT; @@ -60,6 +61,11 @@ bool send_report(void *report, uint16_t report_size) { static uint8_t previous_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + uint8_t xIndex = 0; + if (input_mode == INPUT_MODE_XBOXORIGINAL) { + xIndex = xid_get_index_by_type(0, XID_TYPE_GAMECONTROLLER); + } + bool sent = false; if (tud_suspended()) @@ -69,13 +75,15 @@ bool send_report(void *report, uint16_t report_size) { switch (input_mode) { + case INPUT_MODE_XBOXORIGINAL: + sent = xid_send_report(xIndex, report, report_size); + break; case INPUT_MODE_XINPUT: sent = send_xinput_report(report, report_size); break; case INPUT_MODE_KEYBOARD: sent = send_keyboard_report(report); break; - default: sent = send_hid_report(0, report, report_size); break; @@ -108,6 +116,9 @@ const usbd_class_driver_t *usbd_app_driver_get_cb(uint8_t *driver_count) case INPUT_MODE_PS4: return &ps4_driver; + case INPUT_MODE_XBOXORIGINAL: + return xid_get_driver(); + default: return &hid_driver; } @@ -129,12 +140,42 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t HIDReport hid_report; KeyboardReport keyboard_report; PS4Report ps4_report; + NeogeoReport neogeo_report; + MDMiniReport mdmini_report; + PCEngineReport pcengine_report; + EgretReport egret_report; + AstroReport astro_report; + PSClassicReport psclassic_report; switch (input_mode) { case INPUT_MODE_SWITCH: report_size = sizeof(SwitchReport); memcpy(buffer, &switch_report, report_size); break; + case INPUT_MODE_NEOGEO: + report_size = sizeof(NeogeoReport); + memcpy(buffer, &neogeo_report, report_size); + break; + case INPUT_MODE_MDMINI: + report_size = sizeof(MDMiniReport); + memcpy(buffer, &mdmini_report, report_size); + break; + case INPUT_MODE_PCEMINI: + report_size = sizeof(PCEngineReport); + memcpy(buffer, &pcengine_report, report_size); + break; + case INPUT_MODE_EGRET: + report_size = sizeof(EgretReport); + memcpy(buffer, &egret_report, report_size); + break; + case INPUT_MODE_ASTRO: + report_size = sizeof(AstroReport); + memcpy(buffer, &astro_report, report_size); + break; + case INPUT_MODE_PSCLASSIC: + report_size = sizeof(PSClassicReport); + memcpy(buffer, &psclassic_report, report_size); + break; case INPUT_MODE_KEYBOARD: report_size = report_id == KEYBOARD_KEY_REPORT_ID ? sizeof(KeyboardReport::keycode) : sizeof(KeyboardReport::multimedia); memcpy(buffer, report_id == KEYBOARD_KEY_REPORT_ID ? @@ -205,3 +246,19 @@ void tud_resume_cb(void) { usb_suspended = false; } + +// Vendor Controlled XFER occured +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request) +{ + bool ret = false; + switch (input_mode) + { + case INPUT_MODE_XBOXORIGINAL: + ret |= xid_get_driver()->control_xfer_cb(rhport, stage, request); + break; + default: + break; + } + return ret; +} diff --git a/lib/TinyUSB_Gamepad/src/usb_descriptors.cpp b/lib/TinyUSB_Gamepad/src/usb_descriptors.cpp index 979d431ea..ed254be64 100644 --- a/lib/TinyUSB_Gamepad/src/usb_descriptors.cpp +++ b/lib/TinyUSB_Gamepad/src/usb_descriptors.cpp @@ -48,6 +48,27 @@ uint8_t const *tud_descriptor_device_cb(void) case INPUT_MODE_KEYBOARD: return keyboard_device_descriptor; + case INPUT_MODE_NEOGEO: + return neogeo_device_descriptor; + + case INPUT_MODE_MDMINI: + return mdmini_device_descriptor; + + case INPUT_MODE_PCEMINI: + return pcengine_device_descriptor; + + case INPUT_MODE_EGRET: + return egret_device_descriptor; + + case INPUT_MODE_ASTRO: + return astro_device_descriptor; + + case INPUT_MODE_PSCLASSIC: + return psclassic_device_descriptor; + + case INPUT_MODE_XBOXORIGINAL: + return xboxoriginal_device_descriptor; + default: return hid_device_descriptor; } @@ -67,10 +88,27 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) case INPUT_MODE_PS4: return ps4_report_descriptor; - case INPUT_MODE_KEYBOARD: return keyboard_report_descriptor; + case INPUT_MODE_NEOGEO: + return neogeo_report_descriptor; + + case INPUT_MODE_MDMINI: + return mdmini_report_descriptor; + + case INPUT_MODE_PCEMINI: + return pcengine_report_descriptor; + + case INPUT_MODE_EGRET: + return egret_report_descriptor; + + case INPUT_MODE_ASTRO: + return astro_report_descriptor; + + case INPUT_MODE_PSCLASSIC: + return psclassic_report_descriptor; + default: return hid_report_descriptor; } @@ -98,6 +136,27 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index) case INPUT_MODE_KEYBOARD: return keyboard_configuration_descriptor; + case INPUT_MODE_NEOGEO: + return neogeo_configuration_descriptor; + + case INPUT_MODE_MDMINI: + return mdmini_configuration_descriptor; + + case INPUT_MODE_PCEMINI: + return pcengine_configuration_descriptor; + + case INPUT_MODE_EGRET: + return egret_configuration_descriptor; + + case INPUT_MODE_ASTRO: + return astro_configuration_descriptor; + + case INPUT_MODE_PSCLASSIC: + return psclassic_configuration_descriptor; + + case INPUT_MODE_XBOXORIGINAL: + return xboxoriginal_configuration_descriptor; + default: return hid_configuration_descriptor; } diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/LICENSE b/lib/TinyUSB_Gamepad/src/xid_driver/LICENSE new file mode 100644 index 000000000..938ce3a14 --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Ryzee119 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid.c b/lib/TinyUSB_Gamepad/src/xid_driver/xid.c new file mode 100644 index 000000000..f26c9861f --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid.c @@ -0,0 +1,257 @@ +#include "xid.h" + +bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid); +bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid); +bool xremote_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid); + +#define MAX_XIDS (XID_DUKE + XID_STEELBATTALION + XID_XREMOTE) + +CFG_TUSB_MEM_SECTION static xid_interface_t _xid_itf[MAX_XIDS]; + +static inline int8_t get_index_by_itfnum(uint8_t itf_num) +{ + for (uint8_t i = 0; i < MAX_XIDS; i++) + { + if (itf_num == _xid_itf[i].itf_num) + return i; + //Xremote has two interfaces. Handle is separately. + if (_xid_itf[i].type == XID_TYPE_XREMOTE) + { + if (itf_num == _xid_itf[i].itf_num + 1) + return i; + } + } + return -1; +} + +static inline int8_t get_index_by_ep_addr(uint8_t ep_addr) +{ + for (uint8_t i = 0; i < MAX_XIDS; i++) + { + if (ep_addr == _xid_itf[i].ep_in) + return i; + + if (ep_addr == _xid_itf[i].ep_out) + return i; + } + return -1; +} + +static inline xid_interface_t *find_available_interface() +{ + for (uint8_t i = 0; i < MAX_XIDS; i++) + { + if (_xid_itf[i].ep_in == 0) + return &_xid_itf[i]; + } + return NULL; +} + +static void xid_init(void) +{ + + //#define MAX_XIDS (XID_DUKE + XID_STEELBATTALION + XID_XREMOTE) + tu_memclr(_xid_itf, sizeof(_xid_itf)); + for (uint8_t i = 0; i < MAX_XIDS; i++) + { + _xid_itf[i].type = (i < (XID_DUKE)) ? XID_TYPE_GAMECONTROLLER : + (i < (XID_DUKE + XID_STEELBATTALION)) ? XID_TYPE_STEELBATTALION : + (i < (XID_DUKE + XID_STEELBATTALION + XID_XREMOTE)) ? XID_TYPE_XREMOTE : 0xFF; + } +} + +static void xid_reset(uint8_t rhport) +{ + xid_init(); +} + +static uint16_t xid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +{ + TU_VERIFY(itf_desc->bInterfaceClass == XID_INTERFACE_CLASS, 0); + TU_VERIFY(itf_desc->bInterfaceSubClass == XID_INTERFACE_SUBCLASS, 0); + + xid_interface_t *p_xid = find_available_interface(); + TU_ASSERT(p_xid != NULL, 0); + + uint16_t const drv_len = (p_xid->type == XID_TYPE_GAMECONTROLLER) ? TUD_XID_DUKE_DESC_LEN : + (p_xid->type == XID_TYPE_STEELBATTALION) ? TUD_XID_SB_DESC_LEN : + (p_xid->type == XID_TYPE_XREMOTE) ? TUD_XID_XREMOTE_DESC_LEN : 0; + TU_ASSERT(max_len >= drv_len, 0); + + p_xid->itf_num = itf_desc->bInterfaceNumber; + + tusb_desc_endpoint_t *ep_desc; + ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(itf_desc); + if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT) + { + usbd_edpt_open(rhport, ep_desc); + (ep_desc->bEndpointAddress & 0x80) ? (p_xid->ep_in = ep_desc->bEndpointAddress) : + (p_xid->ep_out = ep_desc->bEndpointAddress); + } + + TU_VERIFY(itf_desc->bNumEndpoints >= 2, drv_len); + ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(ep_desc); + if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT) + { + usbd_edpt_open(rhport, ep_desc); + (ep_desc->bEndpointAddress & 0x80) ? (p_xid->ep_in = ep_desc->bEndpointAddress) : + (p_xid->ep_out = ep_desc->bEndpointAddress); + } + + return drv_len; +} + +int8_t xid_get_index_by_type(uint8_t type_index, xid_type_t type) +{ + uint8_t _type_index = 0; + for (uint8_t i = 0; i < MAX_XIDS; i++) + { + if (_xid_itf[i].type == type) + { + if (_type_index == type_index) + return i; + _type_index++; + } + } + return -1; +} + +bool xid_get_report(uint8_t index, void *report, uint16_t len) +{ + TU_VERIFY(index < MAX_XIDS, false); + TU_VERIFY(_xid_itf[index].ep_out != 0, false); + TU_VERIFY(len < XID_MAX_PACKET_SIZE, false); + + memcpy(report, _xid_itf[index].out, len); + + //Queue request on out endpoint + //Most games send to control pipe, but some send to out pipe. THPSX2 atleast + if (tud_ready() && !usbd_edpt_busy(TUD_OPT_RHPORT, _xid_itf[index].ep_out)) + { + usbd_edpt_xfer(TUD_OPT_RHPORT, _xid_itf[index].ep_out, _xid_itf[index].ep_out_buff, len); + } + return true; +} + +bool xid_send_report_ready(uint8_t index) +{ + TU_VERIFY(index < MAX_XIDS, false); + TU_VERIFY(_xid_itf[index].ep_in != 0, false); + return (tud_ready() && !usbd_edpt_busy(TUD_OPT_RHPORT, _xid_itf[index].ep_in)); +} +bool xid_send_report(uint8_t index, void *report, uint16_t len) +{ + TU_VERIFY(len < XID_MAX_PACKET_SIZE, false); + TU_VERIFY(index < MAX_XIDS, false); + TU_VERIFY(_xid_itf[index].ep_in != 0, false); + TU_VERIFY(xid_send_report_ready(index), false); + + if (tud_suspended()) + tud_remote_wakeup(); + + //Maintain a local copy of the report + memcpy(_xid_itf[index].in, report, len); + + //Send it to the host + return usbd_edpt_xfer(TUD_OPT_RHPORT, _xid_itf[index].ep_in, _xid_itf[index].in, len); +} + +static bool xid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)rhport; + uint8_t index = get_index_by_ep_addr(ep_addr); + + TU_VERIFY(result == XFER_RESULT_SUCCESS, true); + TU_VERIFY(index != -1, true); + TU_VERIFY(xferred_bytes < XID_MAX_PACKET_SIZE, true); + + if (ep_addr == _xid_itf[index].ep_out) + { + memcpy(_xid_itf[index].out, _xid_itf[index].ep_out_buff, MIN(xferred_bytes, sizeof( _xid_itf[index].ep_out_buff))); + } + + return true; +} + +bool xid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) +{ + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + uint8_t index = get_index_by_itfnum((uint8_t)request->wIndex); + TU_VERIFY(index != -1, false); + + bool ret = false; + + //Get HID Report + if (request->bmRequestType == 0xA1 && request->bRequest == 0x01 && request->wValue == 0x0100) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending HID report on control pipe for index %02x\n", request->wIndex); + tud_control_xfer(rhport, request, _xid_itf[index].in, MIN(request->wLength, sizeof(_xid_itf[index].in))); + } + return true; + } + + //Set HID Report + if (request->bmRequestType == 0x21 && request->bRequest == 0x09 && request->wValue == 0x0200 && request->wLength == 0x06) + { + if (stage == CONTROL_STAGE_SETUP) + { + //Host is sending a rumble command to control pipe. Queue receipt. + tud_control_xfer(rhport, request, _xid_itf[index].ep_out_buff, MIN(request->wLength, sizeof(_xid_itf[index].ep_out_buff))); + } + else if (stage == CONTROL_STAGE_ACK) + { + //Receipt complete. Copy data to rumble struct + TU_LOG1("Got HID report from control pipe for index %02x\n", request->wIndex); + memcpy(_xid_itf[index].out, _xid_itf[index].ep_out_buff, MIN(request->wLength, sizeof(_xid_itf[index].out))); + } + return true; + } + + switch (_xid_itf[index].type) + { + case XID_TYPE_GAMECONTROLLER: + ret = duke_control_xfer(rhport, stage, request, &_xid_itf[index]); + break; + case XID_TYPE_STEELBATTALION: + ret = steelbattalion_control_xfer(rhport, stage, request, &_xid_itf[index]); + break; + case XID_TYPE_XREMOTE: + ret = xremote_control_xfer(rhport, stage, request, &_xid_itf[index]); + break; + default: + break; + } + + if (ret == false) + { + TU_LOG1("STALL: wIndex: %02x bmRequestType: %02x, bRequest: %02x, wValue: %04x\n", + request->wIndex, + request->bmRequestType, + request->bRequest, + request->wValue); + return false; + } + + return true; +} + +static const usbd_class_driver_t xid_driver = +{ +#if CFG_TUSB_DEBUG >= 2 + .name = "XID DRIVER (DUKE,SB OR XREMOTE)", +#endif + .init = xid_init, + .reset = xid_reset, + .open = xid_open, + .control_xfer_cb = xid_control_xfer_cb, + .xfer_cb = xid_xfer_cb, + .sof = NULL +}; + +const usbd_class_driver_t *xid_get_driver() +{ + return &xid_driver; +} diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid.h b/lib/TinyUSB_Gamepad/src/xid_driver/xid.h new file mode 100644 index 000000000..94fe3d2f2 --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid.h @@ -0,0 +1,53 @@ +#ifndef XID_H_ +#define XID_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include "xid_gamepad.h" +#include "xid_remote.h" +#include "xid_steelbattalion.h" + +#define XID_DUKE 1 +#define XID_STEELBATTALION 0 +#define XID_XREMOTE 0 +#define MSC_XMU 0 + +#define XID_INTERFACE_CLASS 0x58 +#define XID_INTERFACE_SUBCLASS 0x42 +#define XID_MAX_PACKET_SIZE 32 + +typedef enum +{ + XID_TYPE_GAMECONTROLLER, + XID_TYPE_STEELBATTALION, + XID_TYPE_XREMOTE, +} xid_type_t; + +typedef struct +{ + uint8_t itf_num; + xid_type_t type; + uint8_t ep_in; + uint8_t ep_out; + CFG_TUSB_MEM_ALIGN uint8_t ep_out_buff[XID_MAX_PACKET_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t in[XID_MAX_PACKET_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t out[XID_MAX_PACKET_SIZE]; +} xid_interface_t; + +int8_t xid_get_index_by_type(uint8_t type_index, xid_type_t type); +bool xid_get_report(uint8_t index, void *report, uint16_t len); +bool xid_send_report_ready(uint8_t index); +bool xid_send_report(uint8_t index, void *report, uint16_t len); +const usbd_class_driver_t *xid_get_driver(); + +#ifdef __cplusplus +} +#endif + +#endif //XID_H_ \ No newline at end of file diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.c b/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.c new file mode 100644 index 000000000..4cdd4c34d --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.c @@ -0,0 +1,6 @@ +#include "xid.h" + +uint8_t *xremote_get_rom() +{ + return NULL; +} \ No newline at end of file diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.h b/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.h new file mode 100644 index 000000000..7d0113218 --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.h @@ -0,0 +1,87 @@ +#ifndef XID_DRIVER_H_ +#define XID_DRIVER_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include "xid.h" + +static const tusb_desc_device_t XID_DESC_DEVICE = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0110, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0x045E, + .idProduct = 0x0289, + .bcdDevice = 0x0121, + + .iManufacturer = 0x00, + .iProduct = 0x00, + .iSerialNumber = 0x00, + + .bNumConfigurations = 0x01 +}; + +enum +{ +#if (XID_DUKE >= 1) + ITF_NUM_XID_DUKE, +#endif +#if (XID_STEELBATTALION >= 1) + ITF_NUM_XID_STEELBATTALION, +#endif +#if (XID_XREMOTE >= 1) + ITF_NUM_XID_XREMOTE, + ITF_NUM_XID_XREMOTE_ROM, +#endif +#if (MSC_XMU >= 1) + ITF_NUM_MSC, +#endif + XID_ITF_NUM_TOTAL +}; + +#define XID_CONFIG_TOTAL_LEN \ + (TUD_CONFIG_DESC_LEN) + \ + (TUD_XID_DUKE_DESC_LEN * XID_DUKE) + \ + (TUD_XID_SB_DESC_LEN * XID_STEELBATTALION) + \ + (TUD_XID_XREMOTE_DESC_LEN * XID_XREMOTE) + \ + (TUD_MSC_DESC_LEN * MSC_XMU) + +static uint8_t const XID_DESC_CONFIGURATION[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, XID_ITF_NUM_TOTAL, 0, XID_CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 500), + +#if (XID_DUKE >= 1) + TUD_XID_DUKE_DESCRIPTOR(ITF_NUM_XID_DUKE, ITF_NUM_XID_DUKE + 1, 0x80 | (ITF_NUM_XID_DUKE + 1)), +#endif + +#if (XID_STEELBATTALION >= 1) + TUD_XID_SB_DESCRIPTOR(ITF_NUM_XID_STEELBATTALION, ITF_NUM_XID_STEELBATTALION + 1, 0x80 | (ITF_NUM_XID_STEELBATTALION + 1)), +#endif + +#if (XID_XREMOTE >= 1) + TUD_XID_XREMOTE_DESCRIPTOR(ITF_NUM_XID_XREMOTE, 0x80 | (ITF_NUM_XID_XREMOTE + 1)), +#endif + +#if (CFG_TUD_MSC >= 1) + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, ITF_NUM_MSC + 1, 0x80 | (ITF_NUM_MSC + 1), 64), +#endif + +}; + +#ifdef __cplusplus +} +#endif + +#endif //XID_DRIVER_H_ diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.c b/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.c new file mode 100644 index 000000000..10e27f908 --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.c @@ -0,0 +1,33 @@ +#include "xid_driver.h" + +bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid) +{ + if (request->bmRequestType == 0xC1 && request->bRequest == 0x06 && request->wValue == 0x4200) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending DUKE_DESC_XID\n"); + tud_control_xfer(rhport, request, (void *)DUKE_DESC_XID, sizeof(DUKE_DESC_XID)); + } + return true; + } + else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0100) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending DUKE_CAPABILITIES_IN\n"); + tud_control_xfer(rhport, request, (void *)DUKE_CAPABILITIES_IN, sizeof(DUKE_CAPABILITIES_IN)); + } + return true; + } + else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0200) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending DUKE_CAPABILITIES_OUT\n"); + tud_control_xfer(rhport, request, (void *)DUKE_CAPABILITIES_OUT, sizeof(DUKE_CAPABILITIES_OUT)); + } + return true; + } + return false; +} diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.h b/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.h new file mode 100644 index 000000000..3c040660d --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.h @@ -0,0 +1,94 @@ +#ifndef XID_DUKE_H_ +#define XID_DUKE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +/* Digital Button Masks */ +#define XID_DUP (1 << 0) +#define XID_DDOWN (1 << 1) +#define XID_DLEFT (1 << 2) +#define XID_DRIGHT (1 << 3) +#define XID_START (1 << 4) +#define XID_BACK (1 << 5) +#define XID_LS (1 << 6) +#define XID_RS (1 << 7) + +typedef struct __attribute__((packed)) +{ + uint8_t zero; + uint8_t bLength; + uint8_t dButtons; + uint8_t reserved; + uint8_t A; + uint8_t B; + uint8_t X; + uint8_t Y; + uint8_t BLACK; + uint8_t WHITE; + uint8_t L; + uint8_t R; + int16_t leftStickX; + int16_t leftStickY; + int16_t rightStickX; + int16_t rightStickY; +} USB_XboxGamepad_InReport_t; + +typedef struct __attribute__((packed)) +{ + uint8_t zero; + uint8_t bLength; + uint16_t lValue; + uint16_t rValue; +} USB_XboxGamepad_OutReport_t; + +#define TUD_XID_DUKE_DESC_LEN (9+7+7) + +#define TUD_XID_DUKE_DESCRIPTOR(_itfnum, _epout, _epin) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, XID_INTERFACE_CLASS, XID_INTERFACE_SUBCLASS, 0x00, 0x00,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4, \ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4 + +static const uint8_t DUKE_DESC_XID[] = { + 0x10, + 0x42, + 0x00, 0x01, + 0x01, + 0x02, + 0x14, + 0x06, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const uint8_t DUKE_CAPABILITIES_IN[] = { + 0x00, + 0x14, + 0xFF, + 0x00, + 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF +}; + +static const uint8_t DUKE_CAPABILITIES_OUT[] = { + 0x00, + 0x06, + 0xFF, 0xFF, 0xFF, 0xFF +}; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.c b/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.c new file mode 100644 index 000000000..dafbaa0d1 --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.c @@ -0,0 +1,47 @@ +#include "xid_driver.h" + +uint8_t *xremote_get_rom(); + +bool xremote_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid) +{ + if (request->bmRequestType == 0xC1 && request->bRequest == 0x06 && request->wValue == 0x4200) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending REMOTE_DESC_XID\r\n"); + tud_control_xfer(rhport, request, (void *)REMOTE_DESC_XID, sizeof(REMOTE_DESC_XID)); + } + return true; + } + //INFO PACKET (Interface 1) + else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wIndex == 1 && request->wValue == 0x0000) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending XREMOTE INFO\r\n"); + uint8_t *rom = xremote_get_rom(); + if (rom == NULL) + { + return false; //STALL + } + tud_control_xfer(rhport, request, &rom[0], request->wLength); + } + return true; + } + //ROM DATA (Interface 1) + else if (request->bmRequestType == 0xC1 && request->bRequest == 0x02 && request->wIndex == 1) + { + if (stage == CONTROL_STAGE_SETUP) + { + uint8_t *rom = xremote_get_rom(); + if (rom == NULL) + { + return false; //STALL + } + tud_control_xfer(rhport, request, &rom[request->wValue * 1024], request->wLength); + } + return true; + } + + return false; +} diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.h b/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.h new file mode 100644 index 000000000..591695df5 --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.h @@ -0,0 +1,77 @@ +#ifndef XID_REMOTE_H_ +#define XID_REMOTE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "tusb.h" + +#define XID_XREMOTE_ROM_CLASS 0x59 + +typedef enum +{ + XREMOTE_SELECT = 0x0A0B, + XREMOTE_UP = 0x0AA6, + XREMOTE_DOWN = 0x0AA7, + XREMOTE_RIGHT = 0x0AA8, + XREMOTE_LEFT = 0x0AA9, + XREMOTE_INFO = 0x0AC3, + XREMOTE_NINE = 0x0AC6, + XREMOTE_EIGHT = 0x0AC7, + XREMOTE_SEVEN = 0x0AC8, + XREMOTE_SIX = 0x0AC9, + XREMOTE_FIVE = 0x0ACA, + XREMOTE_FOUR = 0x0ACB, + XREMOTE_THREE = 0x0ACC, + XREMOTE_TWO = 0x0ACD, + XREMOTE_ONE = 0x0ACE, + XREMOTE_ZERO = 0x0ACF, + XREMOTE_DISPLAY = 0x0AD5, + XREMOTE_BACK = 0x0AD8, + XREMOTE_SKIP_MINUS = 0x0ADD, + XREMOTE_SKIP_PLUS = 0x0ADF, + XREMOTE_STOP = 0x0AE0, + XREMOTE_REVERSE = 0x0AE2, + XREMOTE_FORWARD = 0x0AE3, + XREMOTE_TITLE = 0x0AE5, + XREMOTE_PAUSE = 0x0AE6, + XREMOTE_PLAY = 0x0AEA, + XREMOTE_MENU = 0x0AF7, +} xremote_buttoncode_t; + +typedef struct __attribute__((packed)) +{ + uint8_t zero; + uint8_t bLength; + xremote_buttoncode_t buttonCode; + uint16_t timeElapsed; //ms since last button press +} USB_XboxRemote_InReport_t; + +#define TUD_XID_XREMOTE_DESC_LEN (9+7+9) + +#define TUD_XID_XREMOTE_DESCRIPTOR(_itfnum, _epin) \ + /* Interface 0 (HID DATA)*/\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, XID_INTERFACE_CLASS, XID_INTERFACE_SUBCLASS, 0x00, 0x00,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(8), 16, \ + /* Interface 1 (ROM DATA)*/\ + 9, TUSB_DESC_INTERFACE, _itfnum + 1, 0, 0, XID_XREMOTE_ROM_CLASS, 0x00, 0x00, 0x00 + +static const uint8_t REMOTE_DESC_XID[] = { + 0x08, + 0x42, + 0x00, 0x01, + 0x03, + 0x00, + 0x06, + 0x00 +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.c b/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.c new file mode 100644 index 000000000..8cea0286a --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.c @@ -0,0 +1,33 @@ +#include "xid_driver.h" + +bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid) +{ + if (request->bmRequestType == 0xC1 && request->bRequest == 0x06 && request->wValue == 0x4200) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending STEELBATTALION_DESC_XID\n"); + tud_control_xfer(rhport, request, (void *)STEELBATTALION_DESC_XID, sizeof(STEELBATTALION_DESC_XID)); + } + return true; + } + else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0100) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending STEELBATTALION_CAPABILITIES_IN\n"); + tud_control_xfer(rhport, request, (void *)STEELBATTALION_CAPABILITIES_IN, sizeof(STEELBATTALION_CAPABILITIES_IN)); + } + return true; + } + else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0200) + { + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG1("Sending STEELBATTALION_CAPABILITIES_OUT\n"); + tud_control_xfer(rhport, request, (void *)STEELBATTALION_CAPABILITIES_OUT, sizeof(STEELBATTALION_CAPABILITIES_OUT)); + } + return true; + } + return false; +} diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.h b/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.h new file mode 100644 index 000000000..f5d56641f --- /dev/null +++ b/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.h @@ -0,0 +1,155 @@ +#ifndef XID_STEELBATTALION_H_ +#define XID_STEELBATTALION_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +/* https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/master/src/core/hle/XAPI/XapiCxbxr.h */ +#define CXBX_SBC_GAMEPAD_W0_RIGHTJOYMAINWEAPON 0x0001 +#define CXBX_SBC_GAMEPAD_W0_RIGHTJOYFIRE 0x0002 +#define CXBX_SBC_GAMEPAD_W0_RIGHTJOYLOCKON 0x0004 +#define CXBX_SBC_GAMEPAD_W0_EJECT 0x0008 +#define CXBX_SBC_GAMEPAD_W0_COCKPITHATCH 0x0010 +#define CXBX_SBC_GAMEPAD_W0_IGNITION 0x0020 +#define CXBX_SBC_GAMEPAD_W0_START 0x0040 +#define CXBX_SBC_GAMEPAD_W0_MULTIMONOPENCLOSE 0x0080 +#define CXBX_SBC_GAMEPAD_W0_MULTIMONMAPZOOMINOUT 0x0100 +#define CXBX_SBC_GAMEPAD_W0_MULTIMONMODESELECT 0x0200 +#define CXBX_SBC_GAMEPAD_W0_MULTIMONSUBMONITOR 0x0400 +#define CXBX_SBC_GAMEPAD_W0_MAINMONZOOMIN 0x0800 +#define CXBX_SBC_GAMEPAD_W0_MAINMONZOOMOUT 0x1000 +#define CXBX_SBC_GAMEPAD_W0_FUNCTIONFSS 0x2000 +#define CXBX_SBC_GAMEPAD_W0_FUNCTIONMANIPULATOR 0x4000 +#define CXBX_SBC_GAMEPAD_W0_FUNCTIONLINECOLORCHANGE 0x8000 + +#define CXBX_SBC_GAMEPAD_W1_WASHING 0x0001 +#define CXBX_SBC_GAMEPAD_W1_EXTINGUISHER 0x0002 +#define CXBX_SBC_GAMEPAD_W1_CHAFF 0x0004 +#define CXBX_SBC_GAMEPAD_W1_FUNCTIONTANKDETACH 0x0008 +#define CXBX_SBC_GAMEPAD_W1_FUNCTIONOVERRIDE 0x0010 +#define CXBX_SBC_GAMEPAD_W1_FUNCTIONNIGHTSCOPE 0x0020 +#define CXBX_SBC_GAMEPAD_W1_FUNCTIONF1 0x0040 +#define CXBX_SBC_GAMEPAD_W1_FUNCTIONF2 0x0080 +#define CXBX_SBC_GAMEPAD_W1_FUNCTIONF3 0x0100 +#define CXBX_SBC_GAMEPAD_W1_WEAPONCONMAIN 0x0200 +#define CXBX_SBC_GAMEPAD_W1_WEAPONCONSUB 0x0400 +#define CXBX_SBC_GAMEPAD_W1_WEAPONCONMAGAZINE 0x0800 +#define CXBX_SBC_GAMEPAD_W1_COMM1 0x1000 +#define CXBX_SBC_GAMEPAD_W1_COMM2 0x2000 +#define CXBX_SBC_GAMEPAD_W1_COMM3 0x4000 +#define CXBX_SBC_GAMEPAD_W1_COMM4 0x8000 + +#define CXBX_SBC_GAMEPAD_W2_COMM5 0x0001 +#define CXBX_SBC_GAMEPAD_W2_LEFTJOYSIGHTCHANGE 0x0002 +#define CXBX_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL 0x0004 +#define CXBX_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY 0x0008 +#define CXBX_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE 0x0010 +#define CXBX_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL 0x0020 +#define CXBX_SBC_GAMEPAD_W2_TOGGLEVTLOCATION 0x0040 + + +typedef struct __attribute__((packed)) +{ + uint8_t zero; + uint8_t bLength; + uint16_t dButtons[3]; + uint16_t aimingX; //0 to 2^16 left to right + uint16_t aimingY; //0 to 2^16 top to bottom + int16_t rotationLever; + int16_t sightChangeX; + int16_t sightChangeY; + uint16_t leftPedal; //Sidestep, 0x0000 to 0xFF00 + uint16_t middlePedal; //Brake, 0x0000 to 0xFF00 + uint16_t rightPedal; //Acceleration, 0x0000 to oxFF00 + int8_t tunerDial; //0-15 is from 9oclock, around clockwise + int8_t gearLever; //7-13 is gears R,1,2,3,4,5 +} USB_SteelBattalion_InReport_t; + +typedef struct +{ + uint8_t zero; + uint8_t bLength; + uint8_t CockpitHatch_EmergencyEject; + uint8_t Start_Ignition; + uint8_t MapZoomInOut_OpenClose; + uint8_t SubMonitorModeSelect_ModeSelect; + uint8_t MainMonitorZoomOut_MainMonitorZoomIn; + uint8_t Manipulator_ForecastShootingSystem; + uint8_t Washing_LineColorChange; + uint8_t Chaff_Extinguisher; + uint8_t Override_TankDetach; + uint8_t F1_NightScope; + uint8_t F3_F2; + uint8_t SubWeaponControl_MainWeaponControl; + uint8_t Comm1_MagazineChange; + uint8_t Comm3_Comm2; + uint8_t Comm5_Comm4; + uint8_t GearR_; + uint8_t Gear1_GearN; + uint8_t Gear3_Gear2; + uint8_t Gear5_Gear4; + uint8_t dummy; +} USB_SteelBattalion_OutReport_t; + +#define TUD_XID_SB_DESC_LEN (9+7+7) + +#define TUD_XID_SB_DESCRIPTOR(_itfnum, _epout, _epin) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, XID_INTERFACE_CLASS, XID_INTERFACE_SUBCLASS, 0x00, 0x00,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4, \ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4 + +static const uint8_t STEELBATTALION_DESC_XID[] = { + 0x10, + 0x42, + 0x00, 0x01, + 0x80, + 0x01, + 0x1A, + 0x16, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const uint8_t STEELBATTALION_CAPABILITIES_IN[] = { + 0x00, + 0x1A, + 0xFF, + 0xFF, + 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF +}; + +static const uint8_t STEELBATTALION_CAPABILITIES_OUT[] = { + 0x00, + 0x16, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF +}; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/proto/enums.proto b/proto/enums.proto index 3beec44c3..6d383ce9a 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -88,6 +88,13 @@ enum InputMode INPUT_MODE_HID = 2; INPUT_MODE_KEYBOARD = 3; INPUT_MODE_PS4 = 4; + INPUT_MODE_MDMINI = 6; + INPUT_MODE_NEOGEO = 7; + INPUT_MODE_PCEMINI = 8; + INPUT_MODE_EGRET = 9; + INPUT_MODE_ASTRO = 10; + INPUT_MODE_PSCLASSIC = 11; + INPUT_MODE_XBOXORIGINAL = 12; INPUT_MODE_CONFIG = 255; } diff --git a/src/addons/i2cdisplay.cpp b/src/addons/i2cdisplay.cpp index bef4e2996..e9e4fa61d 100644 --- a/src/addons/i2cdisplay.cpp +++ b/src/addons/i2cdisplay.cpp @@ -1018,6 +1018,13 @@ void I2CDisplayAddon::drawStatusBar(Gamepad * gamepad) case INPUT_MODE_HID: statusBar += "DINPUT"; break; case INPUT_MODE_SWITCH: statusBar += "SWITCH"; break; case INPUT_MODE_XINPUT: statusBar += "XINPUT"; break; + case INPUT_MODE_MDMINI: statusBar += "GEN/MD"; break; + case INPUT_MODE_NEOGEO: statusBar += "NEOGEO"; break; + case INPUT_MODE_PCEMINI: statusBar += "PCE/TG"; break; + case INPUT_MODE_EGRET: statusBar += "EGRET"; break; + case INPUT_MODE_ASTRO: statusBar += "ASTRO"; break; + case INPUT_MODE_PSCLASSIC: statusBar += "PSC"; break; + case INPUT_MODE_XBOXORIGINAL: statusBar += "OGXBOX"; break; case INPUT_MODE_PS4: if ( PS4Data::getInstance().ps4ControllerType == PS4ControllerType::PS4_CONTROLLER ) { if (PS4Data::getInstance().authsent == true ) diff --git a/src/gamepad.cpp b/src/gamepad.cpp index d9dc62b9f..55d20ce96 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -86,6 +86,92 @@ static XInputReport xinputReport ._reserved = { }, }; +static NeogeoReport neogeoReport +{ + .buttons = 0, + .hat = 0xf, + .const0 = 0x80, + .const1 = 0x80, + .const2 = 0x80, + .const3 = 0x80, + .const4 = 0, + .const5 = 0, + .const6 = 0, + .const7 = 0, + .const8 = 0, + .const9 = 0, + .const10 = 0, + .const11 = 0, + .const12 = 0, + .const13 = 0, + .const14 = 0, + .const15 = 0, + .const16 = 0, + .const17 = 0, +}; + +static MDMiniReport mdminiReport +{ + .id = 0x01, + .notuse1 = 0x7f, + .notuse2 = 0x7f, + .lx = 0x7f, + .ly = 0x7f, + .buttons = 0x0f, + .notuse3 = 0x00, +}; + +static PCEngineReport pcengineReport +{ + .buttons = 0, + .hat = 0xf, + .const0 = 0x80, + .const1 = 0x80, + .const2 = 0x80, + .const3 = 0x80, + .const4 = 0, +}; + +static AstroReport astroReport +{ + .id = 1, + .notuse1 = 0x7f, + .notuse2 = 0x7f, + .lx = 0x7f, + .ly = 0x7f, + .buttons = 0xf, + .notuse3 = 0, +}; + +static EgretReport egretReport +{ + .buttons = 0, + .lx = EGRET_JOYSTICK_MID, + .ly = EGRET_JOYSTICK_MID, +}; + +static PSClassicReport psClassicReport +{ + .buttons = 0x0014 +}; + +static XboxOriginalReport xboxOriginalReport +{ + .dButtons = 0, + .A = 0, + .B = 0, + .X = 0, + .Y = 0, + .BLACK = 0, + .WHITE = 0, + .L = 0, + .R = 0, + .leftStickX = 0, + .leftStickY = 0, + .rightStickX = 0, + .rightStickY = 0, +}; + static TouchpadData touchpadData; static uint8_t last_report_counter = 0; @@ -452,6 +538,27 @@ void * Gamepad::getReport() case INPUT_MODE_KEYBOARD: return getKeyboardReport(); + case INPUT_MODE_NEOGEO: + return getNeogeoReport(); + + case INPUT_MODE_MDMINI: + return getMDMiniReport(); + + case INPUT_MODE_PCEMINI: + return getPCEngineReport(); + + case INPUT_MODE_EGRET: + return getEgretReport(); + + case INPUT_MODE_ASTRO: + return getAstroReport(); + + case INPUT_MODE_PSCLASSIC: + return getPSClassicReport(); + + case INPUT_MODE_XBOXORIGINAL: + return getXboxOriginalReport(); + default: return getHIDReport(); } @@ -474,12 +581,32 @@ uint16_t Gamepad::getReportSize() case INPUT_MODE_KEYBOARD: return sizeof(KeyboardReport); + case INPUT_MODE_NEOGEO: + return sizeof(NeogeoReport); + + case INPUT_MODE_MDMINI: + return sizeof(MDMiniReport); + + case INPUT_MODE_PCEMINI: + return sizeof(PCEngineReport); + + case INPUT_MODE_EGRET: + return sizeof(EgretReport); + + case INPUT_MODE_ASTRO: + return sizeof(AstroReport); + + case INPUT_MODE_PSCLASSIC: + return sizeof(PSClassicReport); + + case INPUT_MODE_XBOXORIGINAL: + return sizeof(XboxOriginalReport); + default: return sizeof(HIDReport); } } - HIDReport *Gamepad::getHIDReport() { switch (state.dpad & GAMEPAD_MASK_DPAD) @@ -730,3 +857,223 @@ KeyboardReport *Gamepad::getKeyboardReport() if(pressedA2()) { pressKey(keyboardMapping.keyButtonA2); } return &keyboardReport; } + +PCEngineReport *Gamepad::getPCEngineReport() +{ + + switch (state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: pcengineReport.hat = PCENGINE_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: pcengineReport.hat = PCENGINE_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_UPLEFT; break; + default: pcengineReport.hat = PCENGINE_HAT_NOTHING; break; + } + + pcengineReport.buttons = 0x0 + | (pressedB1() ? PCENGINE_MASK_1 : 0) + | (pressedB2() ? PCENGINE_MASK_2 : 0) + | (pressedS1() ? PCENGINE_MASK_SELECT : 0) + | (pressedS2() ? PCENGINE_MASK_RUN : 0) + ; + + return &pcengineReport; +} + +NeogeoReport *Gamepad::getNeogeoReport() +{ + + switch (state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: neogeoReport.hat = NEOGEO_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: neogeoReport.hat = NEOGEO_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_UPLEFT; break; + default: neogeoReport.hat = NEOGEO_HAT_NOTHING; break; + } + + neogeoReport.buttons = 0x0 + | (pressedB3() ? NEOGEO_MASK_A : 0) + | (pressedB1() ? NEOGEO_MASK_B : 0) + | (pressedB4() ? NEOGEO_MASK_C : 0) + | (pressedB2() ? NEOGEO_MASK_D : 0) + | (pressedS1() ? NEOGEO_MASK_SELECT : 0) + | (pressedS2() ? NEOGEO_MASK_START : 0) + ; + + return &neogeoReport; +} + + +MDMiniReport *Gamepad::getMDMiniReport() +{ + mdminiReport.lx = 0x7f; + mdminiReport.ly = 0x7f; + + if (pressedLeft()) { mdminiReport.lx = MDMINI_MASK_LEFT; } + if (pressedRight()) { mdminiReport.lx = MDMINI_MASK_RIGHT; } + + if (pressedUp()) { mdminiReport.ly = MDMINI_MASK_UP; } + if (pressedDown()) { mdminiReport.ly = MDMINI_MASK_DOWN; } + + mdminiReport.buttons = 0x0F + | (pressedB1() ? MDMINI_MASK_A : 0) + | (pressedB2() ? MDMINI_MASK_B : 0) + | (pressedB3() ? MDMINI_MASK_X : 0) + | (pressedB4() ? MDMINI_MASK_Y : 0) + | (pressedR1() ? MDMINI_MASK_Z : 0) + | (pressedR2() ? MDMINI_MASK_C : 0) + | (pressedS2() ? MDMINI_MASK_START : 0) + | (pressedS1() ? MDMINI_MASK_MODE : 0) + ; + + return &mdminiReport; +} + +AstroReport *Gamepad::getAstroReport() +{ + astroReport.lx = 0x7f; + astroReport.ly = 0x7f; + + switch (state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MIN; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MIN; break; + case GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MID; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MAX; break; + case GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MID; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MIN; break; + default: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MID; break; + } + + + astroReport.buttons = 0x0F + | (pressedB1() ? ASTRO_MASK_A : 0) + | (pressedB2() ? ASTRO_MASK_B : 0) + | (pressedB3() ? ASTRO_MASK_D : 0) + | (pressedB4() ? ASTRO_MASK_E : 0) + | (pressedR1() ? ASTRO_MASK_C : 0) + | (pressedR2() ? ASTRO_MASK_F : 0) + | (pressedS1() ? ASTRO_MASK_CREDIT : 0) + | (pressedS2() ? ASTRO_MASK_START : 0) + ; + + return &astroReport; +} + +EgretReport *Gamepad::getEgretReport() +{ + switch (state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MIN; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MIN; break; + case GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MID; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MAX; break; + case GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MID; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MIN; break; + default: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MID; break; + } + + + egretReport.buttons = 0 + | (pressedB1() ? EGRET_MASK_A : 0) + | (pressedB2() ? EGRET_MASK_B : 0) + | (pressedB3() ? EGRET_MASK_C : 0) + | (pressedB4() ? EGRET_MASK_D : 0) + | (pressedR1() ? EGRET_MASK_E : 0) + | (pressedR2() ? EGRET_MASK_F : 0) + | (pressedS1() ? EGRET_MASK_CREDIT : 0) + | (pressedS2() ? EGRET_MASK_START : 0) + | (pressedA1() ? EGRET_MASK_MENU : 0) + ; + + return &egretReport; +} + +PSClassicReport *Gamepad::getPSClassicReport() +{ + psClassicReport.buttons = PSCLASSIC_MASK_CENTER; + + switch (state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: psClassicReport.buttons = PSCLASSIC_MASK_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_UP_RIGHT; break; + case GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_DOWN_RIGHT; break; + case GAMEPAD_MASK_DOWN: psClassicReport.buttons = PSCLASSIC_MASK_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_DOWN_LEFT; break; + case GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_UP_LEFT; break; + default: psClassicReport.buttons = PSCLASSIC_MASK_CENTER; break; + } + + psClassicReport.buttons |= + (pressedS2() ? PSCLASSIC_MASK_SELECT : 0) + | (pressedS1() ? PSCLASSIC_MASK_START : 0) + | (pressedB1() ? PSCLASSIC_MASK_CROSS : 0) + | (pressedB2() ? PSCLASSIC_MASK_CIRCLE : 0) + | (pressedB3() ? PSCLASSIC_MASK_SQUARE : 0) + | (pressedB4() ? PSCLASSIC_MASK_TRIANGLE : 0) + | (pressedL1() ? PSCLASSIC_MASK_L1 : 0) + | (pressedR1() ? PSCLASSIC_MASK_R1 : 0) + | (pressedL2() ? PSCLASSIC_MASK_L2 : 0) + | (pressedR2() ? PSCLASSIC_MASK_R2 : 0) + ; + + return &psClassicReport; +} + +XboxOriginalReport *Gamepad::getXboxOriginalReport() +{ + // digital buttons + xboxOriginalReport.dButtons = 0 + | (pressedUp() ? XID_DUP : 0) + | (pressedDown() ? XID_DDOWN : 0) + | (pressedLeft() ? XID_DLEFT : 0) + | (pressedRight() ? XID_DRIGHT : 0) + | (pressedS2() ? XID_START : 0) + | (pressedS1() ? XID_BACK : 0) + | (pressedL3() ? XID_LS : 0) + | (pressedR3() ? XID_RS : 0) + ; + + // analog buttons - convert to digital + xboxOriginalReport.A = (pressedB1() ? 0xFF : 0); + xboxOriginalReport.B = (pressedB2() ? 0xFF : 0); + xboxOriginalReport.X = (pressedB3() ? 0xFF : 0); + xboxOriginalReport.Y = (pressedB4() ? 0xFF : 0); + xboxOriginalReport.BLACK = (pressedL1() ? 0xFF : 0); + xboxOriginalReport.WHITE = (pressedR1() ? 0xFF : 0); + + // analog triggers + if (hasAnalogTriggers) + { + xboxOriginalReport.L = pressedL2() ? 0xFF : state.lt; + xboxOriginalReport.R = pressedR2() ? 0xFF : state.rt; + } + else + { + xboxOriginalReport.L = pressedL2() ? 0xFF : 0; + xboxOriginalReport.R = pressedR2() ? 0xFF : 0; + } + + // analog sticks + xboxOriginalReport.leftStickX = static_cast(state.lx) + INT16_MIN; + xboxOriginalReport.leftStickY = static_cast(~state.ly) + INT16_MIN; + xboxOriginalReport.rightStickX = static_cast(state.rx) + INT16_MIN; + xboxOriginalReport.rightStickY = static_cast(~state.ry) + INT16_MIN; + + return &xboxOriginalReport; +} diff --git a/src/gamepad/GamepadDescriptors.cpp b/src/gamepad/GamepadDescriptors.cpp index f40dc6f4d..34491f3ac 100644 --- a/src/gamepad/GamepadDescriptors.cpp +++ b/src/gamepad/GamepadDescriptors.cpp @@ -20,6 +20,34 @@ static uint16_t getConfigurationDescriptor(const uint8_t *buffer, InputMode mode buffer = ps4_configuration_descriptor; return sizeof(ps4_configuration_descriptor); + case INPUT_MODE_NEOGEO: + buffer = neogeo_configuration_descriptor; + return sizeof(neogeo_configuration_descriptor); + + case INPUT_MODE_MDMINI: + buffer = mdmini_configuration_descriptor; + return sizeof(mdmini_configuration_descriptor); + + case INPUT_MODE_PCEMINI: + buffer = pcengine_configuration_descriptor; + return sizeof(pcengine_configuration_descriptor); + + case INPUT_MODE_EGRET: + buffer = egret_configuration_descriptor; + return sizeof(egret_configuration_descriptor); + + case INPUT_MODE_ASTRO: + buffer = astro_configuration_descriptor; + return sizeof(astro_configuration_descriptor); + + case INPUT_MODE_PSCLASSIC: + buffer = psclassic_configuration_descriptor; + return sizeof(psclassic_configuration_descriptor); + + case INPUT_MODE_XBOXORIGINAL: + buffer = xboxoriginal_configuration_descriptor; + return sizeof(xboxoriginal_configuration_descriptor); + default: buffer = hid_configuration_descriptor; return sizeof(hid_configuration_descriptor); @@ -46,6 +74,34 @@ static uint16_t getDeviceDescriptor(const uint8_t *buffer, InputMode mode) buffer = ps4_device_descriptor; return sizeof(ps4_device_descriptor); + case INPUT_MODE_NEOGEO: + buffer = neogeo_device_descriptor; + return sizeof(neogeo_device_descriptor); + + case INPUT_MODE_MDMINI: + buffer = mdmini_device_descriptor; + return sizeof(mdmini_device_descriptor); + + case INPUT_MODE_PCEMINI: + buffer = pcengine_device_descriptor; + return sizeof(pcengine_device_descriptor); + + case INPUT_MODE_EGRET: + buffer = egret_device_descriptor; + return sizeof(egret_device_descriptor); + + case INPUT_MODE_ASTRO: + buffer = astro_device_descriptor; + return sizeof(astro_device_descriptor); + + case INPUT_MODE_PSCLASSIC: + buffer = psclassic_device_descriptor; + return sizeof(psclassic_device_descriptor); + + case INPUT_MODE_XBOXORIGINAL: + buffer = xboxoriginal_device_descriptor; + return sizeof(xboxoriginal_device_descriptor); + default: buffer = hid_device_descriptor; return sizeof(hid_device_descriptor); @@ -64,6 +120,30 @@ static uint16_t getHIDDescriptor(const uint8_t *buffer, InputMode mode) buffer = keyboard_hid_descriptor; return sizeof(keyboard_hid_descriptor); + case INPUT_MODE_NEOGEO: + buffer = neogeo_hid_descriptor; + return sizeof(neogeo_hid_descriptor); + + case INPUT_MODE_MDMINI: + buffer = mdmini_hid_descriptor; + return sizeof(mdmini_hid_descriptor); + + case INPUT_MODE_PCEMINI: + buffer = pcengine_hid_descriptor; + return sizeof(pcengine_hid_descriptor); + + case INPUT_MODE_EGRET: + buffer = egret_hid_descriptor; + return sizeof(egret_hid_descriptor); + + case INPUT_MODE_ASTRO: + buffer = astro_hid_descriptor; + return sizeof(astro_hid_descriptor); + + case INPUT_MODE_PSCLASSIC: + buffer = psclassic_hid_descriptor; + return sizeof(psclassic_hid_descriptor); + default: buffer = hid_hid_descriptor; return sizeof(hid_hid_descriptor); @@ -82,6 +162,30 @@ static uint16_t getHIDReport(const uint8_t *buffer, InputMode mode) buffer = keyboard_report_descriptor; return sizeof(keyboard_report_descriptor); + case INPUT_MODE_NEOGEO: + buffer = neogeo_report_descriptor; + return sizeof(neogeo_report_descriptor); + + case INPUT_MODE_MDMINI: + buffer = mdmini_report_descriptor; + return sizeof(mdmini_report_descriptor); + + case INPUT_MODE_PCEMINI: + buffer = pcengine_report_descriptor; + return sizeof(pcengine_report_descriptor); + + case INPUT_MODE_EGRET: + buffer = egret_report_descriptor; + return sizeof(egret_report_descriptor); + + case INPUT_MODE_ASTRO: + buffer = astro_report_descriptor; + return sizeof(astro_report_descriptor); + + case INPUT_MODE_PSCLASSIC: + buffer = psclassic_report_descriptor; + return sizeof(psclassic_report_descriptor); + default: buffer = hid_report_descriptor; return sizeof(hid_report_descriptor); @@ -118,6 +222,41 @@ static uint16_t getStringDescriptor(const uint16_t *buffer, InputMode mode, uint size = sizeof(ps4_string_descriptors[index]); break; + case INPUT_MODE_NEOGEO: + value = (const char *)neogeo_string_descriptors[index]; + size = sizeof(neogeo_string_descriptors[index]); + break; + + case INPUT_MODE_MDMINI: + value = (const char *)mdmini_string_descriptors[index]; + size = sizeof(mdmini_string_descriptors[index]); + break; + + case INPUT_MODE_PCEMINI: + value = (const char *)pcengine_string_descriptors[index]; + size = sizeof(pcengine_string_descriptors[index]); + break; + + case INPUT_MODE_EGRET: + value = (const char *)egret_string_descriptors[index]; + size = sizeof(egret_string_descriptors[index]); + break; + + case INPUT_MODE_ASTRO: + value = (const char *)astro_string_descriptors[index]; + size = sizeof(astro_string_descriptors[index]); + break; + + case INPUT_MODE_PSCLASSIC: + value = (const char *)psclassic_string_descriptors[index]; + size = sizeof(psclassic_string_descriptors[index]); + break; + + case INPUT_MODE_XBOXORIGINAL: + value = (const char *)xboxoriginal_string_descriptors[index]; + size = sizeof(xboxoriginal_string_descriptors[index]); + break; + default: value = (const char *)hid_string_descriptors[index]; size = sizeof(hid_string_descriptors[index]); diff --git a/src/gp2040.cpp b/src/gp2040.cpp index b38374b61..c8ecad59a 100644 --- a/src/gp2040.cpp +++ b/src/gp2040.cpp @@ -93,6 +93,7 @@ void GP2040::setup() { addons.LoadAddon(new TiltInput(), CORE0_INPUT); addons.LoadAddon(new InputMacro(), CORE0_INPUT); + const BootAction bootAction = getBootAction(); switch (bootAction) { @@ -115,6 +116,13 @@ void GP2040::setup() { case BootAction::SET_INPUT_MODE_XINPUT: case BootAction::SET_INPUT_MODE_PS4: case BootAction::SET_INPUT_MODE_KEYBOARD: + case BootAction::SET_INPUT_MODE_NEOGEO: + case BootAction::SET_INPUT_MODE_MDMINI: + case BootAction::SET_INPUT_MODE_PCEMINI: + case BootAction::SET_INPUT_MODE_EGRET: + case BootAction::SET_INPUT_MODE_ASTRO: + case BootAction::SET_INPUT_MODE_PSCLASSIC: + case BootAction::SET_INPUT_MODE_XBOXORIGINAL: case BootAction::NONE: { InputMode inputMode = gamepad->getOptions().inputMode; @@ -128,6 +136,20 @@ void GP2040::setup() { inputMode = INPUT_MODE_PS4; } else if (bootAction == BootAction::SET_INPUT_MODE_KEYBOARD) { inputMode = INPUT_MODE_KEYBOARD; + } else if (bootAction == BootAction::SET_INPUT_MODE_NEOGEO) { + inputMode = INPUT_MODE_NEOGEO; + } else if (bootAction == BootAction::SET_INPUT_MODE_MDMINI) { + inputMode = INPUT_MODE_MDMINI; + } else if (bootAction == BootAction::SET_INPUT_MODE_PCEMINI) { + inputMode = INPUT_MODE_PCEMINI; + } else if (bootAction == BootAction::SET_INPUT_MODE_EGRET) { + inputMode = INPUT_MODE_EGRET; + } else if (bootAction == BootAction::SET_INPUT_MODE_ASTRO) { + inputMode = INPUT_MODE_ASTRO; + } else if (bootAction == BootAction::SET_INPUT_MODE_PSCLASSIC) { + inputMode = INPUT_MODE_PSCLASSIC; + } else if (bootAction == BootAction::SET_INPUT_MODE_XBOXORIGINAL) { + inputMode = INPUT_MODE_XBOXORIGINAL; } if (inputMode != gamepad->getOptions().inputMode) { @@ -301,6 +323,20 @@ GP2040::BootAction GP2040::getBootAction() { return BootAction::SET_INPUT_MODE_KEYBOARD; case INPUT_MODE_PS4: return BootAction::SET_INPUT_MODE_PS4; + case INPUT_MODE_NEOGEO: + return BootAction::SET_INPUT_MODE_NEOGEO; + case INPUT_MODE_MDMINI: + return BootAction::SET_INPUT_MODE_MDMINI; + case INPUT_MODE_PCEMINI: + return BootAction::SET_INPUT_MODE_PCEMINI; + case INPUT_MODE_EGRET: + return BootAction::SET_INPUT_MODE_EGRET; + case INPUT_MODE_ASTRO: + return BootAction::SET_INPUT_MODE_ASTRO; + case INPUT_MODE_PSCLASSIC: + return BootAction::SET_INPUT_MODE_PSCLASSIC; + case INPUT_MODE_XBOXORIGINAL: + return BootAction::SET_INPUT_MODE_XBOXORIGINAL; default: return BootAction::NONE; } diff --git a/www/src/Locales/en/SettingsPage.jsx b/www/src/Locales/en/SettingsPage.jsx index f6288f58a..d62957deb 100644 --- a/www/src/Locales/en/SettingsPage.jsx +++ b/www/src/Locales/en/SettingsPage.jsx @@ -9,6 +9,13 @@ export default { ps3: 'PS3/DirectInput', keyboard: 'Keyboard', ps4: 'PS4', + neogeo: 'NEOGEO mini', + mdmini: 'Sega Genesis/MegaDrive Mini', + pcemini: 'PC Engine/Turbografx 16 Mini', + egret: 'EGRET II mini', + astro: 'ASTROCITY Mini', + psclassic: 'Playstation Classic', + xboxoriginal: 'Original Xbox', }, 'boot-input-mode-label': 'Boot Input Modes', 'ps4-mode-options': { @@ -23,7 +30,7 @@ export default { }, 'socd-cleaning-mode-label': 'SOCD Cleaning Mode', 'socd-cleaning-mode-note': - 'Note: PS4, PS3 and Nintendo Switch modes do not support setting SOCD Cleaning to Off and will default to Neutral SOCD Cleaning mode.', + 'Note: PS4, PS3, Nintendo Switch, and mini series modes do not support setting SOCD Cleaning to Off and will default to Neutral SOCD Cleaning mode.', 'socd-cleaning-mode-options': { 'up-priority': 'Up Priority', neutral: 'Neutral', diff --git a/www/src/Pages/SettingsPage.jsx b/www/src/Pages/SettingsPage.jsx index f82cf8a05..13eb89f3a 100644 --- a/www/src/Pages/SettingsPage.jsx +++ b/www/src/Pages/SettingsPage.jsx @@ -17,6 +17,13 @@ const INPUT_MODES = [ { labelKey: 'input-mode-options.ps3', value: 2 }, { labelKey: 'input-mode-options.keyboard', value: 3 }, { labelKey: 'input-mode-options.ps4', value: PS4Mode }, + { labelKey: 'input-mode-options.mdmini', value: 6 }, + { labelKey: 'input-mode-options.neogeo', value: 7 }, + { labelKey: 'input-mode-options.pcemini', value: 8 }, + { labelKey: 'input-mode-options.egret', value: 9 }, + { labelKey: 'input-mode-options.astro', value: 10 }, + { labelKey: 'input-mode-options.psclassic', value: 11 }, + { labelKey: 'input-mode-options.xboxoriginal', value: 12 }, ]; const INPUT_BOOT_MODES = [ @@ -26,6 +33,13 @@ const INPUT_BOOT_MODES = [ { labelKey: 'input-mode-options.ps3', value: 2 }, { labelKey: 'input-mode-options.keyboard', value: 3 }, { labelKey: 'input-mode-options.ps4', value: PS4Mode }, + { labelKey: 'input-mode-options.mdmini', value: 6 }, + { labelKey: 'input-mode-options.neogeo', value: 7 }, + { labelKey: 'input-mode-options.pcemini', value: 8 }, + { labelKey: 'input-mode-options.egret', value: 9 }, + { labelKey: 'input-mode-options.astro', value: 10 }, + { labelKey: 'input-mode-options.psclassic', value: 11 }, + { labelKey: 'input-mode-options.xboxoriginal', value: 12 }, ]; const DPAD_MODES = [