Refactor USB drivers

This commit is contained in:
Frederik Walk 2024-11-03 22:30:29 +01:00
parent fc15457cbf
commit 55c9966b88
30 changed files with 752 additions and 598 deletions

3
.gitignore vendored
View File

@ -1,6 +1,5 @@
.vscode/
build/
research
research/
*.pio.h

View File

@ -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"

View File

@ -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 <stdint.h>
#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_

View File

@ -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_

View File

@ -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 <stdint.h>
#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_
#endif // _USB_DEVICE_HID_KEYBOARD_DRIVER_H_

View File

@ -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 <stdint.h>
#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_
#endif // _USB_DEVICE_HID_PS3_DRIVER_H_

View File

@ -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 <stdint.h>
#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_
#endif // _USB_DEVICE_HID_PS4_DRIVER_H_

View File

@ -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 <stdint.h>
#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_
#endif // _USB_DEVICE_HID_SWITCH_DRIVER_H_

View File

@ -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 <stdint.h>
#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_
#endif // _USB_DEVICE_MIDI_DRIVER_H_

12
include/usb/device/vendor/common.h vendored Normal file
View File

@ -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_

View File

@ -0,0 +1,20 @@
#ifndef _USB_DEVICE_VENDOR_DEBUG_DRIVER_H_
#define _USB_DEVICE_VENDOR_DEBUG_DRIVER_H_
#include "usb/device_driver.h"
#include <stdint.h>
#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_

View File

@ -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 <stdint.h>
#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_

View File

@ -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 <stdint.h>
#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_

View File

@ -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_

View File

@ -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 <stdint.h>
#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_

View File

@ -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 <stdint.h>
#include <string>

View File

@ -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"

View File

@ -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::SettingsStore>();
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);
}

View File

@ -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",

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

22
src/usb/device/vendor/common.c vendored Normal file
View File

@ -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;
}

View File

@ -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;

256
src/usb/device/vendor/xinput_driver.c vendored Normal file
View File

@ -0,0 +1,256 @@
#include "usb/device/vendor/xinput_driver.h"
#include "device/usbd_pvt.h"
#include "tusb.h"
#include <stdlib.h>
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,
};

152
src/usb/device_driver.c Normal file
View File

@ -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 <string.h>
#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;
}

View File

@ -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;
}

View File

@ -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};