diff --git a/CMakeLists.txt b/CMakeLists.txt index e78431ad3..0455165e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,6 +155,7 @@ src/drivers/mdmini/MDMiniDriver.cpp src/drivers/neogeo/NeoGeoDriver.cpp src/drivers/net/NetDriver.cpp src/drivers/pcengine/PCEngineDriver.cpp +src/drivers/ps3/PS3Driver.cpp src/drivers/ps4/PS4Auth.cpp src/drivers/ps4/PS4AuthUSBListener.cpp src/drivers/ps4/PS4Driver.cpp diff --git a/headers/display/ui/screens/ButtonLayoutScreen.h b/headers/display/ui/screens/ButtonLayoutScreen.h index 828f13e10..1f15d88c5 100644 --- a/headers/display/ui/screens/ButtonLayoutScreen.h +++ b/headers/display/ui/screens/ButtonLayoutScreen.h @@ -140,7 +140,8 @@ class ButtonLayoutScreen : public GPScreen { void generateHeader(); const std::map displayModeLookup = { - {INPUT_MODE_HID, 0}, + {INPUT_MODE_PS3, 0}, + {INPUT_MODE_GENERIC, 0}, {INPUT_MODE_SWITCH, 1}, {INPUT_MODE_XINPUT, 2}, {INPUT_MODE_XBONE, 2}, @@ -194,4 +195,4 @@ class ButtonLayoutScreen : public GPScreen { bool pressedDownRight(); }; -#endif \ No newline at end of file +#endif diff --git a/headers/drivers/hid/HIDDescriptors.h b/headers/drivers/hid/HIDDescriptors.h index 239eac39f..fedb71a1b 100644 --- a/headers/drivers/hid/HIDDescriptors.h +++ b/headers/drivers/hid/HIDDescriptors.h @@ -22,8 +22,6 @@ * **************************************************************************/ -#define ENDPOINT0_SIZE 64 - #define GAMEPAD_INTERFACE 0 #define GAMEPAD_ENDPOINT 1 #define GAMEPAD_SIZE 64 @@ -42,22 +40,6 @@ #define HID_HAT_UPLEFT 0x07 #define HID_HAT_NOTHING 0x08 -// Button report (16 bits) -#define HID_MASK_SQUARE (1U << 0) -#define HID_MASK_CROSS (1U << 1) -#define HID_MASK_CIRCLE (1U << 2) -#define HID_MASK_TRIANGLE (1U << 3) -#define HID_MASK_L1 (1U << 4) -#define HID_MASK_R1 (1U << 5) -#define HID_MASK_L2 (1U << 6) -#define HID_MASK_R2 (1U << 7) -#define HID_MASK_SELECT (1U << 8) -#define HID_MASK_START (1U << 9) -#define HID_MASK_L3 (1U << 10) -#define HID_MASK_R3 (1U << 11) -#define HID_MASK_PS (1U << 12) -#define HID_MASK_TP (1U << 13) - // HID analog sticks only report 8 bits #define HID_JOYSTICK_MIN 0x00 #define HID_JOYSTICK_MID 0x80 @@ -66,64 +48,25 @@ typedef struct __attribute((packed, aligned(1))) { // digital buttons, 0 = off, 1 = on + uint32_t buttons; - uint8_t square_btn : 1; - uint8_t cross_btn : 1; - uint8_t circle_btn : 1; - uint8_t triangle_btn : 1; - - uint8_t l1_btn : 1; - uint8_t r1_btn : 1; - uint8_t l2_btn : 1; - uint8_t r2_btn : 1; - - uint8_t select_btn : 1; - uint8_t start_btn : 1; - uint8_t l3_btn : 1; - uint8_t r3_btn : 1; - - uint8_t ps_btn : 1; - uint8_t tp_btn : 1; -// uint8_t l2_btn_alt : 1; - -// uint8_t r2_btn_alt : 1; - uint8_t : 2; - - // digital direction, use the dir_* constants(enum) + // digital direction, use the dir_* constants(enum) as a hat // 8 = center, 0 = up, 1 = up/right, 2 = right, 3 = right/down // 4 = down, 5 = down/left, 6 = left, 7 = left/up + uint8_t direction : 4; + // four bits would fill this out... + uint8_t dummy : 4; - uint8_t direction; - - // left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down - + // analogs --- left stick x/y, right stick x/y uint8_t l_x_axis; uint8_t l_y_axis; uint8_t r_x_axis; uint8_t r_y_axis; - - // button analog values for the d-pad. - uint8_t right_axis; - uint8_t left_axis; - uint8_t up_axis; - uint8_t down_axis; - - // button axis, 0x00 = unpressed, 0xff = fully pressed - - uint8_t triangle_axis; - uint8_t circle_axis; - uint8_t cross_axis; - uint8_t square_axis; - - uint8_t l1_axis; - uint8_t r1_axis; - uint8_t l2_axis; - uint8_t r2_axis; } HIDReport; static const uint8_t hid_string_language[] = { 0x09, 0x04 }; static const uint8_t hid_string_manufacturer[] = "Open Stick Community"; -static const uint8_t hid_string_product[] = "GP2040-CE (D-Input)"; +static const uint8_t hid_string_product[] = "GP2040-CE (Generic)"; static const uint8_t hid_string_version[] = "1.0"; static const uint8_t *hid_string_descriptors[] __attribute__((unused)) = @@ -136,20 +79,20 @@ static const uint8_t *hid_string_descriptors[] __attribute__((unused)) = static const uint8_t hid_device_descriptor[] = { - 18, // bLength - 1, // bDescriptorType - 0x00, 0x02, // bcdUSB - 0, // bDeviceClass - 0, // bDeviceSubClass - 0, // bDeviceProtocol - ENDPOINT0_SIZE, // bMaxPacketSize0 - LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor - LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct - 0x00, 0x01, // bcdDevice - 1, // iManufacturer - 2, // iProduct - 0, // iSerialNumber - 1 // bNumConfigurations + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB + 0, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol + HID_ENDPOINT_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 0, // iSerialNumber + 1 // bNumConfigurations }; static const uint8_t hid_report_descriptor[] = @@ -157,29 +100,28 @@ static const uint8_t hid_report_descriptor[] = 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x05, // USAGE (Gamepad) 0xa1, 0x01, // COLLECTION (Application) + // 32 buttons + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x20, // USAGE_MAXIMUM (Button 32) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x35, 0x00, // PHYSICAL_MINIMUM (0) - 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x20, // REPORT_COUNT (32) 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x0e, // REPORT_COUNT (13) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x0e, // USAGE_MAXIMUM (Button 13) 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x02, // REPORT_COUNT (3) - 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + // hat (dpad) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x39, // USAGE (Hat switch) 0x25, 0x07, // LOGICAL_MAXIMUM (7) - 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) - 0x75, 0x04, // REPORT_SIZE (4) 0x95, 0x01, // REPORT_COUNT (1) - 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) - 0x09, 0x39, // USAGE (Hat switch) + 0x75, 0x04, // REPORT_SIZE (4) 0x81, 0x42, // INPUT (Data,Var,Abs,Null) - 0x65, 0x00, // UNIT (None) + // padding the hat 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x04, // REPORT_SIZE (4) 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + // analogs + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) 0x09, 0x30, // USAGE (X) @@ -187,77 +129,49 @@ static const uint8_t hid_report_descriptor[] = 0x09, 0x32, // USAGE (Z) 0x09, 0x35, // USAGE (Rz) 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x04, // REPORT_COUNT (6) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Specific) - 0x09, 0x20, // Unknown - 0x09, 0x21, // Unknown - 0x09, 0x22, // Unknown - 0x09, 0x23, // Unknown - 0x09, 0x24, // Unknown - 0x09, 0x25, // Unknown - 0x09, 0x26, // Unknown - 0x09, 0x27, // Unknown - 0x09, 0x28, // Unknown - 0x09, 0x29, // Unknown - 0x09, 0x2a, // Unknown - 0x09, 0x2b, // Unknown - 0x95, 0x0c, // REPORT_COUNT (12) + 0x95, 0x04, // REPORT_COUNT (4) 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x0a, 0x21, 0x26, // Unknown - 0x95, 0x08, // REPORT_COUNT (8) - 0xb1, 0x02, // FEATURE (Data,Var,Abs) + // done 0xc0 // END_COLLECTION }; -static const uint8_t hid_hid_descriptor[] = -{ - 0x09, // bLength - 0x21, // bDescriptorType (HID) - 0x11, 0x01, // bcdHID 1.11 - 0x00, // bCountryCode - 0x01, // bNumDescriptors - 0x22, // bDescriptorType[0] (HID) - sizeof(hid_report_descriptor), 0x00, // wDescriptorLength[0] 90 -}; - #define CONFIG1_DESC_SIZE (9+9+9+7) static const uint8_t hid_configuration_descriptor[] = { - // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 + // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 9, // bLength; 2, // bDescriptorType; - LSB(CONFIG1_DESC_SIZE), // wTotalLength + LSB(CONFIG1_DESC_SIZE), // wTotalLength MSB(CONFIG1_DESC_SIZE), - 1, // bNumInterfaces - 1, // bConfigurationValue - 0, // iConfiguration - 0x80, // bmAttributes - 50, // bMaxPower - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - GAMEPAD_INTERFACE, // bInterfaceNumber - 0, // bAlternateSetting - 1, // bNumEndpoints - 0x03, // bInterfaceClass (0x03 = HID) - 0x00, // bInterfaceSubClass (0x00 = No Boot) - 0x00, // bInterfaceProtocol (0x00 = No Protocol) - 0, // iInterface - // HID interface descriptor, HID 1.11 spec, section 6.2.1 - 9, // bLength - 0x21, // bDescriptorType - 0x11, 0x01, // bcdHID - 0, // bCountryCode - 1, // bNumDescriptors - 0x22, // bDescriptorType - sizeof(hid_report_descriptor), // wDescriptorLength + 1, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0x80, // bmAttributes + 50, // bMaxPower + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + GAMEPAD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass (0x00 = No Boot) + 0x00, // bInterfaceProtocol (0x00 = No Protocol) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(hid_report_descriptor), // wDescriptorLength 0, - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength 5, // bDescriptorType - GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress - 0x03, // bmAttributes (0x03=intr) - GAMEPAD_SIZE, 0, // wMaxPacketSize + GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + GAMEPAD_SIZE, 0, // wMaxPacketSize 1 // bInterval (1 ms) }; diff --git a/headers/drivers/ps3/PS3Descriptors.h b/headers/drivers/ps3/PS3Descriptors.h new file mode 100644 index 000000000..6d7ae2fa0 --- /dev/null +++ b/headers/drivers/ps3/PS3Descriptors.h @@ -0,0 +1,263 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) + */ + +#pragma once + +#include + +#define PS3_ENDPOINT_SIZE 64 + +// Mac OS-X and Linux automatically load the correct drivers. On +// Windows, even though the driver is supplied by Microsoft, an +// INF file is needed to load the driver. These numbers need to +// match the INF file. +#define VENDOR_ID 0x10C4 +#define PRODUCT_ID 0x82C0 + +/************************************************************************** + * + * Endpoint Buffer Configuration + * + **************************************************************************/ + +#define ENDPOINT0_SIZE 64 + +#define GAMEPAD_INTERFACE 0 +#define GAMEPAD_ENDPOINT 1 +#define GAMEPAD_SIZE 64 + +#define LSB(n) (n & 255) +#define MSB(n) ((n >> 8) & 255) + +// HAT report (4 bits) +#define PS3_HAT_UP 0x00 +#define PS3_HAT_UPRIGHT 0x01 +#define PS3_HAT_RIGHT 0x02 +#define PS3_HAT_DOWNRIGHT 0x03 +#define PS3_HAT_DOWN 0x04 +#define PS3_HAT_DOWNLEFT 0x05 +#define PS3_HAT_LEFT 0x06 +#define PS3_HAT_UPLEFT 0x07 +#define PS3_HAT_NOTHING 0x08 + +// Button report (16 bits) +#define PS3_MASK_SQUARE (1U << 0) +#define PS3_MASK_CROSS (1U << 1) +#define PS3_MASK_CIRCLE (1U << 2) +#define PS3_MASK_TRIANGLE (1U << 3) +#define PS3_MASK_L1 (1U << 4) +#define PS3_MASK_R1 (1U << 5) +#define PS3_MASK_L2 (1U << 6) +#define PS3_MASK_R2 (1U << 7) +#define PS3_MASK_SELECT (1U << 8) +#define PS3_MASK_START (1U << 9) +#define PS3_MASK_L3 (1U << 10) +#define PS3_MASK_R3 (1U << 11) +#define PS3_MASK_PS (1U << 12) +#define PS3_MASK_TP (1U << 13) + +// HID analog sticks only report 8 bits +#define PS3_JOYSTICK_MIN 0x00 +#define PS3_JOYSTICK_MID 0x80 +#define PS3_JOYSTICK_MAX 0xFF + +typedef struct __attribute((packed, aligned(1))) +{ + // digital buttons, 0 = off, 1 = on + + uint8_t square_btn : 1; + uint8_t cross_btn : 1; + uint8_t circle_btn : 1; + uint8_t triangle_btn : 1; + + uint8_t l1_btn : 1; + uint8_t r1_btn : 1; + uint8_t l2_btn : 1; + uint8_t r2_btn : 1; + + uint8_t select_btn : 1; + uint8_t start_btn : 1; + uint8_t l3_btn : 1; + uint8_t r3_btn : 1; + + uint8_t ps_btn : 1; + uint8_t tp_btn : 1; +// uint8_t l2_btn_alt : 1; + +// uint8_t r2_btn_alt : 1; + uint8_t : 2; + + // digital direction, use the dir_* constants(enum) + // 8 = center, 0 = up, 1 = up/right, 2 = right, 3 = right/down + // 4 = down, 5 = down/left, 6 = left, 7 = left/up + + uint8_t direction; + + // left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down + + uint8_t l_x_axis; + uint8_t l_y_axis; + uint8_t r_x_axis; + uint8_t r_y_axis; + + // button analog values for the d-pad. + uint8_t right_axis; + uint8_t left_axis; + uint8_t up_axis; + uint8_t down_axis; + + // button axis, 0x00 = unpressed, 0xff = fully pressed + + uint8_t triangle_axis; + uint8_t circle_axis; + uint8_t cross_axis; + uint8_t square_axis; + + uint8_t l1_axis; + uint8_t r1_axis; + uint8_t l2_axis; + uint8_t r2_axis; +} PS3Report; + +static const uint8_t ps3_string_language[] = { 0x09, 0x04 }; +static const uint8_t ps3_string_manufacturer[] = "Open Stick Community"; +static const uint8_t ps3_string_product[] = "GP2040-CE (PS3)"; +static const uint8_t ps3_string_version[] = "1.0"; + +static const uint8_t *ps3_string_descriptors[] __attribute__((unused)) = +{ + ps3_string_language, + ps3_string_manufacturer, + ps3_string_product, + ps3_string_version +}; + +static const uint8_t ps3_device_descriptor[] = +{ + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB + 0, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol + ENDPOINT0_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 0, // iSerialNumber + 1 // bNumConfigurations +}; + +static const uint8_t ps3_report_descriptor[] = +{ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Gamepad) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x0e, // REPORT_COUNT (13) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0e, // USAGE_MAXIMUM (Button 13) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x02, // REPORT_COUNT (3) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x25, 0x07, // LOGICAL_MAXIMUM (7) + 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x09, 0x39, // USAGE (Hat switch) + 0x81, 0x42, // INPUT (Data,Var,Abs,Null) + 0x65, 0x00, // UNIT (None) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x04, // REPORT_COUNT (6) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Specific) + 0x09, 0x20, // Unknown + 0x09, 0x21, // Unknown + 0x09, 0x22, // Unknown + 0x09, 0x23, // Unknown + 0x09, 0x24, // Unknown + 0x09, 0x25, // Unknown + 0x09, 0x26, // Unknown + 0x09, 0x27, // Unknown + 0x09, 0x28, // Unknown + 0x09, 0x29, // Unknown + 0x09, 0x2a, // Unknown + 0x09, 0x2b, // Unknown + 0x95, 0x0c, // REPORT_COUNT (12) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x0a, 0x21, 0x26, // Unknown + 0x95, 0x08, // REPORT_COUNT (8) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; + +static const uint8_t ps3_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + sizeof(ps3_report_descriptor), 0x00, // wDescriptorLength[0] 90 +}; + +#define CONFIG1_DESC_SIZE (9+9+9+7) +static const uint8_t ps3_configuration_descriptor[] = +{ + // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 + 9, // bLength; + 2, // bDescriptorType; + LSB(CONFIG1_DESC_SIZE), // wTotalLength + MSB(CONFIG1_DESC_SIZE), + 1, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0x80, // bmAttributes + 50, // bMaxPower + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + GAMEPAD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass (0x00 = No Boot) + 0x00, // bInterfaceProtocol (0x00 = No Protocol) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(ps3_report_descriptor), // wDescriptorLength + 0, + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + GAMEPAD_SIZE, 0, // wMaxPacketSize + 1 // bInterval (1 ms) +}; diff --git a/headers/drivers/ps3/PS3Driver.h b/headers/drivers/ps3/PS3Driver.h new file mode 100644 index 000000000..9c32deeee --- /dev/null +++ b/headers/drivers/ps3/PS3Driver.h @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _PS3_DRIVER_H_ +#define _PS3_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/ps3/PS3Descriptors.h" + +class PS3Driver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void initializeAux() {} + virtual void processAux() {} + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); + virtual USBListener * get_usb_auth_listener() { return nullptr; } +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + PS3Report ps3Report; +}; + +#endif // _PS3_DRIVER_H_ diff --git a/headers/gamepad.h b/headers/gamepad.h index 4d86ebf65..4a37346c1 100644 --- a/headers/gamepad.h +++ b/headers/gamepad.h @@ -16,8 +16,6 @@ extern uint32_t getMillis(); extern uint64_t getMicro(); -#define GAMEPAD_FEATURE_REPORT_SIZE 32 - struct GamepadButtonMapping { GamepadButtonMapping(Mask_t bm) : @@ -26,11 +24,9 @@ struct GamepadButtonMapping {} uint32_t pinMask; - const uint16_t buttonMask; + const uint32_t buttonMask; }; -#define GAMEPAD_DIGITAL_INPUT_COUNT 18 // Total number of buttons, including D-pad - class Gamepad { public: Gamepad(); @@ -62,7 +58,7 @@ class Gamepad { /** * @brief Check for a button press. Used by `pressed[Button]` helper methods. */ - inline bool __attribute__((always_inline)) pressedButton(const uint16_t mask) { + inline bool __attribute__((always_inline)) pressedButton(const uint32_t mask) { return (state.buttons & mask) == mask; } @@ -117,6 +113,18 @@ class Gamepad { inline bool __attribute__((always_inline)) pressedA2() { return pressedButton(GAMEPAD_MASK_A2); } inline bool __attribute__((always_inline)) pressedA3() { return pressedButton(GAMEPAD_MASK_A3); } inline bool __attribute__((always_inline)) pressedA4() { return pressedButton(GAMEPAD_MASK_A4); } + inline bool __attribute__((always_inline)) pressedE1() { return pressedButton(GAMEPAD_MASK_E1); } + inline bool __attribute__((always_inline)) pressedE2() { return pressedButton(GAMEPAD_MASK_E2); } + inline bool __attribute__((always_inline)) pressedE3() { return pressedButton(GAMEPAD_MASK_E3); } + inline bool __attribute__((always_inline)) pressedE4() { return pressedButton(GAMEPAD_MASK_E4); } + inline bool __attribute__((always_inline)) pressedE5() { return pressedButton(GAMEPAD_MASK_E5); } + inline bool __attribute__((always_inline)) pressedE6() { return pressedButton(GAMEPAD_MASK_E6); } + inline bool __attribute__((always_inline)) pressedE7() { return pressedButton(GAMEPAD_MASK_E7); } + inline bool __attribute__((always_inline)) pressedE8() { return pressedButton(GAMEPAD_MASK_E8); } + inline bool __attribute__((always_inline)) pressedE9() { return pressedButton(GAMEPAD_MASK_E9); } + inline bool __attribute__((always_inline)) pressedE10() { return pressedButton(GAMEPAD_MASK_E10); } + inline bool __attribute__((always_inline)) pressedE11() { return pressedButton(GAMEPAD_MASK_E11); } + inline bool __attribute__((always_inline)) pressedE12() { return pressedButton(GAMEPAD_MASK_E12); } const GamepadOptions& getOptions() const { return options; } @@ -147,6 +155,18 @@ class Gamepad { GamepadButtonMapping *mapButtonA2; GamepadButtonMapping *mapButtonA3; GamepadButtonMapping *mapButtonA4; + GamepadButtonMapping *mapButtonE1; + GamepadButtonMapping *mapButtonE2; + GamepadButtonMapping *mapButtonE3; + GamepadButtonMapping *mapButtonE4; + GamepadButtonMapping *mapButtonE5; + GamepadButtonMapping *mapButtonE6; + GamepadButtonMapping *mapButtonE7; + GamepadButtonMapping *mapButtonE8; + GamepadButtonMapping *mapButtonE9; + GamepadButtonMapping *mapButtonE10; + GamepadButtonMapping *mapButtonE11; + GamepadButtonMapping *mapButtonE12; GamepadButtonMapping *mapButtonFn; // gamepad specific proxy of debounced buttons --- 1 = active (inverse of the raw GPIO) @@ -158,7 +178,8 @@ class Gamepad { // These are special to SOCD inline static const SOCDMode resolveSOCDMode(const GamepadOptions& options) { return (options.socdMode == SOCD_MODE_BYPASS && - (options.inputMode == INPUT_MODE_HID || + (options.inputMode == INPUT_MODE_PS3 || + options.inputMode == INPUT_MODE_GENERIC || options.inputMode == INPUT_MODE_SWITCH || options.inputMode == INPUT_MODE_NEOGEO || options.inputMode == INPUT_MODE_PS4)) ? diff --git a/headers/gamepad/GamepadState.h b/headers/gamepad/GamepadState.h index 7d4b6bffe..b3249edfa 100644 --- a/headers/gamepad/GamepadState.h +++ b/headers/gamepad/GamepadState.h @@ -12,8 +12,6 @@ using namespace std; #include "enums.pb.h" -#define GAMEPAD_BUTTON_COUNT 14 - /* Gamepad button mapping table: @@ -66,12 +64,21 @@ using namespace std; #define GAMEPAD_MASK_DL (1UL << 18) #define GAMEPAD_MASK_DR (1UL << 19) -// For detecting analog sticks as buttons - -#define GAMEPAD_MASK_LX (1UL << 20) -#define GAMEPAD_MASK_LY (1UL << 21) -#define GAMEPAD_MASK_RX (1UL << 22) -#define GAMEPAD_MASK_RY (1UL << 23) +// extra buttons (no particular host expectation for these, unlike 0..13 above +// which have predetermined functions for consoles or whatever) + +#define GAMEPAD_MASK_E1 (1UL << 20) +#define GAMEPAD_MASK_E2 (1UL << 21) +#define GAMEPAD_MASK_E3 (1UL << 22) +#define GAMEPAD_MASK_E4 (1UL << 23) +#define GAMEPAD_MASK_E5 (1UL << 24) +#define GAMEPAD_MASK_E6 (1UL << 25) +#define GAMEPAD_MASK_E7 (1UL << 26) +#define GAMEPAD_MASK_E8 (1UL << 27) +#define GAMEPAD_MASK_E9 (1UL << 28) +#define GAMEPAD_MASK_E10 (1UL << 29) +#define GAMEPAD_MASK_E11 (1UL << 30) +#define GAMEPAD_MASK_E12 (1UL << 31) #define GAMEPAD_MASK_DPAD (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT) @@ -96,7 +103,7 @@ const uint8_t dpadMasks[] = GAMEPAD_MASK_RIGHT, }; -const uint16_t buttonMasks[] = +const uint32_t buttonMasks[] = { GAMEPAD_MASK_B1, GAMEPAD_MASK_B2, @@ -112,12 +119,24 @@ const uint16_t buttonMasks[] = GAMEPAD_MASK_R3, GAMEPAD_MASK_A1, GAMEPAD_MASK_A2, + GAMEPAD_MASK_E1, + GAMEPAD_MASK_E2, + GAMEPAD_MASK_E3, + GAMEPAD_MASK_E4, + GAMEPAD_MASK_E5, + GAMEPAD_MASK_E6, + GAMEPAD_MASK_E7, + GAMEPAD_MASK_E8, + GAMEPAD_MASK_E9, + GAMEPAD_MASK_E10, + GAMEPAD_MASK_E11, + GAMEPAD_MASK_E12, }; struct GamepadState { uint8_t dpad {0}; - uint16_t buttons {0}; + uint32_t buttons {0}; uint16_t aux {0}; uint16_t lx {GAMEPAD_JOYSTICK_MID}; uint16_t ly {GAMEPAD_JOYSTICK_MID}; diff --git a/headers/gp2040.h b/headers/gp2040.h index 8945f8949..5519267c2 100644 --- a/headers/gp2040.h +++ b/headers/gp2040.h @@ -46,10 +46,11 @@ class GP2040 { NONE, ENTER_WEBCONFIG_MODE, ENTER_USB_MODE, - SET_INPUT_MODE_HID, SET_INPUT_MODE_SWITCH, SET_INPUT_MODE_XINPUT, SET_INPUT_MODE_KEYBOARD, + SET_INPUT_MODE_GENERIC, + SET_INPUT_MODE_PS3, SET_INPUT_MODE_PS4, SET_INPUT_MODE_PS5, SET_INPUT_MODE_XBONE, diff --git a/proto/enums.proto b/proto/enums.proto index f2bf0a20e..868ee532d 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -122,7 +122,7 @@ enum InputMode INPUT_MODE_XINPUT = 0; INPUT_MODE_SWITCH = 1; - INPUT_MODE_HID = 2; + INPUT_MODE_PS3 = 2; INPUT_MODE_KEYBOARD = 3; INPUT_MODE_PS4 = 4; INPUT_MODE_XBONE = 5; @@ -134,6 +134,7 @@ enum InputMode INPUT_MODE_PSCLASSIC = 11; INPUT_MODE_XBOXORIGINAL = 12; INPUT_MODE_PS5 = 13; + INPUT_MODE_GENERIC = 14; INPUT_MODE_CONFIG = 255; } @@ -228,6 +229,18 @@ enum GpioAction CUSTOM_BUTTON_COMBO = 40; BUTTON_PRESS_A3 = 41; BUTTON_PRESS_A4 = 42; + BUTTON_PRESS_E1 = 43; + BUTTON_PRESS_E2 = 44; + BUTTON_PRESS_E3 = 45; + BUTTON_PRESS_E4 = 46; + BUTTON_PRESS_E5 = 47; + BUTTON_PRESS_E6 = 48; + BUTTON_PRESS_E7 = 49; + BUTTON_PRESS_E8 = 50; + BUTTON_PRESS_E9 = 51; + BUTTON_PRESS_E10 = 52; + BUTTON_PRESS_E11 = 53; + BUTTON_PRESS_E12 = 54; } enum GpioDirection diff --git a/src/config_legacy.cpp b/src/config_legacy.cpp index 9d69c8842..c19db6f86 100644 --- a/src/config_legacy.cpp +++ b/src/config_legacy.cpp @@ -32,7 +32,7 @@ namespace ConfigLegacy { INPUT_MODE_XINPUT, INPUT_MODE_SWITCH, - INPUT_MODE_HID, + INPUT_MODE_PS3, INPUT_MODE_KEYBOARD, INPUT_MODE_PS4, INPUT_MODE_CONFIG = 255, @@ -483,7 +483,7 @@ static bool isValidInputMode(ConfigLegacy::InputMode inputMode) { case INPUT_MODE_XINPUT: case INPUT_MODE_SWITCH: - case INPUT_MODE_HID: + case INPUT_MODE_PS3: case INPUT_MODE_KEYBOARD: case INPUT_MODE_PS4: return true; diff --git a/src/config_utils.cpp b/src/config_utils.cpp index 4ebbbf8e7..bca144e41 100644 --- a/src/config_utils.cpp +++ b/src/config_utils.cpp @@ -86,7 +86,7 @@ #define DEFAULT_INPUT_MODE_B2 INPUT_MODE_XINPUT #endif #ifndef DEFAULT_INPUT_MODE_B3 - #define DEFAULT_INPUT_MODE_B3 INPUT_MODE_HID + #define DEFAULT_INPUT_MODE_B3 INPUT_MODE_PS3 #endif #ifndef DEFAULT_INPUT_MODE_B4 #define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS4 diff --git a/src/display/ui/screens/ButtonLayoutScreen.cpp b/src/display/ui/screens/ButtonLayoutScreen.cpp index c4b8ca01f..3e716cf3e 100644 --- a/src/display/ui/screens/ButtonLayoutScreen.cpp +++ b/src/display/ui/screens/ButtonLayoutScreen.cpp @@ -129,7 +129,8 @@ void ButtonLayoutScreen::generateHeader() { // Display standard header switch (inputMode) { - case INPUT_MODE_HID: statusBar += "DINPUT"; break; + 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; diff --git a/src/drivermanager.cpp b/src/drivermanager.cpp index f03bbd0e0..fd764c155 100644 --- a/src/drivermanager.cpp +++ b/src/drivermanager.cpp @@ -9,6 +9,7 @@ #include "drivers/neogeo/NeoGeoDriver.h" #include "drivers/pcengine/PCEngineDriver.h" #include "drivers/psclassic/PSClassicDriver.h" +#include "drivers/ps3/PS3Driver.h" #include "drivers/ps4/PS4Driver.h" #include "drivers/switch/SwitchDriver.h" #include "drivers/xbone/XBOneDriver.h" @@ -28,12 +29,12 @@ void DriverManager::setup(InputMode mode) { case INPUT_MODE_EGRET: driver = new EgretDriver(); break; - case INPUT_MODE_HID: - driver = new HIDDriver(); - break; case INPUT_MODE_KEYBOARD: driver = new KeyboardDriver(); break; + case INPUT_MODE_GENERIC: + driver = new HIDDriver(); + break; case INPUT_MODE_MDMINI: driver = new MDMiniDriver(); break; @@ -46,6 +47,9 @@ void DriverManager::setup(InputMode mode) { case INPUT_MODE_PCEMINI: driver = new PCEngineDriver(); break; + case INPUT_MODE_PS3: + driver = new PS3Driver(); + break; case INPUT_MODE_PS4: driver = new PS4Driver(PS4_CONTROLLER); break; diff --git a/src/drivers/hid/HIDDriver.cpp b/src/drivers/hid/HIDDriver.cpp index 0633f2b2b..1f666c60f 100644 --- a/src/drivers/hid/HIDDriver.cpp +++ b/src/drivers/hid/HIDDriver.cpp @@ -7,33 +7,17 @@ #include "drivers/hid/HIDDescriptors.h" #include "drivers/shared/driverhelper.h" -// Magic byte sequence to enable PS button on PS3 -static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; - static bool hid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { - if ( request->bmRequestType == 0xA1 && - request->bRequest == HID_REQ_CONTROL_GET_REPORT && - request->wValue == 0x0300 ) { - return tud_control_xfer(rhport, request, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes)); - } else { - return hidd_control_xfer_cb(rhport, stage, request); - } + return hidd_control_xfer_cb(rhport, stage, request); } void HIDDriver::initialize() { hidReport = { - .square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0, - .l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0, - .select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0, - .direction = 0x08, - .l_x_axis = HID_JOYSTICK_MID, - .l_y_axis = HID_JOYSTICK_MID, - .r_x_axis = HID_JOYSTICK_MID, - .r_y_axis = HID_JOYSTICK_MID, - .right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00, - .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, - .l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00 + .buttons = 0, + .direction = HID_HAT_NOTHING, + .l_x_axis = HID_JOYSTICK_MID, .l_y_axis = HID_JOYSTICK_MID, + .r_x_axis = HID_JOYSTICK_MID, .r_y_axis = HID_JOYSTICK_MID, }; class_driver = { @@ -64,45 +48,48 @@ void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { default: hidReport.direction = HID_HAT_NOTHING; break; } - hidReport.cross_btn = gamepad->pressedB1(); - hidReport.circle_btn = gamepad->pressedB2(); - hidReport.square_btn = gamepad->pressedB3(); - hidReport.triangle_btn = gamepad->pressedB4(); - hidReport.l1_btn = gamepad->pressedL1(); - hidReport.r1_btn = gamepad->pressedR1(); - hidReport.l2_btn = gamepad->pressedL2(); - hidReport.r2_btn = gamepad->pressedR2(); - hidReport.select_btn = gamepad->pressedS1(); - hidReport.start_btn = gamepad->pressedS2(); - hidReport.l3_btn = gamepad->pressedL3(); - hidReport.r3_btn = gamepad->pressedR3(); - hidReport.ps_btn = gamepad->pressedA1(); - hidReport.tp_btn = gamepad->pressedA2(); - hidReport.l_x_axis = static_cast(gamepad->state.lx >> 8); hidReport.l_y_axis = static_cast(gamepad->state.ly >> 8); hidReport.r_x_axis = static_cast(gamepad->state.rx >> 8); hidReport.r_y_axis = static_cast(gamepad->state.ry >> 8); - if (gamepad->hasAnalogTriggers) - { - hidReport.l2_axis = gamepad->state.lt; - hidReport.r2_axis = gamepad->state.rt; - } else { - hidReport.l2_axis = gamepad->pressedL2() ? 0xFF : 0; - hidReport.r2_axis = gamepad->pressedR2() ? 0xFF : 0; - } - - hidReport.triangle_axis = gamepad->pressedB4() ? 0xFF : 0; - hidReport.circle_axis = gamepad->pressedB2() ? 0xFF : 0; - hidReport.cross_axis = gamepad->pressedB1() ? 0xFF : 0; - hidReport.square_axis = gamepad->pressedB3() ? 0xFF : 0; - hidReport.l1_axis = gamepad->pressedL1() ? 0xFF : 0; - hidReport.r1_axis = gamepad->pressedR1() ? 0xFF : 0; - hidReport.right_axis = gamepad->state.dpad & GAMEPAD_MASK_RIGHT ? 0xFF : 0; - hidReport.left_axis = gamepad->state.dpad & GAMEPAD_MASK_LEFT ? 0xFF : 0; - hidReport.up_axis = gamepad->state.dpad & GAMEPAD_MASK_UP ? 0xFF : 0; - hidReport.down_axis = gamepad->state.dpad & GAMEPAD_MASK_DOWN ? 0xFF : 0; + // these first three buttons are in this unintuitive order to be compatible with + // expectations, e.g. both PS3/4/5 modes and Switch modes map to HID as + // B3 B4 == 1 4 + // B1 B2 == 2 3 + hidReport.buttons = 0 + | (gamepad->pressedB1() ? GAMEPAD_MASK_B2 : 0) + | (gamepad->pressedB2() ? GAMEPAD_MASK_B3 : 0) + | (gamepad->pressedB3() ? GAMEPAD_MASK_B1 : 0) + | (gamepad->pressedB4() ? GAMEPAD_MASK_B4 : 0) + | (gamepad->pressedL1() ? GAMEPAD_MASK_L1 : 0) + | (gamepad->pressedR1() ? GAMEPAD_MASK_R1 : 0) + | (gamepad->pressedL2() ? GAMEPAD_MASK_L2 : 0) + | (gamepad->pressedR2() ? GAMEPAD_MASK_R2 : 0) + | (gamepad->pressedS1() ? GAMEPAD_MASK_S1 : 0) + | (gamepad->pressedS2() ? GAMEPAD_MASK_S2 : 0) + | (gamepad->pressedL3() ? GAMEPAD_MASK_L3 : 0) + | (gamepad->pressedR3() ? GAMEPAD_MASK_R3 : 0) + | (gamepad->pressedA1() ? GAMEPAD_MASK_A1 : 0) + | (gamepad->pressedA2() ? GAMEPAD_MASK_A2 : 0) + // buttons 15 and 16 are reserved for future expansion + | (gamepad->pressedUp() ? GAMEPAD_MASK_DU : 0) + | (gamepad->pressedDown() ? GAMEPAD_MASK_DD : 0) + | (gamepad->pressedLeft() ? GAMEPAD_MASK_DL : 0) + | (gamepad->pressedRight() ? GAMEPAD_MASK_DR : 0) + | (gamepad->pressedE1() ? GAMEPAD_MASK_E1 : 0) + | (gamepad->pressedE2() ? GAMEPAD_MASK_E2 : 0) + | (gamepad->pressedE3() ? GAMEPAD_MASK_E3 : 0) + | (gamepad->pressedE4() ? GAMEPAD_MASK_E4 : 0) + | (gamepad->pressedE5() ? GAMEPAD_MASK_E5 : 0) + | (gamepad->pressedE6() ? GAMEPAD_MASK_E6 : 0) + | (gamepad->pressedE7() ? GAMEPAD_MASK_E7 : 0) + | (gamepad->pressedE8() ? GAMEPAD_MASK_E8 : 0) + | (gamepad->pressedE9() ? GAMEPAD_MASK_E9 : 0) + | (gamepad->pressedE10() ? GAMEPAD_MASK_E10 : 0) + | (gamepad->pressedE11() ? GAMEPAD_MASK_E11 : 0) + | (gamepad->pressedE12() ? GAMEPAD_MASK_E12 : 0) + ; // Wake up TinyUSB device if (tud_suspended()) @@ -121,7 +108,7 @@ void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { // tud_hid_get_report_cb uint16_t HIDDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { - memcpy(buffer, &hidReport, sizeof(HIDReport)); + memcpy(buffer, &hidReport, sizeof(HIDReport)); return sizeof(HIDReport); } @@ -130,7 +117,7 @@ void HIDDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uin // Only XboxOG and Xbox One use vendor control xfer cb bool HIDDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { - return false; + return false; } const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { @@ -139,15 +126,15 @@ const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t lan } const uint8_t * HIDDriver::get_descriptor_device_cb() { - return hid_device_descriptor; + return hid_device_descriptor; } const uint8_t * HIDDriver::get_hid_descriptor_report_cb(uint8_t itf) { - return hid_report_descriptor; + return hid_report_descriptor; } const uint8_t * HIDDriver::get_descriptor_configuration_cb(uint8_t index) { - return hid_configuration_descriptor; + return hid_configuration_descriptor; } const uint8_t * HIDDriver::get_descriptor_device_qualifier_cb() { diff --git a/src/drivers/ps3/PS3Driver.cpp b/src/drivers/ps3/PS3Driver.cpp new file mode 100644 index 000000000..5377f5677 --- /dev/null +++ b/src/drivers/ps3/PS3Driver.cpp @@ -0,0 +1,159 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#include "drivers/ps3/PS3Driver.h" +#include "drivers/ps3/PS3Descriptors.h" +#include "drivers/shared/driverhelper.h" + +// Magic byte sequence to enable PS button on PS3 +static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; + +static bool ps3_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( request->bmRequestType == 0xA1 && + request->bRequest == HID_REQ_CONTROL_GET_REPORT && + request->wValue == 0x0300 ) { + return tud_control_xfer(rhport, request, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes)); + } else { + return hidd_control_xfer_cb(rhport, stage, request); + } +} + +void PS3Driver::initialize() { + ps3Report = { + .square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0, + .l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0, + .select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0, + .direction = 0x08, + .l_x_axis = PS3_JOYSTICK_MID, + .l_y_axis = PS3_JOYSTICK_MID, + .r_x_axis = PS3_JOYSTICK_MID, + .r_y_axis = PS3_JOYSTICK_MID, + .right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00, + .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, + .l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00 + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "PS3", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = ps3_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +// Generate PS3 report from gamepad and send to TUSB Device +void PS3Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: ps3Report.direction = PS3_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: ps3Report.direction = PS3_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_UPLEFT; break; + default: ps3Report.direction = PS3_HAT_NOTHING; break; + } + + ps3Report.cross_btn = gamepad->pressedB1(); + ps3Report.circle_btn = gamepad->pressedB2(); + ps3Report.square_btn = gamepad->pressedB3(); + ps3Report.triangle_btn = gamepad->pressedB4(); + ps3Report.l1_btn = gamepad->pressedL1(); + ps3Report.r1_btn = gamepad->pressedR1(); + ps3Report.l2_btn = gamepad->pressedL2(); + ps3Report.r2_btn = gamepad->pressedR2(); + ps3Report.select_btn = gamepad->pressedS1(); + ps3Report.start_btn = gamepad->pressedS2(); + ps3Report.l3_btn = gamepad->pressedL3(); + ps3Report.r3_btn = gamepad->pressedR3(); + ps3Report.ps_btn = gamepad->pressedA1(); + ps3Report.tp_btn = gamepad->pressedA2(); + + ps3Report.l_x_axis = static_cast(gamepad->state.lx >> 8); + ps3Report.l_y_axis = static_cast(gamepad->state.ly >> 8); + ps3Report.r_x_axis = static_cast(gamepad->state.rx >> 8); + ps3Report.r_y_axis = static_cast(gamepad->state.ry >> 8); + + if (gamepad->hasAnalogTriggers) + { + ps3Report.l2_axis = gamepad->state.lt; + ps3Report.r2_axis = gamepad->state.rt; + } else { + ps3Report.l2_axis = gamepad->pressedL2() ? 0xFF : 0; + ps3Report.r2_axis = gamepad->pressedR2() ? 0xFF : 0; + } + + ps3Report.triangle_axis = gamepad->pressedB4() ? 0xFF : 0; + ps3Report.circle_axis = gamepad->pressedB2() ? 0xFF : 0; + ps3Report.cross_axis = gamepad->pressedB1() ? 0xFF : 0; + ps3Report.square_axis = gamepad->pressedB3() ? 0xFF : 0; + ps3Report.l1_axis = gamepad->pressedL1() ? 0xFF : 0; + ps3Report.r1_axis = gamepad->pressedR1() ? 0xFF : 0; + ps3Report.right_axis = gamepad->state.dpad & GAMEPAD_MASK_RIGHT ? 0xFF : 0; + ps3Report.left_axis = gamepad->state.dpad & GAMEPAD_MASK_LEFT ? 0xFF : 0; + ps3Report.up_axis = gamepad->state.dpad & GAMEPAD_MASK_UP ? 0xFF : 0; + ps3Report.down_axis = gamepad->state.dpad & GAMEPAD_MASK_DOWN ? 0xFF : 0; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &ps3Report; + uint16_t report_size = sizeof(ps3Report); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t PS3Driver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &ps3Report, sizeof(PS3Report)); + return sizeof(PS3Report); +} + +// Only PS4 does anything with set report +void PS3Driver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool PS3Driver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * PS3Driver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)ps3_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * PS3Driver::get_descriptor_device_cb() { + return ps3_device_descriptor; +} + +const uint8_t * PS3Driver::get_hid_descriptor_report_cb(uint8_t itf) { + return ps3_report_descriptor; +} + +const uint8_t * PS3Driver::get_descriptor_configuration_cb(uint8_t index) { + return ps3_configuration_descriptor; +} + +const uint8_t * PS3Driver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t PS3Driver::GetJoystickMidValue() { + return PS3_JOYSTICK_MID << 8; +} diff --git a/src/gamepad.cpp b/src/gamepad.cpp index 5c076858d..b57a36630 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -55,6 +55,18 @@ void Gamepad::setup() mapButtonA2 = new GamepadButtonMapping(GAMEPAD_MASK_A2); mapButtonA3 = new GamepadButtonMapping(GAMEPAD_MASK_A3); mapButtonA4 = new GamepadButtonMapping(GAMEPAD_MASK_A4); + mapButtonE1 = new GamepadButtonMapping(GAMEPAD_MASK_E1); + mapButtonE2 = new GamepadButtonMapping(GAMEPAD_MASK_E2); + mapButtonE3 = new GamepadButtonMapping(GAMEPAD_MASK_E3); + mapButtonE4 = new GamepadButtonMapping(GAMEPAD_MASK_E4); + mapButtonE5 = new GamepadButtonMapping(GAMEPAD_MASK_E5); + mapButtonE6 = new GamepadButtonMapping(GAMEPAD_MASK_E6); + mapButtonE7 = new GamepadButtonMapping(GAMEPAD_MASK_E7); + mapButtonE8 = new GamepadButtonMapping(GAMEPAD_MASK_E8); + mapButtonE9 = new GamepadButtonMapping(GAMEPAD_MASK_E9); + mapButtonE10 = new GamepadButtonMapping(GAMEPAD_MASK_E10); + mapButtonE11 = new GamepadButtonMapping(GAMEPAD_MASK_E11); + mapButtonE12 = new GamepadButtonMapping(GAMEPAD_MASK_E12); mapButtonFn = new GamepadButtonMapping(AUX_MASK_FUNCTION); const auto assignCustomMappingToMaps = [&](GpioMappingInfo mapInfo, Pin_t pin) -> void { @@ -101,6 +113,18 @@ void Gamepad::setup() case GpioAction::BUTTON_PRESS_A2: mapButtonA2->pinMask |= 1 << pin; break; case GpioAction::BUTTON_PRESS_A3: mapButtonA3->pinMask |= 1 << pin; break; case GpioAction::BUTTON_PRESS_A4: mapButtonA4->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E1: mapButtonE1->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E2: mapButtonE2->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E3: mapButtonE3->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E4: mapButtonE4->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E5: mapButtonE5->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E6: mapButtonE6->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E7: mapButtonE7->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E8: mapButtonE8->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E9: mapButtonE9->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E10: mapButtonE10->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E11: mapButtonE11->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E12: mapButtonE12->pinMask |= 1 << pin; break; case GpioAction::BUTTON_PRESS_FN: mapButtonFn->pinMask |= 1 << pin; break; case GpioAction::CUSTOM_BUTTON_COMBO: assignCustomMappingToMaps(pinMappings[pin], pin); break; default: break; @@ -134,6 +158,18 @@ void Gamepad::reinit() delete mapButtonA2; delete mapButtonA3; delete mapButtonA4; + delete mapButtonE1; + delete mapButtonE2; + delete mapButtonE3; + delete mapButtonE4; + delete mapButtonE5; + delete mapButtonE6; + delete mapButtonE7; + delete mapButtonE8; + delete mapButtonE9; + delete mapButtonE10; + delete mapButtonE11; + delete mapButtonE12; delete mapButtonFn; // reinitialize pin mappings @@ -250,6 +286,18 @@ void Gamepad::read() | ((values & mapButtonA2->pinMask) ? mapButtonA2->buttonMask : 0) | ((values & mapButtonA3->pinMask) ? mapButtonA3->buttonMask : 0) | ((values & mapButtonA4->pinMask) ? mapButtonA4->buttonMask : 0) + | ((values & mapButtonE1->pinMask) ? mapButtonE1->buttonMask : 0) + | ((values & mapButtonE2->pinMask) ? mapButtonE2->buttonMask : 0) + | ((values & mapButtonE3->pinMask) ? mapButtonE3->buttonMask : 0) + | ((values & mapButtonE4->pinMask) ? mapButtonE4->buttonMask : 0) + | ((values & mapButtonE5->pinMask) ? mapButtonE5->buttonMask : 0) + | ((values & mapButtonE6->pinMask) ? mapButtonE6->buttonMask : 0) + | ((values & mapButtonE7->pinMask) ? mapButtonE7->buttonMask : 0) + | ((values & mapButtonE8->pinMask) ? mapButtonE8->buttonMask : 0) + | ((values & mapButtonE9->pinMask) ? mapButtonE9->buttonMask : 0) + | ((values & mapButtonE10->pinMask) ? mapButtonE10->buttonMask : 0) + | ((values & mapButtonE11->pinMask) ? mapButtonE11->buttonMask : 0) + | ((values & mapButtonE12->pinMask) ? mapButtonE12->buttonMask : 0) ; state.lx = joystickMid; diff --git a/src/gp2040.cpp b/src/gp2040.cpp index 55275bf40..6665a6f46 100644 --- a/src/gp2040.cpp +++ b/src/gp2040.cpp @@ -123,15 +123,15 @@ void GP2040::setup() { case BootAction::ENTER_USB_MODE: reset_usb_boot(0, 0); return; - case BootAction::SET_INPUT_MODE_HID: // HID drivers - inputMode = INPUT_MODE_HID; - break; case BootAction::SET_INPUT_MODE_SWITCH: inputMode = INPUT_MODE_SWITCH; break; case BootAction::SET_INPUT_MODE_KEYBOARD: inputMode = INPUT_MODE_KEYBOARD; break; + case BootAction::SET_INPUT_MODE_GENERIC: + inputMode = INPUT_MODE_GENERIC; + break; case BootAction::SET_INPUT_MODE_NEOGEO: inputMode = INPUT_MODE_NEOGEO; break; @@ -153,6 +153,9 @@ void GP2040::setup() { case BootAction::SET_INPUT_MODE_XINPUT: // X-Input Driver inputMode = INPUT_MODE_XINPUT; break; + case BootAction::SET_INPUT_MODE_PS3: // PS3 (HID with quirks) driver + inputMode = INPUT_MODE_PS3; + break; case BootAction::SET_INPUT_MODE_PS4: // PS4 / PS5 Driver inputMode = INPUT_MODE_PS4; break; @@ -377,10 +380,12 @@ GP2040::BootAction GP2040::getBootAction() { return BootAction::SET_INPUT_MODE_XINPUT; case INPUT_MODE_SWITCH: return BootAction::SET_INPUT_MODE_SWITCH; - case INPUT_MODE_HID: - return BootAction::SET_INPUT_MODE_HID; case INPUT_MODE_KEYBOARD: return BootAction::SET_INPUT_MODE_KEYBOARD; + case INPUT_MODE_GENERIC: + return BootAction::SET_INPUT_MODE_GENERIC; + case INPUT_MODE_PS3: + return BootAction::SET_INPUT_MODE_PS3; case INPUT_MODE_PS4: return BootAction::SET_INPUT_MODE_PS4; case INPUT_MODE_PS5: @@ -399,8 +404,8 @@ GP2040::BootAction GP2040::getBootAction() { return BootAction::SET_INPUT_MODE_PSCLASSIC; case INPUT_MODE_XBOXORIGINAL: return BootAction::SET_INPUT_MODE_XBOXORIGINAL; - case INPUT_MODE_XBONE: - return BootAction::SET_INPUT_MODE_XBONE; + case INPUT_MODE_XBONE: + return BootAction::SET_INPUT_MODE_XBONE; default: return BootAction::NONE; } diff --git a/www/src/Data/Buttons.js b/www/src/Data/Buttons.js index 3e235937c..873674168 100644 --- a/www/src/Data/Buttons.js +++ b/www/src/Data/Buttons.js @@ -22,6 +22,18 @@ export const BUTTONS = { A2: 'A2', A3: 'A3', A4: 'A4', + E1: 'Extra 1', + E2: 'Extra 2', + E3: 'Extra 3', + E4: 'Extra 4', + E5: 'Extra 5', + E6: 'Extra 6', + E7: 'Extra 7', + E8: 'Extra 8', + E9: 'Extra 9', + E10: 'Extra 10', + E11: 'Extra 11', + E12: 'Extra 12', Fn: 'Function', }, arcade: { @@ -47,6 +59,18 @@ export const BUTTONS = { A2: '-', A3: '-', A4: '-', + E1: 'Extra 1', + E2: 'Extra 2', + E3: 'Extra 3', + E4: 'Extra 4', + E5: 'Extra 5', + E6: 'Extra 6', + E7: 'Extra 7', + E8: 'Extra 8', + E9: 'Extra 9', + E10: 'Extra 10', + E11: 'Extra 11', + E12: 'Extra 12', Fn: 'Function', }, xinput: { @@ -72,6 +96,18 @@ export const BUTTONS = { A2: '-', A3: '-', A4: '-', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, switch: { @@ -97,6 +133,18 @@ export const BUTTONS = { A2: 'Capture', A3: '-', A4: '-', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, ps3: { @@ -122,6 +170,18 @@ export const BUTTONS = { A2: '-', A3: '-', A4: '-', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, ps4: { @@ -147,10 +207,23 @@ export const BUTTONS = { A2: 'Touchpad Center', A3: 'Touchpad Left', A4: 'Touchpad Right', + A2: 'Touchpad', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, dinput: { - label: 'DInput', + label: 'Generic', value: 'dinput', Up: 'Up', Down: 'Down', @@ -172,6 +245,18 @@ export const BUTTONS = { A2: '14', A3: '15', A4: '16', + E1: '21', + E2: '22', + E3: '23', + E4: '24', + E5: '25', + E6: '26', + E7: '27', + E8: '28', + E9: '29', + E10: '30', + E11: '31', + E12: '32', Fn: 'Function', }, }; @@ -429,6 +514,18 @@ export const BUTTON_MASKS_OPTIONS = [ { label: 'Down', value: 1 << 17 }, { label: 'Left', value: 1 << 18 }, { label: 'Right', value: 1 << 19 }, + { label: 'E1', value: 1 << 20 }, + { label: 'E2', value: 1 << 21 }, + { label: 'E3', value: 1 << 22 }, + { label: 'E4', value: 1 << 23 }, + { label: 'E5', value: 1 << 24 }, + { label: 'E6', value: 1 << 25 }, + { label: 'E7', value: 1 << 26 }, + { label: 'E8', value: 1 << 27 }, + { label: 'E9', value: 1 << 28 }, + { label: 'E10', value: 1 << 29 }, + { label: 'E11', value: 1 << 30 }, + { label: 'E12', value: 1 << 31 }, ]; export const ANALOG_PINS = [26, 27, 28, 29]; diff --git a/www/src/Data/Pins.ts b/www/src/Data/Pins.ts index 7c6a82652..cc46abe6e 100644 --- a/www/src/Data/Pins.ts +++ b/www/src/Data/Pins.ts @@ -45,6 +45,18 @@ export const BUTTON_ACTIONS = { CUSTOM_BUTTON_COMBO: 40, BUTTON_PRESS_A3: 41, BUTTON_PRESS_A4: 42, + BUTTON_PRESS_E1: 43, + BUTTON_PRESS_E2: 44, + BUTTON_PRESS_E3: 45, + BUTTON_PRESS_E4: 46, + BUTTON_PRESS_E5: 47, + BUTTON_PRESS_E6: 48, + BUTTON_PRESS_E7: 49, + BUTTON_PRESS_E8: 50, + BUTTON_PRESS_E9: 51, + BUTTON_PRESS_E10: 52, + BUTTON_PRESS_E11: 53, + BUTTON_PRESS_E12: 54, } as const; export const PIN_DIRECTIONS = { diff --git a/www/src/Locales/en/PinMapping.jsx b/www/src/Locales/en/PinMapping.jsx index 3a86a4d9e..021ed211e 100644 --- a/www/src/Locales/en/PinMapping.jsx +++ b/www/src/Locales/en/PinMapping.jsx @@ -62,5 +62,17 @@ export default { BUTTON_PRESS_MACRO_5: 'Macro 5', BUTTON_PRESS_MACRO_6: 'Macro 6', CUSTOM_BUTTON_COMBO: 'Assigned to multi mapping', + BUTTON_PRESS_E1: 'Extra 1', + BUTTON_PRESS_E2: 'Extra 2', + BUTTON_PRESS_E3: 'Extra 3', + BUTTON_PRESS_E4: 'Extra 4', + BUTTON_PRESS_E5: 'Extra 5', + BUTTON_PRESS_E6: 'Extra 6', + BUTTON_PRESS_E7: 'Extra 7', + BUTTON_PRESS_E8: 'Extra 8', + BUTTON_PRESS_E9: 'Extra 9', + BUTTON_PRESS_E10: 'Extra 10', + BUTTON_PRESS_E11: 'Extra 11', + BUTTON_PRESS_E12: 'Extra 12', }, }; diff --git a/www/src/Locales/en/SettingsPage.jsx b/www/src/Locales/en/SettingsPage.jsx index 09c1a2cd7..1bb789e46 100644 --- a/www/src/Locales/en/SettingsPage.jsx +++ b/www/src/Locales/en/SettingsPage.jsx @@ -10,7 +10,8 @@ export default { none: 'No Mode Selected', xinput: 'XInput', 'nintendo-switch': 'Nintendo Switch', - ps3: 'PS3/DirectInput', + ps3: 'PS3', + generic: 'Generic HID', keyboard: 'Keyboard', ps4: 'PS4', ps5: 'PS5', diff --git a/www/src/Pages/SettingsPage.jsx b/www/src/Pages/SettingsPage.jsx index c17035d06..2d588aa2f 100644 --- a/www/src/Pages/SettingsPage.jsx +++ b/www/src/Pages/SettingsPage.jsx @@ -147,6 +147,7 @@ const INPUT_MODES = [ group: 'primary', required: ['usb'], }, + { labelKey: 'input-mode-options.generic', value: 14, group: 'primary' }, { labelKey: 'input-mode-options.mdmini', value: 6, group: 'mini' }, { labelKey: 'input-mode-options.neogeo', value: 7, group: 'mini' }, { labelKey: 'input-mode-options.pcemini', value: 8, group: 'mini' }, @@ -184,6 +185,7 @@ const INPUT_BOOT_MODES = [ group: 'primary', required: ['usb'], }, + { labelKey: 'input-mode-options.generic', value: 14, group: 'primary' }, { labelKey: 'input-mode-options.mdmini', value: 6, group: 'mini' }, { labelKey: 'input-mode-options.neogeo', value: 7, group: 'mini' }, { labelKey: 'input-mode-options.pcemini', value: 8, group: 'mini' },