1+ /*
2+ * Copyright (c) 2026, sakumisu
3+ *
4+ * SPDX-License-Identifier: Apache-2.0
5+ */
6+ #ifndef USB_GAMEPAD_H
7+ #define USB_GAMEPAD_H
8+
9+ #include "usb_hid.h"
10+
11+ /*
12+ * GAMEPAD BUTTON LAYOUT
13+ *
14+ * ____________________________ __
15+ * / [__L2__] [__R2__] \ |
16+ * / [__ L1 __] [__ R1 __] \ | Triggers
17+ * __/________________________________\__ __|
18+ * / _ \ |
19+ * / /\ __ (B4) \ |
20+ * / || __ |A1| __ _ _ \ | Main Pad
21+ * | <===DP===> |S1| |S2| (B3) -|- (B2)| |
22+ * \ || ¯¯ ¯¯ _ / |
23+ * /\ \/ / \ / \ (B1) /\ __|
24+ * / \________ | LS | ____ | RS | _______/ \ |
25+ * | / \ \___/ / \ \___/ / \ | | Sticks
26+ * | / \_____/ \_____/ \ | __|
27+ * | / L3 R3 \ |
28+ * \_____/ \_____/
29+ *
30+ * |________|______| |______|___________|
31+ * D-Pad Left Right Face
32+ * Stick Stick Buttons
33+ *
34+ * Extended: A2=Touchpad/Capture A3=Mute L4/R4=Paddles
35+ */
36+
37+ // W3C Gamepad API standard button order
38+ // Bit position = W3C button index (trivial conversion: 1 << index)
39+ //
40+ // Gamepad XInput Switch PS3/4/5 DInput
41+ // ------ ------ ------ ------- ------
42+
43+ // Face buttons (right cluster)
44+ #define USB_GAMEPAD_BUTTON_B1 (1 << 0) // A B Cross 2
45+ #define USB_GAMEPAD_BUTTON_B2 (1 << 1) // B A Circle 3
46+ #define USB_GAMEPAD_BUTTON_B3 (1 << 2) // X Y Square 1
47+ #define USB_GAMEPAD_BUTTON_B4 (1 << 3) // Y X Triangle 4
48+
49+ // Shoulder buttons
50+ #define USB_GAMEPAD_BUTTON_L1 (1 << 4) // LB L L1 5
51+ #define USB_GAMEPAD_BUTTON_R1 (1 << 5) // RB R R1 6
52+ #define USB_GAMEPAD_BUTTON_L2 (1 << 6) // LT ZL L2 7
53+ #define USB_GAMEPAD_BUTTON_R2 (1 << 7) // RT ZR R2 8
54+
55+ // Center cluster
56+ #define USB_GAMEPAD_BUTTON_S1 (1 << 8) // Back - Select 9
57+ #define USB_GAMEPAD_BUTTON_S2 (1 << 9) // Start + Start 10
58+
59+ // Stick clicks
60+ #define USB_GAMEPAD_BUTTON_L3 (1 << 10) // LS LS L3 11
61+ #define USB_GAMEPAD_BUTTON_R3 (1 << 11) // RS RS R3 12
62+
63+ // D-pad
64+ #define USB_GAMEPAD_BUTTON_DU (1 << 12) // D-Up D-Up D-Up Hat
65+ #define USB_GAMEPAD_BUTTON_DD (1 << 13) // D-Down D-Down D-Down Hat
66+ #define USB_GAMEPAD_BUTTON_DL (1 << 14) // D-Left D-Left D-Left Hat
67+ #define USB_GAMEPAD_BUTTON_DR (1 << 15) // D-Right D-Right D-Right Hat
68+
69+ // Auxiliary
70+ #define USB_GAMEPAD_BUTTON_A1 (1 << 16) // Guide Home PS 13
71+ #define USB_GAMEPAD_BUTTON_A2 (1 << 17) // - Capture Touchpad 14
72+ #define USB_GAMEPAD_BUTTON_A3 (1 << 18) // - - Mute -
73+ #define USB_GAMEPAD_BUTTON_A4 (1 << 19) // - - - -
74+
75+ // Paddles (extended)
76+ #define USB_GAMEPAD_BUTTON_L4 (1 << 20) // P1 - - -
77+ #define USB_GAMEPAD_BUTTON_R4 (1 << 21) // P2 - - -
78+
79+ #define XINPUT_VID 0x045E // Microsoft
80+ #define XINPUT_PID 0x028E // Xbox 360 Controller
81+ #define XINPUT_BCD_DEVICE 0x0114 // v1.14
82+
83+ /* XInput (Xbox 360) USB */
84+
85+ // XInput Interface Class/Subclass/Protocol
86+ #define XINPUT_INTERFACE_CLASS 0xFF
87+ #define XINPUT_INTERFACE_SUBCLASS 0x5D
88+ #define XINPUT_INTERFACE_PROTOCOL 0x01
89+
90+ #define XINPUT_BUTTON_MASK_UP (1U << 0)
91+ #define XINPUT_BUTTON_MASK_DOWN (1U << 1)
92+ #define XINPUT_BUTTON_MASK_LEFT (1U << 2)
93+ #define XINPUT_BUTTON_MASK_RIGHT (1U << 3)
94+ #define XINPUT_BUTTON_MASK_START (1U << 4)
95+ #define XINPUT_BUTTON_MASK_BACK (1U << 5)
96+ #define XINPUT_BUTTON_MASK_L3 (1U << 6)
97+ #define XINPUT_BUTTON_MASK_R3 (1U << 7)
98+ #define XINPUT_BUTTON_MASK_LB (1U << 8)
99+ #define XINPUT_BUTTON_MASK_RB (1U << 9)
100+ #define XINPUT_BUTTON_MASK_GUIDE (1U << 10)
101+ //#define XINPUT_BUTTON_MASK_UNUSED (1U << 11)
102+ #define XINPUT_BUTTON_MASK_A (1U << 12)
103+ #define XINPUT_BUTTON_MASK_B (1U << 13)
104+ #define XINPUT_BUTTON_MASK_X (1U << 14)
105+ #define XINPUT_BUTTON_MASK_Y (1U << 15)
106+
107+ // LED patterns for report_id 0x01
108+ #define XINPUT_LED_OFF 0x00
109+ #define XINPUT_LED_BLINK 0x01
110+ #define XINPUT_LED_FLASH_1 0x02
111+ #define XINPUT_LED_FLASH_2 0x03
112+ #define XINPUT_LED_FLASH_3 0x04
113+ #define XINPUT_LED_FLASH_4 0x05
114+ #define XINPUT_LED_ON_1 0x06
115+ #define XINPUT_LED_ON_2 0x07
116+ #define XINPUT_LED_ON_3 0x08
117+ #define XINPUT_LED_ON_4 0x09
118+ #define XINPUT_LED_ROTATE 0x0A
119+ #define XINPUT_LED_BLINK_SLOW 0x0B
120+ #define XINPUT_LED_BLINK_SLOW_1 0x0C
121+ #define XINPUT_LED_BLINK_SLOW_2 0x0D
122+
123+ struct xinput_in_report {
124+ uint8_t report_id ; /* Always 0x00 */
125+ uint8_t report_size ; /* Always 0x14 (20) */
126+ uint16_t buttons ; /* DPAD, Start, Back, L3, R3, LB, RB, Guide, A, B, X, Y */
127+ uint8_t lt ; /* Left trigger (0-255) */
128+ uint8_t rt ; /* Right trigger (0-255) */
129+ int16_t lx ; /* Left stick X (-32768 to 32767) */
130+ int16_t ly ; /* Left stick Y (-32768 to 32767) */
131+ int16_t rx ; /* Right stick X (-32768 to 32767) */
132+ int16_t ry ; /* Right stick Y (-32768 to 32767) */
133+ uint8_t reserved [6 ]; /* Reserved/padding */
134+ } __PACKED ;
135+
136+ struct xinput_out_report {
137+ uint8_t report_id ; // 0x00 = rumble, 0x01 = LED
138+ uint8_t report_size ; // 0x08
139+ uint8_t led ; // LED pattern (0x00 for rumble)
140+ uint8_t rumble_l ; // Left motor (large, 0-255)
141+ uint8_t rumble_r ; // Right motor (small, 0-255)
142+ uint8_t reserved [3 ]; // Padding
143+ } __PACKED ;
144+
145+ // clang-format off
146+ #define XINPUT_DESCRIPTOR_LEN (9 + 16 + 7 + 7)
147+
148+ #define XINPUT_DESCRIPTOR_INIT (bInterfaceNumber , out_ep , in_ep ) \
149+ USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, 0x02, 0xff, 0x5d, 0x01, 0x00), /* XInput proprietary descriptor (0x21) */ \
150+ 16 , 0x21 , 0x00 , 0x01 , 0x01 , 0x24 , in_ep , 0x14 , 0x03 , 0x00 , 0x03 , 0x13 , out_ep , 0x00 , 0x03 , 0x00 , \
151+ USB_ENDPOINT_DESCRIPTOR_INIT (in_ep , 0x03 , 32 , 0x01 ), \
152+ USB_ENDPOINT_DESCRIPTOR_INIT (out_ep , 0x03 , 32 , 0x08 )
153+ // clang-format on
154+
155+ #define SWITCH_VID 0x0F0D // 0x057E Nintendo Pro Controller
156+ #define SWITCH_PID 0x0092 // 0x2009
157+ #define SWITCH_BCD_DEVICE 0x0100 // v1.00
158+
159+ // Button masks (16-bit)
160+ #define SWITCH_MASK_Y (1U << 0 )
161+ #define SWITCH_MASK_B (1U << 1 )
162+ #define SWITCH_MASK_A (1U << 2 )
163+ #define SWITCH_MASK_X (1U << 3 )
164+ #define SWITCH_MASK_L (1U << 4 )
165+ #define SWITCH_MASK_R (1U << 5 )
166+ #define SWITCH_MASK_ZL (1U << 6 )
167+ #define SWITCH_MASK_ZR (1U << 7 )
168+ #define SWITCH_MASK_MINUS (1U << 8 )
169+ #define SWITCH_MASK_PLUS (1U << 9 )
170+ #define SWITCH_MASK_L3 (1U << 10 )
171+ #define SWITCH_MASK_R3 (1U << 11 )
172+ #define SWITCH_MASK_HOME (1U << 12 )
173+ #define SWITCH_MASK_CAPTURE (1U << 13 )
174+
175+ // D-pad / Hat switch values
176+ #define SWITCH_HAT_UP 0x00
177+ #define SWITCH_HAT_UP_RIGHT 0x01
178+ #define SWITCH_HAT_RIGHT 0x02
179+ #define SWITCH_HAT_DOWN_RIGHT 0x03
180+ #define SWITCH_HAT_DOWN 0x04
181+ #define SWITCH_HAT_DOWN_LEFT 0x05
182+ #define SWITCH_HAT_LEFT 0x06
183+ #define SWITCH_HAT_UP_LEFT 0x07
184+ #define SWITCH_HAT_CENTER 0x08
185+
186+ // Analog stick range
187+ #define SWITCH_JOYSTICK_MIN 0x00
188+ #define SWITCH_JOYSTICK_MID 0x80
189+ #define SWITCH_JOYSTICK_MAX 0xFF
190+
191+ struct switch_in_report {
192+ uint16_t buttons ; // 16 button bits
193+ uint8_t hat ; // D-pad (hat switch, 0-8)
194+ uint8_t lx ; // Left stick X (0-255, 128 = center)
195+ uint8_t ly ; // Left stick Y (0-255, 128 = center)
196+ uint8_t rx ; // Right stick X (0-255, 128 = center)
197+ uint8_t ry ; // Right stick Y (0-255, 128 = center)
198+ uint8_t vendor ; // Vendor-specific byte
199+ } __PACKED ;
200+
201+ struct switch_out_report {
202+ uint8_t data [8 ]; // Vendor-specific rumble data
203+ } __PACKED ;
204+
205+ #define HID_SWITCH_REPORT_DESC_SIZE 86
206+
207+ // clang-format off
208+ #define SWITCH_DESCRIPTOR_LEN HID_CUSTOM_INOUT_DESCRIPTOR_LEN
209+
210+ #define SWITCH_DESCRIPTOR_INIT (bInterfaceNumber , out_ep , in_ep ) \
211+ HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, HID_SWITCH_REPORT_DESC_SIZE, out_ep, in_ep, 64, 0x01)
212+ // clang-format on
213+
214+ struct usb_gamepad_report {
215+ uint32_t buttons ;
216+ uint8_t lt ;
217+ uint8_t rt ;
218+ uint8_t lx ;
219+ uint8_t ly ;
220+ uint8_t rx ;
221+ uint8_t ry ;
222+ };
223+
224+ #endif /* USB_GAMEPAD_H */
0 commit comments