From 6a7dc59b980304bf0c23ead4d9e1f663d8c671cf Mon Sep 17 00:00:00 2001 From: Luke A Date: Mon, 23 Sep 2024 23:07:38 -0400 Subject: [PATCH] Xbox 360 Pass-through Authentication (#1138) * [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 * Very WIP xbox 360 auth, don't use this for any reason * Packet size has to be 64 * Fixed a bug with descriptor strings that was causing the xbox 360 security auth to fail * X360 Auth Working! Need to go over a lot of this code because I sync cores now, a lot of xinput changes, etc. * Re-enabling printf to figure out what is going wrong with release DO NOT USE THIS VERSION * Let's revert some core dependence if that's the issue on release * Add sync back in and move add-ons to after driver init * Removing stdio init seems to fix haute42 * Lots of code cleaning. Core0 will always setup() before Core1() so we can remove core1 wait. Added nop to while loop just to add some CPU spice * Updating TinyUSB to 0.17.0 release from Sept. 2024 * Getting x360 back up to working, fixing some small bugs * One merge fix for feature data + tud auth data * Formatting, getting ready for merge * Last of the formatting! --------- Signed-off-by: ImgBotApp Co-authored-by: ImgBotApp --- headers/drivers/shared/driverhelper.h | 6 +- headers/drivers/xinput/XInputAuth.h | 58 +++- .../drivers/xinput/XInputAuthUSBListener.h | 32 +- headers/drivers/xinput/XInputDescriptors.h | 295 +++++++++++++----- headers/drivers/xinput/XInputDriver.h | 7 +- headers/gp2040.h | 4 +- headers/gp2040aux.h | 2 + lib/tinyusb | 2 +- src/display/ui/screens/ButtonLayoutScreen.cpp | 9 +- src/drivers/shared/xinput_host.cpp | 45 +++ src/drivers/xbone/XBOneAuthUSBListener.cpp | 2 +- src/drivers/xinput/XInputAuth.cpp | 10 +- src/drivers/xinput/XInputAuthUSBListener.cpp | 230 +++++++++++++- src/drivers/xinput/XInputDriver.cpp | 239 +++++++++----- src/gp2040aux.cpp | 21 +- src/main.cpp | 21 +- www/src/Locales/en/SettingsPage.jsx | 2 + www/src/Pages/SettingsPage.jsx | 29 +- 18 files changed, 815 insertions(+), 199 deletions(-) diff --git a/headers/drivers/shared/driverhelper.h b/headers/drivers/shared/driverhelper.h index 543aec383..6ecf911e9 100644 --- a/headers/drivers/shared/driverhelper.h +++ b/headers/drivers/shared/driverhelper.h @@ -3,14 +3,14 @@ static uint16_t * getStringDescriptor(const char * value, uint8_t index) { - static uint16_t descriptorStringBuffer[32]; // Max 64 bytes, 31 unicode characters + static uint16_t descriptorStringBuffer[128]; // Max 256 bytes, 127 unicode characters size_t charCount; if ( index == 0 ) // language always has a character count of 1 charCount = 1; else { charCount = strlen(value); - if (charCount > 31) - charCount = 31; + if (charCount > 127) + charCount = 127; } // Fill descriptionStringBuffer[1] .. [32] for (uint8_t i = 0; i < charCount; i++) diff --git a/headers/drivers/xinput/XInputAuth.h b/headers/drivers/xinput/XInputAuth.h index e6d33d3cc..d596e558f 100644 --- a/headers/drivers/xinput/XInputAuth.h +++ b/headers/drivers/xinput/XInputAuth.h @@ -6,16 +6,58 @@ 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, + send_auth_dongle_to_console = 2 } XInputAuthState; -typedef struct { - XInputAuthState xboneState; +class XInputAuthBuffer { +public: + XInputAuthBuffer() { + data = nullptr; + length = 0; + } + ~XInputAuthBuffer(){ + if ( data != nullptr ) { + delete [] data; + } + } + + void setBuffer(uint8_t * inData, uint16_t inLen) { + data = new uint8_t[inLen]; + length = inLen; + memcpy(data, inData, inLen); + } + + void reset() { + if ( data != nullptr ) { + delete [] data; + } + data = nullptr; + length = 0; + } - // Console-to-Host e.g. Xbox 360 to MagicBoots - bool authCompleted; + uint8_t * data; + uint16_t length; +}; + +#define X360_AUTHLEN_CONSOLE_INIT 34 +#define X360_AUTHLEN_DONGLE_SERIAL 29 +#define X360_AUTHLEN_DONGLE_INIT 46 +#define X360_AUTHLEN_CHALLENGE 22 + +// We need to keep track of: +// Xbox 360 Console Auth Init 34 bytes +// Dongle Serial 29 bytes +// Console-Dongle Back and Forth 46 bytes & 22 bytes +typedef struct { + XInputAuthState xinputState; + uint8_t consoleInitialAuth[X360_AUTHLEN_CONSOLE_INIT]; // Console Init (Keep when Dongle Reboots) + uint8_t dongleSerial[X360_AUTHLEN_DONGLE_SERIAL]; // Dongle Serial + uint8_t passthruBuffer[X360_AUTHLEN_DONGLE_INIT]; // Back-and-Forth Buffer (46 or 22 bytes) + uint8_t passthruBufferLen; // Length of Passthru (do we need this?) + uint8_t passthruBufferID; // ID of vendor request + bool authCompleted = false; + bool hasInitAuth = false; + bool dongle_ready = false; } XInputAuthData; class XInputAuth : public GPAuthDriver { @@ -23,7 +65,9 @@ class XInputAuth : public GPAuthDriver { virtual void initialize(); virtual bool available(); void process(); + XInputAuthData * getAuthData() { return &xinputAuthData; } private: + XInputAuthData xinputAuthData; }; #endif diff --git a/headers/drivers/xinput/XInputAuthUSBListener.h b/headers/drivers/xinput/XInputAuthUSBListener.h index c40dcf0eb..8da44e552 100644 --- a/headers/drivers/xinput/XInputAuthUSBListener.h +++ b/headers/drivers/xinput/XInputAuthUSBListener.h @@ -2,6 +2,16 @@ #define _XINPUTAUTHUSBLISTENER_H_ #include "usblistener.h" +#include "XInputAuth.h" +#include "usbhostmanager.h" + +#include "drivers/shared/xinput_host.h" +#include "drivers/xinput/XInputDescriptors.h" + +typedef enum { + DONGLE_AUTH_IDLE = 0, + DONGLE_AUTH_WAIT_STATE +} DONGLE_AUTH_STATE; class XInputAuthUSBListener : public USBListener { public: @@ -9,15 +19,31 @@ class XInputAuthUSBListener : public USBListener { 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 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(XInputAuthData *); private: + bool xinputh_vendor_report(tusb_dir_t dir, uint8_t request, uint16_t value, uint16_t length, uint8_t * recvBuf, uintptr_t user_data); + // Helper functions for Xbox 360 Authentication + bool auth_dongle_get_serial(); + bool auth_dongle_init_challenge(); + bool auth_dongle_challenge_verify(); + bool auth_dongle_data_reply(uint8_t replyLen); + bool auth_dongle_wait_get_state(); + bool auth_dongle_keepalive(); + void auth_dongle_wait(uint8_t waitID); uint8_t xinput_dev_addr; uint8_t xinput_instance; - bool mounted; + bool sending; + XInputAuthData * xinputAuthData; + uint32_t wait_time; + uint8_t wait_count; + uint8_t waitBuffer[64]; // wait buffer + uint8_t waitBufferID; + DONGLE_AUTH_STATE dongleAuthState; }; #endif // _XINPUTAUTHUSBLISTENER_H_ diff --git a/headers/drivers/xinput/XInputDescriptors.h b/headers/drivers/xinput/XInputDescriptors.h index 680ac6f8b..c99ae0a20 100644 --- a/headers/drivers/xinput/XInputDescriptors.h +++ b/headers/drivers/xinput/XInputDescriptors.h @@ -33,95 +33,236 @@ typedef struct __attribute((packed, aligned(1))) { - uint8_t report_id; - uint8_t report_size; - uint8_t buttons1; - uint8_t buttons2; - uint8_t lt; - uint8_t rt; - int16_t lx; - int16_t ly; - int16_t rx; - int16_t ry; - uint8_t _reserved[6]; + uint8_t report_id; + uint8_t report_size; + uint8_t buttons1; + uint8_t buttons2; + uint8_t lt; + uint8_t rt; + int16_t lx; + int16_t ly; + int16_t rx; + int16_t ry; + uint8_t _reserved[6]; } XInputReport; static const uint8_t xinput_string_language[] = { 0x09, 0x04 }; -static const uint8_t xinput_string_manfacturer[] = "Microsoft"; -static const uint8_t xinput_string_product[] = "XInput STANDARD GAMEPAD"; -static const uint8_t xinput_string_version[] = "1.0"; +static const uint8_t xinput_string_serial[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t xinput_string_manfacturer[] = "\xa9Microsoft Corporation"; +static const uint8_t xinput_string_product[] = "Controller"; +static const uint8_t xinput_string_version[] = "08FEC93"; // Fake a random serial, doesn't matter +static const uint8_t xinput_string_xsm3[] = "Xbox Security Method 3, Version 1.00, \xa9 2005 Microsoft Corporation. All rights reserved."; static const uint8_t *xinput_string_descriptors[] __attribute__((unused)) = { - xinput_string_language, - xinput_string_manfacturer, - xinput_string_product, - xinput_string_version + xinput_string_serial, + xinput_string_manfacturer, + xinput_string_product, + xinput_string_version, + xinput_string_xsm3 }; static const uint8_t xinput_device_descriptor[] = { - 0x12, // bLength - 0x01, // bDescriptorType (Device) - 0x00, 0x02, // bcdUSB 2.00 - 0xFF, // bDeviceClass - 0xFF, // bDeviceSubClass - 0xFF, // bDeviceProtocol - 0x40, // bMaxPacketSize0 64 - 0x5E, 0x04, // idVendor 0x045E - 0x8E, 0x02, // idProduct 0x028E - 0x14, 0x01, // bcdDevice 2.14 - 0x01, // iManufacturer (String Index) - 0x02, // iProduct (String Index) - 0x03, // iSerialNumber (String Index) - 0x01, // bNumConfigurations 1 + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0xFF, // bDeviceClass + 0xFF, // bDeviceSubClass + 0xFF, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + 0x5E, 0x04, // idVendor 0x045E + 0x8E, 0x02, // idProduct 0x028E + 0x14, 0x01, // bcdDevice 2.14 + 0x01, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x03, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 }; +// This needs to be: + // 4 interfaces + // remote wakeup enabled static const uint8_t xinput_configuration_descriptor[] = { - 0x09, // bLength - 0x02, // bDescriptorType (Configuration) - 0x30, 0x00, // wTotalLength 48 - 0x01, // bNumInterfaces 1 - 0x01, // bConfigurationValue - 0x00, // iConfiguration (String Index) - 0x80, // bmAttributes - 0xFA, // bMaxPower 500mA - - 0x09, // bLength - 0x04, // bDescriptorType (Interface) - 0x00, // bInterfaceNumber 0 - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints 2 - 0xFF, // bInterfaceClass - 0x5D, // bInterfaceSubClass - 0x01, // bInterfaceProtocol - 0x00, // iInterface (String Index) - - 0x10, // bLength - 0x21, // bDescriptorType (HID) - 0x10, 0x01, // bcdHID 1.10 - 0x01, // bCountryCode - 0x24, // bNumDescriptors - 0x81, // bDescriptorType[0] (Unknown 0x81) - 0x14, 0x03, // wDescriptorLength[0] 788 - 0x00, // bDescriptorType[1] (Unknown 0x00) - 0x03, 0x13, // wDescriptorLength[1] 4867 - 0x01, // bDescriptorType[2] (Unknown 0x02) - 0x00, 0x03, // wDescriptorLength[2] 768 - 0x00, // bDescriptorType[3] (Unknown 0x00) - - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x81, // bEndpointAddress (IN/D2H) - 0x03, // bmAttributes (Interrupt) - 0x20, 0x00, // wMaxPacketSize 32 - 0x01, // bInterval 1 (unit depends on device speed) - - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x01, // bEndpointAddress (OUT/H2D) - 0x03, // bmAttributes (Interrupt) - 0x20, 0x00, // wMaxPacketSize 32 - 0x08, // bInterval 8 (unit depends on device speed) + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x99, 0x00, // wTotalLength 0x99 + 0x04, // bNumInterfaces 4 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0xA0, // bmAttributes (remote wakeup) + 0xFA, // bMaxPower 500mA + + // Control Interface (0x5D 0xFF) + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0xFF, // bInterfaceClass + 0x5D, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + // Gamepad Descriptor + 0x11, // bLength + 0x21, // bDescriptorType (HID) + 0x00, 0x01, // bcdHID 1.10 + 0x01, // SUB_TYPE + 0x25, // reserved2 + 0x81, // DEVICE_EPADDR_IN + 0x14, // bMaxDataSizeIn + 0x00, 0x00, 0x00, 0x00, 0x13, // reserved3 + 0x02, // DEVICE_EPADDR_OUT is this right? + 0x08, // bMaxDataSizeOut + 0x00, 0x00, // reserved4 + + // Report IN Endpoint 1.1 + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x01, // bInterval 1 (unit depends on device speed) + + // Report OUT Endpoint 1.2 + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x02, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x08, // bInterval 8 (unit depends on device speed) + + // Interface Audio + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x01, // bInterfaceNumber 1 + 0x00, // bAlternateSetting + 0x04, // bNumEndpoints 4 + 0xFF, // bInterfaceClass + 0x5D, // bInterfaceSubClass + 0x03, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + // Audio Descriptor + 0x1B, // bLength + 0x21, + 0x00, + 0x01, + 0x01, + 0x01, + 0x83, // XINPUT_MIC_IN + 0x40, // ?? + 0x01, // ?? + 0x04, // XINPUT_AUDIO_OUT + 0x20, // ?? + 0x16, // ?? + 0x85, // XINPUT_UNK_IN + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x16, + 0x06, // XINPUT_UNK_OUT + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + // Report IN Endpoint 2.1 + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x83, // bEndpointAddress (XINPUT_MIC_IN) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x02, // bInterval 2 (unit depends on device speed) + + // Report OUT Endpoint 2.2 + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x04, // bEndpointAddress (XINPUT_AUDIO_OUT) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x04, // bInterval 4 (unit depends on device speed) + + // Report IN Endpoint 2.3 + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x85, // bEndpointAddress (XINPUT_UNK_IN) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x40, // bInterval 128 + + // Report OUT Endpoint 2.4 + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x06, // bEndpointAddress (XINPUT_UNK_OUT) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x10, // bInterval 16 + + // Interface Plugin Module + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x02, // bInterfaceNumber 2 + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints 1 + 0xFF, // bInterfaceClass + 0x5D, // bInterfaceSubClass + 0x02, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + //PluginModuleDescriptor : { + 0x09, // bLength + 0x21, // bDescriptorType + 0x00, 0x01, // version 1.00 + 0x01, // ?? + 0x22, // ?? + 0x86, // XINPUT_PLUGIN_MODULE_IN, + 0x03, // ?? + 0x00, // ?? + + // Report IN Endpoint 3.1 + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x86, // bEndpointAddress (XINPUT_PLUGIN_MODULE_IN) + 0x03, // bmAttributes (Interrupt) + 0x20, 0x00, // wMaxPacketSize 32 + 0x10, // bInterval 8 (unit depends on device speed) + + // Interface Security + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x03, // bInterfaceNumber 3 + 0x00, // bAlternateSetting + 0x00, // bNumEndpoints 0 + 0xFF, // bInterfaceClass + 0xFD, // bInterfaceSubClass + 0x13, // bInterfaceProtocol + 0x04, // iInterface (String Index) + + // SecurityDescriptor (XSM3) + 0x06, // bLength + 0x41, // bDescriptType (Xbox 360) + 0x00, + 0x01, + 0x01, + 0x03, }; + +typedef enum +{ + XSM360_AUTH_NONE = 0x00, // None + XSM360_GET_SERIAL = 0x81, // Xbox 360 Get Controller Serial + XSM360_INIT_AUTH = 0x82, // Xbox 360 Initialize Authentication + XSM360_RESPOND_CHALLENGE = 0x83, // Xbox 360 Respond with Challenge + XSM360_AUTH_KEEPALIVE = 0x84, // Xbox 360 Keep Authentication Alive + XSM360_REQUEST_STATE = 0x86, // Xbox 360 Request Authentication State + XSM360_VERIFY_AUTH = 0x87, // Xbox 360 Verify Authentication + +} XSM360AuthRequest; diff --git a/headers/drivers/xinput/XInputDriver.h b/headers/drivers/xinput/XInputDriver.h index f22016f24..83ab03d14 100644 --- a/headers/drivers/xinput/XInputDriver.h +++ b/headers/drivers/xinput/XInputDriver.h @@ -9,6 +9,7 @@ #include "gpdriver.h" #include "usblistener.h" #include "drivers/shared/gpauthdriver.h" +#include "drivers/xinput/XInputAuth.h" #include "drivers/xinput/XInputDescriptors.h" #define XINPUT_OUT_SIZE 32 @@ -20,7 +21,7 @@ class XInputDriver : public GPDriver { 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 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); virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); virtual const uint8_t * get_descriptor_device_cb(); @@ -29,11 +30,13 @@ class XInputDriver : public GPDriver { virtual const uint8_t * get_descriptor_device_qualifier_cb(); virtual uint16_t GetJoystickMidValue(); virtual USBListener * get_usb_auth_listener(); + bool getAuthEnabled(); private: uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; XInputReport xinputReport; - GPAuthDriver * authDriver; + XInputAuth * xAuthDriver; uint8_t featureBuffer[XINPUT_OUT_SIZE]; + uint8_t tud_buffer[64]; }; #endif diff --git a/headers/gp2040.h b/headers/gp2040.h index 5519267c2..c252ef773 100644 --- a/headers/gp2040.h +++ b/headers/gp2040.h @@ -17,8 +17,8 @@ class GP2040 { public: - GP2040() {} - ~GP2040() {} + GP2040(){} + ~GP2040(){} void setup(); // setup core0 void run(); // loop core0 private: diff --git a/headers/gp2040aux.h b/headers/gp2040aux.h index 0ea140fed..60f77ff5e 100644 --- a/headers/gp2040aux.h +++ b/headers/gp2040aux.h @@ -15,9 +15,11 @@ class GP2040Aux { ~GP2040Aux(); void setup(); // setup core1 void run(); // loop core1 + bool ready(){ return isReady; } private: GPDriver * inputDriver; AddonManager addons; + bool isReady; }; #endif diff --git a/lib/tinyusb b/lib/tinyusb index d10b65ada..5217cee5d 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit d10b65ada4be7d5754b3128e80a9b4db72bdb23f +Subproject commit 5217cee5de4cd555018da90f9f1bcc87fb1c1d3a diff --git a/src/display/ui/screens/ButtonLayoutScreen.cpp b/src/display/ui/screens/ButtonLayoutScreen.cpp index 3e716cf3e..e3a9b6e4f 100644 --- a/src/display/ui/screens/ButtonLayoutScreen.cpp +++ b/src/display/ui/screens/ButtonLayoutScreen.cpp @@ -3,6 +3,7 @@ #include "drivermanager.h" #include "drivers/ps4/PS4Driver.h" #include "drivers/xbone/XBOneDriver.h" +#include "drivers/xinput/XInputDriver.h" void ButtonLayoutScreen::init() { const InputHistoryOptions& inputHistoryOptions = Storage::getInstance().getAddonOptions().inputHistoryOptions; @@ -132,7 +133,6 @@ void ButtonLayoutScreen::generateHeader() { case INPUT_MODE_PS3: statusBar += "PS3"; break; case INPUT_MODE_GENERIC: statusBar += "USBHID"; break; case INPUT_MODE_SWITCH: statusBar += "SWITCH"; break; - case INPUT_MODE_XINPUT: statusBar += "XINPUT"; break; case INPUT_MODE_MDMINI: statusBar += "GEN/MD"; break; case INPUT_MODE_NEOGEO: statusBar += "NGMINI"; break; case INPUT_MODE_PCEMINI: statusBar += "PCE/TG"; break; @@ -161,6 +161,13 @@ void ButtonLayoutScreen::generateHeader() { else statusBar += "*"; break; + case INPUT_MODE_XINPUT: + statusBar += "X"; + if(((XInputDriver*)DriverManager::getInstance().getDriver())->getAuthEnabled() == true ) + statusBar += "B360"; + else + statusBar += "INPUT"; + break; case INPUT_MODE_KEYBOARD: statusBar += "HID-KB"; break; case INPUT_MODE_CONFIG: statusBar += "CONFIG"; break; } diff --git a/src/drivers/shared/xinput_host.cpp b/src/drivers/shared/xinput_host.cpp index 67e623ef0..def9c2ca7 100644 --- a/src/drivers/shared/xinput_host.cpp +++ b/src/drivers/shared/xinput_host.cpp @@ -116,6 +116,29 @@ bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance) { return true; } +bool tuh_xinput_receive_vendor_report(uint8_t dev_addr, uint8_t instance, uint8_t request, uint16_t value, uint8_t index, uint16_t length, uint8_t * recvBuf) { + const tusb_control_request_t xfer_ctrl_req = { + .bmRequestType_bit { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = TUSB_DIR_IN, + }, + .bRequest = request, + .wValue = value, + .wIndex = TU_U16(index, 0x03), + .wLength = length + }; + tuh_xfer_t xfer = { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &xfer_ctrl_req, + .buffer = recvBuf, + .complete_cb = NULL, + }; + return tuh_control_xfer(&xfer); +} + + bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); @@ -140,6 +163,28 @@ bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, uint8_t const *r return ret; } +bool tuh_xinput_send_vendor_report(uint8_t dev_addr, uint8_t instance, uint8_t request, uint16_t value, uint8_t index, uint16_t length, uint8_t * sendBuf) { + const tusb_control_request_t xfer_ctrl_req = { + .bmRequestType_bit { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = TUSB_DIR_OUT, + }, + .bRequest = request, + .wValue = value, + .wIndex = TU_U16(index, 0x03), + .wLength = length + }; + tuh_xfer_t xfer = { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &xfer_ctrl_req, + .buffer = sendBuf, + .complete_cb = NULL, + }; + return tuh_control_xfer(&xfer); +} + bool tuh_xinput_ready(uint8_t dev_addr, uint8_t instance) { TU_VERIFY(tuh_xinput_mounted(dev_addr, instance)); diff --git a/src/drivers/xbone/XBOneAuthUSBListener.cpp b/src/drivers/xbone/XBOneAuthUSBListener.cpp index 5c1cc8104..43cb0fabc 100644 --- a/src/drivers/xbone/XBOneAuthUSBListener.cpp +++ b/src/drivers/xbone/XBOneAuthUSBListener.cpp @@ -113,7 +113,7 @@ void XBOneAuthUSBListener::report_received(uint8_t dev_addr, uint8_t instance, u queue_host_report((uint8_t*)outgoingXGIP.generatePacket(), outgoingXGIP.getPacketLength()); break; case GIP_DEVICE_DESCRIPTOR: - if ( incomingXGIP.endOfChunk() == true ) { + if ( incomingXGIP.endOfChunk() == true && xboxOneAuthData->dongle_ready != true) { outgoingXGIP.reset(); // Power-on full string outgoingXGIP.setAttributes(GIP_POWER_MODE_DEVICE_CONFIG, 2, 1, false, 0); outgoingXGIP.setData(xb1_power_on, sizeof(xb1_power_on)); diff --git a/src/drivers/xinput/XInputAuth.cpp b/src/drivers/xinput/XInputAuth.cpp index d6c9c9100..a1e900c45 100644 --- a/src/drivers/xinput/XInputAuth.cpp +++ b/src/drivers/xinput/XInputAuth.cpp @@ -6,6 +6,14 @@ void XInputAuth::initialize() { if ( available() ) { listener = new XInputAuthUSBListener(); } + + if ( available() ) { + listener = new XInputAuthUSBListener(); + xinputAuthData.xinputState = auth_idle_state; + xinputAuthData.authCompleted = false; + ((XInputAuthUSBListener*)listener)->setup(); + ((XInputAuthUSBListener*)listener)->setAuthData(&xinputAuthData); + } } bool XInputAuth::available() { @@ -13,5 +21,5 @@ bool XInputAuth::available() { } void XInputAuth::process() { - + ((XInputAuthUSBListener*)listener)->process(); } \ No newline at end of file diff --git a/src/drivers/xinput/XInputAuthUSBListener.cpp b/src/drivers/xinput/XInputAuthUSBListener.cpp index 6c29dcb7e..799b0eeea 100644 --- a/src/drivers/xinput/XInputAuthUSBListener.cpp +++ b/src/drivers/xinput/XInputAuthUSBListener.cpp @@ -3,39 +3,245 @@ #include "usbhostmanager.h" #include "drivers/shared/xinput_host.h" +#include "drivers/xinput/XInputDescriptors.h" + +// Xbox 360 Auth Magic Numbers (wValue in USB Packet) +#define X360_WVALUE_CONSOLE_DATA 0x0003 +#define X360_WVALUE_CONTROLLER_DATA 0x5C +#define X360_WVALUE_CONTROLLER_ID 0x5B +#define X360_WVALUE_NO_DATA 0x00 + +// How long to wait for calling auth state (in microseconds) +#define WAIT_TIME_MS 100 + +void XInputAuthUSBListener::setAuthData(XInputAuthData * authData ) { + xinputAuthData = authData; + xinputAuthData->dongle_ready = false; + memset(xinputAuthData->dongleSerial, 0, X360_AUTHLEN_DONGLE_SERIAL); + xinputAuthData->passthruBufferLen = 0; + xinputAuthData->xinputState = XInputAuthState::auth_idle_state; +} void XInputAuthUSBListener::setup() { + xinput_dev_addr = 0xFF; + xinput_instance = 0xFF; + dongleAuthState = DONGLE_AUTH_STATE::DONGLE_AUTH_IDLE; + wait_time = 0; + wait_count = 0; + sending = false; + xinputAuthData->dongle_ready = false; +} + +bool XInputAuthUSBListener::xinputh_vendor_report(tusb_dir_t dir, uint8_t request, uint16_t value, uint16_t length, uint8_t * buf, uintptr_t user_data){ + const tusb_control_request_t xfer_ctrl_req = { + .bmRequestType_bit { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = dir, + }, + .bRequest = request, + .wValue = value, + .wIndex = TU_U16(0x01, 0x03), + .wLength = length + }; + + tuh_xfer_t xfer = { + .daddr = xinput_dev_addr, + .ep_addr = 0, + .setup = &xfer_ctrl_req, + .buffer = buf, + .complete_cb = NULL, + .user_data = user_data, + }; + + return tuh_control_xfer(&xfer); } 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; + // Get Xbox Security Method 3 (XSM3) + uint8_t recvBuf[0xB2]; + tuh_descriptor_get_string_sync(xinput_dev_addr, 4, 0x0409, recvBuf, 0xB2); + // If our dongle has remounted for any reason, trigger a re-auth (Magicboots X360) + if ( xinputAuthData->hasInitAuth == true ) { + if ( auth_dongle_init_challenge() == true) { + auth_dongle_wait(XSM360AuthRequest::XSM360_INIT_AUTH); + } + } else { + auth_dongle_get_serial(); + } + xinputAuthData->dongle_ready = 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; + if ( dev_addr == xinput_dev_addr ) { + xinputAuthData->dongle_ready = false; + dongleAuthState = DONGLE_AUTH_STATE::DONGLE_AUTH_IDLE; + } } -void XInputAuthUSBListener::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { - if ( mounted == false ) +void XInputAuthUSBListener::process() { + // No Auth Data or Dongle is not ready (Unmounted or Not Connected) + if ( xinputAuthData == nullptr || xinputAuthData->dongle_ready == false) { return; + } + + // Idle State, check for incoming console data + if ( dongleAuthState == DONGLE_AUTH_STATE::DONGLE_AUTH_IDLE ) { + // Received a packet from the console to dongle + if ( xinputAuthData->xinputState == XInputAuthState::send_auth_console_to_dongle ) { + switch(xinputAuthData->passthruBufferID) { + case XSM360AuthRequest::XSM360_INIT_AUTH: + // Copy to our initial auth buffer incase the dongle reconnects + if ( xinputAuthData->hasInitAuth == false ) { + memcpy(xinputAuthData->consoleInitialAuth, xinputAuthData->passthruBuffer, xinputAuthData->passthruBufferLen); + xinputAuthData->hasInitAuth = true; + } + + // Actions are performed in this order + if ( auth_dongle_init_challenge() == false) { + xinputAuthData->xinputState = XInputAuthState::auth_idle_state; + return; + } + auth_dongle_wait(XSM360AuthRequest::XSM360_INIT_AUTH); + break; + case XSM360AuthRequest::XSM360_VERIFY_AUTH: + // Challenge Verify (22 bytes) + if ( auth_dongle_challenge_verify() == false) { + xinputAuthData->xinputState = XInputAuthState::auth_idle_state; + return; + } + auth_dongle_wait(XSM360AuthRequest::XSM360_VERIFY_AUTH); + break; + default: + break; + } + } + } else if ( dongleAuthState == DONGLE_AUTH_STATE::DONGLE_AUTH_WAIT_STATE ) { + uint64_t now_time = to_ms_since_boot(get_absolute_time()); + if ( now_time > wait_time ) { + if ( auth_dongle_wait_get_state() == false ) { + wait_time = now_time + WAIT_TIME_MS; + wait_count++; + } else { + switch(waitBufferID) { + case XSM360AuthRequest::XSM360_INIT_AUTH: + // Actions are performed in this order + if ( auth_dongle_data_reply(X360_AUTHLEN_DONGLE_INIT) == false ) { + xinputAuthData->xinputState = XInputAuthState::auth_idle_state; + } else { + auth_dongle_keepalive(); + xinputAuthData->xinputState = XInputAuthState::send_auth_dongle_to_console; + } + break; + case XSM360AuthRequest::XSM360_VERIFY_AUTH: + if ( auth_dongle_data_reply(X360_AUTHLEN_CHALLENGE) == false ) { + xinputAuthData->xinputState = XInputAuthState::auth_idle_state; + } else { + xinputAuthData->xinputState = XInputAuthState::send_auth_dongle_to_console; + } + break; + default: + break; + } + dongleAuthState = DONGLE_AUTH_STATE::DONGLE_AUTH_IDLE; + wait_count = 0; + } + // TIMEOUT after 60 attempts + if ( wait_count == 60 ) { + dongleAuthState = DONGLE_AUTH_STATE::DONGLE_AUTH_IDLE; + wait_count = 0; + wait_time = 0; + xinputAuthData->xinputState = XInputAuthState::auth_idle_state; + } + } + } } -void XInputAuthUSBListener::process() { - // Get Serial ID - 0x81 - +bool XInputAuthUSBListener::auth_dongle_get_serial() { + // Get Serial ID Buffer (0x81) + xfer_result_t user_result; + if (xinputh_vendor_report(TUSB_DIR_IN, XSM360AuthRequest::XSM360_GET_SERIAL, + TU_U16(X360_WVALUE_CONTROLLER_ID, X360_AUTHLEN_DONGLE_SERIAL-6), + X360_AUTHLEN_DONGLE_SERIAL, xinputAuthData->dongleSerial, (uintptr_t)&user_result) == false + || user_result != xfer_result_t::XFER_RESULT_SUCCESS) { + return false; + } + return true; +} - // Do Challenge Init - 0x82 (send console -> host) +// Xbox 360 Console Auth Challenge Verify - 0x87 +bool XInputAuthUSBListener::auth_dongle_init_challenge() { + // Send Auth Init Data to Dongle + xfer_result_t user_result; + if ( xinputh_vendor_report(TUSB_DIR_OUT, + XSM360AuthRequest::XSM360_INIT_AUTH, X360_WVALUE_CONSOLE_DATA, + X360_AUTHLEN_CONSOLE_INIT, xinputAuthData->consoleInitialAuth, (uintptr_t)&user_result) == false + || user_result != xfer_result_t::XFER_RESULT_SUCCESS) { + return false; + } + return true; +} - // Get Challenge Response - 0x83 (send console -> host) +// Auth Data reply gets a value of 0x5CXX with XX being the total data length minus 6 bytes for the header +bool XInputAuthUSBListener::auth_dongle_data_reply(uint8_t replyLen) { + // Get Xbox 360 Challenge Reply from Dongle + xfer_result_t user_result; + if ( xinputh_vendor_report(TUSB_DIR_IN, + XSM360AuthRequest::XSM360_RESPOND_CHALLENGE, TU_U16(X360_WVALUE_CONTROLLER_DATA, replyLen-6), + replyLen, xinputAuthData->passthruBuffer, (uintptr_t)&user_result) == false + || user_result != xfer_result_t::XFER_RESULT_SUCCESS) { + return false; + } + xinputAuthData->passthruBufferLen = replyLen; + return true; +} - // ?? - 0x84 +// Xbox 360 Console Auth Challenge Verify - 0x87 +bool XInputAuthUSBListener::auth_dongle_challenge_verify() { + // Send Auth Init Data to Dongle + xfer_result_t user_result; + if ( xinputh_vendor_report(TUSB_DIR_OUT, + XSM360AuthRequest::XSM360_VERIFY_AUTH, X360_WVALUE_CONSOLE_DATA, + X360_AUTHLEN_CHALLENGE, xinputAuthData->passthruBuffer, (uintptr_t)&user_result) == false + || user_result != xfer_result_t::XFER_RESULT_SUCCESS) { + return false; + } + return true; +} + +// Xbox 360 Console Asks for Current Signing State +bool XInputAuthUSBListener::auth_dongle_wait_get_state() { + uint8_t wait_buf[2]; + xfer_result_t user_result = xfer_result_t::XFER_RESULT_SUCCESS; + if ( xinputh_vendor_report(TUSB_DIR_IN, + XSM360AuthRequest::XSM360_REQUEST_STATE, X360_WVALUE_NO_DATA, + 2, wait_buf, (uintptr_t)&user_result) == false || user_result != xfer_result_t::XFER_RESULT_SUCCESS ) { + return false; + } + return ( wait_buf[0] == 2 ); // Dongle is ready! +} - // Get State - 0x86 (1 = in-progress, 2 = complete) +// Xbox 360 Console, Send an 0x84 KeepAlive, all is good message +bool XInputAuthUSBListener::auth_dongle_keepalive() { + // Auth Keepalive does not return anything and stalls on some dongles + xfer_result_t user_result; + xinputh_vendor_report(TUSB_DIR_IN, + XSM360AuthRequest::XSM360_AUTH_KEEPALIVE, X360_WVALUE_CONSOLE_DATA, + 0, NULL, (uintptr_t)&user_result); + return true; +} - // ?? - 0x87 +// Wait for X time before checking auth dongle wait-state (ready, not ready) +void XInputAuthUSBListener::auth_dongle_wait(uint8_t waitID) { + // Setup a wait-for mode for the dongle or controller to finish auth + wait_count = 0; + wait_time = to_ms_since_boot(get_absolute_time()) + WAIT_TIME_MS; + memcpy(waitBuffer, xinputAuthData->passthruBuffer, xinputAuthData->passthruBufferLen); + dongleAuthState = DONGLE_AUTH_STATE::DONGLE_AUTH_WAIT_STATE; + waitBufferID = waitID; } diff --git a/src/drivers/xinput/XInputDriver.cpp b/src/drivers/xinput/XInputDriver.cpp index d8926bfe6..fe466a9f6 100644 --- a/src/drivers/xinput/XInputDriver.cpp +++ b/src/drivers/xinput/XInputDriver.cpp @@ -4,7 +4,6 @@ */ #include "drivers/xinput/XInputDriver.h" -#include "drivers/xinput/XInputAuth.h" #include "drivers/shared/driverhelper.h" #include "storagemanager.h" @@ -22,14 +21,41 @@ #define DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR 0x0004 #define DESC_EXTENDED_PROPERTIES_DESCRIPTOR 0x0005 +#define XINPUT_OUT_SIZE 32 +#define CFG_TUD_XINPUT 4 + +#define XINPUT_DESC_TYPE_RESERVED 0x21 +#define XINPUT_SECURITY_DESC_TYPE_RESERVED 0x41 + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct { + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; // optional Out endpoint + uint8_t boot_protocol; // Boot mouse or keyboard + bool boot_mode; // default = false (Report) + + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[XINPUT_OUT_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[XINPUT_OUT_SIZE]; +} xinputd_interface_t; + +CFG_TUSB_MEM_SECTION static xinputd_interface_t _xinputd_itf[CFG_TUD_XINPUT]; + uint8_t endpoint_in = 0; uint8_t endpoint_out = 0; uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {}; +static XInputAuthData * xinputAuthData = nullptr; -#include -#include "pico/stdlib.h" +/*------------- Helpers -------------*/ +static inline uint8_t get_index_by_itfnum(uint8_t itf_num) { + for (uint8_t i = 0; i < CFG_TUD_XINPUT; i++) { + if (itf_num == _xinputd_itf[i].itf_num) return i; + } -static bool authDriverPresent = false; + return 0xFF; +} // Move to Proto Enums typedef enum @@ -57,31 +83,54 @@ static void xinput_reset(uint8_t rhport) { (void)rhport; } -static uint16_t xinput_open(uint8_t rhport, tusb_desc_interface_t const *itf_descriptor, uint16_t max_length) -{ - uint16_t driver_length = sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)) + 16; - - TU_VERIFY(max_length >= driver_length, 0); - - uint8_t const *current_descriptor = tu_desc_next(itf_descriptor); - uint8_t found_endpoints = 0; - while ((found_endpoints < itf_descriptor->bNumEndpoints) && (driver_length <= max_length)) - { - tusb_desc_endpoint_t const *endpoint_descriptor = (tusb_desc_endpoint_t const *)current_descriptor; - if (TUSB_DESC_ENDPOINT == tu_desc_type(endpoint_descriptor)) - { - TU_ASSERT(usbd_edpt_open(rhport, endpoint_descriptor)); - - if (tu_edpt_dir(endpoint_descriptor->bEndpointAddress) == TUSB_DIR_IN) - endpoint_in = endpoint_descriptor->bEndpointAddress; - else - endpoint_out = endpoint_descriptor->bEndpointAddress; - - ++found_endpoints; - } +static uint16_t xinput_open(uint8_t rhport, tusb_desc_interface_t const *itf_descriptor, uint16_t max_length) { + uint16_t driver_length = 0; + // Xbox 360 Vendor USB Interfaces: Control, Audio, Plug-in, Security + if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_descriptor->bInterfaceClass) { + driver_length = sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + TU_VERIFY(max_length >= driver_length, 0); + + // Find available interface + xinputd_interface_t *p_xinput = NULL; + for (uint8_t i = 0; i < CFG_TUD_XINPUT; i++) { + if (_xinputd_itf[i].ep_in == 0 && _xinputd_itf[i].ep_out == 0) { + p_xinput = &_xinputd_itf[i]; + break; + } + } + + tusb_desc_interface_t *p_desc = (tusb_desc_interface_t *)itf_descriptor; + // Xbox 360 Interfaces (Control 0x01, Audio 0x02, Plug-in 0x03) + if (itf_descriptor->bInterfaceSubClass == 0x5D && + ((itf_descriptor->bInterfaceProtocol == 0x01 ) || + (itf_descriptor->bInterfaceProtocol == 0x02 ) || + (itf_descriptor->bInterfaceProtocol == 0x03 )) ) { + // Get Xbox 360 Definition + p_desc = (tusb_desc_interface_t *)tu_desc_next(p_desc); + TU_VERIFY(XINPUT_DESC_TYPE_RESERVED == p_desc->bDescriptorType, 0); + driver_length += p_desc->bLength; + + p_desc = (tusb_desc_interface_t *)tu_desc_next(p_desc); + TU_ASSERT(usbd_open_edpt_pair(rhport, (const uint8_t*)p_desc, itf_descriptor->bNumEndpoints, + TUSB_XFER_INTERRUPT, &p_xinput->ep_out, &p_xinput->ep_in), 0); + p_xinput->itf_num = itf_descriptor->bInterfaceNumber; + + // Control Endpoints are used for gamepad input/output + if ( itf_descriptor->bInterfaceProtocol == 0x01 ) { + endpoint_in = p_xinput->ep_in; + endpoint_out = p_xinput->ep_out; + } + // Xbox 360 Security Interface + } else if (itf_descriptor->bInterfaceSubClass == 0xFD && + itf_descriptor->bInterfaceProtocol == 0x13) { + // Xinput reserved endpoint + //-------------- Xinput Descriptor --------------// + p_desc = (tusb_desc_interface_t *)tu_desc_next(p_desc); + TU_VERIFY(XINPUT_SECURITY_DESC_TYPE_RESERVED == p_desc->bDescriptorType, 0); + driver_length += p_desc->bLength; + } + } - current_descriptor = tu_desc_next(current_descriptor); - } return driver_length; } @@ -90,32 +139,7 @@ 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; } @@ -166,31 +190,33 @@ void XInputDriver::initialize() { .sof = NULL }; - authDriver = nullptr; + xAuthDriver = nullptr; } void XInputDriver::initializeAux() { - authDriver = nullptr; + xAuthDriver = 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 + xAuthDriver = new XInputAuth(); + if ( xAuthDriver->available() ) { + xAuthDriver->initialize(); + xinputAuthData = xAuthDriver->getAuthData(); } - } - */ + } } USBListener * XInputDriver::get_usb_auth_listener() { - if ( authDriver != nullptr && authDriver->available() ) { - return authDriver->getListener(); + if ( xAuthDriver != nullptr && xAuthDriver->available() ) { + return xAuthDriver->getListener(); } return nullptr; } +bool XInputDriver::getAuthEnabled() { + return (xAuthDriver != nullptr); +} + void XInputDriver::process(Gamepad * gamepad) { Gamepad * processedGamepad = Storage::getInstance().GetProcessedGamepad(); @@ -293,8 +319,8 @@ void XInputDriver::process(Gamepad * gamepad) { } void XInputDriver::processAux() { - if ( authDriver != nullptr && authDriver->available() ) { - ((XInputAuth*)authDriver)->process(); + if ( xAuthDriver != nullptr && xAuthDriver->available() ) { + xAuthDriver->process(); } } @@ -304,12 +330,81 @@ uint16_t XInputDriver::get_report(uint8_t report_id, hid_report_type_t report_ty return sizeof(XInputReport); } -// Only PS4 does anything with set report -void XInputDriver::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 +// Only respond to vendor control xfers if we have a mounted x360 device bool XInputDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { - return false; + // Do nothing if we have no auth driver + if ( xAuthDriver == nullptr || !xAuthDriver->available() ) { + return false; + } + + uint16_t len = 0; + if (request->bmRequestType_bit.direction == TUSB_DIR_IN) { + // Write IN data on control_stage_setup only + if (stage == CONTROL_STAGE_SETUP) { + uint16_t state = 1; // 1 = in-progress, 2 = complete + switch (request->bRequest) { + case XSM360_GET_SERIAL: + // Stall if we don't have a dongle ready + if ( xinputAuthData->dongle_ready == false ) { + return false; + } + len = X360_AUTHLEN_DONGLE_SERIAL; + memcpy(tud_buffer, xinputAuthData->dongleSerial, len); + break; + case XSM360_RESPOND_CHALLENGE: + if ( xinputAuthData->xinputState == XInputAuthState::send_auth_dongle_to_console ) { + memcpy(tud_buffer, xinputAuthData->passthruBuffer, xinputAuthData->passthruBufferLen); + len = xinputAuthData->passthruBufferLen; + } else { + // Stall if we don't have a dongle ready + return false; + } + break; + case XSM360_AUTH_KEEPALIVE: + len = 0; + break; + case XSM360_REQUEST_STATE: + // State Ready = 2, Not-Ready = 1 + if ( xinputAuthData->xinputState == XInputAuthState::send_auth_dongle_to_console ) { + state = 2; + } else { + state = 1; + } + memcpy(tud_buffer, &state, sizeof(state)); + len = sizeof(state); + break; + default: + break; + }; + tud_control_xfer(rhport, request, tud_buffer, len); + } + } else if (request->bmRequestType_bit.direction == TUSB_DIR_OUT) { + if (stage == CONTROL_STAGE_SETUP ) { // Pass on output setup in DIR OUT stage + tud_control_xfer(rhport, request, tud_buffer, request->wLength); + } else if ( stage == CONTROL_STAGE_DATA ) { + // Buf is filled, we can save the data to our auth + switch (request->bRequest) { + case XSM360AuthRequest::XSM360_INIT_AUTH: + if ( xinputAuthData->xinputState == XInputAuthState::auth_idle_state ) { + memcpy(xinputAuthData->passthruBuffer, tud_buffer, request->wLength); + xinputAuthData->passthruBufferLen = request->wLength; + xinputAuthData->passthruBufferID = XSM360AuthRequest::XSM360_INIT_AUTH; + xinputAuthData->xinputState = XInputAuthState::send_auth_console_to_dongle; + } + break; + case XSM360AuthRequest::XSM360_VERIFY_AUTH: + memcpy(xinputAuthData->passthruBuffer, tud_buffer, request->wLength); + xinputAuthData->passthruBufferLen = request->wLength; + xinputAuthData->passthruBufferID = XSM360AuthRequest::XSM360_VERIFY_AUTH; + xinputAuthData->xinputState = XInputAuthState::send_auth_console_to_dongle; + break; + default: + break; + }; + } + } + + return true; } const uint16_t * XInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { diff --git a/src/gp2040aux.cpp b/src/gp2040aux.cpp index bd669989b..ebd016ce5 100644 --- a/src/gp2040aux.cpp +++ b/src/gp2040aux.cpp @@ -16,7 +16,7 @@ #include -GP2040Aux::GP2040Aux() : inputDriver(nullptr) { +GP2040Aux::GP2040Aux() : isReady(false), inputDriver(nullptr) { } GP2040Aux::~GP2040Aux() { @@ -29,15 +29,6 @@ void GP2040Aux::setup() { PeripheralManager::getInstance().initSPI(); PeripheralManager::getInstance().initUSB(); - // Setup Add-ons - 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 DRV8833RumbleAddon(), CORE1_LOOP); - addons.LoadAddon(new ReactiveLEDAddon(), CORE1_LOOP); - // Initialize our input driver's auxilliary functions inputDriver = DriverManager::getInstance().getDriver(); if ( inputDriver != nullptr ) { @@ -52,6 +43,16 @@ void GP2040Aux::setup() { // Initialize our USB manager USBHostManager::getInstance().start(); + + // Setup Add-ons + 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); + + // Ready to sync Core0 and Core1 + isReady = true; } void GP2040Aux::run() { diff --git a/src/main.cpp b/src/main.cpp index 87dcfcad6..66c694060 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,25 +20,34 @@ void __verbose_terminate_handler() } } +static GP2040 * gp2040Core0 = nullptr; +static GP2040Aux * gp2040Core1 = nullptr; + // Launch our second core with additional modules loaded in void core1() { multicore_lockout_victim_init(); // block core 1 - // Create GP2040 w/ Additional Modules for Core 1 - GP2040Aux * gp2040Core1 = new GP2040Aux(); + // Create GP2040 w/ Additional Modules for Core 1 gp2040Core1->setup(); gp2040Core1->run(); } int main() { // Create GP2040 Main Core (core0), Core1 is dependent on Core0 - GP2040 * gp2040 = new GP2040(); - gp2040->setup(); + gp2040Core0 = new GP2040(); + gp2040Core1 = new GP2040Aux(); + + // Create GP2040 Main Core - Setup Core0 + gp2040Core0->setup(); // Create GP2040 Thread for Core1 multicore_launch_core1(core1); - // Start Core0 Loop - gp2040->run(); + // Sync Core0 and Core1 + while(gp2040Core1->ready() == false ) { + __asm volatile ("nop\n"); + } + gp2040Core0->run(); + return 0; } diff --git a/www/src/Locales/en/SettingsPage.jsx b/www/src/Locales/en/SettingsPage.jsx index 3e85ee61e..830dc2500 100644 --- a/www/src/Locales/en/SettingsPage.jsx +++ b/www/src/Locales/en/SettingsPage.jsx @@ -79,6 +79,8 @@ export default { 'INFO: Please ensure USB Peripheral is enabled and a PS5 compatible USB device is plugged in.', 'xbone-mode-text': 'INFO: Xbox One requires a USB host connection and USB dongle to properly authenticate in Xbox One mode.', + 'xinput-mode-text': + 'INFO: Xbox 360 mode can either work without authentication or with a USB dongle attached.', 'hotkey-settings-label': 'Hotkey Settings', 'hotkey-settings-sub-header': 'The Fn slider provides a mappable Function button in the Pin Mapping page. By selecting the Fn slider option, the Function button must be held along with the selected hotkey settings.
Additionally, select None from the dropdown to unassign any button.', diff --git a/www/src/Pages/SettingsPage.jsx b/www/src/Pages/SettingsPage.jsx index c5c1273b9..8b2ebc1bb 100644 --- a/www/src/Pages/SettingsPage.jsx +++ b/www/src/Pages/SettingsPage.jsx @@ -120,7 +120,12 @@ const SHA256 = (ascii) => { }; const INPUT_MODES = [ - { labelKey: 'input-mode-options.xinput', value: 0, group: 'primary' }, //, authentication: ['none', 'usb'] }, AUTH WIP + { labelKey: 'input-mode-options.xinput', + value: 0, + group: 'primary', + optional: ['usb'], + authentication: ['none', 'usb'], + }, { labelKey: 'input-mode-options.nintendo-switch', value: 1, @@ -955,6 +960,28 @@ export default function SettingsPage() { )} ); + case 'input-mode-options.xinput': + return ( +
+ {generateAuthSelection( + inputMode, + t('SettingsPage:auth-settings-label'), + 'xinputAuthType', + values.xinputAuthType, + errors.xinputAuthType, + handleChange, + )} + + + }} + /> + + +
+ ); case 'input-mode-options.xbone': return (