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 <ImgBotHelp@gmail.com> * 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 <ImgBotHelp@gmail.com> Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
This commit is contained in:
@@ -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++)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
// Console-to-Host e.g. Xbox 360 to MagicBoots
|
||||
bool authCompleted;
|
||||
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;
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
virtual void initialize();
|
||||
virtual bool available();
|
||||
void process();
|
||||
XInputAuthData * getAuthData() { return &xinputAuthData; }
|
||||
private:
|
||||
XInputAuthData xinputAuthData;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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 @@ public:
|
||||
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_
|
||||
|
||||
@@ -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
|
||||
0x02, // bDescriptorType (Configuration)
|
||||
0x99, 0x00, // wTotalLength 0x99
|
||||
0x04, // bNumInterfaces 4
|
||||
0x01, // bConfigurationValue
|
||||
0x00, // iConfiguration (String Index)
|
||||
0xA0, // bmAttributes (remote wakeup)
|
||||
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)
|
||||
// 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)
|
||||
|
||||
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)
|
||||
// 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
|
||||
|
||||
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 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)
|
||||
|
||||
0x07, // bLength
|
||||
0x05, // bDescriptorType (Endpoint)
|
||||
0x01, // bEndpointAddress (OUT/H2D)
|
||||
0x03, // bmAttributes (Interrupt)
|
||||
0x20, 0x00, // wMaxPacketSize 32
|
||||
0x08, // bInterval 8 (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;
|
||||
|
||||
@@ -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 @@ public:
|
||||
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 @@ public:
|
||||
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
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
class GP2040 {
|
||||
public:
|
||||
GP2040() {}
|
||||
~GP2040() {}
|
||||
GP2040(){}
|
||||
~GP2040(){}
|
||||
void setup(); // setup core0
|
||||
void run(); // loop core0
|
||||
private:
|
||||
|
||||
@@ -15,9 +15,11 @@ public:
|
||||
~GP2040Aux();
|
||||
void setup(); // setup core1
|
||||
void run(); // loop core1
|
||||
bool ready(){ return isReady; }
|
||||
private:
|
||||
GPDriver * inputDriver;
|
||||
AddonManager addons;
|
||||
bool isReady;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Submodule lib/tinyusb updated: d10b65ada4...5217cee5de
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
void XInputAuthUSBListener::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
|
||||
if ( mounted == false )
|
||||
return;
|
||||
if ( dev_addr == xinput_dev_addr ) {
|
||||
xinputAuthData->dongle_ready = false;
|
||||
dongleAuthState = DONGLE_AUTH_STATE::DONGLE_AUTH_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void XInputAuthUSBListener::process() {
|
||||
// Get Serial ID - 0x81
|
||||
|
||||
// No Auth Data or Dongle is not ready (Unmounted or Not Connected)
|
||||
if ( xinputAuthData == nullptr || xinputAuthData->dongle_ready == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do Challenge Init - 0x82 (send console -> host)
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Get Challenge Response - 0x83 (send console -> host)
|
||||
|
||||
// ?? - 0x84
|
||||
|
||||
// Get State - 0x86 (1 = in-progress, 2 = complete)
|
||||
|
||||
// ?? - 0x87
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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!
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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 <stdio.h>
|
||||
#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;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
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;
|
||||
|
||||
if (tu_edpt_dir(endpoint_descriptor->bEndpointAddress) == TUSB_DIR_IN)
|
||||
endpoint_in = endpoint_descriptor->bEndpointAddress;
|
||||
else
|
||||
endpoint_out = endpoint_descriptor->bEndpointAddress;
|
||||
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;
|
||||
|
||||
++found_endpoints;
|
||||
}
|
||||
// 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) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <iterator>
|
||||
|
||||
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() {
|
||||
|
||||
21
src/main.cpp
21
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;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ export default {
|
||||
'<span>INFO:</span> Please ensure USB Peripheral is enabled and a PS5 compatible USB device is plugged in.',
|
||||
'xbone-mode-text':
|
||||
'<span>INFO:</span> Xbox One requires a USB host connection and USB dongle to properly authenticate in Xbox One mode.',
|
||||
'xinput-mode-text':
|
||||
'<span>INFO:</span> Xbox 360 mode can either work without authentication or with a USB dongle attached.',
|
||||
'hotkey-settings-label': 'Hotkey Settings',
|
||||
'hotkey-settings-sub-header':
|
||||
'The <strong>Fn</strong> slider provides a mappable Function button in the <link_pinmap>Pin Mapping</link_pinmap> page. By selecting the <strong>Fn</strong> slider option, the Function button must be held along with the selected hotkey settings. <br /> Additionally, select <strong>None</strong> from the dropdown to unassign any button.',
|
||||
|
||||
@@ -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() {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
case 'input-mode-options.xinput':
|
||||
return (
|
||||
<div className="row mb-3">
|
||||
{generateAuthSelection(
|
||||
inputMode,
|
||||
t('SettingsPage:auth-settings-label'),
|
||||
'xinputAuthType',
|
||||
values.xinputAuthType,
|
||||
errors.xinputAuthType,
|
||||
handleChange,
|
||||
)}
|
||||
<Row className="mb-3">
|
||||
<Col sm={10}>
|
||||
<Trans
|
||||
ns="SettingsPage"
|
||||
i18nKey="xinput-mode-text"
|
||||
components={{ span: <span className="text-success" /> }}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
case 'input-mode-options.xbone':
|
||||
return (
|
||||
<div className="row mb-3">
|
||||
|
||||
Reference in New Issue
Block a user