From 55c9966b8809026f457f77dc3c827e2c06680a82 Mon Sep 17 00:00:00 2001 From: Frederik Walk Date: Sun, 3 Nov 2024 22:30:29 +0100 Subject: [PATCH] Refactor USB drivers --- .gitignore | 3 +- include/peripherals/Display.h | 2 +- include/usb/debug_driver.h | 27 -- include/usb/device/hid/common.h | 16 ++ .../hid/keyboard_driver.h} | 17 +- .../hid/ps3_driver.h} | 17 +- .../hid/ps4_driver.h} | 19 +- .../hid/switch_driver.h} | 19 +- include/usb/{ => device}/midi_driver.h | 19 +- include/usb/device/vendor/common.h | 12 + include/usb/device/vendor/debug_driver.h | 20 ++ include/usb/device/vendor/xinput_driver.h | 36 +++ include/usb/{usb_driver.h => device_driver.h} | 44 +-- include/usb/hid_driver.h | 22 -- include/usb/xinput_driver.h | 41 --- include/utils/InputState.h | 11 +- include/utils/SettingsStore.h | 2 +- src/main.cpp | 30 +- src/usb/{hid_driver.c => device/hid/common.c} | 35 ++- .../hid/keyboard_driver.c} | 19 +- .../hid/ps3_driver.c} | 29 +- .../hid/ps4_driver.c} | 38 ++- .../hid/switch_driver.c} | 35 ++- src/usb/{ => device}/midi_driver.c | 36 ++- src/usb/device/vendor/common.c | 22 ++ src/usb/{ => device/vendor}/debug_driver.c | 21 +- src/usb/device/vendor/xinput_driver.c | 256 ++++++++++++++++++ src/usb/device_driver.c | 152 +++++++++++ src/usb/usb_driver.c | 196 -------------- src/usb/xinput_driver.c | 154 ----------- 30 files changed, 752 insertions(+), 598 deletions(-) delete mode 100644 include/usb/debug_driver.h create mode 100644 include/usb/device/hid/common.h rename include/usb/{hid_keyboard_driver.h => device/hid/keyboard_driver.h} (62%) rename include/usb/{hid_ps3_driver.h => device/hid/ps3_driver.h} (76%) rename include/usb/{hid_ps4_driver.h => device/hid/ps4_driver.h} (76%) rename include/usb/{hid_switch_driver.h => device/hid/switch_driver.h} (61%) rename include/usb/{ => device}/midi_driver.h (53%) create mode 100644 include/usb/device/vendor/common.h create mode 100644 include/usb/device/vendor/debug_driver.h create mode 100644 include/usb/device/vendor/xinput_driver.h rename include/usb/{usb_driver.h => device_driver.h} (56%) delete mode 100644 include/usb/hid_driver.h delete mode 100644 include/usb/xinput_driver.h rename src/usb/{hid_driver.c => device/hid/common.c} (74%) rename src/usb/{hid_keyboard_driver.c => device/hid/keyboard_driver.c} (84%) rename src/usb/{hid_ps3_driver.c => device/hid/ps3_driver.c} (94%) rename src/usb/{hid_ps4_driver.c => device/hid/ps4_driver.c} (96%) rename src/usb/{hid_switch_driver.c => device/hid/switch_driver.c} (86%) rename src/usb/{ => device}/midi_driver.c (88%) create mode 100644 src/usb/device/vendor/common.c rename src/usb/{ => device/vendor}/debug_driver.c (91%) create mode 100644 src/usb/device/vendor/xinput_driver.c create mode 100644 src/usb/device_driver.c delete mode 100644 src/usb/usb_driver.c delete mode 100644 src/usb/xinput_driver.c diff --git a/.gitignore b/.gitignore index a87b059..d871cce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ .vscode/ build/ - -research +research/ *.pio.h \ No newline at end of file diff --git a/include/peripherals/Display.h b/include/peripherals/Display.h index 7a7821e..d01c727 100644 --- a/include/peripherals/Display.h +++ b/include/peripherals/Display.h @@ -1,7 +1,7 @@ #ifndef _PERIPHERALS_DISPLAY_H_ #define _PERIPHERALS_DISPLAY_H_ -#include "usb/usb_driver.h" +#include "usb/device_driver.h" #include "utils/InputState.h" #include "utils/Menu.h" diff --git a/include/usb/debug_driver.h b/include/usb/debug_driver.h deleted file mode 100644 index a4dc697..0000000 --- a/include/usb/debug_driver.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _USB_DEBUG_DRIVER_H_ -#define _USB_DEBUG_DRIVER_H_ - -#include "usb/usb_driver.h" - -#include "device/usbd_pvt.h" - -#include - -#define USBD_DEBUG_CDC_NAME "Serial Debug" -#define USBD_DEBUG_RESET_NAME "Picotool Reset" - -#ifdef __cplusplus -extern "C" { -#endif - -bool send_debug_report(usb_report_t report); - -extern const tusb_desc_device_t debug_desc_device; -extern const uint8_t debug_desc_cfg[]; -extern const usbd_class_driver_t debug_app_driver; - -#ifdef __cplusplus -} -#endif - -#endif // _USB_DEBUG_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/device/hid/common.h b/include/usb/device/hid/common.h new file mode 100644 index 0000000..84cc2f6 --- /dev/null +++ b/include/usb/device/hid/common.h @@ -0,0 +1,16 @@ +#ifndef _USB_DEVICE_HID_COMMON_H_ +#define _USB_DEVICE_HID_COMMON_H_ + +#include "device/usbd_pvt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const usbd_class_driver_t hid_app_driver; + +#ifdef __cplusplus +} +#endif + +#endif // _USB_DEVICE_HID_COMMON_H_ \ No newline at end of file diff --git a/include/usb/hid_keyboard_driver.h b/include/usb/device/hid/keyboard_driver.h similarity index 62% rename from include/usb/hid_keyboard_driver.h rename to include/usb/device/hid/keyboard_driver.h index 270802b..5378351 100644 --- a/include/usb/hid_keyboard_driver.h +++ b/include/usb/device/hid/keyboard_driver.h @@ -1,14 +1,12 @@ -#ifndef _USB_HID_KEYBOARD_DRIVER_H_ -#define _USB_HID_KEYBOARD_DRIVER_H_ +#ifndef _USB_DEVICE_HID_KEYBOARD_DRIVER_H_ +#define _USB_DEVICE_HID_KEYBOARD_DRIVER_H_ -#include "usb/usb_driver.h" +#include "usb/device_driver.h" -#include "device/usbd_pvt.h" +#include "class/hid/hid_device.h" #include -#define USBD_KEYBOARD_NAME "Keyboard Mode" - #ifdef __cplusplus extern "C" { #endif @@ -17,11 +15,10 @@ typedef struct __attribute((packed, aligned(1))) { uint8_t keycodes[32]; } hid_nkro_keyboard_report_t; -extern const tusb_desc_device_t keyboard_desc_device; -extern const uint8_t keyboard_desc_cfg[]; +extern const usbd_driver_t hid_keyboard_device_driver; + extern const uint8_t keyboard_desc_hid_report[]; -bool send_hid_keyboard_report(usb_report_t report); uint16_t hid_keyboard_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); void hid_keyboard_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, @@ -31,4 +28,4 @@ void hid_keyboard_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_ } #endif -#endif // _USB_HID_KEYBOARD_DRIVER_H_ \ No newline at end of file +#endif // _USB_DEVICE_HID_KEYBOARD_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/hid_ps3_driver.h b/include/usb/device/hid/ps3_driver.h similarity index 76% rename from include/usb/hid_ps3_driver.h rename to include/usb/device/hid/ps3_driver.h index 306c136..3c8cfc8 100644 --- a/include/usb/hid_ps3_driver.h +++ b/include/usb/device/hid/ps3_driver.h @@ -1,14 +1,12 @@ -#ifndef _USB_HID_PS3_DRIVER_H_ -#define _USB_HID_PS3_DRIVER_H_ +#ifndef _USB_DEVICE_HID_PS3_DRIVER_H_ +#define _USB_DEVICE_HID_PS3_DRIVER_H_ -#include "usb/usb_driver.h" +#include "usb/device_driver.h" -#include "device/usbd_pvt.h" +#include "class/hid/hid_device.h" #include -#define USBD_PS3_NAME "Dualshock3 Emulation" - #ifdef __cplusplus extern "C" { #endif @@ -40,11 +38,10 @@ typedef struct __attribute((packed, aligned(1))) { uint8_t unknown_0x02_2; } hid_ps3_report_t; -extern const tusb_desc_device_t ds3_desc_device; -extern const uint8_t ps3_desc_cfg[]; +extern const usbd_driver_t hid_ds3_device_driver; + extern const uint8_t ps3_desc_hid_report[]; -bool send_hid_ps3_report(usb_report_t report); uint16_t hid_ps3_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); void hid_ps3_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, @@ -54,4 +51,4 @@ void hid_ps3_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep } #endif -#endif // _USB_HID_PS3_DRIVER_H_ \ No newline at end of file +#endif // _USB_DEVICE_HID_PS3_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/hid_ps4_driver.h b/include/usb/device/hid/ps4_driver.h similarity index 76% rename from include/usb/hid_ps4_driver.h rename to include/usb/device/hid/ps4_driver.h index 337b36a..10cd994 100644 --- a/include/usb/hid_ps4_driver.h +++ b/include/usb/device/hid/ps4_driver.h @@ -1,14 +1,12 @@ -#ifndef _USB_HID_PS4_DRIVER_H_ -#define _USB_HID_PS4_DRIVER_H_ +#ifndef _USB_DEVICE_HID_PS4_DRIVER_H_ +#define _USB_DEVICE_HID_PS4_DRIVER_H_ -#include "usb/usb_driver.h" +#include "usb/device_driver.h" -#include "device/usbd_pvt.h" +#include "class/hid/hid_device.h" #include -#define USBD_PS4_NAME "Dualshock4 Emulation" - #ifdef __cplusplus extern "C" { #endif @@ -44,12 +42,11 @@ typedef struct __attribute((packed, aligned(1))) { uint8_t _reserved3[3]; } hid_ps4_report_t; -extern const tusb_desc_device_t ps4_tatacon_desc_device; -extern const tusb_desc_device_t ds4_desc_device; -extern const uint8_t ps4_desc_cfg[]; +extern const usbd_driver_t hid_ds4_device_driver; +extern const usbd_driver_t hid_ps4_tatacon_device_driver; + extern const uint8_t ps4_desc_hid_report[]; -bool send_hid_ps4_report(usb_report_t report); uint16_t hid_ps4_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); void hid_ps4_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, @@ -59,4 +56,4 @@ void hid_ps4_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep } #endif -#endif // _USB_HID_PS4_DRIVER_H_ \ No newline at end of file +#endif // _USB_DEVICE_HID_PS4_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/hid_switch_driver.h b/include/usb/device/hid/switch_driver.h similarity index 61% rename from include/usb/hid_switch_driver.h rename to include/usb/device/hid/switch_driver.h index 698e8dc..be0d6f5 100644 --- a/include/usb/hid_switch_driver.h +++ b/include/usb/device/hid/switch_driver.h @@ -1,14 +1,12 @@ -#ifndef _USB_HID_SWITCH_DRIVER_H_ -#define _USB_HID_SWITCH_DRIVER_H_ +#ifndef _USB_DEVICE_HID_SWITCH_DRIVER_H_ +#define _USB_DEVICE_HID_SWITCH_DRIVER_H_ -#include "usb/usb_driver.h" +#include "usb/device_driver.h" -#include "device/usbd_pvt.h" +#include "class/hid/hid_device.h" #include -#define USBD_SWITCH_NAME "Switch Horipad Emulation" - #ifdef __cplusplus extern "C" { #endif @@ -23,12 +21,11 @@ typedef struct __attribute((packed, aligned(1))) { uint8_t vendor; } hid_switch_report_t; -extern const tusb_desc_device_t switch_tatacon_desc_device; -extern const tusb_desc_device_t switch_horipad_desc_device; -extern const uint8_t switch_desc_cfg[]; +extern const usbd_driver_t hid_switch_horipad_device_driver; +extern const usbd_driver_t hid_switch_tatacon_device_driver; + extern const uint8_t switch_desc_hid_report[]; -bool send_hid_switch_report(usb_report_t report); uint16_t hid_switch_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); void hid_switch_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, @@ -38,4 +35,4 @@ void hid_switch_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t } #endif -#endif // _USB_HID_SWITCH_DRIVER_H_ \ No newline at end of file +#endif // _USB_DEVICE_HID_SWITCH_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/midi_driver.h b/include/usb/device/midi_driver.h similarity index 53% rename from include/usb/midi_driver.h rename to include/usb/device/midi_driver.h index 7fcd371..4f0043a 100644 --- a/include/usb/midi_driver.h +++ b/include/usb/device/midi_driver.h @@ -1,14 +1,10 @@ -#ifndef _USB_MIDI_DRIVER_H_ -#define _USB_MIDI_DRIVER_H_ +#ifndef _USB_DEVICE_MIDI_DRIVER_H_ +#define _USB_DEVICE_MIDI_DRIVER_H_ -#include "usb/usb_driver.h" - -#include "device/usbd_pvt.h" +#include "usb/device_driver.h" #include -#define USBD_MIDI_NAME "MIDI Controller" - #ifdef __cplusplus extern "C" { #endif @@ -29,15 +25,10 @@ typedef struct __attribute((packed, aligned(1))) { } velocity; } midi_report_t; -bool receive_midi_report(void); -bool send_midi_report(usb_report_t report); - -extern const tusb_desc_device_t midi_desc_device; -extern const uint8_t midi_desc_cfg[]; -extern const usbd_class_driver_t midi_app_driver; +extern const usbd_driver_t midi_device_driver; #ifdef __cplusplus } #endif -#endif // _USB_MIDI_DRIVER_H_ \ No newline at end of file +#endif // _USB_DEVICE_MIDI_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/device/vendor/common.h b/include/usb/device/vendor/common.h new file mode 100644 index 0000000..1ab1f59 --- /dev/null +++ b/include/usb/device/vendor/common.h @@ -0,0 +1,12 @@ +#ifndef _USB_DEVICE_VENDOR_COMMON_H_ +#define _USB_DEVICE_VENDOR_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _USB_DEVICE_VENDOR_COMMON_H_ \ No newline at end of file diff --git a/include/usb/device/vendor/debug_driver.h b/include/usb/device/vendor/debug_driver.h new file mode 100644 index 0000000..9cb0fda --- /dev/null +++ b/include/usb/device/vendor/debug_driver.h @@ -0,0 +1,20 @@ +#ifndef _USB_DEVICE_VENDOR_DEBUG_DRIVER_H_ +#define _USB_DEVICE_VENDOR_DEBUG_DRIVER_H_ + +#include "usb/device_driver.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const usbd_driver_t debug_device_driver; + +bool debug_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + +#ifdef __cplusplus +} +#endif + +#endif // _USB_DEVICE_VENDOR_DEBUG_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/device/vendor/xinput_driver.h b/include/usb/device/vendor/xinput_driver.h new file mode 100644 index 0000000..07b77bb --- /dev/null +++ b/include/usb/device/vendor/xinput_driver.h @@ -0,0 +1,36 @@ +#ifndef _USB_DEVICE_VENDOR_XINPUT_DRIVER_H_ +#define _USB_DEVICE_VENDOR_XINPUT_DRIVER_H_ + +#include "usb/device_driver.h" + +#include "tusb.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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]; +} xinput_report_t; + +extern const usbd_driver_t xinput_device_driver; + +bool xinput_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + +#ifdef __cplusplus +} +#endif + +#endif // _USB_DEVICE_VENDOR_XINPUT_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/usb_driver.h b/include/usb/device_driver.h similarity index 56% rename from include/usb/usb_driver.h rename to include/usb/device_driver.h index f76e451..258c83d 100644 --- a/include/usb/usb_driver.h +++ b/include/usb/device_driver.h @@ -1,12 +1,12 @@ -#ifndef _USB_USB_DRIVER_H_ -#define _USB_USB_DRIVER_H_ +#ifndef _USB_DEVICE_DRIVER_H_ +#define _USB_DEVICE_DRIVER_H_ -#include "tusb.h" +#include "device/usbd_pvt.h" #include -#define USBD_MANUFACTURER "DonCon" -#define USBD_PRODUCT "DonCon rev1" +#define USBD_MANUFACTURER "DonCon2040" +#define USBD_PRODUCT_BASE "Taiko Controller" #define USBD_MAX_POWER_MAX (500) @@ -34,14 +34,6 @@ enum { USBD_STR_MANUFACTURER, USBD_STR_PRODUCT, USBD_STR_SERIAL, - USBD_STR_CDC, - USBD_STR_SWITCH, - USBD_STR_PS3, - USBD_STR_PS4, - USBD_STR_KEYBOARD, - USBD_STR_XINPUT, - USBD_STR_MIDI, - USBD_STR_RPI_RESET, }; typedef struct { @@ -49,6 +41,18 @@ typedef struct { uint16_t size; } usb_report_t; +typedef struct { + const char *name; + const usbd_class_driver_t *app_driver; + // Descriptors + const tusb_desc_device_t *desc_device; + const uint8_t *desc_cfg; + const uint8_t *desc_hid_report; + const uint8_t *desc_bos; + // Callbacks + bool (*send_report)(usb_report_t report); +} usbd_driver_t; + typedef enum { USB_PLAYER_LED_ID, USB_PLAYER_LED_COLOR, @@ -70,18 +74,18 @@ extern char *const usbd_desc_str[]; typedef void (*usbd_player_led_cb_t)(usb_player_led_t); -void usb_driver_init(usb_mode_t mode); -void usb_driver_task(); +void usbd_driver_init(usb_mode_t mode); +void usbd_driver_task(); -usb_mode_t usb_driver_get_mode(); +usb_mode_t usbd_driver_get_mode(); -void usb_driver_send_and_receive_report(usb_report_t report); +void usbd_driver_send_report(usb_report_t report); -void usb_driver_set_player_led_cb(usbd_player_led_cb_t cb); -usbd_player_led_cb_t usb_driver_get_player_led_cb(); +void usbd_driver_set_player_led_cb(usbd_player_led_cb_t cb); +usbd_player_led_cb_t usbd_driver_get_player_led_cb(); #ifdef __cplusplus } #endif -#endif // _USB_USB_DRIVER_H_ +#endif // _USB_DEVICE_DRIVER_H_ diff --git a/include/usb/hid_driver.h b/include/usb/hid_driver.h deleted file mode 100644 index 4bcbab9..0000000 --- a/include/usb/hid_driver.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _USB_HID_DRIVER_H_ -#define _USB_HID_DRIVER_H_ - -#include "usb/hid_keyboard_driver.h" -#include "usb/hid_ps3_driver.h" -#include "usb/hid_ps4_driver.h" -#include "usb/hid_switch_driver.h" -#include "usb/usb_driver.h" - -#include "device/usbd_pvt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern const usbd_class_driver_t hid_app_driver; - -#ifdef __cplusplus -} -#endif - -#endif // _USB_HID_DRIVER_H_ \ No newline at end of file diff --git a/include/usb/xinput_driver.h b/include/usb/xinput_driver.h deleted file mode 100644 index 0cf5d9a..0000000 --- a/include/usb/xinput_driver.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _USB_XINPUT_DRIVER_H_ -#define _USB_XINPUT_DRIVER_H_ - -#include "usb/usb_driver.h" - -#include "device/usbd_pvt.h" - -#include - -#define USBD_XINPUT_NAME "XInput Gamepad" - -#ifdef __cplusplus -extern "C" { -#endif - -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]; -} xinput_report_t; - -bool receive_xinput_report(void); -bool send_xinput_report(usb_report_t report); - -extern const tusb_desc_device_t xinput_desc_device; -extern const uint8_t xinput_desc_cfg[]; -extern const usbd_class_driver_t xinput_app_driver; - -#ifdef __cplusplus -} -#endif - -#endif // _USB_XINPUT_DRIVER_H_ \ No newline at end of file diff --git a/include/utils/InputState.h b/include/utils/InputState.h index df7f37b..d8bc868 100644 --- a/include/utils/InputState.h +++ b/include/utils/InputState.h @@ -1,10 +1,13 @@ #ifndef _UTILS_INPUTSTATE_H_ #define _UTILS_INPUTSTATE_H_ -#include "usb/hid_driver.h" -#include "usb/midi_driver.h" -#include "usb/usb_driver.h" -#include "usb/xinput_driver.h" +#include "usb/device/hid/keyboard_driver.h" +#include "usb/device/hid/ps3_driver.h" +#include "usb/device/hid/ps4_driver.h" +#include "usb/device/hid/switch_driver.h" +#include "usb/device/midi_driver.h" +#include "usb/device/vendor/xinput_driver.h" +#include "usb/device_driver.h" #include #include diff --git a/include/utils/SettingsStore.h b/include/utils/SettingsStore.h index e931c94..32888d4 100644 --- a/include/utils/SettingsStore.h +++ b/include/utils/SettingsStore.h @@ -2,7 +2,7 @@ #define _UTILS_SETTINGSSTORE_H_ #include "peripherals/Drum.h" -#include "usb/usb_driver.h" +#include "usb/device_driver.h" #include "hardware/flash.h" diff --git a/src/main.cpp b/src/main.cpp index 96729c1..8c154fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ #include "peripherals/Display.h" #include "peripherals/Drum.h" #include "peripherals/StatusLed.h" -#include "usb/usb_driver.h" +#include "usb/device_driver.h" #include "utils/Menu.h" #include "utils/SettingsStore.h" @@ -34,13 +34,15 @@ struct ControlMessage { union { usb_mode_t usb_mode; usb_player_led_t player_led; - uint8_t brightness; + uint8_t led_brightness; } data; }; void core1_task() { multicore_lockout_victim_init(); + // Init i2c port here because Controller and Display share it and + // therefore can't init it themself. gpio_set_function(Config::Default::i2c_config.sda_pin, GPIO_FUNC_I2C); gpio_set_function(Config::Default::i2c_config.scl_pin, GPIO_FUNC_I2C); gpio_pull_up(Config::Default::i2c_config.sda_pin); @@ -77,7 +79,7 @@ void core1_task() { } break; case ControlCommand::SetLedBrightness: - led.setBrightness(control_msg.data.brightness); + led.setBrightness(control_msg.data.led_brightness); break; case ControlCommand::EnterMenu: display.showMenu(); @@ -104,18 +106,20 @@ int main() { queue_init(&menu_display_queue, sizeof(Utils::Menu::State), 1); queue_init(&drum_input_queue, sizeof(Utils::InputState::Drum), 1); queue_init(&controller_input_queue, sizeof(Utils::InputState::Controller), 1); - multicore_launch_core1(core1_task); Utils::InputState input_state; auto settings_store = std::make_shared(); Utils::Menu menu(settings_store); + auto mode = settings_store->getUsbMode(); + Peripherals::Drum drum(Config::Default::drum_config); - auto mode = settings_store->getUsbMode(); - usb_driver_init(mode); - usb_driver_set_player_led_cb([](usb_player_led_t player_led) { + multicore_launch_core1(core1_task); + + usbd_driver_init(mode); + usbd_driver_set_player_led_cb([](usb_player_led_t player_led) { auto ctrl_message = ControlMessage{ControlCommand::SetPlayerLed, {.player_led = player_led}}; queue_add_blocking(&control_queue, &ctrl_message); }); @@ -128,7 +132,7 @@ int main() { ctrl_message = {ControlCommand::SetUsbMode, {.usb_mode = mode}}; queue_add_blocking(&control_queue, &ctrl_message); - ctrl_message = {ControlCommand::SetLedBrightness, {.brightness = settings_store->getLedBrightness()}}; + ctrl_message = {ControlCommand::SetLedBrightness, {.led_brightness = settings_store->getLedBrightness()}}; queue_add_blocking(&control_queue, &ctrl_message); drum.setDebounceDelay(settings_store->getDebounceDelay()); @@ -154,21 +158,19 @@ int main() { } readSettings(); + input_state.releaseAll(); } else if (input_state.checkHotkey()) { menu.activate(); - input_state.releaseAll(); - usb_driver_send_and_receive_report(input_state.getReport(mode)); - ControlMessage ctrl_message{ControlCommand::EnterMenu, {}}; queue_add_blocking(&control_queue, &ctrl_message); - } else { - usb_driver_send_and_receive_report(input_state.getReport(mode)); } - usb_driver_task(); + usbd_driver_send_report(input_state.getReport(mode)); + usbd_driver_task(); + // TODO don't send whole input_state queue_try_add(&drum_input_queue, &input_state); } diff --git a/src/usb/hid_driver.c b/src/usb/device/hid/common.c similarity index 74% rename from src/usb/hid_driver.c rename to src/usb/device/hid/common.c index c7de731..24773f0 100644 --- a/src/usb/hid_driver.c +++ b/src/usb/device/hid/common.c @@ -1,13 +1,17 @@ -#include "usb/hid_driver.h" -#include "usb/usb_driver.h" +#include "usb/device/hid/common.h" + +#include "usb/device/hid/keyboard_driver.h" +#include "usb/device/hid/ps3_driver.h" +#include "usb/device/hid/ps4_driver.h" +#include "usb/device/hid/switch_driver.h" +#include "usb/device_driver.h" #include "class/hid/hid_device.h" - #include "tusb.h" uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { - switch (usb_driver_get_mode()) { + switch (usbd_driver_get_mode()) { case USB_MODE_SWITCH_TATACON: case USB_MODE_SWITCH_HORIPAD: return hid_switch_get_report_cb(itf, report_id, report_type, buffer, reqlen); @@ -27,7 +31,7 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { - switch (usb_driver_get_mode()) { + switch (usbd_driver_get_mode()) { case USB_MODE_SWITCH_TATACON: case USB_MODE_SWITCH_HORIPAD: hid_switch_set_report_cb(itf, report_id, report_type, buffer, bufsize); @@ -59,6 +63,27 @@ bool hid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c } } +uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) { + (void)itf; + + switch (usbd_driver_get_mode()) { + case USB_MODE_SWITCH_TATACON: + case USB_MODE_SWITCH_HORIPAD: + return switch_desc_hid_report; + case USB_MODE_DUALSHOCK3: + return ps3_desc_hid_report; + case USB_MODE_PS4_TATACON: + case USB_MODE_DUALSHOCK4: + return ps4_desc_hid_report; + case USB_MODE_KEYBOARD_P1: + case USB_MODE_KEYBOARD_P2: + return keyboard_desc_hid_report; + default: + } + + return NULL; +} + const usbd_class_driver_t hid_app_driver = { #if CFG_TUSB_DEBUG >= 2 .name = "HID", diff --git a/src/usb/hid_keyboard_driver.c b/src/usb/device/hid/keyboard_driver.c similarity index 84% rename from src/usb/hid_keyboard_driver.c rename to src/usb/device/hid/keyboard_driver.c index 3b1f5b9..4cc1325 100644 --- a/src/usb/hid_keyboard_driver.c +++ b/src/usb/device/hid/keyboard_driver.c @@ -1,8 +1,6 @@ -#include "usb/hid_keyboard_driver.h" -#include "usb/usb_driver.h" +#include "usb/device/hid/keyboard_driver.h" -#include "class/hid/hid_device.h" -#include "pico/unique_id.h" +#include "usb/device/hid/common.h" #include "tusb.h" @@ -48,8 +46,8 @@ const uint8_t keyboard_desc_hid_report[] = { uint8_t const keyboard_desc_cfg[] = { TUD_CONFIG_DESCRIPTOR(0x01, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_KEYBOARD_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MAX), - TUD_HID_DESCRIPTOR(USBD_ITF_HID, USBD_STR_KEYBOARD, HID_ITF_PROTOCOL_KEYBOARD, sizeof(keyboard_desc_hid_report), - 0x81, CFG_TUD_HID_EP_BUFSIZE, 1), + TUD_HID_DESCRIPTOR(USBD_ITF_HID, 0, HID_ITF_PROTOCOL_KEYBOARD, sizeof(keyboard_desc_hid_report), 0x81, + CFG_TUD_HID_EP_BUFSIZE, 1), }; static hid_keyboard_report_t last_report = {}; @@ -87,3 +85,12 @@ void hid_keyboard_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_ (void)buffer; (void)bufsize; } + +const usbd_driver_t hid_keyboard_device_driver = { + .name = "Keyboard", + .app_driver = &hid_app_driver, + .desc_device = &keyboard_desc_device, + .desc_cfg = keyboard_desc_cfg, + .desc_bos = NULL, + .send_report = send_hid_keyboard_report, +}; \ No newline at end of file diff --git a/src/usb/hid_ps3_driver.c b/src/usb/device/hid/ps3_driver.c similarity index 94% rename from src/usb/hid_ps3_driver.c rename to src/usb/device/hid/ps3_driver.c index 33893de..a1f1d64 100644 --- a/src/usb/hid_ps3_driver.c +++ b/src/usb/device/hid/ps3_driver.c @@ -1,7 +1,7 @@ -#include "usb/hid_ps3_driver.h" -#include "usb/usb_driver.h" +#include "usb/device/hid/ps3_driver.h" + +#include "usb/device/hid/common.h" -#include "class/hid/hid_device.h" #include "pico/unique_id.h" #include "tusb.h" @@ -28,12 +28,6 @@ enum { USBD_ITF_MAX, }; -#define USBD_PS3_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) -const uint8_t ps3_desc_cfg[] = { - TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_PS3_DESC_LEN, 0, USBD_MAX_POWER_MAX), - TUD_HID_INOUT_DESCRIPTOR(USBD_ITF_HID, USBD_STR_PS3, 0, 148, 0x02, 0x81, CFG_TUD_HID_EP_BUFSIZE, 1), -}; - const uint8_t ps3_desc_hid_report[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x04, // Usage (Joystick) @@ -112,6 +106,12 @@ const uint8_t ps3_desc_hid_report[] = { 0xC0, // End Collection }; +#define USBD_PS3_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) +const uint8_t ps3_desc_cfg[] = { + TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_PS3_DESC_LEN, 0, USBD_MAX_POWER_MAX), + TUD_HID_INOUT_DESCRIPTOR(USBD_ITF_HID, 0, 0, sizeof(ps3_desc_hid_report), 0x02, 0x81, CFG_TUD_HID_EP_BUFSIZE, 1), +}; + static hid_ps3_report_t last_report = {}; bool send_hid_ps3_report(usb_report_t report) { @@ -201,9 +201,18 @@ void hid_ps3_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep | ((report->leds_bitmap & 0x08) ? (1 << 2) : 0) // | ((report->leds_bitmap & 0x10) ? (1 << 3) : 0); - usb_driver_get_player_led_cb()(player_led); + usbd_driver_get_player_led_cb()(player_led); } break; default: } } + +const usbd_driver_t hid_ds3_device_driver = { + .name = "DS3", + .app_driver = &hid_app_driver, + .desc_device = &ds3_desc_device, + .desc_cfg = ps3_desc_cfg, + .desc_bos = NULL, + .send_report = send_hid_ps3_report, +}; diff --git a/src/usb/hid_ps4_driver.c b/src/usb/device/hid/ps4_driver.c similarity index 96% rename from src/usb/hid_ps4_driver.c rename to src/usb/device/hid/ps4_driver.c index ff388b1..61597c4 100644 --- a/src/usb/hid_ps4_driver.c +++ b/src/usb/device/hid/ps4_driver.c @@ -1,7 +1,7 @@ -#include "usb/hid_ps4_driver.h" -#include "usb/usb_driver.h" +#include "usb/device/hid/ps4_driver.h" + +#include "usb/device/hid/common.h" -#include "class/hid/hid_device.h" #include "pico/unique_id.h" #include "tusb.h" @@ -45,12 +45,6 @@ enum { USBD_ITF_MAX, }; -#define USBD_PS4_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) -const uint8_t ps4_desc_cfg[] = { - TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_PS4_DESC_LEN, 0, USBD_MAX_POWER_MAX), - TUD_HID_INOUT_DESCRIPTOR(USBD_ITF_HID, USBD_STR_PS4, 0, 483, 0x03, 0x84, CFG_TUD_HID_EP_BUFSIZE, 1), -}; - const uint8_t ps4_desc_hid_report[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x05, // Usage (Game Pad) @@ -292,6 +286,12 @@ const uint8_t ps4_desc_hid_report[] = { 0xC0, // End Collection }; +#define USBD_PS4_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) +const uint8_t ps4_desc_cfg[] = { + TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_PS4_DESC_LEN, 0, USBD_MAX_POWER_MAX), + TUD_HID_INOUT_DESCRIPTOR(USBD_ITF_HID, 0, 0, sizeof(ps4_desc_hid_report), 0x03, 0x84, CFG_TUD_HID_EP_BUFSIZE, 1), +}; + // MAC Address static uint8_t ps4_0x81_report[] = {0x39, 0x39, 0x39, 0x68, 0x22, 0x00}; @@ -404,10 +404,28 @@ void hid_ps4_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep .red = report->led_red, .green = report->led_green, .blue = report->led_blue}; - usb_driver_get_player_led_cb()(player_led); + usbd_driver_get_player_led_cb()(player_led); } } break; default: } } + +const usbd_driver_t hid_ds4_device_driver = { + .name = "DS4", + .app_driver = &hid_app_driver, + .desc_device = &ds4_desc_device, + .desc_cfg = ps4_desc_cfg, + .desc_bos = NULL, + .send_report = send_hid_ps4_report, +}; + +const usbd_driver_t hid_ps4_tatacon_device_driver = { + .name = "PS4 Tatacon", + .app_driver = &hid_app_driver, + .desc_device = &ps4_tatacon_desc_device, + .desc_cfg = ps4_desc_cfg, + .desc_bos = NULL, + .send_report = send_hid_ps4_report, +}; \ No newline at end of file diff --git a/src/usb/hid_switch_driver.c b/src/usb/device/hid/switch_driver.c similarity index 86% rename from src/usb/hid_switch_driver.c rename to src/usb/device/hid/switch_driver.c index 7a26bcf..602fe6d 100644 --- a/src/usb/hid_switch_driver.c +++ b/src/usb/device/hid/switch_driver.c @@ -1,7 +1,6 @@ -#include "usb/hid_switch_driver.h" -#include "usb/usb_driver.h" +#include "usb/device/hid/switch_driver.h" -#include "class/hid/hid_device.h" +#include "usb/device/hid/common.h" #include "tusb.h" @@ -44,12 +43,6 @@ enum { USBD_ITF_MAX, }; -#define USBD_SWITCH_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) -const uint8_t switch_desc_cfg[] = { - TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_SWITCH_DESC_LEN, 0, USBD_MAX_POWER_MAX), - TUD_HID_INOUT_DESCRIPTOR(USBD_ITF_HID, USBD_STR_SWITCH, 0, 86, 0x02, 0x81, CFG_TUD_HID_EP_BUFSIZE, 1), -}; - const uint8_t switch_desc_hid_report[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x05, // Usage (Game Pad) @@ -94,6 +87,12 @@ const uint8_t switch_desc_hid_report[] = { 0xC0, // End Collection }; +#define USBD_SWITCH_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) +const uint8_t switch_desc_cfg[] = { + TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_SWITCH_DESC_LEN, 0, USBD_MAX_POWER_MAX), + TUD_HID_INOUT_DESCRIPTOR(USBD_ITF_HID, 0, 0, sizeof(switch_desc_hid_report), 0x02, 0x81, CFG_TUD_HID_EP_BUFSIZE, 1), +}; + static hid_switch_report_t last_report = {}; bool send_hid_switch_report(usb_report_t report) { @@ -128,3 +127,21 @@ void hid_switch_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t (void)bufsize; (void)buffer; } + +const usbd_driver_t hid_switch_horipad_device_driver = { + .name = "Switch", + .app_driver = &hid_app_driver, + .desc_device = &switch_horipad_desc_device, + .desc_cfg = switch_desc_cfg, + .desc_bos = NULL, + .send_report = send_hid_switch_report, +}; + +const usbd_driver_t hid_switch_tatacon_device_driver = { + .name = "Switch Tatacon", + .app_driver = &hid_app_driver, + .desc_device = &switch_tatacon_desc_device, + .desc_cfg = switch_desc_cfg, + .desc_bos = NULL, + .send_report = send_hid_switch_report, +}; \ No newline at end of file diff --git a/src/usb/midi_driver.c b/src/usb/device/midi_driver.c similarity index 88% rename from src/usb/midi_driver.c rename to src/usb/device/midi_driver.c index 4332cc6..cd0a904 100644 --- a/src/usb/midi_driver.c +++ b/src/usb/device/midi_driver.c @@ -1,5 +1,4 @@ -#include "usb/midi_driver.h" -#include "usb/usb_driver.h" +#include "usb/device/midi_driver.h" #include "class/midi/midi_device.h" @@ -14,7 +13,7 @@ const tusb_desc_device_t midi_desc_device = { .bDeviceProtocol = 0x00, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .idVendor = 0x1209, - .idProduct = 0x3939, + .idProduct = 0x3902, .bcdDevice = 0x0100, .iManufacturer = USBD_STR_MANUFACTURER, .iProduct = USBD_STR_PRODUCT, @@ -40,16 +39,6 @@ const uint8_t midi_desc_cfg[USBD_DESC_LEN] = { static midi_report_t last_report = {}; -bool receive_midi_report(void) { - // Read and discard incoming data to avoid blocking the sender - uint8_t packet[4]; - while (tud_midi_available()) { - tud_midi_packet_read(packet); - } - - return true; -} - static void write_midi_message(uint8_t status, uint8_t byte1, uint8_t byte2) { uint8_t midi_message[3] = {status, byte1, byte2}; tud_midi_stream_write(0, midi_message, sizeof(midi_message)); @@ -86,7 +75,17 @@ bool send_midi_report(usb_report_t report) { return true; } -const usbd_class_driver_t midi_app_driver = { +void tud_midi_rx_cb(uint8_t itf) { + (void)itf; + + // Read and discard incoming data to avoid blocking the sender + uint8_t packet[4]; + while (tud_midi_available()) { + tud_midi_packet_read(packet); + } +} + +static const usbd_class_driver_t midi_app_driver = { #if CFG_TUSB_DEBUG >= 2 .name = "MIDI", #endif @@ -96,3 +95,12 @@ const usbd_class_driver_t midi_app_driver = { .control_xfer_cb = midid_control_xfer_cb, .xfer_cb = midid_xfer_cb, .sof = NULL}; + +const usbd_driver_t midi_device_driver = { + .name = "MIDI", + .app_driver = &midi_app_driver, + .desc_device = &midi_desc_device, + .desc_cfg = midi_desc_cfg, + .desc_bos = NULL, + .send_report = send_midi_report, +}; diff --git a/src/usb/device/vendor/common.c b/src/usb/device/vendor/common.c new file mode 100644 index 0000000..39d6621 --- /dev/null +++ b/src/usb/device/vendor/common.c @@ -0,0 +1,22 @@ +#include "usb/device/vendor/common.h" + +#include "usb/device/vendor/debug_driver.h" +#include "usb/device/vendor/xinput_driver.h" +#include "usb/device_driver.h" + +#include "tusb.h" + +// Implement TinyUSB internal callback since vendor control requests are not forwarded to custom drivers. +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + switch (usbd_driver_get_mode()) { + case USB_MODE_XBOX360: + case USB_MODE_XBOX360_ANALOG_P1: + case USB_MODE_XBOX360_ANALOG_P2: + return xinput_control_xfer_cb(rhport, stage, request); + case USB_MODE_DEBUG: + return debug_control_xfer_cb(rhport, stage, request); + default: + } + + return false; +} \ No newline at end of file diff --git a/src/usb/debug_driver.c b/src/usb/device/vendor/debug_driver.c similarity index 91% rename from src/usb/debug_driver.c rename to src/usb/device/vendor/debug_driver.c index df87a75..97a335a 100644 --- a/src/usb/debug_driver.c +++ b/src/usb/device/vendor/debug_driver.c @@ -1,4 +1,4 @@ -#include "usb/debug_driver.h" +#include "usb/device/vendor/debug_driver.h" #include "device/usbd_pvt.h" #include "hardware/watchdog.h" @@ -45,9 +45,9 @@ enum { const uint8_t debug_desc_cfg[USBD_DESC_LEN] = { TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_DESC_LEN, 0, USBD_MAX_POWER_MAX), - TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, - USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE), - TUD_RPI_RESET_DESCRIPTOR(USBD_ITF_RPI_RESET, USBD_STR_RPI_RESET), + TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, 0, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, + USBD_CDC_IN_OUT_MAX_SIZE), + TUD_RPI_RESET_DESCRIPTOR(USBD_ITF_RPI_RESET, 0), }; #define TUD_DEBUG_MS_OS_20_DESC_LEN 166 @@ -147,7 +147,7 @@ static bool debug_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, return true; } -const usbd_class_driver_t debug_app_driver = { +static usbd_class_driver_t const debug_app_driver = { #if CFG_TUSB_DEBUG >= 2 .name = "DEBUG", #endif @@ -158,6 +158,15 @@ const usbd_class_driver_t debug_app_driver = { .xfer_cb = debug_xfer_cb, .sof = NULL}; +const usbd_driver_t debug_device_driver = { + .name = "Debug", + .app_driver = &debug_app_driver, + .desc_device = &debug_desc_device, + .desc_cfg = debug_desc_cfg, + .desc_bos = debug_desc_bos, + .send_report = send_debug_report, +}; + // Support for default BOOTSEL reset by changing baud rate void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding) { (void)itf; @@ -165,4 +174,4 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding) if (p_line_coding->bit_rate == PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE) { reset_usb_boot(0, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); } -} \ No newline at end of file +} diff --git a/src/usb/device/vendor/xinput_driver.c b/src/usb/device/vendor/xinput_driver.c new file mode 100644 index 0000000..f9b6d95 --- /dev/null +++ b/src/usb/device/vendor/xinput_driver.c @@ -0,0 +1,256 @@ +#include "usb/device/vendor/xinput_driver.h" + +#include "device/usbd_pvt.h" +#include "tusb.h" + +#include + +const tusb_desc_device_t xinput_desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_VENDOR_SPECIFIC, + .bDeviceSubClass = 0xFF, + .bDeviceProtocol = 0xFF, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x045E, + .idProduct = 0x028E, + .bcdDevice = 0x0114, + .iManufacturer = USBD_STR_MANUFACTURER, + .iProduct = USBD_STR_PRODUCT, + .iSerialNumber = USBD_STR_SERIAL, + .bNumConfigurations = 1, +}; + +enum { + USBD_ITF_XINPUT, + USBD_ITF_MAX, +}; + +#define XINPUT_INTERFACE_SUBCLASS 0x5D +#define XINPUT_INTERFACE_PROTOCOL 0x01 +#define XINPUT_DESC_VENDOR 0x21 + +#define TUD_XINPUT_EP_BUFSIZE 32 +#define TUD_XINPUT_EP_OUT 0x01 +#define TUD_XINPUT_EP_IN 0x81 + +#define TUD_XINPUT_DESC_LEN (9 + 16 + 7 + 7) + +#define TUD_XINPUT_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, XINPUT_INTERFACE_SUBCLASS, \ + XINPUT_INTERFACE_PROTOCOL, _stridx, 16, XINPUT_DESC_VENDOR, 0x10, 0x01, 0x01, 0x24, 0x81, 0x14, 0x03, 0x00, \ + 0x03, 0x13, 0x01, 0x00, 0x03, 0x00, 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), \ + 1, 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), 8 + +#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_XINPUT_DESC_LEN) + +const uint8_t xinput_desc_cfg[USBD_DESC_LEN] = { + TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_DESC_LEN, 0, USBD_MAX_POWER_MAX), + TUD_XINPUT_DESCRIPTOR(USBD_ITF_XINPUT, 0, TUD_XINPUT_EP_OUT, TUD_XINPUT_EP_IN, TUD_XINPUT_EP_BUFSIZE), +}; + +typedef struct __attribute((packed, aligned(1))) { + uint8_t type; + uint8_t size; + uint8_t led; + uint8_t rumble_strong; + uint8_t rumble_light; + uint8_t _reserved[3]; +} hid_xinput_ouput_report_t; + +typedef struct { + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[TUD_XINPUT_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[TUD_XINPUT_EP_BUFSIZE]; +} xinput_interface_t; + +CFG_TUSB_MEM_SECTION static xinput_interface_t _xinput_itf; + +static bool xinput_ready() { + uint8_t const ep_in = _xinput_itf.ep_in; + + return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(0, ep_in); +} + +bool send_xinput_report(usb_report_t report) { + if (!xinput_ready()) { + return false; + } + + TU_VERIFY(usbd_edpt_claim(0, _xinput_itf.ep_in)); + + uint16_t size = tu_min16(report.size, TUD_XINPUT_EP_BUFSIZE); + memcpy(_xinput_itf.epin_buf, report.data, size); + + return usbd_edpt_xfer(0, _xinput_itf.ep_in, _xinput_itf.epin_buf, size); +} + +static bool receive_xinput_report(uint8_t const *buf, uint32_t size) { + enum { + REPORT_RUMBLE = 0x00, + REPORT_LED = 0x01, + }; + enum { + ALL_OFF = 0x00, + ALL_BLINK = 0x01, + P1_FLASH_ON = 0x02, + P2_FLASH_ON = 0x03, + P3_FLASH_ON = 0x04, + P4_FLASH_ON = 0x05, + P1_ON = 0x06, + P2_ON = 0x07, + P3_ON = 0x08, + P4_ON = 0x09, + ALL_ROTATE = 0x0A, + CURRENT_BLINK = 0x0B, + CURRENT_BLINK_SLOW = 0x0C, + ALL_ALTERNATE = 0x0D, + ALL_SLOW_BLINK = 0x0E, + ALL_BLINK_ONCE = 0x0F, + }; + + hid_xinput_ouput_report_t *report = (hid_xinput_ouput_report_t *)buf; + + switch (report->type) { + case REPORT_RUMBLE: + // Ignore, we ain't doing that + return true; + case REPORT_LED: { + TU_ASSERT(size >= 3); + + usb_player_led_t player_led = {.type = USB_PLAYER_LED_ID, .id = 0}; + + switch (report->led) { + case ALL_OFF: + player_led.id = 0x00; + break; + case ALL_ROTATE: + case ALL_ALTERNATE: + player_led.id = 0x0F; + break; + case P1_FLASH_ON: + case P1_ON: + player_led.id = 0x01; + break; + case P2_FLASH_ON: + case P2_ON: + player_led.id = 0x02; + break; + case P3_FLASH_ON: + case P3_ON: + player_led.id = 0x04; + break; + case P4_FLASH_ON: + case P4_ON: + player_led.id = 0x08; + break; + case ALL_SLOW_BLINK: + player_led.id = 0x0F; + break; + case ALL_BLINK: + case CURRENT_BLINK: + case CURRENT_BLINK_SLOW: + case ALL_BLINK_ONCE: + default: + player_led.id = 0x00; + break; + } + + usbd_driver_get_player_led_cb()(player_led); + } + default: + } + + return false; +} + +static void xinput_reset(uint8_t rhport) { + (void)rhport; + + tu_memclr(&_xinput_itf, sizeof(_xinput_itf)); +} + +static void xinput_init(void) { xinput_reset(0); } + +static uint16_t xinput_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { + TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); + + uint16_t const drv_len = + (uint16_t)(sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t) + 16); + TU_ASSERT(max_len >= drv_len, 0); + + _xinput_itf.itf_num = desc_itf->bInterfaceNumber; + + // Unknown vendor specific descriptor + uint8_t const *p_desc = tu_desc_next(desc_itf); + TU_ASSERT(p_desc[1] == XINPUT_DESC_VENDOR, 0); + + // Endpoint descriptors + p_desc = tu_desc_next(p_desc); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &_xinput_itf.ep_out, + &_xinput_itf.ep_in), + 0); + + if (_xinput_itf.ep_out) { + TU_ASSERT(usbd_edpt_xfer(rhport, _xinput_itf.ep_out, _xinput_itf.epout_buf, sizeof(_xinput_itf.epout_buf)), 0); + } + + return drv_len; +} + +bool xinput_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + (void)rhport; + + if (stage != CONTROL_STAGE_SETUP) + return true; + + // This is mainly to suppress a warning from the linux kernel: + // https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c#L1756 + // + // Hopefully nobody expects actual data here. + if (!(request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR && request->bRequest == 0x01 && + request->wIndex == 0x00)) { + return false; + } + + uint8_t *dummy_data = calloc(request->wLength, sizeof(uint8_t)); + bool success = tud_control_xfer(rhport, request, (void *)(uintptr_t)dummy_data, request->wLength); + free(dummy_data); + + return success; +} + +static bool xinput_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + TU_ASSERT(result == XFER_RESULT_SUCCESS); + + if (ep_addr == _xinput_itf.ep_out) { + receive_xinput_report(_xinput_itf.epout_buf, xferred_bytes); + TU_ASSERT(usbd_edpt_xfer(rhport, _xinput_itf.ep_out, _xinput_itf.epout_buf, sizeof(_xinput_itf.epout_buf))); + } + + return true; +} + +static const usbd_class_driver_t xinput_app_driver = { +#if CFG_TUSB_DEBUG >= 2 + .name = "XINPUT", +#endif + .init = xinput_init, + .reset = xinput_reset, + .open = xinput_open, + .control_xfer_cb = xinput_control_xfer_cb, + .xfer_cb = xinput_xfer_cb, + .sof = NULL}; + +const usbd_driver_t xinput_device_driver = { + .name = "XInput", + .app_driver = &xinput_app_driver, + .desc_device = &xinput_desc_device, + .desc_cfg = xinput_desc_cfg, + .desc_bos = NULL, + .send_report = send_xinput_report, +}; diff --git a/src/usb/device_driver.c b/src/usb/device_driver.c new file mode 100644 index 0000000..0080d70 --- /dev/null +++ b/src/usb/device_driver.c @@ -0,0 +1,152 @@ +#include "usb/device_driver.h" + +#include "usb/device/hid/keyboard_driver.h" +#include "usb/device/hid/ps3_driver.h" +#include "usb/device/hid/ps4_driver.h" +#include "usb/device/hid/switch_driver.h" +#include "usb/device/midi_driver.h" +#include "usb/device/vendor/debug_driver.h" +#include "usb/device/vendor/xinput_driver.h" + +#include "bsp/board.h" +#include "pico/unique_id.h" +#include "tusb.h" + +#include + +#define DESC_STR_MAX (127) + +static usb_mode_t usbd_mode = USB_MODE_DEBUG; +static usbd_driver_t usbd_driver = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +static usbd_player_led_cb_t usbd_player_led_cb = NULL; + +#define USBD_SERIAL_STR_SIZE (PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1 + 3) +static char usbd_serial_str[USBD_SERIAL_STR_SIZE] = {}; +static char usbd_product_str[DESC_STR_MAX] = {}; + +char *const usbd_desc_str[] = { + [USBD_STR_MANUFACTURER] = USBD_MANUFACTURER, // + [USBD_STR_PRODUCT] = usbd_product_str, // + [USBD_STR_SERIAL] = usbd_serial_str, // +}; + +void usbd_driver_init(usb_mode_t mode) { + usbd_mode = mode; + + switch (mode) { + case USB_MODE_SWITCH_TATACON: + usbd_driver = hid_switch_tatacon_device_driver; + break; + case USB_MODE_SWITCH_HORIPAD: + usbd_driver = hid_switch_horipad_device_driver; + break; + case USB_MODE_DUALSHOCK3: + usbd_driver = hid_ds3_device_driver; + break; + case USB_MODE_PS4_TATACON: + usbd_driver = hid_ps4_tatacon_device_driver; + break; + case USB_MODE_DUALSHOCK4: + usbd_driver = hid_ds4_device_driver; + break; + case USB_MODE_KEYBOARD_P1: + case USB_MODE_KEYBOARD_P2: + usbd_driver = hid_keyboard_device_driver; + break; + case USB_MODE_XBOX360_ANALOG_P1: + case USB_MODE_XBOX360_ANALOG_P2: + case USB_MODE_XBOX360: + usbd_driver = xinput_device_driver; + break; + case USB_MODE_MIDI: + usbd_driver = midi_device_driver; + break; + case USB_MODE_DEBUG: + usbd_driver = debug_device_driver; + break; + } + + tud_init(BOARD_TUD_RHPORT); +} + +void usbd_driver_task() { tud_task(); } + +usb_mode_t usbd_driver_get_mode() { return usbd_mode; } + +void usbd_driver_send_report(usb_report_t report) { + static const uint64_t interval_us = 900; + static uint64_t start_us = 0; + + if (to_us_since_boot(get_absolute_time()) - start_us <= interval_us) { + return; + } + start_us += interval_us; + + if (tud_suspended()) { + tud_remote_wakeup(); + } + + if (usbd_driver.send_report) { + usbd_driver.send_report(report); + } +} + +void usbd_driver_set_player_led_cb(usbd_player_led_cb_t cb) { usbd_player_led_cb = cb; }; +usbd_player_led_cb_t usbd_driver_get_player_led_cb() { return usbd_player_led_cb; }; + +const uint8_t *tud_descriptor_device_cb(void) { return (const uint8_t *)usbd_driver.desc_device; } + +const uint8_t *tud_descriptor_configuration_cb(uint8_t index) { + (void)index; + + return usbd_driver.desc_cfg; +} + +const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void)langid; + + static uint16_t desc_str[DESC_STR_MAX]; + + // Assign the SN using the unique flash id + if (!usbd_serial_str[0]) { + pico_get_unique_board_id_string(usbd_serial_str, sizeof(usbd_serial_str)); + usbd_serial_str[USBD_SERIAL_STR_SIZE - 4] = '-'; + usbd_serial_str[USBD_SERIAL_STR_SIZE - 3] = '0' + ((usbd_mode / 10) % 10); + usbd_serial_str[USBD_SERIAL_STR_SIZE - 2] = '0' + (usbd_mode % 10); + usbd_serial_str[USBD_SERIAL_STR_SIZE - 1] = '\0'; + } + + if (!usbd_product_str[0]) { + strcpy(usbd_product_str, USBD_PRODUCT_BASE); + strcat(usbd_product_str, " ("); + strcat(usbd_product_str, usbd_driver.name); + strcat(usbd_product_str, ")"); + } + + uint8_t len; + if (index == USBD_STR_LANGUAGE) { + desc_str[1] = 0x0409; // Supported language is English + len = 1; + } else { + if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) { + return NULL; + } + const char *str = usbd_desc_str[index]; + for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) { + desc_str[1 + len] = str[len]; + } + } + + // first byte is length (including header), second byte is string type + desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * len + 2)); + + return desc_str; +} + +uint8_t const *tud_descriptor_bos_cb(void) { return usbd_driver.desc_bos; } + +// Implement callback to add our custom driver +const usbd_class_driver_t *usbd_app_driver_get_cb(uint8_t *driver_count) { + *driver_count = 1; + return usbd_driver.app_driver; +} diff --git a/src/usb/usb_driver.c b/src/usb/usb_driver.c deleted file mode 100644 index d3ae3d8..0000000 --- a/src/usb/usb_driver.c +++ /dev/null @@ -1,196 +0,0 @@ -#include "usb/usb_driver.h" -#include "usb/debug_driver.h" -#include "usb/hid_driver.h" -#include "usb/midi_driver.h" -#include "usb/xinput_driver.h" - -#include "bsp/board.h" -#include "pico/unique_id.h" - -static usb_mode_t usbd_mode = USB_MODE_DEBUG; -static usbd_player_led_cb_t usbd_player_led_cb = NULL; -static const tusb_desc_device_t *usbd_desc_device = NULL; -static const uint8_t *usbd_desc_cfg = NULL; -static const uint8_t *usbd_desc_hid_report = NULL; -static const usbd_class_driver_t *usbd_app_driver = NULL; -static bool (*usbd_send_report)(usb_report_t report) = NULL; -static bool (*usbd_receive_report)() = NULL; - -#define USBD_SERIAL_STR_SIZE (PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1 + 3) -static char usbd_serial_str[USBD_SERIAL_STR_SIZE] = {}; - -char *const usbd_desc_str[] = { - [USBD_STR_MANUFACTURER] = USBD_MANUFACTURER, // - [USBD_STR_PRODUCT] = USBD_PRODUCT, // - [USBD_STR_SERIAL] = usbd_serial_str, // - [USBD_STR_SWITCH] = USBD_SWITCH_NAME, // - [USBD_STR_PS3] = USBD_PS3_NAME, // - [USBD_STR_PS4] = USBD_PS4_NAME, // - [USBD_STR_KEYBOARD] = USBD_KEYBOARD_NAME, // - [USBD_STR_XINPUT] = USBD_XINPUT_NAME, // - [USBD_STR_MIDI] = USBD_MIDI_NAME, // - [USBD_STR_CDC] = USBD_DEBUG_CDC_NAME, // - [USBD_STR_RPI_RESET] = USBD_DEBUG_RESET_NAME, // -}; - -void usb_driver_init(usb_mode_t mode) { - usbd_mode = mode; - - switch (mode) { - case USB_MODE_SWITCH_TATACON: - usbd_desc_device = &switch_tatacon_desc_device; - usbd_desc_cfg = switch_desc_cfg; - usbd_desc_hid_report = switch_desc_hid_report; - usbd_app_driver = &hid_app_driver; - usbd_send_report = send_hid_switch_report; - usbd_receive_report = NULL; - break; - case USB_MODE_SWITCH_HORIPAD: - usbd_desc_device = &switch_horipad_desc_device; - usbd_desc_cfg = switch_desc_cfg; - usbd_desc_hid_report = switch_desc_hid_report; - usbd_app_driver = &hid_app_driver; - usbd_send_report = send_hid_switch_report; - usbd_receive_report = NULL; - break; - case USB_MODE_DUALSHOCK3: - usbd_desc_device = &ds3_desc_device; - usbd_desc_cfg = ps3_desc_cfg; - usbd_desc_hid_report = ps3_desc_hid_report; - usbd_app_driver = &hid_app_driver; - usbd_send_report = send_hid_ps3_report; - usbd_receive_report = NULL; - break; - case USB_MODE_PS4_TATACON: - usbd_desc_device = &ps4_tatacon_desc_device; - usbd_desc_cfg = ps4_desc_cfg; - usbd_desc_hid_report = ps4_desc_hid_report; - usbd_app_driver = &hid_app_driver; - usbd_send_report = send_hid_ps4_report; - usbd_receive_report = NULL; - break; - case USB_MODE_DUALSHOCK4: - usbd_desc_device = &ds4_desc_device; - usbd_desc_cfg = ps4_desc_cfg; - usbd_desc_hid_report = ps4_desc_hid_report; - usbd_app_driver = &hid_app_driver; - usbd_send_report = send_hid_ps4_report; - usbd_receive_report = NULL; - break; - case USB_MODE_KEYBOARD_P1: - case USB_MODE_KEYBOARD_P2: - usbd_desc_device = &keyboard_desc_device; - usbd_desc_cfg = keyboard_desc_cfg; - usbd_desc_hid_report = keyboard_desc_hid_report; - usbd_app_driver = &hid_app_driver; - usbd_send_report = send_hid_keyboard_report; - usbd_receive_report = NULL; - break; - case USB_MODE_XBOX360_ANALOG_P1: - case USB_MODE_XBOX360_ANALOG_P2: - case USB_MODE_XBOX360: - usbd_desc_device = &xinput_desc_device; - usbd_desc_cfg = xinput_desc_cfg; - usbd_app_driver = &xinput_app_driver; - usbd_send_report = send_xinput_report; - usbd_receive_report = receive_xinput_report; - break; - case USB_MODE_MIDI: - usbd_desc_device = &midi_desc_device; - usbd_desc_cfg = midi_desc_cfg; - usbd_app_driver = &midi_app_driver; - usbd_send_report = send_midi_report; - usbd_receive_report = receive_midi_report; - break; - case USB_MODE_DEBUG: - usbd_desc_device = &debug_desc_device; - usbd_desc_cfg = debug_desc_cfg; - usbd_app_driver = &debug_app_driver; - usbd_send_report = send_debug_report; - usbd_receive_report = NULL; - break; - } - - tusb_init(); -} - -void usb_driver_task() { tud_task(); } - -usb_mode_t usb_driver_get_mode() { return usbd_mode; } - -void usb_driver_send_and_receive_report(usb_report_t report) { - static const uint32_t interval_ms = 1; - static uint32_t start_ms = 0; - - if (board_millis() - start_ms < interval_ms) { - return; - } - start_ms += interval_ms; - - if (tud_suspended()) { - tud_remote_wakeup(); - } - - if (usbd_send_report) { - usbd_send_report(report); - } - - if (usbd_receive_report) { - usbd_receive_report(); - } -} - -void usb_driver_set_player_led_cb(usbd_player_led_cb_t cb) { usbd_player_led_cb = cb; }; - -usbd_player_led_cb_t usb_driver_get_player_led_cb() { return usbd_player_led_cb; }; - -const uint8_t *tud_descriptor_device_cb(void) { return (const uint8_t *)usbd_desc_device; } - -const uint8_t *tud_descriptor_configuration_cb(uint8_t __unused index) { return usbd_desc_cfg; } - -const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { -#define DESC_STR_MAX (20) - (void)langid; - - static uint16_t desc_str[DESC_STR_MAX]; - - // Assign the SN using the unique flash id - if (!usbd_serial_str[0]) { - pico_get_unique_board_id_string(usbd_serial_str, sizeof(usbd_serial_str)); - usbd_serial_str[USBD_SERIAL_STR_SIZE - 4] = '-'; - usbd_serial_str[USBD_SERIAL_STR_SIZE - 3] = '0' + ((usbd_mode / 10) % 10); - usbd_serial_str[USBD_SERIAL_STR_SIZE - 2] = '0' + (usbd_mode % 10); - usbd_serial_str[USBD_SERIAL_STR_SIZE - 1] = '\0'; - } - - uint8_t len; - if (index == USBD_STR_LANGUAGE) { - desc_str[1] = 0x0409; // Supported language is English - len = 1; - } else { - if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) { - return NULL; - } - const char *str = usbd_desc_str[index]; - for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) { - desc_str[1 + len] = str[len]; - } - } - - // first byte is length (including header), second byte is string type - desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * len + 2)); - - return desc_str; -} - -uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) { - (void)itf; - - return usbd_desc_hid_report; -} - -// Implement callback to add our custom driver -const usbd_class_driver_t *usbd_app_driver_get_cb(uint8_t *driver_count) { - *driver_count = 1; - return usbd_app_driver; -} diff --git a/src/usb/xinput_driver.c b/src/usb/xinput_driver.c deleted file mode 100644 index b919ccb..0000000 --- a/src/usb/xinput_driver.c +++ /dev/null @@ -1,154 +0,0 @@ -#include "usb/xinput_driver.h" -#include "usb/usb_driver.h" - -#include "tusb.h" - -#define XINPUT_OUT_SIZE 32 -#define XINPUT_INTERFACE_SUBCLASS (0x5D) -#define XINPUT_INTERFACE_PROTOCOL (0x01) -#define TUD_XINPUT_DESC_LEN (39) - -const tusb_desc_device_t xinput_desc_device = { - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, - .bDeviceClass = TUSB_CLASS_VENDOR_SPECIFIC, - .bDeviceSubClass = 0xFF, - .bDeviceProtocol = 0xFF, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0x045E, - .idProduct = 0x028E, - .bcdDevice = 0x0114, - .iManufacturer = USBD_STR_MANUFACTURER, - .iProduct = USBD_STR_PRODUCT, - .iSerialNumber = USBD_STR_SERIAL, - .bNumConfigurations = 1, -}; - -enum { - USBD_ITF_XINPUT, - USBD_ITF_MAX, -}; - -#define TUD_XINPUT_DESCRIPTOR(_itfnum, _stridx) \ - 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, XINPUT_INTERFACE_SUBCLASS, \ - XINPUT_INTERFACE_PROTOCOL, _stridx, 0x10, 0x21, 0x10, 0x01, 0x01, 0x24, 0x81, 0x14, 0x03, 0x00, 0x03, 0x13, \ - 0x01, 0x00, 0x03, 0x00, 0x07, 0x05, 0x81, 0x03, 0x20, 0x00, 0x01, 0x07, 0x05, 0x01, 0x03, 0x20, 0x00, 0x08 - -#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_XINPUT_DESC_LEN) - -const uint8_t xinput_desc_cfg[USBD_DESC_LEN] = { - TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_DESC_LEN, 0, USBD_MAX_POWER_MAX), - TUD_XINPUT_DESCRIPTOR(USBD_ITF_XINPUT, USBD_STR_XINPUT), -}; - -static uint8_t endpoint_in = 0; -static uint8_t endpoint_out = 0; -static uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {}; - -bool receive_xinput_report(void) { - bool success = false; - - if (tud_ready() && (endpoint_out != 0) && (!usbd_edpt_busy(0, endpoint_out))) { - usbd_edpt_claim(0, endpoint_out); // Take control of OUT endpoint - success = usbd_edpt_xfer(0, endpoint_out, xinput_out_buffer, XINPUT_OUT_SIZE); // Retrieve report buffer - usbd_edpt_release(0, endpoint_out); // Release control of OUT endpoint - } - return success; -} - -bool send_xinput_report(usb_report_t report) { - bool success = false; - - if (tud_ready() && // Is the device ready? - (endpoint_in != 0) && (!usbd_edpt_busy(0, endpoint_in)) // Is the IN endpoint available? - ) { - usbd_edpt_claim(0, endpoint_in); // Take control of IN endpoint - success = usbd_edpt_xfer(0, endpoint_in, report.data, report.size); // Send report buffer - usbd_edpt_release(0, endpoint_in); // Release control of IN endpoint - } - - return success; -} - -static void xinput_init(void) {} - -static void xinput_reset(uint8_t rhport) { (void)rhport; } - -static uint16_t xinput_open(uint8_t rhport, tusb_desc_interface_t const *itf_descriptor, uint16_t max_length) { - uint16_t driver_length = - sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)) + 16; - - TU_VERIFY(max_length >= driver_length, 0); - - uint8_t const *current_descriptor = tu_desc_next(itf_descriptor); - uint8_t found_endpoints = 0; - while ((found_endpoints < itf_descriptor->bNumEndpoints) && (driver_length <= max_length)) { - tusb_desc_endpoint_t const *endpoint_descriptor = (tusb_desc_endpoint_t const *)current_descriptor; - if (TUSB_DESC_ENDPOINT == tu_desc_type(endpoint_descriptor)) { - TU_ASSERT(usbd_edpt_open(rhport, endpoint_descriptor)); - - if (tu_edpt_dir(endpoint_descriptor->bEndpointAddress) == TUSB_DIR_IN) - endpoint_in = endpoint_descriptor->bEndpointAddress; - else - endpoint_out = endpoint_descriptor->bEndpointAddress; - - ++found_endpoints; - } - - current_descriptor = tu_desc_next(current_descriptor); - } - return driver_length; -} - -static bool xinput_control_xfer_callback(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { - (void)rhport; - (void)stage; - (void)request; - - return true; -} - -static bool xinput_xfer_callback(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void)rhport; - (void)xferred_bytes; - - if (result == XFER_RESULT_SUCCESS && ep_addr == endpoint_out) { - if (xinput_out_buffer[0] == 0x01) { // 0x00 is rumble, 0x01 is led - usb_player_led_t player_led = {.type = USB_PLAYER_LED_ID, .id = 0}; - - switch (xinput_out_buffer[2]) { - case 0x02: - case 0x06: - player_led.id = 0x01; - break; - case 0x03: - case 0x07: - player_led.id = 0x02; - break; - case 0x04: - case 0x08: - player_led.id = 0x04; - break; - case 0x05: - case 0x09: - player_led.id = 0x08; - break; - default: - } - usb_driver_get_player_led_cb()(player_led); - } - } - return true; -} - -const usbd_class_driver_t xinput_app_driver = { -#if CFG_TUSB_DEBUG >= 2 - .name = "XINPUT", -#endif - .init = xinput_init, - .reset = xinput_reset, - .open = xinput_open, - .control_xfer_cb = xinput_control_xfer_callback, - .xfer_cb = xinput_xfer_callback, - .sof = NULL};