gamepad_template.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. * Copyright (c) 2026, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbd_core.h"
  7. #include "usbd_gamepad.h"
  8. #define GAMEPAD_IN_EP 0x81
  9. #define GAMEPAD_OUT_EP 0x02
  10. #define USBD_MAX_POWER 500
  11. static const uint8_t xinput_device_descriptor[] = {
  12. USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, XINPUT_VID, XINPUT_PID, XINPUT_BCD_DEVICE, 0x01)
  13. };
  14. static const uint8_t switch_device_descriptor[] = {
  15. USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, SWITCH_VID, SWITCH_PID, SWITCH_BCD_DEVICE, 0x01)
  16. };
  17. static const uint8_t xinput_config_descriptor[] = {
  18. USB_CONFIG_DESCRIPTOR_INIT((9 + XINPUT_DESCRIPTOR_LEN), 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
  19. XINPUT_DESCRIPTOR_INIT(0x00, GAMEPAD_OUT_EP, GAMEPAD_IN_EP)
  20. };
  21. static const uint8_t switch_config_descriptor[] = {
  22. USB_CONFIG_DESCRIPTOR_INIT((9 + SWITCH_DESCRIPTOR_LEN), 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
  23. SWITCH_DESCRIPTOR_INIT(0x00, GAMEPAD_OUT_EP, GAMEPAD_IN_EP)
  24. };
  25. static const char *xinput_string_descriptors[] = {
  26. (const char[]){ 0x09, 0x04 }, /* Langid */
  27. "Microsoft", /* Manufacturer */
  28. "XInput STANDARD GAMEPAD", /* Product */
  29. "1.0", /* Serial Number */
  30. };
  31. static const char *switch_string_descriptors[] = {
  32. (const char[]){ 0x09, 0x04 }, /* Langid */
  33. "HORI", /* Manufacturer */
  34. "Switch Pro Controller", /* Product */
  35. "1.0", /* Serial Number */
  36. };
  37. uint8_t gamepad_mode = USBD_GAMEPAD_MODE_XINPUT;
  38. bool gamepad_init_flag = false;
  39. static const uint8_t *device_descriptor_callback(uint8_t speed)
  40. {
  41. switch (gamepad_mode) {
  42. case USBD_GAMEPAD_MODE_XINPUT:
  43. return xinput_device_descriptor;
  44. case USBD_GAMEPAD_MODE_SWITCH:
  45. return switch_device_descriptor;
  46. case USBD_GAMEPAD_MODE_XBOXONE:
  47. break;
  48. case USBD_GAMEPAD_MODE_PS4:
  49. break;
  50. default:
  51. break;
  52. }
  53. return NULL;
  54. }
  55. static const uint8_t *config_descriptor_callback(uint8_t speed)
  56. {
  57. switch (gamepad_mode) {
  58. case USBD_GAMEPAD_MODE_XINPUT:
  59. return xinput_config_descriptor;
  60. case USBD_GAMEPAD_MODE_SWITCH:
  61. return switch_config_descriptor;
  62. case USBD_GAMEPAD_MODE_XBOXONE:
  63. break;
  64. case USBD_GAMEPAD_MODE_PS4:
  65. break;
  66. default:
  67. break;
  68. }
  69. return NULL;
  70. }
  71. static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
  72. {
  73. return NULL;
  74. }
  75. static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
  76. {
  77. if (index > 3) {
  78. return NULL;
  79. }
  80. switch (gamepad_mode) {
  81. case USBD_GAMEPAD_MODE_XINPUT:
  82. return xinput_string_descriptors[index];
  83. case USBD_GAMEPAD_MODE_SWITCH:
  84. return switch_string_descriptors[index];
  85. case USBD_GAMEPAD_MODE_XBOXONE:
  86. break;
  87. case USBD_GAMEPAD_MODE_PS4:
  88. break;
  89. default:
  90. break;
  91. }
  92. return NULL;
  93. }
  94. const struct usb_descriptor gamepad_descriptor = {
  95. .device_descriptor_callback = device_descriptor_callback,
  96. .config_descriptor_callback = config_descriptor_callback,
  97. .device_quality_descriptor_callback = device_quality_descriptor_callback,
  98. .string_descriptor_callback = string_descriptor_callback
  99. };
  100. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t gamepad_read_buffer[64];
  101. struct usb_gamepad_report gamepad_report;
  102. #define GAMEPAD_STATE_IDLE 0
  103. #define GAMEPAD_STATE_BUSY 1
  104. volatile uint8_t gamepad_state = GAMEPAD_STATE_IDLE;
  105. static void usbd_event_handler(uint8_t busid, uint8_t event)
  106. {
  107. switch (event) {
  108. case USBD_EVENT_RESET:
  109. break;
  110. case USBD_EVENT_CONNECTED:
  111. break;
  112. case USBD_EVENT_DISCONNECTED:
  113. break;
  114. case USBD_EVENT_RESUME:
  115. break;
  116. case USBD_EVENT_SUSPEND:
  117. break;
  118. case USBD_EVENT_CONFIGURED:
  119. usbd_ep_start_read(busid, GAMEPAD_OUT_EP, gamepad_read_buffer, usbd_get_ep_mps(busid, GAMEPAD_OUT_EP));
  120. break;
  121. case USBD_EVENT_SET_REMOTE_WAKEUP:
  122. break;
  123. case USBD_EVENT_CLR_REMOTE_WAKEUP:
  124. break;
  125. default:
  126. break;
  127. }
  128. }
  129. static void usbd_gamepad_int_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
  130. {
  131. gamepad_state = GAMEPAD_STATE_IDLE;
  132. }
  133. void usbd_gamepad_int_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
  134. {
  135. usbd_ep_start_read(busid, GAMEPAD_OUT_EP, gamepad_read_buffer, usbd_get_ep_mps(busid, GAMEPAD_OUT_EP));
  136. }
  137. /*!< endpoint call back */
  138. static struct usbd_endpoint gamepad_in_ep = {
  139. .ep_cb = usbd_gamepad_int_in_callback,
  140. .ep_addr = GAMEPAD_IN_EP
  141. };
  142. static struct usbd_endpoint gamepad_out_ep = {
  143. .ep_cb = usbd_gamepad_int_out_callback,
  144. .ep_addr = GAMEPAD_OUT_EP
  145. };
  146. static struct usbd_interface intf0;
  147. void gamepad_init(uint8_t busid, uintptr_t reg_base)
  148. {
  149. if (gamepad_init_flag) {
  150. return;
  151. }
  152. gamepad_init_flag = true;
  153. usbd_desc_register(busid, &gamepad_descriptor);
  154. switch (gamepad_mode) {
  155. case USBD_GAMEPAD_MODE_XINPUT:
  156. usbd_add_interface(busid, usbd_gamepad_xinput_init_intf(&intf0));
  157. break;
  158. case USBD_GAMEPAD_MODE_SWITCH:
  159. usbd_add_interface(busid, usbd_gamepad_switch_init_intf(&intf0));
  160. break;
  161. case USBD_GAMEPAD_MODE_XBOXONE:
  162. break;
  163. case USBD_GAMEPAD_MODE_PS4:
  164. break;
  165. default:
  166. break;
  167. }
  168. usbd_add_endpoint(busid, &gamepad_in_ep);
  169. usbd_add_endpoint(busid, &gamepad_out_ep);
  170. usbd_initialize(busid, reg_base, usbd_event_handler);
  171. }
  172. void gamepad_change_mode(uint8_t mode, uintptr_t reg_base)
  173. {
  174. gamepad_mode = mode;
  175. if (gamepad_init_flag) {
  176. usbd_deinitialize(0);
  177. }
  178. gamepad_init_flag = false;
  179. gamepad_init(0, reg_base);
  180. }
  181. void gamepad_test(uint8_t busid)
  182. {
  183. static uint32_t test_counter = 0;
  184. if (usb_device_is_configured(busid) == false) {
  185. return;
  186. }
  187. gamepad_state = GAMEPAD_STATE_BUSY;
  188. memset(&gamepad_report, 0, sizeof(gamepad_report));
  189. gamepad_report.buttons = (1 << (test_counter % 18));
  190. switch (gamepad_mode) {
  191. case USBD_GAMEPAD_MODE_XINPUT:
  192. usbd_gamepad_xinput_send_report(GAMEPAD_IN_EP, &gamepad_report);
  193. break;
  194. case USBD_GAMEPAD_MODE_SWITCH:
  195. usbd_gamepad_switch_send_report(GAMEPAD_IN_EP, &gamepad_report);
  196. break;
  197. case USBD_GAMEPAD_MODE_XBOXONE:
  198. break;
  199. case USBD_GAMEPAD_MODE_PS4:
  200. break;
  201. default:
  202. break;
  203. }
  204. test_counter++;
  205. while (gamepad_state == GAMEPAD_STATE_BUSY) {
  206. }
  207. }