summaryrefslogtreecommitdiff
path: root/class/gamepad/usb_gamepad.h
blob: 8b93713a7dfe5b0b4b1945e6bb54bba907db497d (plain)
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 */