Driver Input Updates & Auth Mechanisms (UI & FW) (#890)

* [ImgBot] Optimize images

*Total -- 6,536.44kb -> 6,081.92kb (6.95%)

/configs/OpenCore0/assets/Open_Core0_LED_order.png -- 81.87kb -> 34.77kb (57.53%)
/configs/OpenCore0/assets/Open_Core0_pin_mapping.png -- 79.46kb -> 34.15kb (57.02%)
/configs/OpenCore0/assets/Open_Core0_layout.png -- 80.33kb -> 34.76kb (56.73%)
/configs/OpenCore0/assets/Open_Core0_2.jpg -- 3,134.92kb -> 2,976.17kb (5.06%)
/configs/OpenCore0/assets/Open_Core0.jpg -- 3,159.87kb -> 3,002.07kb (4.99%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>

* Doesn't compile yet but this is the start of the input auth code

* Moving add-ons over to drivers for authentication, added a special call to get USB driver if available.

Lots of other changes

* Updates for all drivers and config utils, removed ps4 report hack, lots of updates to the auth drivers

* Large amount of changes to remove authentication add-ons and move everything over to drivers. This also removes the PS4Data global I've been using, and cleans all of that up to pointers and class storage variables.

* Moved reset auth to where it should be. Updated web page to work with PS4 keys. PS4/PS5 modes shouuuuld work now on keys and USB separately

* Xbox One auth is now working. Added a XBON* to XBONE transition on display to indicate auth

* Required with new changes

* huh, this one was missed

* Updated our X-Input auth listener, we can now mount/unmount the dongle!

Now for actual authentication work....

* First start of X-Input Auth for passthrough

* Patching out auth to get a PR going

* Small www fix for x-input auth removal

* Fix to make this compile and moved keyboard host update over to listener

* This cleans up most of the remnants from ps passthrough, ps4 mode, and xbone pass through in JSX and webconfig.

This also auto-migrates users from 0.7.7 to 0.7.8 who had ps5 enabled using USB, including updating their boot modes and current input mode.

Small tweak to PS4 Driver to clarify controllerType is NOT the old saved ps4ControllerType protobuf variable.

* Delete src/addons/display.cpp.bak

* So many tabs and spaces mixed together. Converted to spaces for now until we come up with a standard of any kind.

* Memory issue with XGIP protocol reset, caused crashing in Xbox One

* Added define LEDS_PRESS_COLOR_COOLDOWN_TIME for the LED cooldown timer, defaulted to 0 instead of 500ms.

Updated board configs to follow convention for PS5 mode and add USB authentication where applicable.

USB block defines used instead of add-on config options.

* Gamepad Settings & Input Mode Settings rearrange

* Fixed a strange web-config reboot bug with XGIP protocol

Fixed a missing keyboard mapping sub-header in addons

* Reduced profile display to 2 seconds, added a check for display list size

* Xbox One would not auth because I missed "get_descriptor_string_cb" function call for Xbox One.

Also fixed gpscreen to be an iterator loop to hopefully fix the .at(i) weirdness I'm getting.

Added back in tud vendor control function callback.

* Rewrote Xbox One guide button logic to properly check for USB-send completion.

---------

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
This commit is contained in:
Luke A
2024-03-22 15:56:43 -04:00
committed by GitHub
parent 540b9f4dbb
commit 8905b74e94
126 changed files with 4844 additions and 4418 deletions

View File

@@ -155,9 +155,13 @@ src/drivers/mdmini/MDMiniDriver.cpp
src/drivers/neogeo/NeoGeoDriver.cpp
src/drivers/net/NetDriver.cpp
src/drivers/pcengine/PCEngineDriver.cpp
src/drivers/ps4/PS4Auth.cpp
src/drivers/ps4/PS4AuthUSBListener.cpp
src/drivers/ps4/PS4Driver.cpp
src/drivers/psclassic/PSClassicDriver.cpp
src/drivers/switch/SwitchDriver.cpp
src/drivers/xbone/XBOneAuth.cpp
src/drivers/xbone/XBOneAuthUSBListener.cpp
src/drivers/xbone/XBOneDriver.cpp
src/drivers/xboxog/xid/xid_driver.c
src/drivers/xboxog/xid/xid_gamepad.c
@@ -165,6 +169,8 @@ src/drivers/xboxog/xid/xid_remote.c
src/drivers/xboxog/xid/xid_steelbattalion.c
src/drivers/xboxog/xid/xid.c
src/drivers/xboxog/XboxOriginalDriver.cpp
src/drivers/xinput/XInputAuth.cpp
src/drivers/xinput/XInputAuthUSBListener.cpp
src/drivers/xinput/XInputDriver.cpp
src/interfaces/i2c/ssd1306/obd_ssd1306.cpp
src/interfaces/i2c/ssd1306/tiny_ssd1306.cpp
@@ -198,14 +204,13 @@ src/addons/focus_mode.cpp
src/addons/buzzerspeaker.cpp
src/addons/dualdirectional.cpp
src/addons/keyboard_host.cpp
src/addons/keyboard_host_listener.cpp
src/addons/i2canalog1219.cpp
src/addons/jslider.cpp
src/addons/display.cpp
src/addons/neopicoleds.cpp
src/addons/playernum.cpp
src/addons/playerleds.cpp
src/addons/ps4mode.cpp
src/addons/pspassthrough.cpp
src/addons/rotaryencoder.cpp
src/addons/reverse.cpp
src/addons/turbo.cpp
@@ -214,7 +219,6 @@ src/addons/wiiext.cpp
src/addons/input_macro.cpp
src/addons/snes_input.cpp
src/addons/tilt.cpp
src/addons/xbonepassthrough.cpp
src/addons/spi_analog_ads1256.cpp
${PROTO_OUTPUT_DIR}/enums.pb.c
${PROTO_OUTPUT_DIR}/config.pb.c

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "BentoBox"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Fightboard V3"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Fightboard V3 Mirrored"

View File

@@ -7,6 +7,7 @@
#define FLATBOX_REV4_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Flatbox Rev. 4"

View File

@@ -7,6 +7,7 @@
#define FLATBOX_REV5_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Flatbox Rev. 5"

View File

@@ -7,6 +7,7 @@
#define FLATBOX_REV5_RGB_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Flatbox Rev. 5 RGB"

View File

@@ -7,6 +7,7 @@
#define FLATBOX_REV5_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Flatbox Rev. 5 Southpaw"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Granola Arcade"
@@ -63,13 +64,11 @@
#define KEY_BUTTON_FN -1 // Hotkey Function |
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_PS4CONTROLLER_TYPE PS4_ARCADESTICK
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 28
#define USB_PERIPHERAL_PIN_ORDER 0
#define PSPASSTHROUGH_ENABLED 1
#define XBONEPASSTHROUGH_ENABLED 1
#endif

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Haute 42"
@@ -53,8 +54,13 @@
#define KEY_BUTTON_A2 HID_KEY_F2 // A2 | ~ | Capture | ~ | 14 | ~ |
#define KEY_BUTTON_FN -1 // Hotkey Function |
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 23
#define USB_PERIPHERAL_PIN_ORDER 0
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_PS4CONTROLLER_TYPE PS4_ARCADESTICK
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
#define TURBO_ENABLED 1
#define GPIO_PIN_14 GpioAction::BUTTON_PRESS_TURBO
@@ -95,15 +101,8 @@
#define GPIO_PIN_27 GpioAction::BUTTON_PRESS_UP
#define GPIO_PIN_26 GpioAction::BUTTON_PRESS_L3
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 23
#define USB_PERIPHERAL_PIN_ORDER 0
// Keyboard Host enabled by default
#define KEYBOARD_HOST_ENABLED 1
#define KEYBOARD_HOST_PIN_DPLUS 23
#define PSPASSTHROUGH_ENABLED 1
#define XBONEPASSTHROUGH_ENABLED 1
#define BOARD_LED_ENABLED 1
#define BOARD_LED_TYPE ON_BOARD_LED_MODE_MODE_INDICATOR

View File

@@ -5,7 +5,9 @@
#ifndef PICO_BOARD_CONFIG_H_
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "KB2040"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Keyboard Converter"

View File

@@ -2,6 +2,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Liatris"

View File

@@ -7,6 +7,7 @@
#define MAVERCADE_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Mavercade"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Open_Core0"
@@ -65,9 +66,12 @@
#define GPIO_PIN_22 GpioAction::SUSTAIN_SOCD_MODE_SECOND_WIN
#define SLIDER_SOCD_SLOT_DEFAULT SOCD_MODE_NEUTRAL
#define DEFAULT_PS4CONTROLLER_TYPE PS4_ARCADESTICK
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 28
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
#define BOARD_LEDS_PIN 8
@@ -115,9 +119,5 @@
#define FOCUS_MODE_PIN 21
#define FOCUS_MODE_BUTTON_LOCK_ENABLED 1
#define PSPASSTHROUGH_ENABLED 1
#define PSPASSTHROUGH_PIN_DPLUS 28
#define XBONEPASSTHROUGH_ENABLED 1
#endif

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Open_Core0 WASD"
@@ -53,9 +54,13 @@
#define KEY_BUTTON_A2 HID_KEY_F2 // A2 | ~ | Capture | ~ | 14 | ~ |
#define KEY_BUTTON_FN -1 // Hotkey Function |
#define DEFAULT_PS4CONTROLLER_TYPE PS4_ARCADESTICK
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 28
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
#define TURBO_ENABLED 1
#define GPIO_PIN_27 GpioAction::BUTTON_PRESS_TURBO
@@ -112,9 +117,5 @@
#define FOCUS_MODE_PIN 22
#define FOCUS_MODE_BUTTON_LOCK_ENABLED 1
#define PSPASSTHROUGH_ENABLED 1
#define PSPASSTHROUGH_PIN_DPLUS 28
#define XBONEPASSTHROUGH_ENABLED 1
#endif

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Pico"

View File

@@ -7,6 +7,7 @@
#define PICOANN_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Pico Ann"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Pico Fighting Board"

View File

@@ -7,6 +7,7 @@
#define PICOW_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Pico-W"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "RP2040 Advanced Breakout Board"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "RP2040 Advanced Breakout Board - USB Passthrough"
@@ -76,9 +77,11 @@
#define I2C0_PIN_SCL 1
#define DISPLAY_I2C_BLOCK i2c0
#define PSPASSTHROUGH_ENABLED 1
#define PSPASSTHROUGH_PIN_DPLUS 23
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 23
#define XBONEPASSTHROUGH_ENABLED 1
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
#endif

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "RP2040 Mini Breakout Board"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Rana Tadpole"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Reflex Ctrl SNES"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Reflex Encode v1.2"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Reflex Encode v2.0"
@@ -54,14 +55,13 @@
#define KEY_BUTTON_A2 HID_KEY_F2 // A2 | ~ | Capture | ~ | 14 | ~ |
#define KEY_BUTTON_FN -1 // Hotkey Function |
#define DEFAULT_PS4CONTROLLER_TYPE PS4_ARCADESTICK
#define DEFAULT_INPUT_MODE INPUT_MODE_PS4
#define PSPASSTHROUGH_ENABLED 1
#define PSPASSTHROUGH_PIN_DPLUS 14
#define XBONEPASSTHROUGH_ENABLED 1
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 14
#define DEFAULT_INPUT_MODE INPUT_MODE_PS5
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
#define TURBO_ENABLED 1
#define GPIO_PIN_29 GpioAction::BUTTON_PRESS_TURBO

View File

@@ -7,6 +7,7 @@
#define SGF_DEVICES_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "SGF Bridget"

View File

@@ -7,6 +7,7 @@
#define SGF_FAUST_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "SGF Faust"
@@ -54,14 +55,12 @@
#define KEY_BUTTON_A2 HID_KEY_F2 // A2 | ~ | Capture | ~ | 14 | ~ |
#define KEY_BUTTON_FN -1 // Hotkey Function |
#define DEFAULT_PS4CONTROLLER_TYPE PS4_ARCADESTICK
#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 12
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define PSPASSTHROUGH_ENABLED 1
#define PSPASSTHROUGH_PIN_DPLUS 12
#define XBONEPASSTHROUGH_ENABLED 1
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
#define BOARD_LEDS_PIN 7
#define LED_BRIGHTNESS_MAXIMUM 255

View File

@@ -2,6 +2,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "SparkFun Pro Micro"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Stress"

View File

@@ -7,6 +7,7 @@
#define PICO_BOARD_CONFIG_H_
#include "enums.pb.h"
#include "class/hid/hid.h"
#define BOARD_CONFIG_LABEL "Waveshare Zero"

View File

@@ -2,7 +2,6 @@
#define _ADDONMANAGER_H_
#include "gpaddon.h"
#include "usbaddon.h"
#include <vector>
#include <pico/mutex.h>
@@ -23,8 +22,8 @@ class AddonManager {
public:
AddonManager() {}
~AddonManager() {}
void LoadAddon(GPAddon*, ADDON_PROCESS);
void LoadUSBAddon(USBAddon*, ADDON_PROCESS);
bool LoadAddon(GPAddon*, ADDON_PROCESS);
bool LoadUSBAddon(GPAddon*, ADDON_PROCESS);
void ReinitializeAddons(ADDON_PROCESS);
void PreprocessAddons(ADDON_PROCESS);
void ProcessAddons(ADDON_PROCESS);

View File

@@ -1,9 +1,7 @@
#ifndef _KeyboardHost_H
#define _KeyboardHost_H
#include "usbaddon.h"
#include "gamepad.h"
#include "class/hid/hid.h"
#include "gpaddon.h"
#ifndef KEYBOARD_HOST_ENABLED
#define KEYBOARD_HOST_ENABLED 0
@@ -20,61 +18,14 @@
// KeyboardHost Module Name
#define KeyboardHostName "KeyboardHost"
struct KeyboardButtonMapping
{
uint8_t key;
uint16_t buttonMask;
inline void setMask(uint16_t m) {
buttonMask = m;
}
inline void setKey(uint8_t p)
{
key = (p > HID_KEY_NONE && p <=HID_KEY_GUI_RIGHT) ? p : 0xff;
}
bool isAssigned() const { return key != 0xff; }
};
class KeyboardHostAddon : public USBAddon {
class KeyboardHostAddon : public GPAddon {
public:
virtual bool available();
virtual void setup(); // KeyboardHost Setup
virtual void process() {} // KeyboardHost Process
virtual void preprocess();
virtual std::string name() { return KeyboardHostName; }
// USB Add-on Features
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) {}
virtual void unmount(uint8_t dev_addr);
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {}
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {}
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {}
private:
bool _keyboard_host_enabled;
uint8_t getKeycodeFromModifier(uint8_t modifier);
void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report);
GamepadState _keyboard_host_state;
KeyboardButtonMapping _keyboard_host_mapDpadUp;
KeyboardButtonMapping _keyboard_host_mapDpadDown;
KeyboardButtonMapping _keyboard_host_mapDpadLeft;
KeyboardButtonMapping _keyboard_host_mapDpadRight;
KeyboardButtonMapping _keyboard_host_mapButtonB1;
KeyboardButtonMapping _keyboard_host_mapButtonB2;
KeyboardButtonMapping _keyboard_host_mapButtonB3;
KeyboardButtonMapping _keyboard_host_mapButtonB4;
KeyboardButtonMapping _keyboard_host_mapButtonL1;
KeyboardButtonMapping _keyboard_host_mapButtonR1;
KeyboardButtonMapping _keyboard_host_mapButtonL2;
KeyboardButtonMapping _keyboard_host_mapButtonR2;
KeyboardButtonMapping _keyboard_host_mapButtonS1;
KeyboardButtonMapping _keyboard_host_mapButtonS2;
KeyboardButtonMapping _keyboard_host_mapButtonL3;
KeyboardButtonMapping _keyboard_host_mapButtonR3;
KeyboardButtonMapping _keyboard_host_mapButtonA1;
KeyboardButtonMapping _keyboard_host_mapButtonA2;
};
#endif // _KeyboardHost_H_

View File

@@ -0,0 +1,63 @@
#ifndef _KeyboardHostListener_H
#define _KeyboardHostListener_H
#include "usblistener.h"
#include "gamepad.h"
#include "class/hid/hid.h"
struct KeyboardButtonMapping
{
uint8_t key;
uint16_t buttonMask;
inline void setMask(uint16_t m) {
buttonMask = m;
}
inline void setKey(uint8_t p)
{
key = (p > HID_KEY_NONE && p <= HID_KEY_GUI_RIGHT) ? p : 0xff;
}
bool isAssigned() const { return key != 0xff; }
};
class KeyboardHostListener : public USBListener {
public:// USB Listener Features
virtual void setup();
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) {}
virtual void unmount(uint8_t dev_addr);
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {}
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {}
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {}
void process();
private:
GamepadState _keyboard_host_state;
bool _keyboard_host_enabled;
uint8_t getKeycodeFromModifier(uint8_t modifier);
void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report);
KeyboardButtonMapping _keyboard_host_mapDpadUp;
KeyboardButtonMapping _keyboard_host_mapDpadDown;
KeyboardButtonMapping _keyboard_host_mapDpadLeft;
KeyboardButtonMapping _keyboard_host_mapDpadRight;
KeyboardButtonMapping _keyboard_host_mapButtonB1;
KeyboardButtonMapping _keyboard_host_mapButtonB2;
KeyboardButtonMapping _keyboard_host_mapButtonB3;
KeyboardButtonMapping _keyboard_host_mapButtonB4;
KeyboardButtonMapping _keyboard_host_mapButtonL1;
KeyboardButtonMapping _keyboard_host_mapButtonR1;
KeyboardButtonMapping _keyboard_host_mapButtonL2;
KeyboardButtonMapping _keyboard_host_mapButtonR2;
KeyboardButtonMapping _keyboard_host_mapButtonS1;
KeyboardButtonMapping _keyboard_host_mapButtonS2;
KeyboardButtonMapping _keyboard_host_mapButtonL3;
KeyboardButtonMapping _keyboard_host_mapButtonR3;
KeyboardButtonMapping _keyboard_host_mapButtonA1;
KeyboardButtonMapping _keyboard_host_mapButtonA2;
};
#endif // _KeyboardHost_H_

View File

@@ -66,6 +66,10 @@
#define LEDS_CHASE_CYCLE_TIME 85
#endif
#ifndef LEDS_PRESS_COLOR_COOLDOWN_TIME
#define LEDS_PRESS_COLOR_COOLDOWN_TIME 0
#endif
#ifndef LED_BRIGHTNESS_MAXIMUM
#define LED_BRIGHTNESS_MAXIMUM 128
#endif

View File

@@ -1,28 +0,0 @@
#ifndef PS4MODE_H_
#define PS4MODE_H_
#include "gpaddon.h"
#include "storagemanager.h"
#include "mbedtls/rsa.h"
#ifndef PS4MODE_ADDON_ENABLED
#define PS4MODE_ADDON_ENABLED 0
#endif
// Turbo Module Name
#define PS4ModeName "PS4Mode"
class PS4ModeAddon : public GPAddon {
public:
virtual bool available();
virtual void setup(); // TURBO Button Setup
virtual void preprocess() {}
virtual void process(); // TURBO Setting of buttons (Enable/Disable)
virtual std::string name() { return PS4ModeName; }
private:
struct mbedtls_rsa_context rsa_context;
bool ready;
};
#endif // PS4MODE_H_

View File

@@ -1,47 +0,0 @@
#ifndef _PSPassthrough_H
#define _PSPassthrough_H
#include "usbaddon.h"
#include "drivers/shared/ps4data.h"
#ifndef PSPASSTHROUGH_ENABLED
#define PSPASSTHROUGH_ENABLED 0
#endif
#ifndef PSPASSTHROUGH_PIN_DPLUS
#define PSPASSTHROUGH_PIN_DPLUS -1
#endif
#ifndef PSPASSTHROUGH_PIN_5V
#define PSPASSTHROUGH_PIN_5V -1
#endif
// KeyboardHost Module Name
#define PSPassthroughName "PSPassthrough"
class PSPassthroughAddon : public USBAddon {
public:
virtual bool available();
virtual void setup(); // PSPassthrough Setup
virtual void process(); // PSPassthrough Process
virtual void preprocess() {}
virtual std::string name() { return PSPassthroughName; }
// USB Add-on Features
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) {}
virtual void unmount(uint8_t dev_addr);
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {}
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {}
private:
uint8_t ps_dev_addr;
uint8_t ps_instance;
int8_t nonce_page;
PS4State passthrough_state;
int8_t send_nonce_part;
uint8_t report_buffer[64];
bool awaiting_cb;
};
#endif // _PSPassthrough_H_

View File

@@ -1,42 +0,0 @@
#ifndef _XBOnePassthrough_H
#define _XBOnePassthrough_H
#include "usbaddon.h"
#include "drivers/shared/xgip_protocol.h"
#ifndef XBONEPASSTHROUGH_ENABLED
#define XBONEPASSTHROUGH_ENABLED 0
#endif
// KeyboardHost Module Name
#define XBOnePassthroughName "XBOnePassthrough"
class XBOnePassthroughAddon : public USBAddon {
public:
virtual bool available();
virtual void setup(); // XBOnePassthrough Setup
virtual void process(); // XBOnePassthrough Process
virtual void preprocess() {}
virtual std::string name() { return XBOnePassthroughName; }
// USB Add-on Features
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {}
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype);
virtual void unmount(uint8_t dev_addr);
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {}
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {}
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {}
void queue_host_report(void* report, uint16_t len);
private:
uint8_t xbone_dev_addr;
uint8_t xbone_instance;
bool dongle_ready;
XGIPProtocol incomingXGIP;
XGIPProtocol outgoingXGIP;
};
#endif // _PSPassthrough_H_

View File

@@ -80,7 +80,7 @@ class ButtonLayoutScreen : public GPScreen {
std::deque<std::string> inputHistory;
std::array<bool, INPUT_HISTORY_MAX_INPUTS> lastInput;
uint8_t profileDelay = 5;
uint8_t profileDelay = 2;
int profileDelayStart = 0;
bool displayProfileBanner = true;

View File

@@ -13,6 +13,8 @@ class AstroDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
AstroReport astroReport;

View File

@@ -13,6 +13,8 @@ class EgretDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
EgretReport egretReport;

View File

@@ -13,6 +13,8 @@ class HIDDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
HIDReport hidReport;

View File

@@ -13,6 +13,8 @@ class KeyboardDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
void releaseAllKeys(void);
void pressKey(uint8_t code);

View File

@@ -13,6 +13,8 @@ class MDMiniDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
MDMiniReport mdminiReport;

View File

@@ -13,6 +13,8 @@ class NeoGeoDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
NeogeoReport neogeoReport;

View File

@@ -12,6 +12,8 @@ class NetDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -21,6 +23,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
};

View File

@@ -13,6 +13,8 @@ class PCEngineDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
PCEngineReport pcengineReport;

View File

@@ -0,0 +1,28 @@
#ifndef _PS4AUTH_H_
#define _PS4AUTH_H_
#include "drivers/shared/gpauthdriver.h"
#include "drivers/ps4/PS4Driver.h"
#include "usblistener.h"
#include "mbedtls/rsa.h"
class PS4Auth : public GPAuthDriver {
public:
PS4Auth(InputModeAuthType inType) { authType = inType; }
virtual void initialize();
virtual bool available();
void process(PS4State, uint8_t, uint8_t*);
uint8_t * getAuthBuffer() { return ps4_auth_buffer; }
bool getAuthReady();
void resetAuth();
private:
struct mbedtls_rsa_context rsa_context;
bool valid_rsa;
// buffer = 256 + 16 + 256 + 256 + 256 + 24
// == 1064 bytes (almost 1 kb)
uint8_t ps4_auth_buffer[1064];
bool ps4_keys_signature_ready;
};
#endif

View File

@@ -0,0 +1,35 @@
#ifndef _PS4AUTHUSBLISTENER_H_
#define _PS4AUTHUSBLISTENER_H_
#include "usblistener.h"
#include "PS4Driver.h"
class PS4AuthUSBListener : public USBListener {
public:
virtual void setup();
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype){}
virtual void unmount(uint8_t dev_addr);
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {}
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {}
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
void process(PS4State pState, uint8_t pNonceId, uint8_t * pNonceBuffer); // add things to process
void setAuthBuffer(uint8_t * buffer) { ps4_auth_buffer = buffer; }
bool getHostAuthReady() { return ps4_auth_host_ready; }
void resetHostAuth();
private:
bool host_get_report(uint8_t report_id, void* report, uint16_t len);
bool host_set_report(uint8_t report_id, void* report, uint16_t len);
uint8_t ps_dev_addr;
uint8_t ps_instance;
int8_t nonce_page;
PS4State passthrough_state;
int8_t send_nonce_part;
uint8_t report_buffer[64];
bool awaiting_cb;
bool ps4_auth_host_ready;
uint8_t * ps4_auth_buffer;
};
#endif // _PS4AUTHUSBLISTENER_H_

View File

@@ -9,10 +9,43 @@
#include "gpdriver.h"
#include "drivers/ps4/PS4Descriptors.h"
// Authentication
#include "drivers/shared/gpauthdriver.h"
typedef enum {
no_nonce = 0,
receiving_nonce = 1,
nonce_ready = 2,
signed_nonce_ready = 3,
sending_nonce = 4,
waiting_reset = 5
} PS4State;
typedef enum
{
PS4_DEFINITION = 0x03, // PS4 Controller Definition
PS4_SET_AUTH_PAYLOAD = 0xF0, // Set Auth Payload
PS4_GET_SIGNATURE_NONCE = 0xF1, // Get Signature Nonce
PS4_GET_SIGNING_STATE = 0xF2, // Get Signing State
PS4_RESET_AUTH = 0xF3 // Unknown (PS4 Report 0xF3)
} PS4AuthReport;
// PS4 Auth buffer must be used by callbacks, core0, and core1
// Send back in 56 byte chunks:
// 256 byte - nonce signature
// 16 byte - ps4 serial
// 256 byte - RSA N
// 256 byte - RSA E
// 256 byte - ps4 signature
// 24 byte - zero padding
class PS4Driver : public GPDriver {
public:
PS4Driver(uint32_t type): controllerType(type) {}
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux();
virtual void processAux();
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,17 +55,27 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener();
bool getAuthSent() { return authsent;}
private:
// Lots of things here
void save_nonce(uint8_t nonce_id, uint8_t nonce_page, uint8_t * buffer, uint16_t buflen);
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
uint8_t last_report_counter;
uint16_t last_axis_counter;
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
uint8_t last_report_counter;
uint16_t last_axis_counter;
uint8_t cur_nonce_id;
PS4Report ps4Report;
TouchpadData touchpadData;
uint32_t last_report_timer;
uint8_t send_nonce_part;
uint32_t controllerType;
GPAuthDriver * authDriver;
PS4State ps4State;
bool authsent;
uint8_t nonce_buffer[256];
uint8_t nonce_id; // used in pass-through mode
};
#endif // _PS4_DRIVER_H_

View File

@@ -13,6 +13,8 @@ class PSClassicDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
PSClassicReport psClassicReport;

View File

@@ -0,0 +1,19 @@
#ifndef _GPAUTHDRIVER_H_
#define _GPAUTHDRIVER_H_
#include "enums.pb.h"
#include "usblistener.h"
class GPAuthDriver {
public:
virtual void initialize() = 0;
virtual bool available() = 0;
virtual USBListener * getListener() { return listener; }
InputModeAuthType getAuthType() { return authType; }
protected:
USBListener * listener;
InputModeAuthType authType;
};
#endif

View File

@@ -1,60 +0,0 @@
#ifndef _PS4_DATA_H_
#define _PS4_DATA_H_
typedef enum {
no_nonce = 0,
receiving_nonce = 1,
nonce_ready = 2,
signed_nonce_ready = 3,
sending_nonce = 4
} PS4State;
typedef enum
{
PS4_DEFINITION = 0x03, // PS4 Controller Definition
PS4_SET_AUTH_PAYLOAD = 0xF0, // Set Auth Payload
PS4_GET_SIGNATURE_NONCE = 0xF1, // Get Signature Nonce
PS4_GET_SIGNING_STATE = 0xF2, // Get Signing State
PS4_RESET_AUTH = 0xF3 // Unknown (PS4 Report 0xF3)
} PS4AuthReport;
// Storage manager for board, LED options, and thread-safe settings
class PS4Data {
public:
PS4Data(PS4Data const&) = delete;
void operator=(PS4Data const&) = delete;
static PS4Data& getInstance() // Thread-safe storage ensures cross-thread talk
{
static PS4Data instance;
return instance;
}
PS4State ps4State;
bool authsent;
uint8_t nonce_buffer[256];
uint8_t nonce_id; // used in pass-through mode
// Send back in 56 byte chunks:
// 256 byte - nonce signature
// 16 byte - ps4 serial
// 256 byte - RSA N
// 256 byte - RSA E
// 256 byte - ps4 signature
// 24 byte - zero padding
// buffer = 256 + 16 + 256 + 256 + 256 + 24
// == 1064 bytes (almost 1 kb)
uint8_t ps4_auth_buffer[1064];
uint32_t ps4ControllerType;
private:
PS4Data() {
ps4State = PS4State::no_nonce;
authsent = false;
memset(nonce_buffer, 0, 256);
memset(ps4_auth_buffer, 0, 1064);
ps4ControllerType = PS4ControllerType::PS4_CONTROLLER;
}
};
#endif // _PS4_DATA_H_

View File

@@ -1,88 +0,0 @@
#ifndef _XBONE_DATA_H_
#define _XBONE_DATA_H_
typedef enum {
auth_idle_state = 0,
send_auth_console_to_dongle = 1,
send_auth_dongle_to_console = 2,
wait_auth_console_to_dongle = 3,
wait_auth_dongle_to_console = 4,
} XboxOneState;
// Storage manager for board, LED options, and thread-safe settings
class XboxOneData {
public:
XboxOneData(XboxOneData const&) = delete;
void operator=(XboxOneData const&) = delete;
static XboxOneData& getInstance() // Thread-safe storage ensures cross-thread talk
{
static XboxOneData instance;
return instance;
}
void setState(XboxOneState newState) {
xboneState = newState;
}
uint8_t * getAuthBuffer() {
return authBuffer;
}
uint8_t getSequence() {
return authSequence;
}
uint16_t getAuthLen() {
return authLen;
}
uint8_t getAuthType() {
return authType;
}
XboxOneState getState() {
return xboneState;
}
void setAuthData(uint8_t * buf, uint16_t bufLen, uint8_t seq, uint8_t type, XboxOneState newState) {
// Cannot copy larger than our buffer
if ( bufLen > 1024) {
return;
}
memcpy(authBuffer, buf, bufLen);
authLen = bufLen;
authType = type;
authSequence = seq;
xboneState = newState;
}
bool getAuthCompleted() {
return authCompleted;
}
void setAuthCompleted(bool completed) {
authCompleted = completed;
}
private:
XboxOneData() {
xboneState = auth_idle_state;
authLen = 0;
authSequence = 0;
authCompleted = false;
}
XboxOneState xboneState;
// Console-to-Host e.g. Xbox One to MagicBoots
// Note: the Xbox One Passthrough can call send_xbone_report() directly but not the other way around
bool authCompleted;
// Auth Buffer
uint8_t authBuffer[1024];
uint8_t authSequence;
uint16_t authLen;
uint8_t authType;
};
#endif // _XBONE_DATA_H_

View File

@@ -45,6 +45,17 @@ extern "C" {
#define CFG_TUH_XINPUT_EPOUT_BUFSIZE 64
#endif
//--------------------------------------------------------------------+
// Enumeration
//--------------------------------------------------------------------+
typedef enum
{
UNKNOWN = 0,
XBOX360,
XBOXONE,
} xinput_type_t;
//--------------------------------------------------------------------+
// Interface API
//--------------------------------------------------------------------+

View File

@@ -13,6 +13,8 @@ class SwitchDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
SwitchReport switchReport;

View File

@@ -0,0 +1,39 @@
#ifndef _XBONEAUTH_H_
#define _XBONEAUTH_H_
#include "drivers/shared/gpauthdriver.h"
#include "drivers/shared/xgip_protocol.h"
typedef enum {
auth_idle_state = 0,
send_auth_console_to_dongle = 1,
send_auth_dongle_to_console = 2,
wait_auth_console_to_dongle = 3,
wait_auth_dongle_to_console = 4,
} XboxOneState;
typedef struct {
XboxOneState xboneState;
// Console-to-Host e.g. Xbox One to MagicBoots
// Note: the Xbox One Passthrough can call send_xbone_report() directly but not the other way around
bool authCompleted;
// Auth Buffer
uint8_t authBuffer[1024];
uint8_t authSequence;
uint16_t authLen;
uint8_t authType;
} XboxOneAuthData;
class XBOneAuth : public GPAuthDriver {
public:
virtual void initialize();
virtual bool available();
void process();
XboxOneAuthData * getAuthData() { return &xboxOneAuthData; }
private:
XboxOneAuthData xboxOneAuthData;
};
#endif

View File

@@ -0,0 +1,33 @@
#ifndef _XBONEAUTHUSBLISTENER_H_
#define _XBONEAUTHUSBLISTENER_H_
#include "drivers/shared/xgip_protocol.h"
#include "usblistener.h"
#include "drivers/xbone/XBOneAuth.h"
class XBOneAuthUSBListener : public USBListener {
public:
virtual void setup();
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len){}
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype);
virtual void unmount(uint8_t dev_addr);
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len){}
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len){}
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len){}
void process();
void setAuthData(XboxOneAuthData *);
private:
void queue_host_report(void* report, uint16_t len);
void process_report_queue();
uint8_t xbone_dev_addr;
uint8_t xbone_instance;
bool dongle_ready;
bool mounted;
XGIPProtocol incomingXGIP;
XGIPProtocol outgoingXGIP;
XboxOneAuthData * xboxOneAuthData;
};
#endif // _XBONEAUTHUSBLISTENER_H_

View File

@@ -9,11 +9,14 @@
#include "gpdriver.h"
#include "drivers/xbone/XBOneDescriptors.h"
#include "drivers/shared/xgip_protocol.h"
#include "drivers/shared/gpauthdriver.h"
class XBOneDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux();
virtual void processAux();
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -23,6 +26,8 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener();
bool getAuthSent();
private:
virtual void update();
bool send_xbone_usb(uint8_t const *buffer, uint16_t bufsize);
@@ -34,6 +39,7 @@ private:
uint8_t keep_alive_sequence;
uint8_t virtual_keycode_sequence;
bool xb1_guide_pressed;
GPAuthDriver * authDriver;
};
#endif // _XBONE_DRIVER_H_

View File

@@ -13,6 +13,8 @@ class XboxOriginalDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux() {}
virtual void processAux() {}
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,6 +24,7 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener() { return nullptr; }
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
XboxOriginalReport xboxOriginalReport;

View File

@@ -0,0 +1,29 @@
#ifndef _XINPUTAUTH_H_
#define _XINPUTAUTH_H_
#include "drivers/shared/gpauthdriver.h"
typedef enum {
auth_idle_state = 0,
send_auth_console_to_dongle = 1,
send_auth_dongle_to_console = 2,
wait_auth_console_to_dongle = 3,
wait_auth_dongle_to_console = 4,
} XInputAuthState;
typedef struct {
XInputAuthState xboneState;
// Console-to-Host e.g. Xbox 360 to MagicBoots
bool authCompleted;
} XInputAuthData;
class XInputAuth : public GPAuthDriver {
public:
virtual void initialize();
virtual bool available();
void process();
private:
};
#endif

View File

@@ -0,0 +1,24 @@
#ifndef _XINPUTAUTHUSBLISTENER_H_
#define _XINPUTAUTHUSBLISTENER_H_
#include "usblistener.h"
class XInputAuthUSBListener : public USBListener {
public:
virtual void setup();
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len){}
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype);
virtual void unmount(uint8_t dev_addr);
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len){}
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len){}
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len){}
void process();
private:
uint8_t xinput_dev_addr;
uint8_t xinput_instance;
bool dongle_ready;
bool mounted;
};
#endif // _XINPUTAUTHUSBLISTENER_H_

View File

@@ -7,12 +7,16 @@
#define _XINPUT_DRIVER_H_
#include "gpdriver.h"
#include "usblistener.h"
#include "drivers/shared/gpauthdriver.h"
#include "drivers/xinput/XInputDescriptors.h"
class XInputDriver : public GPDriver {
public:
virtual void initialize();
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
virtual void initializeAux();
virtual void processAux();
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
@@ -22,9 +26,11 @@ public:
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
virtual const uint8_t * get_descriptor_device_qualifier_cb();
virtual uint16_t GetJoystickMidValue();
virtual USBListener * get_usb_auth_listener();
private:
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
XInputReport xinputReport;
GPAuthDriver * authDriver;
};
#endif

View File

@@ -51,6 +51,7 @@ private:
SET_INPUT_MODE_XINPUT,
SET_INPUT_MODE_KEYBOARD,
SET_INPUT_MODE_PS4,
SET_INPUT_MODE_PS5,
SET_INPUT_MODE_XBONE,
SET_INPUT_MODE_NEOGEO,
SET_INPUT_MODE_MDMINI,

View File

@@ -6,11 +6,8 @@
#ifndef GP2040CORE1_H_
#define GP2040CORE1_H_
#include <vector>
#include "gpaddon.h"
#include "addonmanager.h"
#include "peripheralmanager.h"
#include "drivermanager.h"
class GP2040Aux {
public:
@@ -19,6 +16,7 @@ public:
void setup(); // setup core1
void run(); // loop core1
private:
GPDriver * inputDriver;
AddonManager addons;
};

View File

@@ -2,25 +2,32 @@
#define _GPAddon_H_
#include "gamepad.h"
#include "usblistener.h"
#include <string>
class GPAddon
{
public:
virtual ~GPAddon() { }
virtual bool available() = 0;
virtual void setup() = 0;
virtual void process() = 0;
virtual void preprocess() = 0;
virtual std::string name() = 0;
virtual ~GPAddon() { }
virtual bool available() = 0;
virtual void setup() = 0;
virtual void process() = 0;
virtual void preprocess() = 0;
virtual std::string name() = 0;
/**
* Reinitialize the addon --- only implement this if it makes sense to, e.g. if this
* addon allows its pin assignments to be changed, in which case it needs to rebuild
* its pin masks, as is needed for DDI and sliders.
*/
virtual void reinit() { }
/**
* Reinitialize the addon --- only implement this if it makes sense to, e.g. if this
* addon allows its pin assignments to be changed, in which case it needs to rebuild
* its pin masks, as is needed for DDI and sliders.
*/
virtual void reinit() { }
// For add-ons that require a USB-host listener, get listener
virtual USBListener * getListener() { return listener; }
protected:
USBListener * listener;
};
#endif

View File

@@ -15,6 +15,8 @@
#include "class/hid/hid.h"
#include "device/usbd_pvt.h"
#include "usblistener.h"
// Forward declare gamepad
class Gamepad;
@@ -24,7 +26,9 @@ class Gamepad;
class GPDriver {
public:
virtual void initialize() = 0;
virtual void initializeAux() = 0;
virtual void process(Gamepad * gamepad, uint8_t * outBuffer) = 0;
virtual void processAux() = 0;
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) = 0;
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) = 0;
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) = 0;
@@ -35,6 +39,7 @@ public:
virtual const uint8_t * get_descriptor_device_qualifier_cb() = 0;
virtual uint16_t GetJoystickMidValue() = 0;
const usbd_class_driver_t * get_class_driver() { return &class_driver; }
virtual USBListener * get_usb_auth_listener() = 0;
protected:
usbd_class_driver_t class_driver;
};

View File

@@ -1,26 +0,0 @@
#ifndef _USBAddon_H_
#define _USBAddon_H_
#include "gpaddon.h"
#include <string>
class USBAddon : public GPAddon
{
public:
virtual ~USBAddon() { }
virtual bool available() = 0;
virtual void setup() = 0;
virtual void process() = 0;
virtual void preprocess() = 0;
virtual std::string name() = 0;
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) = 0;
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) = 0;
virtual void unmount(uint8_t dev_addr) = 0;
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) = 0;
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) = 0;
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) = 0;
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) = 0;
};
#endif

View File

@@ -1,7 +1,7 @@
#ifndef _USBHOSTMANAGER_H_
#define _USBHOSTMANAGER_H_
#include "usbaddon.h"
#include "usblistener.h"
#include <vector>
#include "pio_usb.h"
@@ -25,7 +25,7 @@ public:
}
void start(); // Start USB Host
void shutdown(); // Called on system reboot
void pushAddon(USBAddon *); // If anything needs to update in the gpconfig driver
void pushListener(USBListener *); // If anything needs to update in the gpconfig driver
void process();
void hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
void hid_umount_cb(uint8_t daddr, uint8_t instance);
@@ -38,10 +38,8 @@ public:
void xinput_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
private:
USBHostManager() : tuh_ready(false), core0Ready(false), core1Ready(false) {
}
std::vector<USBAddon*> addons;
USBHostManager() : tuh_ready(false), core0Ready(false), core1Ready(false) {}
std::vector<USBListener*> listeners;
usb_device_t *usb_device;
uint8_t dataPin;
bool tuh_ready;

19
headers/usblistener.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef _USBLISTENER_H_
#define _USBLISTENER_H_
#include <cstdint>
class USBListener
{
public:
virtual void setup() = 0;
virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) = 0;
virtual void xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) = 0;
virtual void unmount(uint8_t dev_addr) = 0;
virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) = 0;
virtual void report_sent(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) = 0;
virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) = 0;
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) = 0;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -123,9 +123,20 @@ enum InputMode
INPUT_MODE_ASTRO = 10;
INPUT_MODE_PSCLASSIC = 11;
INPUT_MODE_XBOXORIGINAL = 12;
INPUT_MODE_PS5 = 13;
INPUT_MODE_CONFIG = 255;
}
enum InputModeAuthType
{
option (nanopb_enumopt).long_names = false;
INPUT_MODE_AUTH_TYPE_NONE = 0;
INPUT_MODE_AUTH_TYPE_KEYS = 1;
INPUT_MODE_AUTH_TYPE_USB = 2;
INPUT_MODE_AUTH_TYPE_I2C = 3;
}
enum DpadMode
{
option (nanopb_enumopt).long_names = false;

View File

@@ -1,29 +1,26 @@
#include "addonmanager.h"
#include "usbhostmanager.h"
void AddonManager::LoadAddon(GPAddon* addon, ADDON_PROCESS processAt) {
bool AddonManager::LoadAddon(GPAddon* addon, ADDON_PROCESS processAt) {
if (addon->available()) {
AddonBlock * block = new AddonBlock;
addon->setup();
addon->setup();
block->ptr = addon;
block->process = processAt;
addons.push_back(block);
} else {
delete addon; // Don't use the memory if we don't have to
return true;
} else {
delete addon; // Don't use the memory if we don't have to
}
return false;
}
void AddonManager::LoadUSBAddon(USBAddon* addon, ADDON_PROCESS processAt) {
if (addon->available()) {
AddonBlock * block = new AddonBlock;
addon->setup();
block->ptr = addon;
block->process = processAt;
addons.push_back(block);
USBHostManager::getInstance().pushAddon(addon);
} else {
delete addon; // Don't use the memory if we don't have to
}
bool AddonManager::LoadUSBAddon(GPAddon* addon, ADDON_PROCESS processAt) {
bool ret = LoadAddon(addon, processAt);
if ( ret == true )
USBHostManager::getInstance().pushListener(addon->getListener());
return ret;
}
void AddonManager::ReinitializeAddons(ADDON_PROCESS processType) {

View File

@@ -1,9 +1,9 @@
#include "addons/board_led.h"
#include "drivers/shared/ps4data.h"
#include "drivermanager.h"
#include "drivers/ps4/PS4Driver.h"
#include "usbdriver.h"
#include "helper.h"
#include "config.pb.h"
#include "drivermanager.h"
bool BoardLedAddon::available() {
const OnBoardLedOptions& options = Storage::getInstance().getAddonOptions().onBoardLedOptions;
@@ -70,7 +70,10 @@ void BoardLedAddon::process() {
}
break;
case OnBoardLedMode::ON_BOARD_LED_MODE_PS_AUTH:
state = PS4Data::getInstance().authsent == true;
if(processedGamepad->getOptions().inputMode == INPUT_MODE_PS4 ||
processedGamepad->getOptions().inputMode == INPUT_MODE_PS5) {
state = ((PS4Driver*)DriverManager::getInstance().getDriver())->getAuthSent() == true;
}
if (prevState != state) {
gpio_put(BOARD_LED_PIN, state ? 1 : 0);
}

View File

@@ -9,7 +9,9 @@
#include "storagemanager.h"
#include "pico/stdlib.h"
#include "bitmaps.h"
#include "drivers/shared/ps4data.h"
#include "drivers/ps4/PS4Driver.h"
#include "drivers/xbone/XBOneDriver.h"
#include "drivermanager.h"
#include "usbdriver.h"
#include "version.h"
#include "config.pb.h"
@@ -160,19 +162,26 @@ void DisplayAddon::drawStatusBar(Gamepad * gamepad)
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 )
statusBar += "PS4:AS";
else
statusBar += "PS4 ";
} else if ( PS4Data::getInstance().ps4ControllerType == PS4ControllerType::PS4_ARCADESTICK ) {
if (PS4Data::getInstance().authsent == true )
statusBar += "PS5:AS";
else
statusBar += "PS5 ";
}
statusBar += "PS4";
if(((PS4Driver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += ":AS";
else
statusBar += " ";
break;
case INPUT_MODE_PS5:
statusBar += "PS5";
if(((PS4Driver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += ":AS";
else
statusBar += " ";
break;
case INPUT_MODE_XBONE:
statusBar += "XBON";
if(((XBOneDriver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += "E";
else
statusBar += "*";
break;
case INPUT_MODE_XBONE: statusBar += "XBONE"; break;
case INPUT_MODE_KEYBOARD: statusBar += "HID-KB"; break;
case INPUT_MODE_CONFIG: statusBar += "CONFIG"; break;
}

View File

@@ -1,4 +1,5 @@
#include "addons/keyboard_host.h"
#include "addons/keyboard_host_listener.h"
#include "storagemanager.h"
#include "drivermanager.h"
#include "usbhostmanager.h"
@@ -11,144 +12,9 @@ bool KeyboardHostAddon::available() {
}
void KeyboardHostAddon::setup() {
const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions;
const KeyboardMapping& keyboardMapping = keyboardHostOptions.mapping;
_keyboard_host_enabled = false;
_keyboard_host_mapDpadUp.setMask(GAMEPAD_MASK_UP);
_keyboard_host_mapDpadDown.setMask(GAMEPAD_MASK_DOWN);
_keyboard_host_mapDpadLeft.setMask(GAMEPAD_MASK_LEFT);
_keyboard_host_mapDpadRight.setMask(GAMEPAD_MASK_RIGHT);
_keyboard_host_mapButtonB1.setMask(GAMEPAD_MASK_B1);
_keyboard_host_mapButtonB2.setMask(GAMEPAD_MASK_B2);
_keyboard_host_mapButtonB3.setMask(GAMEPAD_MASK_B3);
_keyboard_host_mapButtonB4.setMask(GAMEPAD_MASK_B4);
_keyboard_host_mapButtonL1.setMask(GAMEPAD_MASK_L1);
_keyboard_host_mapButtonR1.setMask(GAMEPAD_MASK_R1);
_keyboard_host_mapButtonL2.setMask(GAMEPAD_MASK_L2);
_keyboard_host_mapButtonR2.setMask(GAMEPAD_MASK_R2);
_keyboard_host_mapButtonS1.setMask(GAMEPAD_MASK_S1);
_keyboard_host_mapButtonS2.setMask(GAMEPAD_MASK_S2);
_keyboard_host_mapButtonL3.setMask(GAMEPAD_MASK_L3);
_keyboard_host_mapButtonR3.setMask(GAMEPAD_MASK_R3);
_keyboard_host_mapButtonA1.setMask(GAMEPAD_MASK_A1);
_keyboard_host_mapButtonA2.setMask(GAMEPAD_MASK_A2);
_keyboard_host_mapDpadUp.setKey(keyboardMapping.keyDpadUp);
_keyboard_host_mapDpadDown.setKey(keyboardMapping.keyDpadDown);
_keyboard_host_mapDpadLeft.setKey(keyboardMapping.keyDpadLeft);
_keyboard_host_mapDpadRight.setKey(keyboardMapping.keyDpadRight);
_keyboard_host_mapButtonB1.setKey(keyboardMapping.keyButtonB1);
_keyboard_host_mapButtonB2.setKey(keyboardMapping.keyButtonB2);
_keyboard_host_mapButtonR2.setKey(keyboardMapping.keyButtonR2);
_keyboard_host_mapButtonL2.setKey(keyboardMapping.keyButtonL2);
_keyboard_host_mapButtonB3.setKey(keyboardMapping.keyButtonB3);
_keyboard_host_mapButtonB4.setKey(keyboardMapping.keyButtonB4);
_keyboard_host_mapButtonR1.setKey(keyboardMapping.keyButtonR1);
_keyboard_host_mapButtonL1.setKey(keyboardMapping.keyButtonL1);
_keyboard_host_mapButtonS1.setKey(keyboardMapping.keyButtonS1);
_keyboard_host_mapButtonS2.setKey(keyboardMapping.keyButtonS2);
_keyboard_host_mapButtonL3.setKey(keyboardMapping.keyButtonL3);
_keyboard_host_mapButtonR3.setKey(keyboardMapping.keyButtonR3);
_keyboard_host_mapButtonA1.setKey(keyboardMapping.keyButtonA1);
_keyboard_host_mapButtonA2.setKey(keyboardMapping.keyButtonA2);
listener = new KeyboardHostListener();
}
void KeyboardHostAddon::preprocess() {
Gamepad *gamepad = Storage::getInstance().GetGamepad();
gamepad->state.dpad |= _keyboard_host_state.dpad;
gamepad->state.buttons |= _keyboard_host_state.buttons;
gamepad->state.lx |= _keyboard_host_state.lx;
gamepad->state.ly |= _keyboard_host_state.ly;
gamepad->state.rx |= _keyboard_host_state.rx;
gamepad->state.ry |= _keyboard_host_state.ry;
if (!gamepad->hasAnalogTriggers) {
gamepad->state.lt |= _keyboard_host_state.lt;
gamepad->state.rt |= _keyboard_host_state.rt;
}
((KeyboardHostListener*)listener)->process();
}
void KeyboardHostAddon::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
_keyboard_host_enabled = true;
}
void KeyboardHostAddon::unmount(uint8_t dev_addr) {
_keyboard_host_enabled = false;
}
void KeyboardHostAddon::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len){
if ( _keyboard_host_enabled == false )
return; // do nothing if our add-on is not enabled
// Interface protocol (hid_interface_protocol_enum_t)
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
// tuh_hid_report_received_cb() will be invoked when report is available
if (itf_protocol != HID_ITF_PROTOCOL_KEYBOARD)
return;
process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report );
}
uint8_t KeyboardHostAddon::getKeycodeFromModifier(uint8_t modifier) {
switch (modifier) {
case KEYBOARD_MODIFIER_LEFTCTRL : return HID_KEY_CONTROL_LEFT ;
case KEYBOARD_MODIFIER_LEFTSHIFT : return HID_KEY_SHIFT_LEFT ;
case KEYBOARD_MODIFIER_LEFTALT : return HID_KEY_ALT_LEFT ;
case KEYBOARD_MODIFIER_LEFTGUI : return HID_KEY_GUI_LEFT ;
case KEYBOARD_MODIFIER_RIGHTCTRL : return HID_KEY_CONTROL_RIGHT;
case KEYBOARD_MODIFIER_RIGHTSHIFT : return HID_KEY_SHIFT_RIGHT ;
case KEYBOARD_MODIFIER_RIGHTALT : return HID_KEY_ALT_RIGHT ;
case KEYBOARD_MODIFIER_RIGHTGUI : return HID_KEY_GUI_RIGHT ;
}
return 0;
}
// convert hid keycode to ascii and print via usb device CDC (ignore non-printable)
void KeyboardHostAddon::process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report)
{
uint16_t joystickMid = GAMEPAD_JOYSTICK_MID;
if ( DriverManager::getInstance().getDriver() != nullptr ) {
joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue();
}
_keyboard_host_state.dpad = 0;
_keyboard_host_state.buttons = 0;
_keyboard_host_state.lx = joystickMid;
_keyboard_host_state.ly = joystickMid;
_keyboard_host_state.rx = joystickMid;
_keyboard_host_state.ry = joystickMid;
_keyboard_host_state.lt = 0;
_keyboard_host_state.rt = 0;
for(uint8_t i=0; i<7; i++)
{
uint8_t keycode = (i < 6) ? report->keycode[i] : getKeycodeFromModifier(report->modifier);
if ( keycode )
{
_keyboard_host_state.dpad |=
((keycode == _keyboard_host_mapDpadUp.key) ? _keyboard_host_mapDpadUp.buttonMask : _keyboard_host_state.dpad)
| ((keycode == _keyboard_host_mapDpadDown.key) ? _keyboard_host_mapDpadDown.buttonMask : _keyboard_host_state.dpad)
| ((keycode == _keyboard_host_mapDpadLeft.key) ? _keyboard_host_mapDpadLeft.buttonMask : _keyboard_host_state.dpad)
| ((keycode == _keyboard_host_mapDpadRight.key) ? _keyboard_host_mapDpadRight.buttonMask : _keyboard_host_state.dpad)
;
_keyboard_host_state.buttons |=
((keycode == _keyboard_host_mapButtonB1.key) ? _keyboard_host_mapButtonB1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonB2.key) ? _keyboard_host_mapButtonB2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonB3.key) ? _keyboard_host_mapButtonB3.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonB4.key) ? _keyboard_host_mapButtonB4.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonL1.key) ? _keyboard_host_mapButtonL1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonR1.key) ? _keyboard_host_mapButtonR1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonL2.key) ? _keyboard_host_mapButtonL2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonR2.key) ? _keyboard_host_mapButtonR2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonS1.key) ? _keyboard_host_mapButtonS1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonS2.key) ? _keyboard_host_mapButtonS2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonL3.key) ? _keyboard_host_mapButtonL3.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonR3.key) ? _keyboard_host_mapButtonR3.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonA1.key) ? _keyboard_host_mapButtonA1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonA2.key) ? _keyboard_host_mapButtonA2.buttonMask : _keyboard_host_state.buttons)
;
}
}
}

View File

@@ -0,0 +1,148 @@
#include "addons/keyboard_host_listener.h"
#include "drivermanager.h"
#include "storagemanager.h"
#include "class/hid/hid_host.h"
void KeyboardHostListener::setup() {
const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions;
const KeyboardMapping& keyboardMapping = keyboardHostOptions.mapping;
_keyboard_host_mapDpadUp.setMask(GAMEPAD_MASK_UP);
_keyboard_host_mapDpadDown.setMask(GAMEPAD_MASK_DOWN);
_keyboard_host_mapDpadLeft.setMask(GAMEPAD_MASK_LEFT);
_keyboard_host_mapDpadRight.setMask(GAMEPAD_MASK_RIGHT);
_keyboard_host_mapButtonB1.setMask(GAMEPAD_MASK_B1);
_keyboard_host_mapButtonB2.setMask(GAMEPAD_MASK_B2);
_keyboard_host_mapButtonB3.setMask(GAMEPAD_MASK_B3);
_keyboard_host_mapButtonB4.setMask(GAMEPAD_MASK_B4);
_keyboard_host_mapButtonL1.setMask(GAMEPAD_MASK_L1);
_keyboard_host_mapButtonR1.setMask(GAMEPAD_MASK_R1);
_keyboard_host_mapButtonL2.setMask(GAMEPAD_MASK_L2);
_keyboard_host_mapButtonR2.setMask(GAMEPAD_MASK_R2);
_keyboard_host_mapButtonS1.setMask(GAMEPAD_MASK_S1);
_keyboard_host_mapButtonS2.setMask(GAMEPAD_MASK_S2);
_keyboard_host_mapButtonL3.setMask(GAMEPAD_MASK_L3);
_keyboard_host_mapButtonR3.setMask(GAMEPAD_MASK_R3);
_keyboard_host_mapButtonA1.setMask(GAMEPAD_MASK_A1);
_keyboard_host_mapButtonA2.setMask(GAMEPAD_MASK_A2);
_keyboard_host_mapDpadUp.setKey(keyboardMapping.keyDpadUp);
_keyboard_host_mapDpadDown.setKey(keyboardMapping.keyDpadDown);
_keyboard_host_mapDpadLeft.setKey(keyboardMapping.keyDpadLeft);
_keyboard_host_mapDpadRight.setKey(keyboardMapping.keyDpadRight);
_keyboard_host_mapButtonB1.setKey(keyboardMapping.keyButtonB1);
_keyboard_host_mapButtonB2.setKey(keyboardMapping.keyButtonB2);
_keyboard_host_mapButtonR2.setKey(keyboardMapping.keyButtonR2);
_keyboard_host_mapButtonL2.setKey(keyboardMapping.keyButtonL2);
_keyboard_host_mapButtonB3.setKey(keyboardMapping.keyButtonB3);
_keyboard_host_mapButtonB4.setKey(keyboardMapping.keyButtonB4);
_keyboard_host_mapButtonR1.setKey(keyboardMapping.keyButtonR1);
_keyboard_host_mapButtonL1.setKey(keyboardMapping.keyButtonL1);
_keyboard_host_mapButtonS1.setKey(keyboardMapping.keyButtonS1);
_keyboard_host_mapButtonS2.setKey(keyboardMapping.keyButtonS2);
_keyboard_host_mapButtonL3.setKey(keyboardMapping.keyButtonL3);
_keyboard_host_mapButtonR3.setKey(keyboardMapping.keyButtonR3);
_keyboard_host_mapButtonA1.setKey(keyboardMapping.keyButtonA1);
_keyboard_host_mapButtonA2.setKey(keyboardMapping.keyButtonA2);
_keyboard_host_enabled = false;
}
void KeyboardHostListener::process() {
Gamepad *gamepad = Storage::getInstance().GetGamepad();
gamepad->state.dpad |= _keyboard_host_state.dpad;
gamepad->state.buttons |= _keyboard_host_state.buttons;
gamepad->state.lx |= _keyboard_host_state.lx;
gamepad->state.ly |= _keyboard_host_state.ly;
gamepad->state.rx |= _keyboard_host_state.rx;
gamepad->state.ry |= _keyboard_host_state.ry;
if (!gamepad->hasAnalogTriggers) {
gamepad->state.lt |= _keyboard_host_state.lt;
gamepad->state.rt |= _keyboard_host_state.rt;
}
}
void KeyboardHostListener::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
_keyboard_host_enabled = true;
}
void KeyboardHostListener::unmount(uint8_t dev_addr) {
_keyboard_host_enabled = false;
}
void KeyboardHostListener::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len){
if ( _keyboard_host_enabled == false )
return; // do nothing if we haven't mounted
// Interface protocol (hid_interface_protocol_enum_t)
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
// tuh_hid_report_received_cb() will be invoked when report is available
if (itf_protocol != HID_ITF_PROTOCOL_KEYBOARD)
return;
process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report );
}
uint8_t KeyboardHostListener::getKeycodeFromModifier(uint8_t modifier) {
switch (modifier) {
case KEYBOARD_MODIFIER_LEFTCTRL : return HID_KEY_CONTROL_LEFT ;
case KEYBOARD_MODIFIER_LEFTSHIFT : return HID_KEY_SHIFT_LEFT ;
case KEYBOARD_MODIFIER_LEFTALT : return HID_KEY_ALT_LEFT ;
case KEYBOARD_MODIFIER_LEFTGUI : return HID_KEY_GUI_LEFT ;
case KEYBOARD_MODIFIER_RIGHTCTRL : return HID_KEY_CONTROL_RIGHT;
case KEYBOARD_MODIFIER_RIGHTSHIFT : return HID_KEY_SHIFT_RIGHT ;
case KEYBOARD_MODIFIER_RIGHTALT : return HID_KEY_ALT_RIGHT ;
case KEYBOARD_MODIFIER_RIGHTGUI : return HID_KEY_GUI_RIGHT ;
}
return 0;
}
// convert hid keycode to ascii and print via usb device CDC (ignore non-printable)
void KeyboardHostListener::process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report)
{
uint16_t joystickMid = GAMEPAD_JOYSTICK_MID;
if ( DriverManager::getInstance().getDriver() != nullptr ) {
joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue();
}
_keyboard_host_state.dpad = 0;
_keyboard_host_state.buttons = 0;
_keyboard_host_state.lx = joystickMid;
_keyboard_host_state.ly = joystickMid;
_keyboard_host_state.rx = joystickMid;
_keyboard_host_state.ry = joystickMid;
_keyboard_host_state.lt = 0;
_keyboard_host_state.rt = 0;
for(uint8_t i=0; i<7; i++)
{
uint8_t keycode = (i < 6) ? report->keycode[i] : getKeycodeFromModifier(report->modifier);
if ( keycode )
{
_keyboard_host_state.dpad |=
((keycode == _keyboard_host_mapDpadUp.key) ? _keyboard_host_mapDpadUp.buttonMask : _keyboard_host_state.dpad)
| ((keycode == _keyboard_host_mapDpadDown.key) ? _keyboard_host_mapDpadDown.buttonMask : _keyboard_host_state.dpad)
| ((keycode == _keyboard_host_mapDpadLeft.key) ? _keyboard_host_mapDpadLeft.buttonMask : _keyboard_host_state.dpad)
| ((keycode == _keyboard_host_mapDpadRight.key) ? _keyboard_host_mapDpadRight.buttonMask : _keyboard_host_state.dpad)
;
_keyboard_host_state.buttons |=
((keycode == _keyboard_host_mapButtonB1.key) ? _keyboard_host_mapButtonB1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonB2.key) ? _keyboard_host_mapButtonB2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonB3.key) ? _keyboard_host_mapButtonB3.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonB4.key) ? _keyboard_host_mapButtonB4.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonL1.key) ? _keyboard_host_mapButtonL1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonR1.key) ? _keyboard_host_mapButtonR1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonL2.key) ? _keyboard_host_mapButtonL2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonR2.key) ? _keyboard_host_mapButtonR2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonS1.key) ? _keyboard_host_mapButtonS1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonS2.key) ? _keyboard_host_mapButtonS2.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonL3.key) ? _keyboard_host_mapButtonL3.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonR3.key) ? _keyboard_host_mapButtonR3.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonA1.key) ? _keyboard_host_mapButtonA1.buttonMask : _keyboard_host_state.buttons)
| ((keycode == _keyboard_host_mapButtonA2.key) ? _keyboard_host_mapButtonA2.buttonMask : _keyboard_host_state.buttons)
;
}
}
}

View File

@@ -1,113 +0,0 @@
/*
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
*/
#include "addons/ps4mode.h"
#include "helper.h"
#include "config.pb.h"
#include "drivers/shared/ps4data.h"
#include "mbedtls/error.h"
#include "mbedtls/rsa.h"
#include "mbedtls/sha256.h"
#define NEW_CONFIG_MPI(name, buf, size) \
mbedtls_mpi_uint *bytes ## name = new mbedtls_mpi_uint[size / sizeof(mbedtls_mpi_uint)]; \
mbedtls_mpi name = { .s=1, .n=size / sizeof(mbedtls_mpi_uint), .p=bytes ## name }; \
memcpy(bytes ## name, buf, size);
#define DELETE_CONFIG_MPI(name) delete bytes ## name;
bool PS4ModeAddon::available() {
const PS4Options& options = Storage::getInstance().getAddonOptions().ps4Options;
return options.enabled
&& options.serial.size == sizeof(options.serial.bytes)
&& options.signature.size == sizeof(options.signature.bytes)
&& options.rsaN.size == sizeof(options.rsaN.bytes)
&& options.rsaE.size == sizeof(options.rsaE.bytes)
&& options.rsaP.size == sizeof(options.rsaP.bytes)
&& options.rsaQ.size == sizeof(options.rsaQ.bytes);
}
void PS4ModeAddon::setup() {
const PS4Options& options = Storage::getInstance().getAddonOptions().ps4Options;
ready = false;
NEW_CONFIG_MPI(N, options.rsaN.bytes, options.rsaN.size)
NEW_CONFIG_MPI(E, options.rsaE.bytes, options.rsaE.size)
NEW_CONFIG_MPI(P, options.rsaP.bytes, options.rsaP.size)
NEW_CONFIG_MPI(Q, options.rsaQ.bytes, options.rsaQ.size)
mbedtls_rsa_init(&rsa_context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
if (mbedtls_rsa_import(&rsa_context, &N, &P, &Q, nullptr, &E) == 0 &&
mbedtls_rsa_complete(&rsa_context) == 0) {
ready = true;
}
DELETE_CONFIG_MPI(N)
DELETE_CONFIG_MPI(E)
DELETE_CONFIG_MPI(P)
DELETE_CONFIG_MPI(Q)
}
void PS4ModeAddon::process() {
if (!ready) {
return;
}
const PS4Options& options = Storage::getInstance().getAddonOptions().ps4Options;
int rss_error = 0;
// Check to see if the PS4 Authentication needs work
if ( PS4Data::getInstance().ps4State == PS4State::nonce_ready ) {
// Generate some random for RNG
srand(getMillis());
auto rng = [](void*p_rng, unsigned char* p, size_t len) {
(void) p_rng;
p[0] = rand();
return 0;
};
uint8_t hashed_nonce[32];
uint8_t * nonce_buffer = PS4Data::getInstance().nonce_buffer;
uint8_t * ps4_auth_buffer = PS4Data::getInstance().ps4_auth_buffer;
// Sign the nonce now that we got it!
//
if ( mbedtls_sha256_ret(nonce_buffer, 256, hashed_nonce, 0) < 0 ) {
return;
}
rss_error = mbedtls_rsa_rsassa_pss_sign(&rsa_context, rng, nullptr,
MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256,
32, hashed_nonce,
&ps4_auth_buffer[0]);
if ( rss_error < 0 ) {
return;
}
// copy the parts into our authentication buffer
size_t offset = 256;
memcpy(&ps4_auth_buffer[offset], options.serial.bytes, 16);
offset += 16;
mbedtls_rsa_export_raw(
&rsa_context,
&ps4_auth_buffer[offset], 256,
nullptr, 0,
nullptr, 0,
nullptr, 0,
&ps4_auth_buffer[offset+256], 256
);
offset += 512;
memcpy(&ps4_auth_buffer[offset], options.signature.bytes, 256);
offset += 256;
memset(&ps4_auth_buffer[offset], 0, 24);
PS4Data::getInstance().ps4State = PS4State::signed_nonce_ready; // signed and ready to party
}
}

View File

@@ -1,161 +0,0 @@
#include "addons/pspassthrough.h"
#include "storagemanager.h"
#include "usbhostmanager.h"
#include "peripheralmanager.h"
#include "class/hid/hid.h"
#include "class/hid/hid_host.h"
#include "CRC32.h"
// Data passed between PS Passthrough and TinyUSB Host callbacks
bool PSPassthroughAddon::available() {
const PSPassthroughOptions& psOptions = Storage::getInstance().getAddonOptions().psPassthroughOptions;
const GamepadOptions& gamepadOptions = Storage::getInstance().GetGamepad()->getOptions();
return psOptions.enabled && PeripheralManager::getInstance().isUSBEnabled(0) && (gamepadOptions.inputMode == INPUT_MODE_PS4);
}
void PSPassthroughAddon::setup() {
nonce_page = 0; // no nonce yet
send_nonce_part = 0; // which part of the nonce are we getting from send?
awaiting_cb = false; // did we receive the sign state yet
passthrough_state = PS4State::no_nonce;
}
void PSPassthroughAddon::process() {
if (awaiting_cb)
return;
switch ( passthrough_state ) {
case PS4State::no_nonce:
// Did we get the nonce? Let's begin auth
if ( PS4Data::getInstance().ps4State == nonce_ready ) {
uint8_t const output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 };
uint8_t* buf = report_buffer;
uint16_t len = sizeof(output_0xf3);
memcpy(buf, output_0xf3, len);
awaiting_cb = true;
tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_RESET_AUTH, HID_REPORT_TYPE_FEATURE, buf, len);
}
break;
case PS4State::receiving_nonce:
{
uint8_t noncelen;
uint32_t crc32;
uint8_t nonce_buffer[64]; // [0xF0, ID, Page, 0, nonce(54 or 32 with 0 padding), CRC32 of data]
nonce_buffer[0] = PS4AuthReport::PS4_SET_AUTH_PAYLOAD;
nonce_buffer[1] = PS4Data::getInstance().nonce_id;
nonce_buffer[2] = nonce_page;
nonce_buffer[3] = 0;
if ( nonce_page == 4 ) {
noncelen = 32; // from 4 to 64 - 24 - 4
memcpy(&nonce_buffer[4], &PS4Data::getInstance().nonce_buffer[nonce_page*56], noncelen);
memset(&nonce_buffer[4+noncelen], 0, 24); // zero padding
} else {
noncelen = 56;
memcpy(&nonce_buffer[4], &PS4Data::getInstance().nonce_buffer[nonce_page*56], noncelen);
}
nonce_page++;
crc32 = CRC32::calculate(nonce_buffer, 60);
memcpy(&nonce_buffer[60], &crc32, sizeof(uint32_t));
uint8_t* buf = report_buffer;
uint16_t len = sizeof(nonce_buffer);
memcpy(buf, nonce_buffer, len);
awaiting_cb = true;
tuh_hid_set_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_SET_AUTH_PAYLOAD, HID_REPORT_TYPE_FEATURE, buf, len);
}
break;
case PS4State::signed_nonce_ready:
{
uint8_t state_buffer[16];
memset(state_buffer, 0, 16);
state_buffer[0] = PS4AuthReport::PS4_GET_SIGNING_STATE;
state_buffer[1] = PS4Data::getInstance().nonce_id;
memset(&state_buffer[2], 0, 14);
uint8_t* buf = report_buffer;
uint16_t len = sizeof(state_buffer);
memcpy(buf, state_buffer, len);
awaiting_cb = true;
tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_GET_SIGNING_STATE, HID_REPORT_TYPE_FEATURE, buf, len);
}
break;
case PS4State::sending_nonce:
{
uint8_t nonce_buffer[64];
nonce_buffer[0] = PS4AuthReport::PS4_GET_SIGNATURE_NONCE;
nonce_buffer[1] = PS4Data::getInstance().nonce_id; // nonce_id
nonce_buffer[2] = send_nonce_part; // next_part
memset(&nonce_buffer[3], 0, 61); // zero rest of memory
uint8_t* buf = report_buffer;
uint16_t len = sizeof(nonce_buffer);
memcpy(buf, nonce_buffer, len);
send_nonce_part++; // Nonce Part is reset during callback
awaiting_cb = true;
tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_GET_SIGNATURE_NONCE, HID_REPORT_TYPE_FEATURE, buf, len);
}
break;
default:
break;
};
}
void PSPassthroughAddon::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
ps_dev_addr = dev_addr;
ps_instance = instance;
// Reset as soon as its connected
memset(report_buffer, 0, sizeof(report_buffer));
report_buffer[0] = PS4AuthReport::PS4_DEFINITION;
uint8_t* buf = report_buffer;
uint16_t len = 48;
awaiting_cb = true;
tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_DEFINITION, HID_REPORT_TYPE_FEATURE, buf, len);
}
void PSPassthroughAddon::unmount(uint8_t dev_addr) {
nonce_page = 0; // no nonce yet
send_nonce_part = 0; // which part of the nonce are we getting from send?
awaiting_cb = false; // did we receive the sign state yet
passthrough_state = PS4State::no_nonce;
}
void PSPassthroughAddon::set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {
switch(report_id) {
case PS4AuthReport::PS4_SET_AUTH_PAYLOAD:
if (nonce_page == 5) {
nonce_page = 0;
passthrough_state = PS4State::signed_nonce_ready;
}
break;
default:
break;
};
awaiting_cb = false;
}
void PSPassthroughAddon::get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {
switch(report_id) {
case PS4AuthReport::PS4_DEFINITION:
break;
case PS4AuthReport::PS4_RESET_AUTH:
if ( PS4Data::getInstance().ps4State == PS4State::nonce_ready)
passthrough_state = PS4State::receiving_nonce;
break;
case PS4AuthReport::PS4_GET_SIGNING_STATE:
if (report_buffer[2] == 0) // 0 = ready, 1 = error in signing, 16 = not ready
passthrough_state = PS4State::sending_nonce;
break;
case PS4AuthReport::PS4_GET_SIGNATURE_NONCE:
memcpy(&PS4Data::getInstance().ps4_auth_buffer[(send_nonce_part-1)*56], &report_buffer[4], 56);
if (send_nonce_part == 19) {
send_nonce_part = 0;
passthrough_state = PS4State::no_nonce; // something we don't support
PS4Data::getInstance().ps4State = PS4State::signed_nonce_ready;
}
break;
default:
break;
};
awaiting_cb = false;
}

View File

@@ -24,8 +24,6 @@
#include "addons/neopicoleds.h"
#include "addons/playernum.h"
#include "addons/pleds.h"
#include "addons/ps4mode.h"
#include "addons/pspassthrough.h"
#include "addons/reverse.h"
#include "addons/slider_socd.h"
#include "addons/spi_analog_ads1256.h"
@@ -33,7 +31,6 @@
#include "addons/wiiext.h"
#include "addons/snes_input.h"
#include "addons/input_macro.h"
#include "addons/xbonepassthrough.h"
#include "addons/rotaryencoder.h"
#include "CRC32.h"
@@ -125,6 +122,18 @@
#define DEFAULT_PS4_REPORTHACK false
#endif
#ifndef DEFAULT_PS4AUTHENTICATION_TYPE
#define DEFAULT_PS4AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_NONE
#endif
#ifndef DEFAULT_PS5AUTHENTICATION_TYPE
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_NONE
#endif
#ifndef DEFAULT_XINPUTAUTHENTICATION_TYPE
#define DEFAULT_XINPUTAUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_NONE
#endif
#ifndef GPIO_PIN_00
#define GPIO_PIN_00 GpioAction::NONE
#endif
@@ -253,7 +262,9 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.gamepadOptions, inputModeL2, DEFAULT_INPUT_MODE_L2);
INIT_UNSET_PROPERTY(config.gamepadOptions, inputModeR1, DEFAULT_INPUT_MODE_R1);
INIT_UNSET_PROPERTY(config.gamepadOptions, inputModeR2, DEFAULT_INPUT_MODE_R2);
INIT_UNSET_PROPERTY(config.gamepadOptions, ps4ReportHack, DEFAULT_PS4_REPORTHACK);
INIT_UNSET_PROPERTY(config.gamepadOptions, ps4AuthType, DEFAULT_PS4AUTHENTICATION_TYPE);
INIT_UNSET_PROPERTY(config.gamepadOptions, ps5AuthType, DEFAULT_PS5AUTHENTICATION_TYPE);
INIT_UNSET_PROPERTY(config.gamepadOptions, xinputAuthType, DEFAULT_XINPUTAUTHENTICATION_TYPE);
// hotkeyOptions
HotkeyOptions& hotkeyOptions = config.hotkeyOptions;
@@ -402,10 +413,10 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(peripheralOptions.blockSPI1, sck, (!!SPI1_ENABLED) ? SPI1_PIN_SCK : -1);
INIT_UNSET_PROPERTY(peripheralOptions.blockSPI1, tx, (!!SPI1_ENABLED) ? SPI1_PIN_TX : -1);
INIT_UNSET_PROPERTY(peripheralOptions.blockUSB0, enabled, (PSPASSTHROUGH_ENABLED ? PSPASSTHROUGH_ENABLED : USB_PERIPHERAL_ENABLED));
INIT_UNSET_PROPERTY(peripheralOptions.blockUSB0, dp, (PSPASSTHROUGH_PIN_DPLUS != -1 ? PSPASSTHROUGH_PIN_DPLUS : USB_PERIPHERAL_PIN_DPLUS));
INIT_UNSET_PROPERTY(peripheralOptions.blockUSB0, enabled, USB_PERIPHERAL_ENABLED);
INIT_UNSET_PROPERTY(peripheralOptions.blockUSB0, dp, USB_PERIPHERAL_PIN_DPLUS);
INIT_UNSET_PROPERTY(peripheralOptions.blockUSB0, order, USB_PERIPHERAL_PIN_ORDER);
INIT_UNSET_PROPERTY(peripheralOptions.blockUSB0, enable5v, (PSPASSTHROUGH_PIN_5V != -1 ? PSPASSTHROUGH_PIN_5V : USB_PERIPHERAL_PIN_5V));
INIT_UNSET_PROPERTY(peripheralOptions.blockUSB0, enable5v, USB_PERIPHERAL_PIN_5V);
// ledOptions
INIT_UNSET_PROPERTY(config.ledOptions, dataPin, BOARD_LEDS_PIN);
@@ -494,7 +505,7 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.animationOptions, customThemeR3Pressed, 0);
INIT_UNSET_PROPERTY(config.animationOptions, customThemeA1Pressed, 0);
INIT_UNSET_PROPERTY(config.animationOptions, customThemeA2Pressed, 0);
INIT_UNSET_PROPERTY(config.animationOptions, buttonPressColorCooldownTimeInMs, 500);
INIT_UNSET_PROPERTY(config.animationOptions, buttonPressColorCooldownTimeInMs, LEDS_PRESS_COLOR_COOLDOWN_TIME);
// addonOptions.bootselButtonOptions
INIT_UNSET_PROPERTY(config.addonOptions.bootselButtonOptions, enabled, !!BOOTSEL_BUTTON_ENABLED);
@@ -628,7 +639,6 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.addonOptions.playerNumberOptions, number, PLAYER_NUMBER);
// addonOptions.ps4Options
INIT_UNSET_PROPERTY(config.addonOptions.ps4Options, enabled, PS4MODE_ADDON_ENABLED);
INIT_UNSET_PROPERTY_BYTES(config.addonOptions.ps4Options, serial, emptyByteArray);
INIT_UNSET_PROPERTY_BYTES(config.addonOptions.ps4Options, signature, emptyByteArray);
INIT_UNSET_PROPERTY_BYTES(config.addonOptions.ps4Options, rsaN, emptyByteArray);
@@ -703,12 +713,6 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.addonOptions.focusModeOptions, buttonLockEnabled, !!FOCUS_MODE_BUTTON_LOCK_ENABLED);
INIT_UNSET_PROPERTY(config.addonOptions.focusModeOptions, macroLockEnabled, !!FOCUS_MODE_MACRO_LOCK_ENABLED);
// PS Passthrough
INIT_UNSET_PROPERTY(config.addonOptions.psPassthroughOptions, enabled, PSPASSTHROUGH_ENABLED);
// Xbox One Passthrough
INIT_UNSET_PROPERTY(config.addonOptions.xbonePassthroughOptions, enabled, XBONEPASSTHROUGH_ENABLED);
INIT_UNSET_PROPERTY(config.addonOptions.macroOptions, enabled, !!INPUT_MACRO_ENABLED);
INIT_UNSET_PROPERTY(config.addonOptions.macroOptions, pin, INPUT_MACRO_PIN);
INIT_UNSET_PROPERTY(config.addonOptions.macroOptions, macroBoardLedEnabled, INPUT_MACRO_BOARD_LED_ENABLED);
@@ -957,7 +961,7 @@ void gpioMappingsMigrationCore(Config& config)
GPIO_PIN_27, GPIO_PIN_28, GPIO_PIN_29};
// If we didn't import from protobuf, import from boardconfig
for(int i = 0; i < NUM_BANK0_GPIOS; i++) {
for(unsigned int i = 0; i < NUM_BANK0_GPIOS; i++) {
fromBoardConfig(i, boardConfig[i]);
}
@@ -1230,6 +1234,40 @@ void checkAdditionalMigrations(Config& config) {
config.gpioMappings.pins[turboOptions.deprecatedButtonPin].action = GpioAction::BUTTON_PRESS_TURBO;
turboOptions.deprecatedButtonPin = -1; // set our turbo options to -1 for subsequent calls
}
// Auth migrations
GamepadOptions & gamepadOptions = config.gamepadOptions;
PS4Options & ps4Options = config.addonOptions.ps4Options;
PSPassthroughOptions & psPassthroughOptions = config.addonOptions.psPassthroughOptions;
XBOnePassthroughOptions & xbonePassthroughOptions = config.addonOptions.xbonePassthroughOptions;
if ( ps4Options.enabled == true ) { // PS4-Mode "on", assume keys are loaded, do not change modes
gamepadOptions.ps4AuthType = InputModeAuthType::INPUT_MODE_AUTH_TYPE_KEYS;
ps4Options.enabled = false; // disable PS4-Mode add-on permanently
}
if ( psPassthroughOptions.enabled == true ) { // PS5 add-on "on", USB pass through, update ps4->ps5 boot
gamepadOptions.ps5AuthType = InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB;
// If current mode is PS4, update to PS5
if ( gamepadOptions.inputMode == INPUT_MODE_PS4 ) {
gamepadOptions.inputMode = INPUT_MODE_PS5;
}
// Also update our boot mode from PS4 to PS5 if set
int32_t * bootModes[8] = { &config.gamepadOptions.inputModeB1, &config.gamepadOptions.inputModeB2,
&config.gamepadOptions.inputModeB3, &config.gamepadOptions.inputModeB4,
&config.gamepadOptions.inputModeL1, &config.gamepadOptions.inputModeL2,
&config.gamepadOptions.inputModeR1, &config.gamepadOptions.inputModeR2};
for(int32_t i = 0; i < 8; i++ ) {
if ( *bootModes[i] == INPUT_MODE_PS4 ) {
*bootModes[i] = INPUT_MODE_PS5; // modify ps4 -> ps5
}
}
psPassthroughOptions.enabled = false; // disable PS-Passthrough add-on permanently
}
if ( xbonePassthroughOptions.enabled == true ) { // Xbox One add-on "on", USB pass through is assumed
xbonePassthroughOptions.enabled = false; // disable and go on our way
}
}
// populate existing configurations' buttonsMask and auxMask to mirror behavior

File diff suppressed because it is too large Load Diff

View File

@@ -4,12 +4,13 @@ void GPScreen::draw() {
getRenderer()->clearScreen();
// draw the display list
std::sort(displayList.begin(), displayList.end(), [](GPWidget* a, GPWidget* b){ return a->getPriority() > b->getPriority(); });
for (uint16_t i=0; i<displayList.size(); i++) {
displayList.at(i)->draw();
if ( displayList.size() > 0 ) {
std::sort(displayList.begin(), displayList.end(), [](GPWidget* a, GPWidget* b){ return a->getPriority() > b->getPriority(); });
for(std::vector<GPWidget*>::iterator it = displayList.begin(); it != displayList.end(); it++) {
(*it)->draw();
}
}
drawScreen();
getRenderer()->render();
}

View File

@@ -15,6 +15,8 @@
#include "drivers/xboxog/XboxOriginalDriver.h"
#include "drivers/xinput/XInputDriver.h"
#include "usbhostmanager.h"
void DriverManager::setup(InputMode mode) {
switch (mode) {
case INPUT_MODE_CONFIG:
@@ -45,7 +47,10 @@ void DriverManager::setup(InputMode mode) {
driver = new PCEngineDriver();
break;
case INPUT_MODE_PS4:
driver = new PS4Driver();
driver = new PS4Driver(PS4_CONTROLLER);
break;
case INPUT_MODE_PS5:
driver = new PS4Driver(PS4_ARCADESTICK);
break;
case INPUT_MODE_SWITCH:
driver = new SwitchDriver();

148
src/drivers/ps4/PS4Auth.cpp Normal file
View File

@@ -0,0 +1,148 @@
#include "host/usbh.h"
#include "class/hid/hid.h"
#include "class/hid/hid_host.h"
#include "drivers/ps4/PS4Auth.h"
#include "drivers/ps4/PS4AuthUSBListener.h"
#include "CRC32.h"
#include "peripheralmanager.h"
#include "storagemanager.h"
#include "usbhostmanager.h"
#include "enums.pb.h"
#include "mbedtls/error.h"
#include "mbedtls/rsa.h"
#include "mbedtls/sha256.h"
#define NEW_CONFIG_MPI(name, buf, size) \
mbedtls_mpi_uint *bytes ## name = new mbedtls_mpi_uint[size / sizeof(mbedtls_mpi_uint)]; \
mbedtls_mpi name = { .s=1, .n=size / sizeof(mbedtls_mpi_uint), .p=bytes ## name }; \
memcpy(bytes ## name, buf, size);
#define DELETE_CONFIG_MPI(name) delete bytes ## name;
static inline int rng(void*p_rng, unsigned char* p, size_t len) {
(void) p_rng;
p[0] = rand();
return 0;
}
void PS4Auth::initialize() {
if ( !available() ) {
return;
}
memset(ps4_auth_buffer, 0, 1064); // we might not need to 0
if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_KEYS ) {
const PS4Options& options = Storage::getInstance().getAddonOptions().ps4Options;
valid_rsa = false;
NEW_CONFIG_MPI(N, options.rsaN.bytes, options.rsaN.size)
NEW_CONFIG_MPI(E, options.rsaE.bytes, options.rsaE.size)
NEW_CONFIG_MPI(P, options.rsaP.bytes, options.rsaP.size)
NEW_CONFIG_MPI(Q, options.rsaQ.bytes, options.rsaQ.size)
mbedtls_rsa_init(&rsa_context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
if (mbedtls_rsa_import(&rsa_context, &N, &P, &Q, nullptr, &E) == 0 &&
mbedtls_rsa_complete(&rsa_context) == 0) {
valid_rsa = true;
}
DELETE_CONFIG_MPI(N)
DELETE_CONFIG_MPI(E)
DELETE_CONFIG_MPI(P)
DELETE_CONFIG_MPI(Q)
ps4_keys_signature_ready = false;
listener = nullptr;
// Generate some random for RNG
srand(getMillis());
} else if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB ) {
PS4AuthUSBListener * newListener = new PS4AuthUSBListener();
newListener->setup();
newListener->setAuthBuffer(ps4_auth_buffer);
listener = newListener;
}
}
bool PS4Auth::available() {
// Move options over to their own ps4 data structure or gamepad?
if ( authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_KEYS ) {
const PS4Options& options = Storage::getInstance().getAddonOptions().ps4Options;
return options.serial.size == sizeof(options.serial.bytes)
&& options.signature.size == sizeof(options.signature.bytes)
&& options.rsaN.size == sizeof(options.rsaN.bytes)
&& options.rsaE.size == sizeof(options.rsaE.bytes)
&& options.rsaP.size == sizeof(options.rsaP.bytes)
&& options.rsaQ.size == sizeof(options.rsaQ.bytes);
} else if ( authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB ) {
return (PeripheralManager::getInstance().isUSBEnabled(0));
}
return false;
}
void PS4Auth::process(PS4State pState, uint8_t pNonceId, uint8_t * pNonceBuffer) {
if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_KEYS ) {
// Do not run if RSA is invalid
if (!valid_rsa) {
return;
}
// Check to see if the PS4 Authentication needs work
if ( pState == PS4State::nonce_ready && ps4_keys_signature_ready == false ) {
const PS4Options& options = Storage::getInstance().getAddonOptions().ps4Options;
int rss_error = 0;
uint8_t hashed_nonce[32];
// Sign the nonce now that we got it!
//
if ( mbedtls_sha256_ret(pNonceBuffer, 256, hashed_nonce, 0) < 0 ) {
return;
}
rss_error = mbedtls_rsa_rsassa_pss_sign(&rsa_context, rng, nullptr,
MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256,
32, hashed_nonce,
ps4_auth_buffer);
if ( rss_error < 0 ) {
return;
}
// copy the parts into our authentication buffer
size_t offset = 256;
memcpy(&ps4_auth_buffer[offset], options.serial.bytes, 16);
offset += 16;
mbedtls_rsa_export_raw(
&rsa_context,
&ps4_auth_buffer[offset], 256,
nullptr, 0,
nullptr, 0,
nullptr, 0,
&ps4_auth_buffer[offset+256], 256
);
offset += 512;
memcpy(&ps4_auth_buffer[offset], options.signature.bytes, 256);
offset += 256;
memset(&ps4_auth_buffer[offset], 0, 24);
ps4_keys_signature_ready = true; // auth buffer is ready
}
} else if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB ) {
((PS4AuthUSBListener*)listener)->process(pState, pNonceId, pNonceBuffer); // process HOST with client data
}
}
bool PS4Auth::getAuthReady() {
if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_KEYS ) {
return ps4_keys_signature_ready;
} else if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB ) {
return ((PS4AuthUSBListener*)listener)->getHostAuthReady();
}
return false;
}
void PS4Auth::resetAuth() {
if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_KEYS ) {
ps4_keys_signature_ready = false;
} else if (authType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB ) {
((PS4AuthUSBListener*)listener)->resetHostAuth();
}
}

View File

@@ -0,0 +1,150 @@
#include "host/usbh.h"
#include "class/hid/hid.h"
#include "class/hid/hid_host.h"
#include "drivers/ps4/PS4AuthUSBListener.h"
#include "CRC32.h"
#include "peripheralmanager.h"
#include "usbhostmanager.h"
static const uint8_t output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 };
void PS4AuthUSBListener::setup() {
nonce_page = 0; // no nonce yet
send_nonce_part = 0; // which part of the nonce are we getting from send?
awaiting_cb = false; // did we receive the sign state yet
passthrough_state = PS4State::no_nonce;
ps4_auth_host_ready = false;
ps4_auth_buffer = nullptr;
}
void PS4AuthUSBListener::process(PS4State pState, uint8_t pNonceId, uint8_t * pNonceBuffer) {
if ( awaiting_cb == true)
return;
uint8_t noncelen;
uint32_t crc32;
uint8_t buffer[64]; // [0xF0, ID, Page, 0, nonce(54 or 32 with 0 padding), CRC32 of data]
switch ( passthrough_state ) {
case PS4State::no_nonce:
// Did we get the nonce? Let's begin auth
if ( pState == nonce_ready ) {
ps4_auth_host_ready = false;
memcpy(report_buffer, output_0xf3, sizeof(output_0xf3));
host_get_report(PS4AuthReport::PS4_RESET_AUTH, report_buffer, sizeof(output_0xf3));
}
break;
case PS4State::receiving_nonce:
buffer[0] = PS4AuthReport::PS4_SET_AUTH_PAYLOAD; // [0xF0, ID, Page, 0, nonce(54 or 32 with 0 padding), CRC32 of data]
buffer[1] = pNonceId;
buffer[2] = nonce_page;
buffer[3] = 0;
if ( nonce_page == 4 ) {
noncelen = 32; // from 4 to 64 - 24 - 4
memcpy(&buffer[4], &pNonceBuffer[nonce_page*56], noncelen);
memset(&buffer[4+noncelen], 0, 24); // zero padding
} else {
noncelen = 56;
memcpy(&buffer[4], &pNonceBuffer[nonce_page*56], noncelen);
}
nonce_page++;
crc32 = CRC32::calculate(buffer, 60);
memcpy(&buffer[60], &crc32, sizeof(uint32_t));
memcpy(report_buffer, buffer, 64);
host_set_report(PS4AuthReport::PS4_SET_AUTH_PAYLOAD, report_buffer, 64);
break;
case PS4State::signed_nonce_ready:
buffer[0] = PS4AuthReport::PS4_GET_SIGNING_STATE;
buffer[1] = pNonceId;
memset(&buffer[2], 0, 14);
memcpy(report_buffer, buffer, 16);
host_get_report(PS4AuthReport::PS4_GET_SIGNING_STATE, report_buffer, 16);
break;
case PS4State::sending_nonce:
buffer[0] = PS4AuthReport::PS4_GET_SIGNATURE_NONCE;
buffer[1] = pNonceId; // nonce_id
buffer[2] = send_nonce_part; // next_part
memset(&buffer[3], 0, 61); // zero rest of memory
memcpy(report_buffer, buffer, 64);
send_nonce_part++; // Nonce Part is reset during callback
host_get_report(PS4AuthReport::PS4_GET_SIGNATURE_NONCE, report_buffer, 64);
break;
case PS4State::waiting_reset:
default:
break;
};
}
void PS4AuthUSBListener::resetHostAuth() {
nonce_page = 0; // no nonce yet
send_nonce_part = 0; // which part of the nonce are we getting from send?
passthrough_state = PS4State::no_nonce;
}
bool PS4AuthUSBListener::host_get_report(uint8_t report_id, void* report, uint16_t len) {
awaiting_cb = true;
return tuh_hid_get_report(ps_dev_addr, ps_instance, report_id, HID_REPORT_TYPE_FEATURE, report, len);
}
bool PS4AuthUSBListener::host_set_report(uint8_t report_id, void* report, uint16_t len) {
awaiting_cb = true;
return tuh_hid_set_report(ps_dev_addr, ps_instance, report_id, HID_REPORT_TYPE_FEATURE, report, len);
}
void PS4AuthUSBListener::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
ps_dev_addr = dev_addr;
ps_instance = instance;
// Reset as soon as its connected
memset(report_buffer, 0, sizeof(report_buffer));
report_buffer[0] = PS4AuthReport::PS4_DEFINITION;
host_get_report(PS4AuthReport::PS4_DEFINITION, report_buffer, 48);
}
void PS4AuthUSBListener::unmount(uint8_t dev_addr) {
nonce_page = 0; // no nonce yet
send_nonce_part = 0; // which part of the nonce are we getting from send?
awaiting_cb = false; // did we receive the sign state yet
passthrough_state = PS4State::no_nonce;
ps4_auth_host_ready = false;
}
void PS4AuthUSBListener::set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {
switch(report_id) {
case PS4AuthReport::PS4_SET_AUTH_PAYLOAD:
if (nonce_page == 5) {
nonce_page = 0;
passthrough_state = PS4State::signed_nonce_ready;
}
break;
default:
break;
};
awaiting_cb = false;
}
void PS4AuthUSBListener::get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {
switch(report_id) {
case PS4AuthReport::PS4_DEFINITION:
break;
case PS4AuthReport::PS4_RESET_AUTH:
passthrough_state = PS4State::receiving_nonce;
break;
case PS4AuthReport::PS4_GET_SIGNING_STATE:
if (report_buffer[2] == 0) // 0 = ready, 1 = error in signing, 16 = not ready
passthrough_state = PS4State::sending_nonce;
break;
case PS4AuthReport::PS4_GET_SIGNATURE_NONCE:
// probably should mutex lock
memcpy(&ps4_auth_buffer[(send_nonce_part-1)*56], &report_buffer[4], 56);
if (send_nonce_part == 19) {
send_nonce_part = 0;
passthrough_state = PS4State::waiting_reset; // something we don't support
ps4_auth_host_ready = true;
}
break;
default:
break;
};
awaiting_cb = false;
}

View File

@@ -1,5 +1,4 @@
#include "drivers/ps4/PS4Driver.h"
#include "drivers/shared/ps4data.h"
#include "drivers/shared/driverhelper.h"
#include "storagemanager.h"
#include "CRC32.h"
@@ -9,143 +8,174 @@
#include <random>
#include "class/hid/hid.h"
// ensure a report is sent every X ms
// PS4/PS5 Auth Systems
#include "drivers/ps4/PS4Auth.h"
#include "enums.pb.h"
// force a report to be sent every X ms
#define PS4_KEEPALIVE_TIMER 250
void PS4Driver::initialize() {
//touchpadData = {
// .p1 = 0x00,
// .p2 = 0x00
//};
//touchpadData = {
// .p1 = 0x00,
// .p2 = 0x00
//};
ps4Report = {
.report_id = 0x01,
.left_stick_x = PS4_JOYSTICK_MID,
.left_stick_y = PS4_JOYSTICK_MID,
.right_stick_x = PS4_JOYSTICK_MID,
.right_stick_y = PS4_JOYSTICK_MID,
.dpad = 0x08,
.button_west = 0, .button_south = 0, .button_east = 0, .button_north = 0,
.button_l1 = 0, .button_r1 = 0, .button_l2 = 0, .button_r2 = 0,
.button_select = 0, .button_start = 0, .button_l3 = 0, .button_r3 = 0, .button_home = 0,
.padding = 0,
.mystery = { },
.touchpad_data = touchpadData,
.mystery_2 = { }
};
ps4Report = {
.report_id = 0x01,
.left_stick_x = PS4_JOYSTICK_MID,
.left_stick_y = PS4_JOYSTICK_MID,
.right_stick_x = PS4_JOYSTICK_MID,
.right_stick_y = PS4_JOYSTICK_MID,
.dpad = 0x08,
.button_west = 0, .button_south = 0, .button_east = 0, .button_north = 0,
.button_l1 = 0, .button_r1 = 0, .button_l2 = 0, .button_r2 = 0,
.button_select = 0, .button_start = 0, .button_l3 = 0, .button_r3 = 0, .button_home = 0,
.padding = 0,
.mystery = { },
.touchpad_data = touchpadData,
.mystery_2 = { }
};
class_driver = {
#if CFG_TUSB_DEBUG >= 2
.name = "PS4",
#endif
.init = hidd_init,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
};
class_driver = {
#if CFG_TUSB_DEBUG >= 2
.name = "PS4",
#endif
.init = hidd_init,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
};
// setup PS5 compatibility
GamepadOptions& gamepadOptions = Storage::getInstance().getGamepadOptions();
PS4Data::getInstance().ps4ControllerType = gamepadOptions.ps4ControllerType;
last_report_counter = 0;
last_axis_counter = 0;
last_report_counter = 0;
last_axis_counter = 0;
cur_nonce_id = 1;
last_report_timer = to_ms_since_boot(get_absolute_time());
send_nonce_part = 0;
last_report_timer = to_ms_since_boot(get_absolute_time());
send_nonce_part = 0;
// for PS4 encryption
ps4State = PS4State::no_nonce;
authsent = false;
memset(nonce_buffer, 0, 256);
}
void PS4Driver::initializeAux() {
authDriver = nullptr;
GamepadOptions & gamepadOptions = Storage::getInstance().getGamepadOptions();
if ( controllerType == PS4ControllerType::PS4_CONTROLLER ) {
authDriver = new PS4Auth(gamepadOptions.ps4AuthType);
} else if ( controllerType == PS4ControllerType::PS4_ARCADESTICK ) {
// Setup PS5 Auth System
authDriver = new PS4Auth(gamepadOptions.ps5AuthType);
}
// If authentication driver is set AND auth driver can load (usb enabled, i2c enabled, keys loaded, etc.)
if ( authDriver != nullptr && authDriver->available() ) {
authDriver->initialize();
}
}
void PS4Driver::process(Gamepad * gamepad, uint8_t * outBuffer) {
const GamepadOptions & options = gamepad->getOptions();
switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD)
{
case GAMEPAD_MASK_UP: ps4Report.dpad = PS4_HAT_UP; break;
case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_UPRIGHT; break;
case GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_RIGHT; break;
case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_DOWNRIGHT; break;
case GAMEPAD_MASK_DOWN: ps4Report.dpad = PS4_HAT_DOWN; break;
case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_DOWNLEFT; break;
case GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_LEFT; break;
case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_UPLEFT; break;
default: ps4Report.dpad = PS4_HAT_NOTHING; break;
}
const GamepadOptions & options = gamepad->getOptions();
switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD)
{
case GAMEPAD_MASK_UP: ps4Report.dpad = PS4_HAT_UP; break;
case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_UPRIGHT; break;
case GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_RIGHT; break;
case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_DOWNRIGHT; break;
case GAMEPAD_MASK_DOWN: ps4Report.dpad = PS4_HAT_DOWN; break;
case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_DOWNLEFT; break;
case GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_LEFT; break;
case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_UPLEFT; break;
default: ps4Report.dpad = PS4_HAT_NOTHING; break;
}
ps4Report.button_south = gamepad->pressedB1();
ps4Report.button_east = gamepad->pressedB2();
ps4Report.button_west = gamepad->pressedB3();
ps4Report.button_north = gamepad->pressedB4();
ps4Report.button_l1 = gamepad->pressedL1();
ps4Report.button_r1 = gamepad->pressedR1();
ps4Report.button_l2 = gamepad->pressedL2();
ps4Report.button_r2 = gamepad->pressedR2();
ps4Report.button_select = options.switchTpShareForDs4 ? gamepad->pressedA2() : gamepad->pressedS1();
ps4Report.button_start = gamepad->pressedS2();
ps4Report.button_l3 = gamepad->pressedL3();
ps4Report.button_r3 = gamepad->pressedR3();
ps4Report.button_home = gamepad->pressedA1();
ps4Report.button_touchpad = options.switchTpShareForDs4 ? gamepad->pressedS1() : gamepad->pressedA2();
ps4Report.button_south = gamepad->pressedB1();
ps4Report.button_east = gamepad->pressedB2();
ps4Report.button_west = gamepad->pressedB3();
ps4Report.button_north = gamepad->pressedB4();
ps4Report.button_l1 = gamepad->pressedL1();
ps4Report.button_r1 = gamepad->pressedR1();
ps4Report.button_l2 = gamepad->pressedL2();
ps4Report.button_r2 = gamepad->pressedR2();
ps4Report.button_select = options.switchTpShareForDs4 ? gamepad->pressedA2() : gamepad->pressedS1();
ps4Report.button_start = gamepad->pressedS2();
ps4Report.button_l3 = gamepad->pressedL3();
ps4Report.button_r3 = gamepad->pressedR3();
ps4Report.button_home = gamepad->pressedA1();
ps4Report.button_touchpad = options.switchTpShareForDs4 ? gamepad->pressedS1() : gamepad->pressedA2();
ps4Report.left_stick_x = static_cast<uint8_t>(gamepad->state.lx >> 8);
ps4Report.left_stick_y = static_cast<uint8_t>(gamepad->state.ly >> 8);
ps4Report.right_stick_x = static_cast<uint8_t>(gamepad->state.rx >> 8);
ps4Report.right_stick_y = static_cast<uint8_t>(gamepad->state.ry >> 8);
ps4Report.left_stick_x = static_cast<uint8_t>(gamepad->state.lx >> 8);
ps4Report.left_stick_y = static_cast<uint8_t>(gamepad->state.ly >> 8);
ps4Report.right_stick_x = static_cast<uint8_t>(gamepad->state.rx >> 8);
ps4Report.right_stick_y = static_cast<uint8_t>(gamepad->state.ry >> 8);
if (gamepad->hasAnalogTriggers)
{
ps4Report.left_trigger = gamepad->state.lt;
ps4Report.right_trigger = gamepad->state.rt;
} else {
ps4Report.left_trigger = gamepad->pressedL2() ? 0xFF : 0;
ps4Report.right_trigger = gamepad->pressedR2() ? 0xFF : 0;
}
if (gamepad->hasAnalogTriggers)
{
ps4Report.left_trigger = gamepad->state.lt;
ps4Report.right_trigger = gamepad->state.rt;
} else {
ps4Report.left_trigger = gamepad->pressedL2() ? 0xFF : 0;
ps4Report.right_trigger = gamepad->pressedR2() ? 0xFF : 0;
}
// set touchpad to nothing
touchpadData.p1.unpressed = 1;
touchpadData.p2.unpressed = 1;
ps4Report.touchpad_data = touchpadData;
// set touchpad to nothing
touchpadData.p1.unpressed = 1;
touchpadData.p2.unpressed = 1;
ps4Report.touchpad_data = touchpadData;
// Wake up TinyUSB device
if (tud_suspended())
tud_remote_wakeup();
// Wake up TinyUSB device
if (tud_suspended())
tud_remote_wakeup();
uint32_t now = to_ms_since_boot(get_absolute_time());
void * report = &ps4Report;
uint16_t report_size = sizeof(ps4Report);
if (memcmp(last_report, report, report_size) != 0)
{
// HID ready + report sent, copy previous report
if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) {
memcpy(last_report, report, report_size);
}
// keep track of our last successful report, for keepalive purposes
last_report_timer = now;
} else {
// some games apparently can miss reports, or they rely on official behavior of getting frequent
// updates. we normally only send a report when the value changes; if we increment the counters
// every time we generate the report (every GP2040::run loop), we apparently overburden
// TinyUSB and introduce roughly 1ms of latency. but we want to loop often and report on every
// true update in order to achieve our tight <1ms report timing when we *do* have a different
// report to send.
// the "PS4 Hack" disables the counters so that we only report on changes, but this
// means we never report the same data twice, and games that expected it would get stuck
// inputs. the below code is a compromise: keep the tight report timing, but occasionally change
// the report counter and axis timing values in order to force a changed report --- this should
// eliminate the need for the PS4 Hack, but it's kept here at the moment for A/B testing purposes
if ( !options.ps4ReportHack ) {
if ((now - last_report_timer) > PS4_KEEPALIVE_TIMER) {
last_report_counter = (last_report_counter+1) & 0x3F;
ps4Report.report_counter = last_report_counter; // report counter is 6 bits
ps4Report.axis_timing = now; // axis counter is 16 bits
// the *next* process() will be a forced report (or real user input)
}
}
}
uint32_t now = to_ms_since_boot(get_absolute_time());
void * report = &ps4Report;
uint16_t report_size = sizeof(ps4Report);
if (memcmp(last_report, report, report_size) != 0)
{
// HID ready + report sent, copy previous report
if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) {
memcpy(last_report, report, report_size);
}
// keep track of our last successful report, for keepalive purposes
last_report_timer = now;
} else {
// some games apparently can miss reports, or they rely on official behavior of getting frequent
// updates. we normally only send a report when the value changes; if we increment the counters
// every time we generate the report (every GP2040::run loop), we apparently overburden
// TinyUSB and introduce roughly 1ms of latency. but we want to loop often and report on every
// true update in order to achieve our tight <1ms report timing when we *do* have a different
// report to send.
if ((now - last_report_timer) > PS4_KEEPALIVE_TIMER) {
last_report_counter = (last_report_counter+1) & 0x3F;
ps4Report.report_counter = last_report_counter; // report counter is 6 bits
ps4Report.axis_timing = now; // axis counter is 16 bits
// the *next* process() will be a forced report (or real user input)
}
}
}
// Called by Core1, PS4 key signing will lock the CPU
void PS4Driver::processAux() {
// If authentication driver is set AND auth driver can load (usb enabled, i2c enabled, keys loaded, etc.)
if ( authDriver != nullptr && authDriver->available() ) {
((PS4Auth*)authDriver)->process(ps4State, nonce_id, nonce_buffer);
}
}
USBListener * PS4Driver::get_usb_auth_listener() {
if ( authDriver != nullptr && authDriver->getAuthType() == InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB ) {
return authDriver->getListener();;
}
return nullptr;
}
// Controller descriptor (byte[4] = 0x00 for ps4, 0x07 for ps5)
static constexpr uint8_t output_0x03[] = {
0x21, 0x27, 0x04, 0xcf, 0x00, 0x2c, 0x56,
0x21, 0x27, 0x04, 0xcf, 0x00, 0x2c, 0x56,
0x08, 0x00, 0x3d, 0x00, 0xe8, 0x03, 0x04, 0x00,
0xff, 0x7f, 0x0d, 0x0d, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -159,128 +189,134 @@ static constexpr uint8_t output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 };
// tud_hid_get_report_cb
uint16_t PS4Driver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
if ( report_type != HID_REPORT_TYPE_FEATURE ) {
memcpy(buffer, &ps4Report, sizeof(ps4Report));
return sizeof(ps4Report);
}
if ( report_type != HID_REPORT_TYPE_FEATURE ) {
memcpy(buffer, &ps4Report, sizeof(ps4Report));
return sizeof(ps4Report);
}
PS4Auth * ps4AuthDriver = (PS4Auth*)authDriver;
uint8_t * ps4_auth_buffer = ps4AuthDriver->getAuthBuffer();
bool ps4_auth_buffer_ready = ps4AuthDriver->getAuthReady();
uint8_t data[64] = {};
uint32_t crc32;
//ps4_out_buffer[0] = report_id;
switch(report_id) {
// Controller Definition Report
case PS4AuthReport::PS4_DEFINITION:
if (reqlen != sizeof(output_0x03)) {
return -1;
}
memcpy(buffer, output_0x03, reqlen);
buffer[4] = (uint8_t)PS4Data::getInstance().ps4ControllerType; // Change controller type in definition
return reqlen;
// Use our private RSA key to sign the nonce and return chunks
case PS4AuthReport::PS4_GET_SIGNATURE_NONCE:
// We send 56 byte chunks back to the PS4, we've already calculated these
data[0] = 0xF1;
data[1] = cur_nonce_id; // nonce_id
data[2] = send_nonce_part; // next_part
data[3] = 0;
uint32_t crc32;
//ps4_out_buffer[0] = report_id;
switch(report_id) {
// Controller Definition Report
case PS4AuthReport::PS4_DEFINITION:
if (reqlen != sizeof(output_0x03)) {
return -1;
}
memcpy(buffer, output_0x03, reqlen);
buffer[4] = (uint8_t)controllerType; // Change controller type in definition
return reqlen;
// Use our private RSA key to sign the nonce and return chunks
case PS4AuthReport::PS4_GET_SIGNATURE_NONCE:
// We send 56 byte chunks back to the PS4, we've already calculated these
data[0] = 0xF1;
data[1] = cur_nonce_id; // nonce_id
data[2] = send_nonce_part; // next_part
data[3] = 0;
// 56 byte chunks
memcpy(&data[4], &PS4Data::getInstance().ps4_auth_buffer[send_nonce_part*56], 56);
// 56 byte chunks
memcpy(&data[4], &ps4_auth_buffer[send_nonce_part*56], 56);
// calculate the CRC32 of the buffer and write it back
crc32 = CRC32::calculate(data, 60);
memcpy(&data[60], &crc32, sizeof(uint32_t));
memcpy(buffer, &data[1], 63); // move data over to buffer
if ( (++send_nonce_part) == 19 ) {
PS4Data::getInstance().ps4State = PS4State::no_nonce;
PS4Data::getInstance().authsent = true;
send_nonce_part = 0;
}
return 63;
// Are we ready to sign?
case PS4AuthReport::PS4_GET_SIGNING_STATE:
data[0] = 0xF2;
data[1] = cur_nonce_id;
data[2] = PS4Data::getInstance().ps4State == PS4State::signed_nonce_ready ? 0 : 16; // 0 means auth is ready, 16 means we're still signing
memset(&data[3], 0, 9);
crc32 = CRC32::calculate(data, 12);
memcpy(&data[12], &crc32, sizeof(uint32_t));
memcpy(buffer, &data[1], 15); // move data over to buffer
return 15;
case PS4AuthReport::PS4_RESET_AUTH: // Reset the Authentication
if (reqlen != sizeof(output_0xf3)) {
return -1;
}
memcpy(buffer, output_0xf3, reqlen);
PS4Data::getInstance().ps4State = PS4State::no_nonce;
return reqlen;
default:
break;
};
return -1;
// calculate the CRC32 of the buffer and write it back
crc32 = CRC32::calculate(data, 60);
memcpy(&data[60], &crc32, sizeof(uint32_t));
memcpy(buffer, &data[1], 63); // move data over to buffer
if ( (++send_nonce_part) == 19 ) {
ps4State = PS4State::no_nonce;
authsent = true;
send_nonce_part = 0;
}
return 63;
// Are we ready to sign?
case PS4AuthReport::PS4_GET_SIGNING_STATE:
data[0] = 0xF2;
data[1] = cur_nonce_id;
data[2] = ps4_auth_buffer_ready == true ? 0 : 16; // 0 means auth is ready, 16 means we're still signing
memset(&data[3], 0, 9);
crc32 = CRC32::calculate(data, 12);
memcpy(&data[12], &crc32, sizeof(uint32_t));
memcpy(buffer, &data[1], 15); // move data over to buffer
return 15;
case PS4AuthReport::PS4_RESET_AUTH: // Reset the Authentication
if (reqlen != sizeof(output_0xf3)) {
return -1;
}
memcpy(buffer, output_0xf3, reqlen);
ps4State = PS4State::no_nonce;
if ( authDriver != nullptr ) {
((PS4Auth*)authDriver)->resetAuth(); // reset the auth driver if it exists
}
return reqlen;
default:
break;
};
return -1;
}
// Only PS4 does anything with set report
void PS4Driver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
if ( report_type != HID_REPORT_TYPE_FEATURE )
return;
if ( report_type != HID_REPORT_TYPE_FEATURE )
return;
uint8_t nonce_id;
uint8_t nonce_page;
uint32_t crc32;
uint8_t sendBuffer[64];
uint8_t nonce[56]; // max nonce data
uint16_t noncelen;
uint16_t buflen;
uint8_t nonce_id;
uint8_t nonce_page;
uint32_t crc32;
uint8_t sendBuffer[64];
uint8_t nonce[56]; // max nonce data
uint16_t noncelen;
uint16_t buflen;
if (report_id == PS4AuthReport::PS4_SET_AUTH_PAYLOAD) {
if (bufsize != 63 ) {
return;
}
if (report_id == PS4AuthReport::PS4_SET_AUTH_PAYLOAD) {
if (bufsize != 63 ) {
return;
}
// Setup CRC32 buffer
sendBuffer[0] = report_id;
memcpy(&sendBuffer[1], buffer, bufsize);
buflen = bufsize + 1;
// Setup CRC32 buffer
sendBuffer[0] = report_id;
memcpy(&sendBuffer[1], buffer, bufsize);
buflen = bufsize + 1;
nonce_id = buffer[0];
nonce_page = buffer[1];
// data[2] is zero padding
nonce_id = buffer[0];
nonce_page = buffer[1];
// data[2] is zero padding
crc32 = CRC32::calculate(sendBuffer, buflen-sizeof(uint32_t));
if ( crc32 != *((unsigned int*)&sendBuffer[buflen-sizeof(uint32_t)])) {
return; // CRC32 failed on set report
}
crc32 = CRC32::calculate(sendBuffer, buflen-sizeof(uint32_t));
if ( crc32 != *((unsigned int*)&sendBuffer[buflen-sizeof(uint32_t)])) {
return; // CRC32 failed on set report
}
// 256 byte nonce, with 56 byte packets leaves 24 extra bytes on the last packet?
if ( nonce_page == 4 ) {
// Copy/append data from buffer[4:64-28] into our nonce
noncelen = 32; // from 4 to 64 - 24 - 4
PS4Data::getInstance().nonce_id = nonce_id; // for pass-through only
} else {
// Copy/append data from buffer[4:64-4] into our nonce
noncelen = 56;
// from 4 to 64 - 4
}
// 256 byte nonce, with 56 byte packets leaves 24 extra bytes on the last packet?
if ( nonce_page == 4 ) {
// Copy/append data from buffer[4:64-28] into our nonce
noncelen = 32; // from 4 to 64 - 24 - 4
nonce_id = nonce_id; // for pass-through only
} else {
// Copy/append data from buffer[4:64-4] into our nonce
noncelen = 56;
// from 4 to 64 - 4
}
memcpy(nonce, &sendBuffer[4], noncelen);
save_nonce(nonce_id, nonce_page, nonce, noncelen);
}
memcpy(nonce, &sendBuffer[4], noncelen);
save_nonce(nonce_id, nonce_page, nonce, noncelen);
}
}
void PS4Driver::save_nonce(uint8_t nonce_id, uint8_t nonce_page, uint8_t * buffer, uint16_t buflen) {
if ( nonce_page != 0 && nonce_id != cur_nonce_id ) {
PS4Data::getInstance().ps4State = PS4State::no_nonce;
return; // setting nonce with mismatched id
}
if ( nonce_page != 0 && nonce_id != cur_nonce_id ) {
ps4State = PS4State::no_nonce;
return; // setting nonce with mismatched id
}
memcpy(&PS4Data::getInstance().nonce_buffer[nonce_page*56], buffer, buflen);
if ( nonce_page == 4 ) {
PS4Data::getInstance().ps4State = PS4State::nonce_ready;
} else if ( nonce_page == 0 ) {
cur_nonce_id = nonce_id;
PS4Data::getInstance().ps4State = PS4State::receiving_nonce;
}
memcpy(&nonce_buffer[nonce_page*56], buffer, buflen);
if ( nonce_page == 4 ) {
ps4State = PS4State::nonce_ready;
} else if ( nonce_page == 0 ) {
cur_nonce_id = nonce_id;
ps4State = PS4State::receiving_nonce;
}
}
// Only XboxOG and Xbox One use vendor control xfer cb
@@ -289,8 +325,8 @@ bool PS4Driver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_contr
}
const uint16_t * PS4Driver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
const char *value = (const char *)ps4_string_descriptors[index];
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
const char *value = (const char *)ps4_string_descriptors[index];
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
}
const uint8_t * PS4Driver::get_descriptor_device_cb() {
@@ -306,9 +342,9 @@ const uint8_t * PS4Driver::get_descriptor_configuration_cb(uint8_t index) {
}
const uint8_t * PS4Driver::get_descriptor_device_qualifier_cb() {
return nullptr;
return nullptr;
}
uint16_t PS4Driver::GetJoystickMidValue() {
return PS4_JOYSTICK_MID << 8;
return PS4_JOYSTICK_MID << 8;
}

View File

@@ -28,13 +28,14 @@
// Default Constructor
XGIPProtocol::XGIPProtocol() {
data = nullptr;
reset();
}
// Default Destructor
XGIPProtocol::~XGIPProtocol() {
if ( data != nullptr ) {
delete data;
delete [] data;
}
}

View File

@@ -59,6 +59,23 @@ typedef struct
} xinputh_device_t;
static xinputh_device_t _xinputh_dev[CFG_TUH_DEVICE_MAX];
#define XINPUT_DESC_TYPE_RESERVED 0x21
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
uint8_t flags;
uint8_t reserved;
uint8_t subtype;
uint8_t reserved2;
uint8_t bEndpointAddressIn;
uint8_t bMaxDataSizeIn;
uint8_t reserved3[5];
uint8_t bEndpointAddressOut;
uint8_t bMaxDataSizeOut;
uint8_t reserved4[2];
} __attribute__((packed)) XBOX_ID_DESCRIPTOR;
//------------- Internal prototypes -------------//
// Get HID device & interface
@@ -167,16 +184,6 @@ void xinputh_close(uint8_t dev_addr) {
tu_memclr(hid_dev, sizeof(xinputh_device_t));
}
//--------------------------------------------------------------------+
// Enumeration
//--------------------------------------------------------------------+
typedef enum
{
UNKNOWN = 0,
XBOX360,
XBOXONE,
} xinput_type_t;
bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) {
(void)rhport;
(void)max_len;
@@ -191,7 +198,43 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
}
TU_VERIFY(p_xinput, 0);
uint8_t const *p_desc = (uint8_t const *)desc_itf;
if (desc_itf->bInterfaceSubClass == 0x47 &&
// add instance for Xbox 360 dongle
if (desc_itf->bInterfaceSubClass == 0x5D &&
(desc_itf->bInterfaceProtocol == 0x01 ||
desc_itf->bInterfaceProtocol == 0x03 ||
desc_itf->bInterfaceProtocol == 0x02)) {
//-------------- Xinput Descriptor --------------//
p_desc = tu_desc_next(p_desc);
XBOX_ID_DESCRIPTOR *x_desc =
(XBOX_ID_DESCRIPTOR *)p_desc;
TU_ASSERT(XINPUT_DESC_TYPE_RESERVED == x_desc->bDescriptorType, 0);
//drv_len += x_desc->bLength;
uint8_t endpoints = desc_itf->bNumEndpoints;
while (endpoints--) {
p_desc = tu_desc_next(p_desc);
tusb_desc_endpoint_t const *desc_ep =
(tusb_desc_endpoint_t const *)p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
if (desc_ep->bEndpointAddress & 0x80) {
p_xinput->ep_in = desc_ep->bEndpointAddress;
TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
} else {
p_xinput->ep_out = desc_ep->bEndpointAddress;
TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
}
}
p_xinput->itf_num = desc_itf->bInterfaceNumber;
p_xinput->type = XBOX360;
if (desc_itf->bInterfaceProtocol == 0x01) {
p_xinput->subtype = x_desc->subtype;
usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size);
}
_xinputh_dev->inst_count++;
return true;
// Xbox One instance == 0x47 0xD0
} else if (desc_itf->bInterfaceSubClass == 0x47 &&
desc_itf->bInterfaceProtocol == 0xD0 && desc_itf->bNumEndpoints) {
uint8_t endpoints = desc_itf->bNumEndpoints;
while (endpoints--) {

View File

@@ -0,0 +1,32 @@
#include "host/usbh.h"
#include "class/hid/hid.h"
#include "class/hid/hid_host.h"
#include "drivers/xbone/XBOneAuth.h"
#include "drivers/xbone/XBOneAuthUSBListener.h"
#include "CRC32.h"
#include "peripheralmanager.h"
#include "usbhostmanager.h"
#include "drivers/xbone/XBOneDescriptors.h"
#include "drivers/shared/xgip_protocol.h"
#include "drivers/shared/xinput_host.h"
void XBOneAuth::initialize() {
if ( available() ) {
listener = new XBOneAuthUSBListener();
xboxOneAuthData.xboneState = auth_idle_state;
xboxOneAuthData.authLen = 0;
xboxOneAuthData.authSequence = 0;
xboxOneAuthData.authCompleted = false;
((XBOneAuthUSBListener*)listener)->setup();
((XBOneAuthUSBListener*)listener)->setAuthData(&xboxOneAuthData);
}
}
bool XBOneAuth::available() {
return PeripheralManager::getInstance().isUSBEnabled(0);
}
void XBOneAuth::process() {
((XBOneAuthUSBListener*)listener)->process();
}

View File

@@ -1,14 +1,14 @@
#include "addons/xbonepassthrough.h"
#include "storagemanager.h"
#include "usbhostmanager.h"
#include "host/usbh.h"
#include "class/hid/hid.h"
#include "class/hid/hid_host.h"
#include "drivers/xbone/XBOneAuthUSBListener.h"
#include "CRC32.h"
#include "peripheralmanager.h"
#include "usbhostmanager.h"
#include "drivers/xbone/XBOneDescriptors.h"
#include "drivers/shared/xgip_protocol.h"
#include "drivers/shared/xinput_host.h"
#include "drivers/shared/xbonedata.h"
#define XBONE_EXTENSION_DEBUG true
// power-on states and rumble-on with everything disabled
static uint8_t xb1_power_on[] = {0x06, 0x62, 0x45, 0xb8, 0x77, 0x26, 0x2c, 0x55,
@@ -16,16 +16,6 @@ static uint8_t xb1_power_on[] = {0x06, 0x62, 0x45, 0xb8, 0x77, 0x26, 0x2c, 0x55,
static uint8_t xb1_power_on_single[] = {0x00};
static uint8_t xb1_rumble_on[] = {0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xeb};
bool XBOnePassthroughAddon::available() {
const XBOnePassthroughOptions& xboneOptions = Storage::getInstance().getAddonOptions().xbonePassthroughOptions;
const GamepadOptions& gamepadOptions = Storage::getInstance().GetGamepad()->getOptions();
return xboneOptions.enabled && PeripheralManager::getInstance().isUSBEnabled(0) && (gamepadOptions.inputMode == INPUT_MODE_XBONE);
}
void XBOnePassthroughAddon::setup() {
dongle_ready = false;
}
// Report Queue for big report sizes from dongle
#include <queue>
typedef struct {
@@ -37,47 +27,59 @@ static std::queue<report_queue_t> report_queue;
static uint32_t lastReportQueueSent = 0;
#define REPORT_QUEUE_INTERVAL 15
void XBOnePassthroughAddon::process() {
void XBOneAuthUSBListener::setup() {
dongle_ready = false;
mounted = false;
xboxOneAuthData = nullptr;
}
void XBOneAuthUSBListener::setAuthData(XboxOneAuthData * authData ) {
xboxOneAuthData = authData;
}
void XBOneAuthUSBListener::process() {
if ( mounted == false || xboxOneAuthData == nullptr) // do nothing if we have not mounted an xbox one dongle
return;
// Do not begin processing console auth unless we have the dongle ready
if ( dongle_ready == true ) {
if ( XboxOneData::getInstance().getState() == XboxOneState::send_auth_console_to_dongle ) {
uint8_t isChunked = ( XboxOneData::getInstance().getAuthLen() > GIP_MAX_CHUNK_SIZE );
uint8_t needsAck = (XboxOneData::getInstance().getAuthLen() > 2);
if ( xboxOneAuthData->xboneState == XboxOneState::send_auth_console_to_dongle ) {
uint8_t isChunked = ( xboxOneAuthData->authLen > GIP_MAX_CHUNK_SIZE );
uint8_t needsAck = (xboxOneAuthData->authLen > 2);
outgoingXGIP.reset();
outgoingXGIP.setAttributes(XboxOneData::getInstance().getAuthType(), XboxOneData::getInstance().getSequence(), 1, isChunked, needsAck);
outgoingXGIP.setData(XboxOneData::getInstance().getAuthBuffer(), XboxOneData::getInstance().getAuthLen());
XboxOneData::getInstance().setState(XboxOneState::wait_auth_console_to_dongle);
} else if ( XboxOneData::getInstance().getState() == XboxOneState::wait_auth_console_to_dongle) {
outgoingXGIP.setAttributes(xboxOneAuthData->authType, xboxOneAuthData->authSequence, 1, isChunked, needsAck);
outgoingXGIP.setData(xboxOneAuthData->authBuffer, xboxOneAuthData->authLen);
xboxOneAuthData->xboneState = XboxOneState::wait_auth_console_to_dongle;
} else if ( xboxOneAuthData->xboneState == XboxOneState::wait_auth_console_to_dongle) {
queue_host_report(outgoingXGIP.generatePacket(), outgoingXGIP.getPacketLength());
if ( outgoingXGIP.getChunked() == false || outgoingXGIP.endOfChunk() == true ) {
XboxOneData::getInstance().setState(XboxOneState::auth_idle_state);
xboxOneAuthData->xboneState = XboxOneState::auth_idle_state;
}
}
}
uint32_t now = to_ms_since_boot(get_absolute_time());
if ( !report_queue.empty() && (now - lastReportQueueSent) > REPORT_QUEUE_INTERVAL ) {
if ( tuh_xinput_send_report(xbone_dev_addr, xbone_instance, report_queue.front().report, report_queue.front().len) ) {
report_queue.pop();
lastReportQueueSent = now;
} else { // FAILED: Keeping it on the queue to send again
sleep_ms(REPORT_QUEUE_INTERVAL);
}
}
process_report_queue();
}
void XBOnePassthroughAddon::xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) {
xbone_dev_addr = dev_addr;
xbone_instance = instance;
incomingXGIP.reset();
outgoingXGIP.reset();
void XBOneAuthUSBListener::xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) {
if ( controllerType == xinput_type_t::XBOXONE) {
xbone_dev_addr = dev_addr;
xbone_instance = instance;
incomingXGIP.reset();
outgoingXGIP.reset();
mounted = true;
}
}
void XBOnePassthroughAddon::unmount(uint8_t dev_addr) {
void XBOneAuthUSBListener::unmount(uint8_t dev_addr) {
// Do not reset dongle_ready on unmount (Magic-X will remount but still be ready)
mounted = false;
}
void XBOnePassthroughAddon::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
void XBOneAuthUSBListener::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
if ( mounted == false || xboxOneAuthData == nullptr)
return;
incomingXGIP.parse(report, len);
if ( incomingXGIP.validate() == false ) {
sleep_ms(50); // First packet is invalid, drop and wait for dongle to boot
@@ -117,8 +119,11 @@ void XBOnePassthroughAddon::report_received(uint8_t dev_addr, uint8_t instance,
case GIP_FINAL_AUTH:
if ( incomingXGIP.getChunked() == false ||
(incomingXGIP.getChunked() == true && incomingXGIP.endOfChunk() == true )) {
XboxOneData::getInstance().setAuthData(incomingXGIP.getData(), incomingXGIP.getDataLength(), incomingXGIP.getSequence(),
incomingXGIP.getCommand(), XboxOneState::send_auth_dongle_to_console);
memcpy(xboxOneAuthData->authBuffer, incomingXGIP.getData(), incomingXGIP.getDataLength());
xboxOneAuthData->authLen = incomingXGIP.getDataLength();
xboxOneAuthData->authType = incomingXGIP.getCommand();
xboxOneAuthData->authSequence = incomingXGIP.getSequence();
xboxOneAuthData->xboneState = XboxOneState::send_auth_dongle_to_console;
incomingXGIP.reset();
}
break;
@@ -128,9 +133,21 @@ void XBOnePassthroughAddon::report_received(uint8_t dev_addr, uint8_t instance,
};
}
void XBOnePassthroughAddon::queue_host_report(void* report, uint16_t len) {
void XBOneAuthUSBListener::queue_host_report(void* report, uint16_t len) {
report_queue_t new_queue;
memcpy(new_queue.report, report, len);
new_queue.len = len;
report_queue.push(new_queue);
}
void XBOneAuthUSBListener::process_report_queue() {
uint32_t now = to_ms_since_boot(get_absolute_time());
if ( !report_queue.empty() && (now - lastReportQueueSent) > REPORT_QUEUE_INTERVAL ) {
if ( tuh_xinput_send_report(xbone_dev_addr, xbone_instance, report_queue.front().report, report_queue.front().len) ) {
report_queue.pop();
lastReportQueueSent = now;
} else { // FAILED: Keeping it on the queue to send again
sleep_ms(REPORT_QUEUE_INTERVAL);
}
}
}

View File

@@ -1,6 +1,8 @@
#include "drivers/xbone/XBOneDriver.h"
#include "drivers/shared/driverhelper.h"
#include "drivers/shared/xbonedata.h"
#include "drivers/xbone/XBOneAuth.h"
#include "peripheralmanager.h"
#define XBONE_KEEPALIVE_TIMER 15000
@@ -24,11 +26,11 @@ static uint32_t lastReportQueueSent = 0;
#define REPORT_QUEUE_INTERVAL 15
typedef enum {
IDLE_STATE = 0,
READY_ANNOUNCE,
WAIT_DESCRIPTOR_REQUEST,
SEND_DESCRIPTOR,
SETUP_AUTH
IDLE_STATE = 0,
READY_ANNOUNCE,
WAIT_DESCRIPTOR_REQUEST,
SEND_DESCRIPTOR,
SETUP_AUTH
} XboxOneDriverState;
static XboxOneDriverState xboneDriverState;
@@ -37,9 +39,9 @@ static uint8_t xb1_guide_on[] = { 0x01, 0x5b };
static uint8_t xb1_guide_off[] = { 0x00, 0x5b };
static uint8_t xboneIdle[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Check if Auth is completed (start is 0x01, 0x01, and invalid is 0x01, 0x07)
@@ -48,38 +50,38 @@ const uint8_t authReady[] = {0x01, 0x00};
// Xbox One Announce
static uint8_t announcePacket[] = {
0x00, 0x2a, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0xdf, 0x33, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00,
0x17, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00};
0xdf, 0x33, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00,
0x17, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00};
// Xbox One Descriptor
const uint8_t xboxOneDescriptor[] = {
0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x00,
0x8B, 0x00, 0x16, 0x00, 0x1F, 0x00, 0x20, 0x00,
0x27, 0x00, 0x2D, 0x00, 0x4A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05,
0x01, 0x04, 0x05, 0x06, 0x0A, 0x01, 0x1A, 0x00,
0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x2E,
0x58, 0x62, 0x6F, 0x78, 0x2E, 0x49, 0x6E, 0x70,
0x75, 0x74, 0x2E, 0x47, 0x61, 0x6D, 0x65, 0x70,
0x61, 0x64, 0x04, 0x56, 0xFF, 0x76, 0x97, 0xFD,
0x9B, 0x81, 0x45, 0xAD, 0x45, 0xB6, 0x45, 0xBB,
0xA5, 0x26, 0xD6, 0x2C, 0x40, 0x2E, 0x08, 0xDF,
0x07, 0xE1, 0x45, 0xA5, 0xAB, 0xA3, 0x12, 0x7A,
0xF1, 0x97, 0xB5, 0xE7, 0x1F, 0xF3, 0xB8, 0x86,
0x73, 0xE9, 0x40, 0xA9, 0xF8, 0x2F, 0x21, 0x26,
0x3A, 0xCF, 0xB7, 0xFE, 0xD2, 0xDD, 0xEC, 0x87,
0xD3, 0x94, 0x42, 0xBD, 0x96, 0x1A, 0x71, 0x2E,
0x3D, 0xC7, 0x7D, 0x02, 0x17, 0x00, 0x20, 0x20,
0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x17, 0x00, 0x09, 0x3C, 0x00,
0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00};
0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x00,
0x8B, 0x00, 0x16, 0x00, 0x1F, 0x00, 0x20, 0x00,
0x27, 0x00, 0x2D, 0x00, 0x4A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05,
0x01, 0x04, 0x05, 0x06, 0x0A, 0x01, 0x1A, 0x00,
0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x2E,
0x58, 0x62, 0x6F, 0x78, 0x2E, 0x49, 0x6E, 0x70,
0x75, 0x74, 0x2E, 0x47, 0x61, 0x6D, 0x65, 0x70,
0x61, 0x64, 0x04, 0x56, 0xFF, 0x76, 0x97, 0xFD,
0x9B, 0x81, 0x45, 0xAD, 0x45, 0xB6, 0x45, 0xBB,
0xA5, 0x26, 0xD6, 0x2C, 0x40, 0x2E, 0x08, 0xDF,
0x07, 0xE1, 0x45, 0xA5, 0xAB, 0xA3, 0x12, 0x7A,
0xF1, 0x97, 0xB5, 0xE7, 0x1F, 0xF3, 0xB8, 0x86,
0x73, 0xE9, 0x40, 0xA9, 0xF8, 0x2F, 0x21, 0x26,
0x3A, 0xCF, 0xB7, 0xFE, 0xD2, 0xDD, 0xEC, 0x87,
0xD3, 0x94, 0x42, 0xBD, 0x96, 0x1A, 0x71, 0x2E,
0x3D, 0xC7, 0x7D, 0x02, 0x17, 0x00, 0x20, 0x20,
0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x17, 0x00, 0x09, 0x3C, 0x00,
0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00};
static bool waiting_ack = false;
static uint32_t waiting_ack_timeout=0;
@@ -89,8 +91,8 @@ static bool xbox_one_powered_on;
// Report Queue for big report sizes from dongle
#include <queue>
typedef struct {
uint8_t report[XBONE_ENDPOINT_SIZE];
uint16_t len;
uint8_t report[XBONE_ENDPOINT_SIZE];
uint16_t len;
} report_queue_t;
static std::queue<report_queue_t> report_queue;
@@ -111,8 +113,9 @@ typedef struct {
CFG_TUSB_MEM_SECTION static xboned_interface_t _xboned_itf[CFG_TUD_XBONE];
static XGIPProtocol outgoingXGIP;
static XGIPProtocol incomingXGIP;
static XGIPProtocol * outgoingXGIP = nullptr;
static XGIPProtocol * incomingXGIP = nullptr;
static XboxOneAuthData * xboxOneAuthData = nullptr;
// Windows requires a Descriptor Single for Xbox One
typedef struct {
@@ -141,29 +144,29 @@ const OS_COMPATIBLE_ID_DESCRIPTOR_SINGLE DevCompatIDsOne = {
};
static void xbone_reset(uint8_t rhport) {
(void)rhport;
timer_wait_for_announce = to_ms_since_boot(get_absolute_time());
xbox_one_powered_on = false;
while(!report_queue.empty())
report_queue.pop();
(void)rhport;
timer_wait_for_announce = to_ms_since_boot(get_absolute_time());
xbox_one_powered_on = false;
while(!report_queue.empty())
report_queue.pop();
xboneDriverState = XboxOneDriverState::READY_ANNOUNCE;
xboneDriverState = XboxOneDriverState::READY_ANNOUNCE;
// close any endpoints that are open
tu_memclr(&_xboned_itf, sizeof(_xboned_itf));
// close any endpoints that are open
tu_memclr(&_xboned_itf, sizeof(_xboned_itf));
}
static void xbone_init(void) {
xbone_reset(TUD_OPT_RHPORT);
xbone_reset(TUD_OPT_RHPORT);
}
static uint16_t xbone_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
uint16_t drv_len = 0;
uint16_t drv_len = 0;
if (TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) {
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass, 0);
drv_len = sizeof(tusb_desc_interface_t) +
drv_len = sizeof(tusb_desc_interface_t) +
(itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_VERIFY(max_len >= drv_len, 0);
@@ -171,18 +174,18 @@ static uint16_t xbone_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc
xboned_interface_t *p_xbone = NULL;
for (uint8_t i = 0; i < CFG_TUD_XBONE; i++) {
if (_xboned_itf[i].ep_in == 0 && _xboned_itf[i].ep_out == 0) {
p_xbone = &_xboned_itf[i];
p_xbone = &_xboned_itf[i];
break;
}
}
TU_VERIFY(p_xbone, 0);
uint8_t const *p_desc = (uint8_t const *)itf_desc;
uint8_t const *p_desc = (uint8_t const *)itf_desc;
// Xbox One interface (subclass = 0x47, protocol = 0xD0)
// Xbox One interface (subclass = 0x47, protocol = 0xD0)
if (itf_desc->bInterfaceSubClass == 0x47 &&
itf_desc->bInterfaceProtocol == 0xD0) {
p_desc = tu_desc_next(p_desc);
p_desc = tu_desc_next(p_desc);
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, itf_desc->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_xbone->ep_out, &p_xbone->ep_in), 0);
p_xbone->itf_num = itf_desc->bInterfaceNumber;
@@ -194,266 +197,23 @@ static uint16_t xbone_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc
TU_BREAKPOINT();
}
}
}
}
}
return drv_len;
}
static void queue_xbone_report(void *report, uint16_t report_size) {
report_queue_t item;
memcpy(item.report, report, report_size);
item.len = report_size;
report_queue.push(item);
report_queue_t item;
memcpy(item.report, report, report_size);
item.len = report_size;
report_queue.push(item);
}
bool xbone_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
uint32_t xferred_bytes) {
(void)result;
uint8_t itf = 0;
xboned_interface_t *p_xbone = _xboned_itf;
for (;; itf++, p_xbone++) {
if (itf >= TU_ARRAY_SIZE(_xboned_itf)) return false;
if (ep_addr == p_xbone->ep_out || ep_addr == p_xbone->ep_in) break;
}
if (ep_addr == p_xbone->ep_out) {
// Parse incoming packet and verify its valid
incomingXGIP.parse(p_xbone->epout_buf, xferred_bytes);
// Setup an ack before we change anything about the incoming packet
if ( incomingXGIP.ackRequired() == true ) {
queue_xbone_report((uint8_t*)incomingXGIP.generateAckPacket(), incomingXGIP.getPacketLength());
}
uint8_t command = incomingXGIP.getCommand();
if ( command == GIP_ACK_RESPONSE ) {
waiting_ack = false;
} else if ( command == GIP_DEVICE_DESCRIPTOR ) {
// setup descriptor packet
outgoingXGIP.reset(); // reset if anything was in there
outgoingXGIP.setAttributes(GIP_DEVICE_DESCRIPTOR, incomingXGIP.getSequence(), 1, 1, 0);
outgoingXGIP.setData(xboxOneDescriptor, sizeof(xboxOneDescriptor));
xboneDriverState = XboxOneDriverState::SEND_DESCRIPTOR;
} else if ( command == GIP_POWER_MODE_DEVICE_CONFIG || command == GIP_CMD_WAKEUP || command == GIP_CMD_RUMBLE ) {
xbox_one_powered_on = true;
} else if ( command == GIP_AUTH || command == GIP_FINAL_AUTH) {
if (incomingXGIP.getDataLength() == 2 && memcmp(incomingXGIP.getData(), authReady, sizeof(authReady))==0 )
XboxOneData::getInstance().setAuthCompleted(true);
if ( (incomingXGIP.getChunked() == true && incomingXGIP.endOfChunk() == true) ||
(incomingXGIP.getChunked() == false )) {
XboxOneData::getInstance().setAuthData(incomingXGIP.getData(), incomingXGIP.getDataLength(), incomingXGIP.getSequence(),
incomingXGIP.getCommand(), XboxOneState::send_auth_console_to_dongle);
incomingXGIP.reset();
}
}
TU_ASSERT(usbd_edpt_xfer(rhport, p_xbone->ep_out, p_xbone->epout_buf,
sizeof(p_xbone->epout_buf)));
} else if (ep_addr == p_xbone->ep_in) {
// Nothing needed
}
return true;
}
void XBOneDriver::initialize() {
xboneReport = {
.sync = 0,
.guide = 0,
.start = 0,
.back = 0,
.a = 0,
.b = 0,
.x = 0,
.y = 0,
.dpadUp = 0,
.dpadDown = 0,
.dpadLeft = 0,
.dpadRight = 0,
.leftShoulder = 0,
.rightShoulder = 0,
.leftThumbClick = 0,
.rightThumbClick = 0,
.leftTrigger = 0,
.rightTrigger = 0,
.leftStickX = GAMEPAD_JOYSTICK_MID,
.leftStickY = GAMEPAD_JOYSTICK_MID,
.rightStickX = GAMEPAD_JOYSTICK_MID,
.rightStickY = GAMEPAD_JOYSTICK_MID,
.reserved = {}
};
class_driver = {
#if CFG_TUSB_DEBUG >= 2
.name = "XBONE",
#endif
.init = xbone_init,
.reset = xbone_reset,
.open = xbone_open,
.control_xfer_cb = tud_vendor_control_xfer_cb,
.xfer_cb = xbone_xfer_cb,
.sof = NULL
};
keep_alive_timer = to_ms_since_boot(get_absolute_time());
keep_alive_sequence = 1; // sequence starts at 1?
virtual_keycode_sequence = 0;
xb1_guide_pressed = false;
last_report_counter = 0;
}
void XBOneDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {
uint16_t xboneReportSize = 0;
// Perform update
this->update();
// No input until auth is ready
if ( XboxOneData::getInstance().getAuthCompleted() == false ) {
GIP_HEADER((&xboneReport), GIP_INPUT_REPORT, false, last_report_counter);
memcpy((void*)&((uint8_t*)&xboneReport)[4], xboneIdle, sizeof(xboneIdle));
xboneReportSize = sizeof(XboxOneGamepad_Data_t);
send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize);
return;
}
uint32_t now = to_ms_since_boot(get_absolute_time());
// Send Keep-Alive every 15 seconds (keep_alive_timer updates if send is successful)
if ( (now - keep_alive_timer) > XBONE_KEEPALIVE_TIMER) {
memset(&xboneReport.Header, 0, sizeof(GipHeader_t));
GIP_HEADER((&xboneReport), GIP_KEEPALIVE, 1, keep_alive_sequence);
xboneReport.Header.length = 4;
static uint8_t keepAlive[] = { 0x80, 0x00, 0x00, 0x00 };
memcpy(&((uint8_t*)&xboneReport)[4], &keepAlive, sizeof(keepAlive));
xboneReportSize = sizeof(GipHeader_t) + sizeof(keepAlive);
// If successful, update our keep alive timer/sequence
if ( send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize) == true ) {
keep_alive_timer = to_ms_since_boot(get_absolute_time());
keep_alive_sequence++; // will rollover
if ( keep_alive_sequence == 0 )
keep_alive_sequence = 1;
}
return;
}
// Virtual Keycode for Guide Button
if ( gamepad->pressedA1() || xb1_guide_pressed == true ) {
// In a change-state
if ( (gamepad->pressedA1() && xb1_guide_pressed == false) ||
(!gamepad->pressedA1() && xb1_guide_pressed == true)) {
virtual_keycode_sequence++; // will rollover
if ( virtual_keycode_sequence == 0 )
virtual_keycode_sequence = 1;
GIP_HEADER((&xboneReport), GIP_VIRTUAL_KEYCODE, 1, virtual_keycode_sequence);
xboneReport.Header.length = sizeof(xb1_guide_on);
if ( gamepad->pressedA1() ) {
xb1_guide_pressed = true;
memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_on, sizeof(xb1_guide_on));
} else {
xb1_guide_pressed = false;
memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_off, sizeof(xb1_guide_off));
}
}
xboneReportSize = sizeof(GipHeader_t) + sizeof(xb1_guide_on);
send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize);
return;
}
// Only change xbox one input report if we have different inputs!
XboxOneGamepad_Data_t newInputReport;
// This is due to our tusb_driver.cpp checking memcmp(last_report, report, size)
memset(&newInputReport, 0, sizeof(XboxOneGamepad_Data_t));
GIP_HEADER((&newInputReport), GIP_INPUT_REPORT, false, last_report_counter);
newInputReport.a = gamepad->pressedB1();
newInputReport.b = gamepad->pressedB2();
newInputReport.x = gamepad->pressedB3();
newInputReport.y = gamepad->pressedB4();
newInputReport.leftShoulder = gamepad->pressedL1();
newInputReport.rightShoulder = gamepad->pressedR1();
newInputReport.leftThumbClick = gamepad->pressedL3();
newInputReport.rightThumbClick = gamepad->pressedR3();
newInputReport.start = gamepad->pressedS2();
newInputReport.back = gamepad->pressedS1();
newInputReport.guide = 0; // always 0
newInputReport.sync = 0;
newInputReport.dpadUp = gamepad->pressedUp();
newInputReport.dpadDown = gamepad->pressedDown();
newInputReport.dpadLeft = gamepad->pressedLeft();
newInputReport.dpadRight = gamepad->pressedRight();
newInputReport.leftStickX = static_cast<int16_t>(gamepad->state.lx) + INT16_MIN;
newInputReport.leftStickY = static_cast<int16_t>(~gamepad->state.ly) + INT16_MIN;
newInputReport.rightStickX = static_cast<int16_t>(gamepad->state.rx) + INT16_MIN;
newInputReport.rightStickY = static_cast<int16_t>(~gamepad->state.ry) + INT16_MIN;
if (gamepad->hasAnalogTriggers)
{
newInputReport.leftTrigger = gamepad->pressedL2() ? 0x03FF : gamepad->state.lt;
newInputReport.rightTrigger = gamepad->pressedR2() ? 0x03FF : gamepad->state.rt;
}
else
{
newInputReport.leftTrigger = gamepad->pressedL2() ? 0x03FF : 0;
newInputReport.rightTrigger = gamepad->pressedR2() ? 0x03FF : 0;
}
// We changed inputs since generating our last report, increment last report counter (but don't update until success)
if ( memcmp(&last_report[4], &((uint8_t*)&newInputReport)[4], sizeof(XboxOneGamepad_Data_t)-4) != 0 ) {
xboneReportSize = sizeof(XboxOneGamepad_Data_t);
memcpy(&xboneReport, &newInputReport, xboneReportSize);
xboneReport.Header.sequence = last_report_counter + 1;
if ( xboneReport.Header.sequence == 0 )
xboneReport.Header.sequence = 1;
// Successfully sent report, actually increment last report counter!
if ( send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize) == true ) {
if ( memcmp(&last_report[4], &((uint8_t*)&xboneReport)[4], xboneReportSize-4) != 0) {
last_report_counter++;
if (last_report_counter == 0)
last_report_counter = 1;
memcpy(last_report, &xboneReport, xboneReportSize);
}
}
}
}
bool XBOneDriver::send_xbone_usb(uint8_t const *report, uint16_t report_size) {
uint8_t itf = 0;
xboned_interface_t *p_xbone = _xboned_itf;
for (;; itf++, p_xbone++) {
if (itf >= TU_ARRAY_SIZE(_xboned_itf)) {
return false;
}
if (p_xbone->ep_in)
break;
}
if ( tud_ready() && // Is the device ready?
(p_xbone->ep_in != 0) && (!usbd_edpt_busy(TUD_OPT_RHPORT, p_xbone->ep_in))) // Is the IN endpoint available?
{
usbd_edpt_claim(0, p_xbone->ep_in); // Take control of IN endpoint
usbd_edpt_xfer(0, p_xbone->ep_in, (uint8_t *)report, report_size); // Send report buffer
usbd_edpt_release(0, p_xbone->ep_in); // Release control of IN endpoint
// we successfully sent the report
return true;
}
return false;
}
// tud_hid_get_report_cb
uint16_t XBOneDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
memcpy(buffer, &xboneReport, sizeof(xboneReport));
return sizeof(xboneReport);
}
// Only PS4 does anything with set report
void XBOneDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
// Only XboxOG and Xbox One use vendor control xfer cb
bool XBOneDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
uint8_t buf[255];
// DevCompatIDsOne sends back XGIP10 data when requested by Windows
bool xbone_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request) {
uint8_t buf[255];
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP)
@@ -472,9 +232,333 @@ bool XBOneDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_con
return true;
}
bool xbone_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
uint32_t xferred_bytes) {
// Do nothing if we couldn't setup our auth listener
if ( xboxOneAuthData == nullptr || incomingXGIP == nullptr ||
outgoingXGIP == nullptr) {
return true;
}
(void)result;
uint8_t itf = 0;
xboned_interface_t *p_xbone = _xboned_itf;
for (;; itf++, p_xbone++) {
if (itf >= TU_ARRAY_SIZE(_xboned_itf)) return false;
if (ep_addr == p_xbone->ep_out || ep_addr == p_xbone->ep_in) break;
}
if (ep_addr == p_xbone->ep_out) {
// Parse incoming packet and verify its valid
incomingXGIP->parse(p_xbone->epout_buf, xferred_bytes);
// Setup an ack before we change anything about the incoming packet
if ( incomingXGIP->ackRequired() == true ) {
queue_xbone_report((uint8_t*)incomingXGIP->generateAckPacket(), incomingXGIP->getPacketLength());
}
uint8_t command = incomingXGIP->getCommand();
if ( command == GIP_ACK_RESPONSE ) {
waiting_ack = false;
} else if ( command == GIP_DEVICE_DESCRIPTOR ) {
// setup descriptor packet
outgoingXGIP->reset(); // reset if anything was in there
outgoingXGIP->setAttributes(GIP_DEVICE_DESCRIPTOR, incomingXGIP->getSequence(), 1, 1, 0);
outgoingXGIP->setData(xboxOneDescriptor, sizeof(xboxOneDescriptor));
xboneDriverState = XboxOneDriverState::SEND_DESCRIPTOR;
} else if ( command == GIP_POWER_MODE_DEVICE_CONFIG || command == GIP_CMD_WAKEUP || command == GIP_CMD_RUMBLE ) {
xbox_one_powered_on = true;
} else if ( command == GIP_AUTH || command == GIP_FINAL_AUTH) {
if (incomingXGIP->getDataLength() == 2 && memcmp(incomingXGIP->getData(), authReady, sizeof(authReady))==0 )
xboxOneAuthData->authCompleted = true;
if ( (incomingXGIP->getChunked() == true && incomingXGIP->endOfChunk() == true) ||
(incomingXGIP->getChunked() == false )) {
memcpy(xboxOneAuthData->authBuffer, incomingXGIP->getData(), incomingXGIP->getDataLength());
xboxOneAuthData->authLen = incomingXGIP->getDataLength();
xboxOneAuthData->authType = incomingXGIP->getCommand();
xboxOneAuthData->authSequence = incomingXGIP->getSequence();
xboxOneAuthData->xboneState = XboxOneState::send_auth_console_to_dongle;
incomingXGIP->reset();
}
}
TU_ASSERT(usbd_edpt_xfer(rhport, p_xbone->ep_out, p_xbone->epout_buf,
sizeof(p_xbone->epout_buf)));
} else if (ep_addr == p_xbone->ep_in) {
// Nothing needed
}
return true;
}
void XBOneDriver::initialize() {
xboneReport = {
.sync = 0,
.guide = 0,
.start = 0,
.back = 0,
.a = 0,
.b = 0,
.x = 0,
.y = 0,
.dpadUp = 0,
.dpadDown = 0,
.dpadLeft = 0,
.dpadRight = 0,
.leftShoulder = 0,
.rightShoulder = 0,
.leftThumbClick = 0,
.rightThumbClick = 0,
.leftTrigger = 0,
.rightTrigger = 0,
.leftStickX = GAMEPAD_JOYSTICK_MID,
.leftStickY = GAMEPAD_JOYSTICK_MID,
.rightStickX = GAMEPAD_JOYSTICK_MID,
.rightStickY = GAMEPAD_JOYSTICK_MID,
.reserved = {}
};
class_driver = {
#if CFG_TUSB_DEBUG >= 2
.name = "XBONE",
#endif
.init = xbone_init,
.reset = xbone_reset,
.open = xbone_open,
.control_xfer_cb = xbone_vendor_control_xfer_cb,
.xfer_cb = xbone_xfer_cb,
.sof = NULL
};
keep_alive_timer = to_ms_since_boot(get_absolute_time());
keep_alive_sequence = 1; // sequence starts at 1?
virtual_keycode_sequence = 0;
xb1_guide_pressed = false;
last_report_counter = 0;
incomingXGIP = new XGIPProtocol();
outgoingXGIP = new XGIPProtocol();
xboxOneAuthData = nullptr;
}
void XBOneDriver::initializeAux() {
authDriver = new XBOneAuth();
if ( authDriver->available() ) {
authDriver->initialize();
xboxOneAuthData = ((XBOneAuth*)authDriver)->getAuthData();
} else {
xboxOneAuthData = nullptr;
}
}
USBListener * XBOneDriver::get_usb_auth_listener() {
if ( authDriver->available() ) {
return authDriver->getListener();
}
return nullptr;
}
void XBOneDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {
// Do nothing if we couldn't setup our auth listener
if ( xboxOneAuthData == nullptr) {
return;
}
uint16_t xboneReportSize = 0;
// Perform update
this->update();
// No input until auth is ready
if ( xboxOneAuthData->authCompleted == false ) {
GIP_HEADER((&xboneReport), GIP_INPUT_REPORT, false, last_report_counter);
memcpy((void*)&((uint8_t*)&xboneReport)[4], xboneIdle, sizeof(xboneIdle));
xboneReportSize = sizeof(XboxOneGamepad_Data_t);
send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize);
return;
}
uint32_t now = to_ms_since_boot(get_absolute_time());
// Send Keep-Alive every 15 seconds (keep_alive_timer updates if send is successful)
if ( (now - keep_alive_timer) > XBONE_KEEPALIVE_TIMER) {
memset(&xboneReport.Header, 0, sizeof(GipHeader_t));
GIP_HEADER((&xboneReport), GIP_KEEPALIVE, 1, keep_alive_sequence);
xboneReport.Header.length = 4;
static uint8_t keepAlive[] = { 0x80, 0x00, 0x00, 0x00 };
memcpy(&((uint8_t*)&xboneReport)[4], &keepAlive, sizeof(keepAlive));
xboneReportSize = sizeof(GipHeader_t) + sizeof(keepAlive);
// If successful, update our keep alive timer/sequence
if ( send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize) == true ) {
keep_alive_timer = to_ms_since_boot(get_absolute_time());
keep_alive_sequence++; // will rollover
if ( keep_alive_sequence == 0 )
keep_alive_sequence = 1;
}
return;
}
// Virtual Keycode for Guide Button
bool virtual_keycode_change = false;
if ( (xb1_guide_pressed == true && !gamepad->pressedA1())||
(xb1_guide_pressed == false && gamepad->pressedA1()) ) {
virtual_keycode_change = true;
}
// Virtual Keycode Triggered (Pressed or Released)
if ( virtual_keycode_change == true ) {
uint8_t new_sequence = virtual_keycode_sequence;
new_sequence++; // will rollover
if ( new_sequence == 0 )
new_sequence = 1;
GIP_HEADER((&xboneReport), GIP_VIRTUAL_KEYCODE, 1, new_sequence);
if ( xb1_guide_pressed == false ) {
xboneReport.Header.length = sizeof(xb1_guide_on);
memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_on, sizeof(xb1_guide_on));
xboneReportSize = sizeof(GipHeader_t) + sizeof(xb1_guide_on);
} else {
xboneReport.Header.length = sizeof(xb1_guide_off);
memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_off, sizeof(xb1_guide_off));
xboneReportSize = sizeof(GipHeader_t) + sizeof(xb1_guide_off);
}
if ( send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize) == true ) {
// On success, update our guide pressed state and virtual key code state
virtual_keycode_sequence = new_sequence;
xb1_guide_pressed = !xb1_guide_pressed;
}
return;
}
// Only change xbox one input report if we have different inputs!
XboxOneGamepad_Data_t newInputReport;
// This is due to our tusb_driver.cpp checking memcmp(last_report, report, size)
memset(&newInputReport, 0, sizeof(XboxOneGamepad_Data_t));
GIP_HEADER((&newInputReport), GIP_INPUT_REPORT, false, last_report_counter);
newInputReport.a = gamepad->pressedB1();
newInputReport.b = gamepad->pressedB2();
newInputReport.x = gamepad->pressedB3();
newInputReport.y = gamepad->pressedB4();
newInputReport.leftShoulder = gamepad->pressedL1();
newInputReport.rightShoulder = gamepad->pressedR1();
newInputReport.leftThumbClick = gamepad->pressedL3();
newInputReport.rightThumbClick = gamepad->pressedR3();
newInputReport.start = gamepad->pressedS2();
newInputReport.back = gamepad->pressedS1();
newInputReport.guide = 0; // always 0
newInputReport.sync = 0;
newInputReport.dpadUp = gamepad->pressedUp();
newInputReport.dpadDown = gamepad->pressedDown();
newInputReport.dpadLeft = gamepad->pressedLeft();
newInputReport.dpadRight = gamepad->pressedRight();
newInputReport.leftStickX = static_cast<int16_t>(gamepad->state.lx) + INT16_MIN;
newInputReport.leftStickY = static_cast<int16_t>(~gamepad->state.ly) + INT16_MIN;
newInputReport.rightStickX = static_cast<int16_t>(gamepad->state.rx) + INT16_MIN;
newInputReport.rightStickY = static_cast<int16_t>(~gamepad->state.ry) + INT16_MIN;
if (gamepad->hasAnalogTriggers)
{
newInputReport.leftTrigger = gamepad->pressedL2() ? 0x03FF : gamepad->state.lt;
newInputReport.rightTrigger = gamepad->pressedR2() ? 0x03FF : gamepad->state.rt;
}
else
{
newInputReport.leftTrigger = gamepad->pressedL2() ? 0x03FF : 0;
newInputReport.rightTrigger = gamepad->pressedR2() ? 0x03FF : 0;
}
// We changed inputs since generating our last report, increment last report counter (but don't update until success)
if ( memcmp(&last_report[4], &((uint8_t*)&newInputReport)[4], sizeof(XboxOneGamepad_Data_t)-4) != 0 ) {
xboneReportSize = sizeof(XboxOneGamepad_Data_t);
memcpy(&xboneReport, &newInputReport, xboneReportSize);
xboneReport.Header.sequence = last_report_counter + 1;
if ( xboneReport.Header.sequence == 0 )
xboneReport.Header.sequence = 1;
// Successfully sent report, actually increment last report counter!
if ( send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize) == true ) {
if ( memcmp(&last_report[4], &((uint8_t*)&xboneReport)[4], xboneReportSize-4) != 0) {
last_report_counter++;
if (last_report_counter == 0)
last_report_counter = 1;
memcpy(last_report, &xboneReport, xboneReportSize);
}
}
}
}
void XBOneDriver::processAux() {
if ( authDriver != nullptr && authDriver->available() ) {
((XBOneAuth*)authDriver)->process();
}
}
bool XBOneDriver::getAuthSent() {
if ( xboxOneAuthData == nullptr ) {
return false;
}
return xboxOneAuthData->authCompleted;
}
bool XBOneDriver::send_xbone_usb(uint8_t const *report, uint16_t report_size) {
uint8_t itf = 0;
xboned_interface_t *p_xbone = _xboned_itf;
for (;; itf++, p_xbone++) {
if (itf >= TU_ARRAY_SIZE(_xboned_itf)) {
return false;
}
if (p_xbone->ep_in)
break;
}
if ( tud_ready() && // Is the device ready?
(p_xbone->ep_in != 0) && (!usbd_edpt_busy(TUD_OPT_RHPORT, p_xbone->ep_in))) // Is the IN endpoint available?
{
usbd_edpt_claim(0, p_xbone->ep_in); // Take control of IN endpoint
usbd_edpt_xfer(0, p_xbone->ep_in, (uint8_t *)report, report_size); // Send report buffer
usbd_edpt_release(0, p_xbone->ep_in); // Release control of IN endpoint
// we successfully sent the report
return true;
}
return false;
}
// tud_hid_get_report_cb
uint16_t XBOneDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
memcpy(buffer, &xboneReport, sizeof(xboneReport));
return sizeof(xboneReport);
}
// Only PS4 does anything with set report
void XBOneDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
// Only XboxOG and Xbox One use vendor control xfer cb
bool XBOneDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
uint8_t buf[255];
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP)
return true;
if (request->bmRequestType_bit.direction == TUSB_DIR_IN) { // This is where we should be
uint16_t len = request->wLength;
if ( request->bmRequestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request->bRequest == REQ_GET_OS_FEATURE_DESCRIPTOR &&
request->wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) {
memcpy(buf, &DevCompatIDsOne, len);
}
tud_control_xfer(rhport, request, (void*)buf, len);
} else {
tud_control_xfer(rhport, request, (void*)buf, request->wLength);
}
return true;
}
const uint16_t * XBOneDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
const char *value = (const char *)xbone_string_descriptors[index];
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
const char *value = (const char *)xbone_get_string_descriptor(index);
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
}
const uint8_t * XBOneDriver::get_descriptor_device_cb() {
@@ -490,84 +574,84 @@ const uint8_t * XBOneDriver::get_descriptor_configuration_cb(uint8_t index) {
}
const uint8_t * XBOneDriver::get_descriptor_device_qualifier_cb() {
return xbone_device_qualifier;
return xbone_device_qualifier;
}
void XBOneDriver::set_ack_wait() {
waiting_ack = true;
waiting_ack_timeout = to_ms_since_boot(get_absolute_time()); // 2 second time-out
waiting_ack = true;
waiting_ack_timeout = to_ms_since_boot(get_absolute_time()); // 2 second time-out
}
void XBOneDriver::update() {
uint32_t now = to_ms_since_boot(get_absolute_time());
uint32_t now = to_ms_since_boot(get_absolute_time());
if ( !report_queue.empty() ) {
if ( (now - lastReportQueueSent) > REPORT_QUEUE_INTERVAL ) {
report_queue_t & report_front = report_queue.front();
uint16_t xboneReportSize = report_front.len;
if ( send_xbone_usb(report_front.report, xboneReportSize) ) {
lastReportQueueSent = now;
// Set last report queue sent to our report sent by the queue
memcpy(last_report, &report_front.report, xboneReportSize);
report_queue.pop();
} else {
sleep_ms(REPORT_QUEUE_INTERVAL);
}
}
}
if ( !report_queue.empty() ) {
if ( (now - lastReportQueueSent) > REPORT_QUEUE_INTERVAL ) {
report_queue_t & report_front = report_queue.front();
uint16_t xboneReportSize = report_front.len;
if ( send_xbone_usb(report_front.report, xboneReportSize) ) {
lastReportQueueSent = now;
// Set last report queue sent to our report sent by the queue
memcpy(last_report, &report_front.report, xboneReportSize);
report_queue.pop();
} else {
sleep_ms(REPORT_QUEUE_INTERVAL);
}
}
}
// Do not add logic until our ACK returns
if ( waiting_ack == true ) {
if ((now - waiting_ack_timeout) < XGIP_ACK_WAIT_TIMEOUT) {
return;
} else { // ACK wait time out
waiting_ack = false;
}
}
// Do not add logic until our ACK returns
if ( waiting_ack == true ) {
if ((now - waiting_ack_timeout) < XGIP_ACK_WAIT_TIMEOUT) {
return;
} else { // ACK wait time out
waiting_ack = false;
}
}
switch(xboneDriverState) {
case READY_ANNOUNCE:
// Xbox One announce must wait around 0.5s before sending
if ( now - timer_wait_for_announce > 500 ) {
memcpy((void*)&announcePacket[3], &now, 3);
outgoingXGIP.setAttributes(GIP_ANNOUNCE, 1, 1, 0, 0);
outgoingXGIP.setData(announcePacket, sizeof(announcePacket));
queue_xbone_report(outgoingXGIP.generatePacket(), outgoingXGIP.getPacketLength());
xboneDriverState = WAIT_DESCRIPTOR_REQUEST;
}
break;
case SEND_DESCRIPTOR:
queue_xbone_report(outgoingXGIP.generatePacket(), outgoingXGIP.getPacketLength());
if ( outgoingXGIP.endOfChunk() == true ) {
xboneDriverState = SETUP_AUTH;
}
if ( outgoingXGIP.getPacketAck() == 1 ) { // ACK can happen at different chunks
set_ack_wait();
}
break;
case SETUP_AUTH:
if ( XboxOneData::getInstance().getState() == XboxOneState::send_auth_dongle_to_console ) {
bool isChunked = (XboxOneData::getInstance().getAuthLen() > GIP_MAX_CHUNK_SIZE);
outgoingXGIP.reset();
outgoingXGIP.setAttributes(XboxOneData::getInstance().getAuthType(), XboxOneData::getInstance().getSequence(), 1, isChunked, 1);
outgoingXGIP.setData(XboxOneData::getInstance().getAuthBuffer(), XboxOneData::getInstance().getAuthLen());
XboxOneData::getInstance().setState(wait_auth_dongle_to_console);
} else if ( XboxOneData::getInstance().getState() == XboxOneState::wait_auth_dongle_to_console ) {
queue_xbone_report(outgoingXGIP.generatePacket(), outgoingXGIP.getPacketLength());
if ( outgoingXGIP.getChunked() == false || outgoingXGIP.endOfChunk() == true ) {
XboxOneData::getInstance().setState(XboxOneState::auth_idle_state);
}
if ( outgoingXGIP.getPacketAck() == 1 ) { // ACK can happen at different chunks
set_ack_wait();
}
}
break;
case IDLE_STATE:
default:
break;
};
switch(xboneDriverState) {
case READY_ANNOUNCE:
// Xbox One announce must wait around 0.5s before sending
if ( now - timer_wait_for_announce > 500 ) {
memcpy((void*)&announcePacket[3], &now, 3);
outgoingXGIP->setAttributes(GIP_ANNOUNCE, 1, 1, 0, 0);
outgoingXGIP->setData(announcePacket, sizeof(announcePacket));
queue_xbone_report(outgoingXGIP->generatePacket(), outgoingXGIP->getPacketLength());
xboneDriverState = WAIT_DESCRIPTOR_REQUEST;
}
break;
case SEND_DESCRIPTOR:
queue_xbone_report(outgoingXGIP->generatePacket(), outgoingXGIP->getPacketLength());
if ( outgoingXGIP->endOfChunk() == true ) {
xboneDriverState = SETUP_AUTH;
}
if ( outgoingXGIP->getPacketAck() == 1 ) { // ACK can happen at different chunks
set_ack_wait();
}
break;
case SETUP_AUTH:
if ( xboxOneAuthData->xboneState == XboxOneState::send_auth_dongle_to_console ) {
bool isChunked = (xboxOneAuthData->authLen > GIP_MAX_CHUNK_SIZE);
outgoingXGIP->reset();
outgoingXGIP->setAttributes(xboxOneAuthData->authType, xboxOneAuthData->authSequence, 1, isChunked, 1);
outgoingXGIP->setData(xboxOneAuthData->authBuffer, xboxOneAuthData->authLen);
xboxOneAuthData->xboneState = wait_auth_dongle_to_console;
} else if ( xboxOneAuthData->xboneState == XboxOneState::wait_auth_dongle_to_console ) {
queue_xbone_report(outgoingXGIP->generatePacket(), outgoingXGIP->getPacketLength());
if ( outgoingXGIP->getChunked() == false || outgoingXGIP->endOfChunk() == true ) {
xboxOneAuthData->xboneState = XboxOneState::auth_idle_state;
}
if ( outgoingXGIP->getPacketAck() == 1 ) { // ACK can happen at different chunks
set_ack_wait();
}
}
break;
case IDLE_STATE:
default:
break;
};
}
uint16_t XBOneDriver::GetJoystickMidValue() {
return GAMEPAD_JOYSTICK_MID;
return GAMEPAD_JOYSTICK_MID;
}

View File

@@ -0,0 +1,17 @@
#include "drivers/xinput/XInputAuth.h"
#include "drivers/xinput/XInputAuthUSBListener.h"
#include "peripheralmanager.h"
void XInputAuth::initialize() {
if ( available() ) {
listener = new XInputAuthUSBListener();
}
}
bool XInputAuth::available() {
return PeripheralManager::getInstance().isUSBEnabled(0);
}
void XInputAuth::process() {
}

View File

@@ -0,0 +1,41 @@
#include "drivers/xinput/XInputAuthUSBListener.h"
#include "peripheralmanager.h"
#include "usbhostmanager.h"
#include "drivers/shared/xinput_host.h"
void XInputAuthUSBListener::setup() {
}
void XInputAuthUSBListener::xmount(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) {
if ( controllerType == xinput_type_t::XBOX360) {
xinput_dev_addr = dev_addr;
xinput_instance = instance;
mounted = true;
}
}
void XInputAuthUSBListener::unmount(uint8_t dev_addr) {
// Do not reset dongle_ready on unmount (Magic-X will remount but still be ready)
mounted = false;
}
void XInputAuthUSBListener::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
if ( mounted == false )
return;
}
void XInputAuthUSBListener::process() {
// Get Serial ID - 0x81
// Do Challenge Init - 0x82 (send console -> host)
// Get Challenge Response - 0x83 (send console -> host)
// ?? - 0x84
// Get State - 0x86 (1 = in-progress, 2 = complete)
// ?? - 0x87
}

View File

@@ -4,7 +4,23 @@
*/
#include "drivers/xinput/XInputDriver.h"
#include "drivers/xinput/XInputAuth.h"
#include "drivers/shared/driverhelper.h"
#include "storagemanager.h"
#define USB_SETUP_DEVICE_TO_HOST 0x80
#define USB_SETUP_HOST_TO_DEVICE 0x00
#define USB_SETUP_TYPE_VENDOR 0x40
#define USB_SETUP_TYPE_CLASS 0x20
#define USB_SETUP_TYPE_STANDARD 0x00
#define USB_SETUP_RECIPIENT_INTERFACE 0x01
#define USB_SETUP_RECIPIENT_DEVICE 0x00
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02
#define USB_SETUP_RECIPIENT_OTHER 0x03
#define REQ_GET_OS_FEATURE_DESCRIPTOR 0x20
#define DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR 0x0004
#define DESC_EXTENDED_PROPERTIES_DESCRIPTOR 0x0005
#define XINPUT_OUT_SIZE 32
@@ -12,12 +28,12 @@ uint8_t endpoint_in = 0;
uint8_t endpoint_out = 0;
uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {};
static void xinput_init(void)
{
static bool authDriverPresent = false;
static void xinput_init(void) {
}
static void xinput_reset(uint8_t rhport)
{
static void xinput_reset(uint8_t rhport) {
(void)rhport;
}
@@ -54,7 +70,32 @@ static bool xinput_device_control_request(uint8_t rhport, uint8_t stage, tusb_co
(void)rhport;
(void)stage;
(void)request;
/*
// if authentication is present
if ( authDriverPresent &&
request->bmRequestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) {
switch(request->bRequest) {
case 0x81:
uint8_t serial[0x0B];
return sizeof(id_data_ms_controller);
case 0x82:
return 0;
case 0x83:
memcpy(requestBuffer, challenge_response, sizeof(challenge_response));
return sizeof(challenge_response);
case 0x84:
break;
case 0x86:
short state = 2; // 1 = in-progress, 2 = complete
memcpy(&request->wValue, &state, sizeof(state));
return sizeof(state);
case 0x87:
break;
default:
break;
};
}
*/
return true;
}
@@ -104,6 +145,30 @@ void XInputDriver::initialize() {
.xfer_cb = xinput_xfer_callback,
.sof = NULL
};
authDriver = nullptr;
}
void XInputDriver::initializeAux() {
authDriver = nullptr;
// AUTH DRIVER NON-FUNCTIONAL FOR NOW
/*
GamepadOptions & gamepadOptions = Storage::getInstance().getGamepadOptions();
if ( gamepadOptions.xinputAuthType == InputModeAuthType::INPUT_MODE_AUTH_TYPE_USB ) {
authDriver = new XInputAuth();
if ( authDriver->available() ) {
authDriver->initialize();
authDriverPresent = true; // for callbacks
}
}
*/
}
USBListener * XInputDriver::get_usb_auth_listener() {
if ( authDriver != nullptr && authDriver->available() ) {
return authDriver->getListener();
}
return nullptr;
}
void XInputDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {
@@ -166,6 +231,12 @@ void XInputDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {
}
}
void XInputDriver::processAux() {
if ( authDriver != nullptr && authDriver->available() ) {
((XInputAuth*)authDriver)->process();
}
}
// tud_hid_get_report_cb
uint16_t XInputDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
memcpy(buffer, &xinputReport, sizeof(XInputReport));

View File

@@ -58,12 +58,9 @@ void GP2040::setup() {
PeripheralManager::getInstance().initSPI();
PeripheralManager::getInstance().initUSB();
// Reduce CPU if any USB host add-on is enabled
const AddonOptions & addonOptions = Storage::getInstance().getAddonOptions();
if ( addonOptions.keyboardHostOptions.enabled ||
addonOptions.psPassthroughOptions.enabled ||
addonOptions.xbonePassthroughOptions.enabled ){
set_sys_clock_khz(120000, true); // Set Clock to 120MHz to avoid potential USB timing issues
// Reduce CPU if USB host is enabled
if ( PeripheralManager::getInstance().isUSBEnabled(0) ) {
set_sys_clock_khz(120000, true); // Set Clock to 120MHz to avoid potential USB timing issues
}
// Setup Gamepad and Gamepad Storage
@@ -114,7 +111,6 @@ void GP2040::setup() {
case BootAction::ENTER_WEBCONFIG_MODE:
// Move this to the Net driver initialize
Storage::getInstance().SetConfigMode(true);
//initialize_driver(INPUT_MODE_CONFIG);
DriverManager::getInstance().setup(INPUT_MODE_CONFIG);
ConfigManager::getInstance().setup(CONFIG_TYPE_WEB);
return;
@@ -154,6 +150,9 @@ void GP2040::setup() {
case BootAction::SET_INPUT_MODE_PS4: // PS4 / PS5 Driver
inputMode = INPUT_MODE_PS4;
break;
case BootAction::SET_INPUT_MODE_PS5: // PS4 / PS5 Driver
inputMode = INPUT_MODE_PS5;
break;
case BootAction::SET_INPUT_MODE_XBONE: // Xbox One Driver
inputMode = INPUT_MODE_XBONE;
break;
@@ -378,6 +377,8 @@ GP2040::BootAction GP2040::getBootAction() {
return BootAction::SET_INPUT_MODE_KEYBOARD;
case INPUT_MODE_PS4:
return BootAction::SET_INPUT_MODE_PS4;
case INPUT_MODE_PS5:
return BootAction::SET_INPUT_MODE_PS5;
case INPUT_MODE_NEOGEO:
return BootAction::SET_INPUT_MODE_NEOGEO;
case INPUT_MODE_MDMINI:

View File

@@ -2,41 +2,49 @@
#include "gp2040aux.h"
#include "gamepad.h"
#include "storagemanager.h" // Global Managers
#include "addonmanager.h"
#include "drivermanager.h"
#include "storagemanager.h"
#include "usbhostmanager.h"
#include "addons/board_led.h"
#include "addons/board_led.h" // Add-Ons
#include "addons/buzzerspeaker.h"
#include "addons/display.h" // Add-Ons
#include "addons/display.h"
#include "addons/pleds.h"
#include "addons/ps4mode.h"
#include "addons/pspassthrough.h"
#include "addons/neopicoleds.h"
#include "addons/xbonepassthrough.h"
#include <iterator>
GP2040Aux::GP2040Aux() {
GP2040Aux::GP2040Aux() : inputDriver(nullptr) {
}
GP2040Aux::~GP2040Aux() {
}
// GP2040Aux will always come after GP2040 setup(), so we can rely on the
// GP2040 setup function for certain setup functions.
void GP2040Aux::setup() {
PeripheralManager::getInstance().initI2C();
PeripheralManager::getInstance().initSPI();
PeripheralManager::getInstance().initUSB();
// Setup Add-ons
addons.LoadUSBAddon(new PSPassthroughAddon(), CORE1_LOOP);
addons.LoadUSBAddon(new XBOnePassthroughAddon(), CORE1_LOOP);
addons.LoadAddon(new DisplayAddon(), CORE1_LOOP);
addons.LoadAddon(new NeoPicoLEDAddon(), CORE1_LOOP);
addons.LoadAddon(new PlayerLEDAddon(), CORE1_LOOP);
addons.LoadAddon(new BoardLedAddon(), CORE1_LOOP);
addons.LoadAddon(new BuzzerSpeakerAddon(), CORE1_LOOP);
addons.LoadAddon(new PS4ModeAddon(), CORE1_LOOP);
// Initialize our input driver's auxilliary functions
inputDriver = DriverManager::getInstance().getDriver();
if ( inputDriver != nullptr ) {
inputDriver->initializeAux();
// Check if we have a USB listener
USBListener * listener = inputDriver->get_usb_auth_listener();
if (listener != nullptr) {
USBHostManager::getInstance().pushListener(listener);
}
}
// Initialize our USB manager
USBHostManager::getInstance().start();
@@ -45,5 +53,10 @@ void GP2040Aux::setup() {
void GP2040Aux::run() {
while (1) {
addons.ProcessAddons(CORE1_LOOP);
// Run auxiliary functions for input driver on Core1
if ( inputDriver != nullptr ) {
inputDriver->processAux();
}
}
}

View File

@@ -15,26 +15,6 @@
#include "CRC32.h"
#include "types.h"
#include "addons/analog.h"
#include "addons/board_led.h"
#include "addons/bootsel_button.h"
#include "addons/buzzerspeaker.h"
#include "addons/dualdirectional.h"
#include "addons/i2canalog1219.h"
#include "addons/display.h"
#include "addons/jslider.h"
#include "addons/neopicoleds.h"
#include "addons/playernum.h"
#include "addons/ps4mode.h"
#include "addons/pleds.h"
#include "addons/reverse.h"
#include "addons/turbo.h"
#include "addons/slider_socd.h"
#include "addons/wiiext.h"
#include "addons/input_macro.h"
#include "addons/snes_input.h"
#include "addons/tilt.h"
#include "config_utils.h"
#include "bitmaps.h"

View File

@@ -12,28 +12,24 @@
void USBHostManager::start() {
// This will happen after Gamepad has initialized
if ( !addons.empty() ) {
if (PeripheralManager::getInstance().isUSBEnabled(0)) {
pio_usb_configuration_t* pio_cfg = PeripheralManager::getInstance().getUSB(0)->getController();
tuh_configure(1, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, pio_cfg);
tuh_init(BOARD_TUH_RHPORT);
sleep_us(10); // ensure we are ready
tuh_ready = true;
}
if (PeripheralManager::getInstance().isUSBEnabled(0)) {
pio_usb_configuration_t* pio_cfg = PeripheralManager::getInstance().getUSB(0)->getController();
tuh_configure(1, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, pio_cfg);
tuh_init(BOARD_TUH_RHPORT);
sleep_us(10); // ensure we are ready
tuh_ready = true;
}
}
// Shut down the USB bus if we are running USB right now
void USBHostManager::shutdown() {
if ( !addons.empty() ) {
if (PeripheralManager::getInstance().isUSBEnabled(0)) {
tuh_rhport_reset_bus(BOARD_TUH_RHPORT, false);
}
if (PeripheralManager::getInstance().isUSBEnabled(0)) {
tuh_rhport_reset_bus(BOARD_TUH_RHPORT, false);
}
}
void USBHostManager::pushAddon(USBAddon * usbAddon) { // If anything needs to update in the gpconfig driver
addons.push_back(usbAddon);
void USBHostManager::pushListener(USBListener * usbListener) { // If anything needs to update in the gpconfig driver
listeners.push_back(usbListener);
}
// Host manager should call tuh_task as fast as possible
@@ -44,55 +40,64 @@ void USBHostManager::process() {
}
void USBHostManager::hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->mount(dev_addr, instance, desc_report, desc_len);
}
}
void USBHostManager::hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->unmount(dev_addr);
}
}
void USBHostManager::hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->report_received(dev_addr, instance, report, len);
}
}
void USBHostManager::hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->set_report_complete(dev_addr, instance, report_id, report_type, len);
}
}
void USBHostManager::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->get_report_complete(dev_addr, instance, report_id, report_type, len);
}
}
void USBHostManager::xinput_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t controllerType, uint8_t subtype) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->xmount(dev_addr, instance, controllerType, subtype);
}
}
void USBHostManager::xinput_umount_cb(uint8_t dev_addr) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->unmount(dev_addr);
}
}
void USBHostManager::xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->report_received(dev_addr, instance, report, len);
}
}
void USBHostManager::xinput_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
for( std::vector<USBAddon*>::iterator it = addons.begin(); it != addons.end(); it++ ){
if ( listeners.size() == 0 ) return;
for( std::vector<USBListener*>::iterator it = listeners.begin(); it != listeners.end(); it++ ){
(*it)->report_sent(dev_addr, instance, report, len);
}
}

View File

@@ -90,7 +90,6 @@ app.get('/api/getGamepadOptions', (req, res) => {
fourWayMode: 0,
fnButtonPin: -1,
profileNumber: 1,
ps4ControllerType: 0,
debounceDelay: 5,
inputModeB1: 1,
inputModeB2: 0,
@@ -100,7 +99,9 @@ app.get('/api/getGamepadOptions', (req, res) => {
inputModeL2: -1,
inputModeR1: -1,
inputModeR2: 3,
ps4ReportHack: 0,
ps4AuthType: 0,
ps5AuthType: 0,
xinputAuthType: 0,
hotkey01: {
auxMask: 32768,
buttonsMask: 66304,
@@ -465,14 +466,11 @@ app.get('/api/getAddonsOptions', (req, res) => {
JSliderInputEnabled: 1,
KeyboardHostAddonEnabled: 1,
PlayerNumAddonEnabled: 1,
PS4ModeAddonEnabled: 1,
ReverseInputEnabled: 1,
SliderSOCDInputEnabled: 1,
TurboInputEnabled: 1,
WiiExtensionAddonEnabled: 1,
SNESpadAddonEnabled: 1,
PSPassthroughAddonEnabled: 1,
XBOnePassthroughAddonEnabled: 1,
InputHistoryAddonEnabled: 1,
inputHistoryLength: 21,
inputHistoryCol: 0,

Some files were not shown because too many files have changed in this diff Show More