usbd_gamepad.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright (c) 2026, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbd_core.h"
  7. #include "usbd_hid.h"
  8. #include "usbd_gamepad.h"
  9. extern int hid_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len);
  10. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t gamepad_report_buffer[64];
  11. static int xinput_vendor_class_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
  12. {
  13. struct xinput_in_report xinput_report;
  14. memset(&xinput_report, 0, sizeof(xinput_report));
  15. xinput_report.report_size = 20;
  16. memcpy(*data, &xinput_report, sizeof(xinput_report));
  17. *len = sizeof(xinput_report);
  18. return 0;
  19. }
  20. int usbd_gamepad_xinput_send_report(uint8_t ep, struct usb_gamepad_report *report)
  21. {
  22. struct xinput_in_report *xinput_report;
  23. xinput_report = (struct xinput_in_report *)gamepad_report_buffer;
  24. memset(xinput_report, 0, sizeof(xinput_report));
  25. xinput_report->report_size = 20;
  26. if (report->buttons & USB_GAMEPAD_BUTTON_DU)
  27. xinput_report->buttons |= XINPUT_BUTTON_MASK_UP;
  28. if (report->buttons & USB_GAMEPAD_BUTTON_DD)
  29. xinput_report->buttons |= XINPUT_BUTTON_MASK_DOWN;
  30. if (report->buttons & USB_GAMEPAD_BUTTON_DL)
  31. xinput_report->buttons |= XINPUT_BUTTON_MASK_LEFT;
  32. if (report->buttons & USB_GAMEPAD_BUTTON_DR)
  33. xinput_report->buttons |= XINPUT_BUTTON_MASK_RIGHT;
  34. if (report->buttons & USB_GAMEPAD_BUTTON_S2)
  35. xinput_report->buttons |= XINPUT_BUTTON_MASK_START;
  36. if (report->buttons & USB_GAMEPAD_BUTTON_S1)
  37. xinput_report->buttons |= XINPUT_BUTTON_MASK_BACK;
  38. if (report->buttons & USB_GAMEPAD_BUTTON_L3)
  39. xinput_report->buttons |= XINPUT_BUTTON_MASK_L3;
  40. if (report->buttons & USB_GAMEPAD_BUTTON_R3)
  41. xinput_report->buttons |= XINPUT_BUTTON_MASK_R3;
  42. if (report->buttons & USB_GAMEPAD_BUTTON_L1)
  43. xinput_report->buttons |= XINPUT_BUTTON_MASK_LB;
  44. if (report->buttons & USB_GAMEPAD_BUTTON_R1)
  45. xinput_report->buttons |= XINPUT_BUTTON_MASK_RB;
  46. if (report->buttons & USB_GAMEPAD_BUTTON_A1)
  47. xinput_report->buttons |= XINPUT_BUTTON_MASK_GUIDE;
  48. if (report->buttons & USB_GAMEPAD_BUTTON_B1)
  49. xinput_report->buttons |= XINPUT_BUTTON_MASK_A;
  50. if (report->buttons & USB_GAMEPAD_BUTTON_B2)
  51. xinput_report->buttons |= XINPUT_BUTTON_MASK_B;
  52. if (report->buttons & USB_GAMEPAD_BUTTON_B3)
  53. xinput_report->buttons |= XINPUT_BUTTON_MASK_X;
  54. if (report->buttons & USB_GAMEPAD_BUTTON_B4)
  55. xinput_report->buttons |= XINPUT_BUTTON_MASK_Y;
  56. // Analog triggers (0-255), fall back to digital if analog is 0 but button pressed
  57. xinput_report->lt = report->lt;
  58. xinput_report->rt = report->rt;
  59. if (xinput_report->lt == 0 && (report->buttons & USB_GAMEPAD_BUTTON_L2))
  60. xinput_report->lt = 0xFF;
  61. if (xinput_report->rt == 0 && (report->buttons & USB_GAMEPAD_BUTTON_R2))
  62. xinput_report->rt = 0xFF;
  63. return usbd_ep_start_write(0, ep, gamepad_report_buffer, sizeof(struct xinput_in_report));
  64. }
  65. // Convert gamepad dpad mask to switch hat value
  66. static uint8_t convert_dpad_to_switch_hat(uint32_t buttons)
  67. {
  68. // Joypad uses active-high (1 = pressed)
  69. uint8_t up = (buttons & USB_GAMEPAD_BUTTON_DU) ? 1 : 0;
  70. uint8_t down = (buttons & USB_GAMEPAD_BUTTON_DD) ? 1 : 0;
  71. uint8_t left = (buttons & USB_GAMEPAD_BUTTON_DL) ? 1 : 0;
  72. uint8_t right = (buttons & USB_GAMEPAD_BUTTON_DR) ? 1 : 0;
  73. if (up && right)
  74. return SWITCH_HAT_UP_RIGHT;
  75. if (up && left)
  76. return SWITCH_HAT_UP_LEFT;
  77. if (down && right)
  78. return SWITCH_HAT_DOWN_RIGHT;
  79. if (down && left)
  80. return SWITCH_HAT_DOWN_LEFT;
  81. if (up)
  82. return SWITCH_HAT_UP;
  83. if (down)
  84. return SWITCH_HAT_DOWN;
  85. if (left)
  86. return SWITCH_HAT_LEFT;
  87. if (right)
  88. return SWITCH_HAT_RIGHT;
  89. return SWITCH_HAT_CENTER;
  90. }
  91. int usbd_gamepad_switch_send_report(uint8_t ep, struct usb_gamepad_report *report)
  92. {
  93. struct switch_in_report *switch_report;
  94. switch_report = (struct switch_in_report *)gamepad_report_buffer;
  95. memset(switch_report, 0, sizeof(switch_report));
  96. if (report->buttons & USB_GAMEPAD_BUTTON_S1)
  97. switch_report->buttons |= SWITCH_MASK_MINUS;
  98. if (report->buttons & USB_GAMEPAD_BUTTON_S2)
  99. switch_report->buttons |= SWITCH_MASK_PLUS;
  100. if (report->buttons & USB_GAMEPAD_BUTTON_L1)
  101. switch_report->buttons |= SWITCH_MASK_L;
  102. if (report->buttons & USB_GAMEPAD_BUTTON_R1)
  103. switch_report->buttons |= SWITCH_MASK_R;
  104. if (report->buttons & USB_GAMEPAD_BUTTON_L2)
  105. switch_report->buttons |= SWITCH_MASK_ZL;
  106. if (report->buttons & USB_GAMEPAD_BUTTON_R2)
  107. switch_report->buttons |= SWITCH_MASK_ZR;
  108. if (report->buttons & USB_GAMEPAD_BUTTON_L3)
  109. switch_report->buttons |= SWITCH_MASK_L3;
  110. if (report->buttons & USB_GAMEPAD_BUTTON_R3)
  111. switch_report->buttons |= SWITCH_MASK_R3;
  112. if (report->buttons & USB_GAMEPAD_BUTTON_A1)
  113. switch_report->buttons |= SWITCH_MASK_HOME;
  114. if (report->buttons & USB_GAMEPAD_BUTTON_A2)
  115. switch_report->buttons |= SWITCH_MASK_CAPTURE;
  116. if (report->buttons & USB_GAMEPAD_BUTTON_B1)
  117. switch_report->buttons |= SWITCH_MASK_B;
  118. if (report->buttons & USB_GAMEPAD_BUTTON_B2)
  119. switch_report->buttons |= SWITCH_MASK_A;
  120. if (report->buttons & USB_GAMEPAD_BUTTON_B3)
  121. switch_report->buttons |= SWITCH_MASK_Y;
  122. if (report->buttons & USB_GAMEPAD_BUTTON_B4)
  123. switch_report->buttons |= SWITCH_MASK_X;
  124. switch_report->hat = convert_dpad_to_switch_hat(report->buttons);
  125. // Analog sticks (HID convention: 0=up, 255=down - no inversion needed)
  126. switch_report->lx = report->lx;
  127. switch_report->ly = report->ly;
  128. switch_report->rx = report->rx;
  129. switch_report->ry = report->ry;
  130. switch_report->vendor = 0;
  131. return usbd_ep_start_write(0, ep, gamepad_report_buffer, sizeof(struct switch_in_report));
  132. }
  133. struct usbd_interface *usbd_gamepad_xinput_init_intf(struct usbd_interface *intf)
  134. {
  135. intf->class_interface_handler = NULL;
  136. intf->class_endpoint_handler = NULL;
  137. intf->vendor_handler = xinput_vendor_class_request_handler;
  138. intf->notify_handler = NULL;
  139. return intf;
  140. }
  141. static const uint8_t hid_switch_report_desc[HID_SWITCH_REPORT_DESC_SIZE] = {
  142. 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
  143. 0x09, 0x05, // Usage (Game Pad)
  144. 0xA1, 0x01, // Collection (Application)
  145. 0x15, 0x00, // Logical Minimum (0)
  146. 0x25, 0x01, // Logical Maximum (1)
  147. 0x35, 0x00, // Physical Minimum (0)
  148. 0x45, 0x01, // Physical Maximum (1)
  149. 0x75, 0x01, // Report Size (1)
  150. 0x95, 0x10, // Report Count (16)
  151. 0x05, 0x09, // Usage Page (Button)
  152. 0x19, 0x01, // Usage Minimum (Button 1)
  153. 0x29, 0x10, // Usage Maximum (Button 16)
  154. 0x81, 0x02, // Input (Data,Var,Abs)
  155. 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
  156. 0x25, 0x07, // Logical Maximum (7)
  157. 0x46, 0x3B, 0x01, // Physical Maximum (315)
  158. 0x75, 0x04, // Report Size (4)
  159. 0x95, 0x01, // Report Count (1)
  160. 0x65, 0x14, // Unit (Eng Rot:Angular Pos)
  161. 0x09, 0x39, // Usage (Hat switch)
  162. 0x81, 0x42, // Input (Data,Var,Abs,Null)
  163. 0x65, 0x00, // Unit (None)
  164. 0x95, 0x01, // Report Count (1)
  165. 0x81, 0x01, // Input (Const) - 4-bit padding
  166. 0x26, 0xFF, 0x00, // Logical Maximum (255)
  167. 0x46, 0xFF, 0x00, // Physical Maximum (255)
  168. 0x09, 0x30, // Usage (X) - Left Stick X
  169. 0x09, 0x31, // Usage (Y) - Left Stick Y
  170. 0x09, 0x32, // Usage (Z) - Right Stick X
  171. 0x09, 0x35, // Usage (Rz) - Right Stick Y
  172. 0x75, 0x08, // Report Size (8)
  173. 0x95, 0x04, // Report Count (4)
  174. 0x81, 0x02, // Input (Data,Var,Abs)
  175. 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined)
  176. 0x09, 0x20, // Usage (0x20)
  177. 0x95, 0x01, // Report Count (1)
  178. 0x81, 0x02, // Input (Data,Var,Abs) - Vendor byte
  179. 0x0A, 0x21, 0x26, // Usage (0x2621)
  180. 0x95, 0x08, // Report Count (8)
  181. 0x91, 0x02, // Output (Data,Var,Abs) - Rumble
  182. 0xC0, // End Collection
  183. };
  184. struct usbd_interface *usbd_gamepad_switch_init_intf(struct usbd_interface *intf)
  185. {
  186. intf->class_interface_handler = hid_class_interface_request_handler;
  187. intf->class_endpoint_handler = NULL;
  188. intf->vendor_handler = NULL;
  189. intf->notify_handler = NULL;
  190. intf->hid_report_descriptor = hid_switch_report_desc;
  191. intf->hid_report_descriptor_len = HID_SWITCH_REPORT_DESC_SIZE;
  192. return intf;
  193. }