| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- /*
- * Copyright (c) 2026, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include "usbd_core.h"
- #include "usbd_gamepad.h"
- #define GAMEPAD_IN_EP 0x81
- #define GAMEPAD_OUT_EP 0x02
- #define USBD_MAX_POWER 500
- static const uint8_t xinput_device_descriptor[] = {
- USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, XINPUT_VID, XINPUT_PID, XINPUT_BCD_DEVICE, 0x01)
- };
- static const uint8_t switch_device_descriptor[] = {
- USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, SWITCH_VID, SWITCH_PID, SWITCH_BCD_DEVICE, 0x01)
- };
- static const uint8_t xinput_config_descriptor[] = {
- USB_CONFIG_DESCRIPTOR_INIT((9 + XINPUT_DESCRIPTOR_LEN), 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- XINPUT_DESCRIPTOR_INIT(0x00, GAMEPAD_OUT_EP, GAMEPAD_IN_EP)
- };
- static const uint8_t switch_config_descriptor[] = {
- USB_CONFIG_DESCRIPTOR_INIT((9 + SWITCH_DESCRIPTOR_LEN), 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- SWITCH_DESCRIPTOR_INIT(0x00, GAMEPAD_OUT_EP, GAMEPAD_IN_EP)
- };
- static const char *xinput_string_descriptors[] = {
- (const char[]){ 0x09, 0x04 }, /* Langid */
- "Microsoft", /* Manufacturer */
- "XInput STANDARD GAMEPAD", /* Product */
- "1.0", /* Serial Number */
- };
- static const char *switch_string_descriptors[] = {
- (const char[]){ 0x09, 0x04 }, /* Langid */
- "HORI", /* Manufacturer */
- "Switch Pro Controller", /* Product */
- "1.0", /* Serial Number */
- };
- uint8_t gamepad_mode = USBD_GAMEPAD_MODE_XINPUT;
- bool gamepad_init_flag = false;
- static const uint8_t *device_descriptor_callback(uint8_t speed)
- {
- switch (gamepad_mode) {
- case USBD_GAMEPAD_MODE_XINPUT:
- return xinput_device_descriptor;
- case USBD_GAMEPAD_MODE_SWITCH:
- return switch_device_descriptor;
- case USBD_GAMEPAD_MODE_XBOXONE:
- break;
- case USBD_GAMEPAD_MODE_PS4:
- break;
- default:
- break;
- }
- return NULL;
- }
- static const uint8_t *config_descriptor_callback(uint8_t speed)
- {
- switch (gamepad_mode) {
- case USBD_GAMEPAD_MODE_XINPUT:
- return xinput_config_descriptor;
- case USBD_GAMEPAD_MODE_SWITCH:
- return switch_config_descriptor;
- case USBD_GAMEPAD_MODE_XBOXONE:
- break;
- case USBD_GAMEPAD_MODE_PS4:
- break;
- default:
- break;
- }
- return NULL;
- }
- static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
- {
- return NULL;
- }
- static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
- {
- if (index > 3) {
- return NULL;
- }
- switch (gamepad_mode) {
- case USBD_GAMEPAD_MODE_XINPUT:
- return xinput_string_descriptors[index];
- case USBD_GAMEPAD_MODE_SWITCH:
- return switch_string_descriptors[index];
- case USBD_GAMEPAD_MODE_XBOXONE:
- break;
- case USBD_GAMEPAD_MODE_PS4:
- break;
- default:
- break;
- }
- return NULL;
- }
- const struct usb_descriptor gamepad_descriptor = {
- .device_descriptor_callback = device_descriptor_callback,
- .config_descriptor_callback = config_descriptor_callback,
- .device_quality_descriptor_callback = device_quality_descriptor_callback,
- .string_descriptor_callback = string_descriptor_callback
- };
- USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t gamepad_read_buffer[64];
- struct usb_gamepad_report gamepad_report;
- #define GAMEPAD_STATE_IDLE 0
- #define GAMEPAD_STATE_BUSY 1
- volatile uint8_t gamepad_state = GAMEPAD_STATE_IDLE;
- static void usbd_event_handler(uint8_t busid, uint8_t event)
- {
- switch (event) {
- case USBD_EVENT_RESET:
- break;
- case USBD_EVENT_CONNECTED:
- break;
- case USBD_EVENT_DISCONNECTED:
- break;
- case USBD_EVENT_RESUME:
- break;
- case USBD_EVENT_SUSPEND:
- break;
- case USBD_EVENT_CONFIGURED:
- usbd_ep_start_read(busid, GAMEPAD_OUT_EP, gamepad_read_buffer, usbd_get_ep_mps(busid, GAMEPAD_OUT_EP));
- break;
- case USBD_EVENT_SET_REMOTE_WAKEUP:
- break;
- case USBD_EVENT_CLR_REMOTE_WAKEUP:
- break;
- default:
- break;
- }
- }
- static void usbd_gamepad_int_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
- {
- gamepad_state = GAMEPAD_STATE_IDLE;
- }
- void usbd_gamepad_int_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
- {
- usbd_ep_start_read(busid, GAMEPAD_OUT_EP, gamepad_read_buffer, usbd_get_ep_mps(busid, GAMEPAD_OUT_EP));
- }
- /*!< endpoint call back */
- static struct usbd_endpoint gamepad_in_ep = {
- .ep_cb = usbd_gamepad_int_in_callback,
- .ep_addr = GAMEPAD_IN_EP
- };
- static struct usbd_endpoint gamepad_out_ep = {
- .ep_cb = usbd_gamepad_int_out_callback,
- .ep_addr = GAMEPAD_OUT_EP
- };
- static struct usbd_interface intf0;
- void gamepad_init(uint8_t busid, uintptr_t reg_base)
- {
- if (gamepad_init_flag) {
- return;
- }
- gamepad_init_flag = true;
- usbd_desc_register(busid, &gamepad_descriptor);
- switch (gamepad_mode) {
- case USBD_GAMEPAD_MODE_XINPUT:
- usbd_add_interface(busid, usbd_gamepad_xinput_init_intf(&intf0));
- break;
- case USBD_GAMEPAD_MODE_SWITCH:
- usbd_add_interface(busid, usbd_gamepad_switch_init_intf(&intf0));
- break;
- case USBD_GAMEPAD_MODE_XBOXONE:
- break;
- case USBD_GAMEPAD_MODE_PS4:
- break;
- default:
- break;
- }
- usbd_add_endpoint(busid, &gamepad_in_ep);
- usbd_add_endpoint(busid, &gamepad_out_ep);
- usbd_initialize(busid, reg_base, usbd_event_handler);
- }
- void gamepad_change_mode(uint8_t mode, uintptr_t reg_base)
- {
- gamepad_mode = mode;
- if (gamepad_init_flag) {
- usbd_deinitialize(0);
- }
- gamepad_init_flag = false;
- gamepad_init(0, reg_base);
- }
- void gamepad_test(uint8_t busid)
- {
- static uint32_t test_counter = 0;
- if (usb_device_is_configured(busid) == false) {
- return;
- }
- gamepad_state = GAMEPAD_STATE_BUSY;
- memset(&gamepad_report, 0, sizeof(gamepad_report));
- gamepad_report.buttons = (1 << (test_counter % 18));
- switch (gamepad_mode) {
- case USBD_GAMEPAD_MODE_XINPUT:
- usbd_gamepad_xinput_send_report(GAMEPAD_IN_EP, &gamepad_report);
- break;
- case USBD_GAMEPAD_MODE_SWITCH:
- usbd_gamepad_switch_send_report(GAMEPAD_IN_EP, &gamepad_report);
- break;
- case USBD_GAMEPAD_MODE_XBOXONE:
- break;
- case USBD_GAMEPAD_MODE_PS4:
- break;
- default:
- break;
- }
- test_counter++;
- while (gamepad_state == GAMEPAD_STATE_BUSY) {
- }
- }
|