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