/
SDL_hidapi_xboxone.c
438 lines (378 loc) · 16 KB
1
2
/*
Simple DirectMedia Layer
3
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
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
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef SDL_JOYSTICK_HIDAPI
#include "SDL_hints.h"
#include "SDL_log.h"
#include "SDL_events.h"
#include "SDL_timer.h"
#include "SDL_joystick.h"
#include "SDL_gamecontroller.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
#define USB_PACKET_LENGTH 64
39
40
41
/* The amount of time to wait after hotplug to send controller init sequence */
#define CONTROLLER_INIT_DELAY_MS 100
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
/* This is the full init sequence for the Xbox One Elite Series 2 controller.
Normally it isn't needed, but this switches the controller back to wired report mode after being in Bluetooth mode.
*/
static const Uint8 xboxone_elite_init0[] = {
0x04, 0x20, 0x01, 0x00
};
static const Uint8 xboxone_elite_init1[] = {
0x01, 0x20, 0x28, 0x09, 0x00, 0x04, 0x20, 0x3A,
0x00, 0x00, 0x00, 0x31, 0x01
};
static const Uint8 xboxone_elite_init2[] = {
0x01, 0x20, 0x28, 0x09, 0x00, 0x04, 0x20, 0x6B,
0x01, 0x00, 0x00, 0x00, 0x00
};
static const Uint8 xboxone_elite_init3[] = {
0x05, 0x20, 0x02, 0x0F, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x55, 0x53, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00
};
static const Uint8 xboxone_elite_init4[] = {
0x05, 0x20, 0x03, 0x01, 0x00
};
static const Uint8 xboxone_elite_init5[] = {
0x0A, 0x20, 0x04, 0x03, 0x00, 0x01, 0x14
};
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
/*
* This packet is required for all Xbox One pads with 2015
* or later firmware installed (or present from the factory).
*/
static const Uint8 xboxone_fw2015_init[] = {
0x05, 0x20, 0x00, 0x01, 0x00
};
/*
* This packet is required for the Titanfall 2 Xbox One pads
* (0x0e6f:0x0165) to finish initialization and for Hori pads
* (0x0f0d:0x0067) to make the analog sticks work.
*/
static const Uint8 xboxone_hori_init[] = {
0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
0x00, 0x00, 0x00, 0x80, 0x00
};
/*
* This packet is required for some of the PDP pads to start
* sending input reports. These pads include: (0x0e6f:0x02ab),
* (0x0e6f:0x02a4).
*/
static const Uint8 xboxone_pdp_init1[] = {
0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
};
/*
* This packet is required for some of the PDP pads to start
* sending input reports. These pads include: (0x0e6f:0x02ab),
* (0x0e6f:0x02a4).
*/
static const Uint8 xboxone_pdp_init2[] = {
0x06, 0x20, 0x00, 0x02, 0x01, 0x00
};
/*
* A specific rumble packet is required for some PowerA pads to start
* sending input reports. One of those pads is (0x24c6:0x543a).
*/
static const Uint8 xboxone_rumblebegin_init[] = {
0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
0x1D, 0x1D, 0xFF, 0x00, 0x00
};
/*
* A rumble packet with zero FF intensity will immediately
* terminate the rumbling required to init PowerA pads.
* This should happen fast enough that the motors don't
* spin up to enough speed to actually vibrate the gamepad.
*/
static const Uint8 xboxone_rumbleend_init[] = {
0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
};
/*
* This specifies the selection of init packets that a gamepad
* will be sent on init *and* the order in which they will be
* sent. The correct sequence number will be added when the
* packet is going to be sent.
*/
typedef struct {
Uint16 vendor_id;
Uint16 product_id;
const Uint8 *data;
int size;
} SDL_DriverXboxOne_InitPacket;
137
138
139
140
static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
{ 0x0e6f, 0x0165, xboxone_hori_init, sizeof(xboxone_hori_init) },
{ 0x0f0d, 0x0067, xboxone_hori_init, sizeof(xboxone_hori_init) },
141
142
143
144
145
146
{ 0x045e, 0x0b00, xboxone_elite_init0, sizeof(xboxone_elite_init0) },
{ 0x045e, 0x0b00, xboxone_elite_init1, sizeof(xboxone_elite_init1) },
{ 0x045e, 0x0b00, xboxone_elite_init2, sizeof(xboxone_elite_init2) },
{ 0x045e, 0x0b00, xboxone_elite_init3, sizeof(xboxone_elite_init3) },
{ 0x045e, 0x0b00, xboxone_elite_init4, sizeof(xboxone_elite_init4) },
{ 0x045e, 0x0b00, xboxone_elite_init5, sizeof(xboxone_elite_init5) },
147
{ 0x0000, 0x0000, xboxone_fw2015_init, sizeof(xboxone_fw2015_init) },
148
149
{ 0x0e6f, 0x0000, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
{ 0x0e6f, 0x0000, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
150
151
152
153
154
155
156
157
158
{ 0x24c6, 0x541a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
{ 0x24c6, 0x542a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
{ 0x24c6, 0x543a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
{ 0x24c6, 0x541a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
{ 0x24c6, 0x542a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
{ 0x24c6, 0x543a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
};
typedef struct {
159
160
161
162
Uint16 vendor_id;
Uint16 product_id;
Uint32 start_time;
SDL_bool initialized;
163
164
165
166
167
168
Uint8 sequence;
Uint8 last_state[USB_PACKET_LENGTH];
Uint32 rumble_expiration;
} SDL_DriverXboxOne_Context;
169
170
171
172
173
static SDL_bool
IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
{
/* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
const Uint16 USB_VENDOR_MICROSOFT = 0x045e;
174
175
const Uint16 USB_PRODUCT_XBOX_ONE_S_REV1 = 0x02e0;
const Uint16 USB_PRODUCT_XBOX_ONE_S_REV2 = 0x02fd;
176
177
const Uint16 USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 = 0x0b05;
178
179
180
181
182
183
if (vendor_id == USB_VENDOR_MICROSOFT) {
if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1 ||
product_id == USB_PRODUCT_XBOX_ONE_S_REV2 ||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) {
return SDL_TRUE;
}
184
185
186
187
}
return SDL_FALSE;
}
188
189
190
191
192
193
194
static SDL_bool
SendControllerInit(hid_device *dev, SDL_DriverXboxOne_Context *ctx)
{
Uint16 vendor_id = ctx->vendor_id;
Uint16 product_id = ctx->product_id;
if (!IsBluetoothXboxOneController(vendor_id, product_id)) {
195
int i, j;
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
Uint8 init_packet[USB_PACKET_LENGTH];
for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
continue;
}
if (packet->product_id && (product_id != packet->product_id)) {
continue;
}
SDL_memcpy(init_packet, packet->data, packet->size);
init_packet[2] = ctx->sequence++;
if (hid_write(dev, init_packet, packet->size) != packet->size) {
SDL_SetError("Couldn't write Xbox One initialization packet");
return SDL_FALSE;
}
215
216
217
218
219
220
221
222
223
224
/* After the init we need to sync up the rumble sequence */
if (packet->data == xboxone_fw2015_init) {
for (j = 0; j < 255; ++j) {
if (hid_write(dev, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init)) != sizeof(xboxone_rumbleend_init)) {
SDL_SetError("Couldn't write Xbox One initialization packet");
return SDL_FALSE;
}
}
}
225
226
227
228
229
230
}
}
return SDL_TRUE;
}
231
static SDL_bool
232
HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
233
{
234
#ifdef __LINUX__
235
if (IsBluetoothXboxOneController(vendor_id, product_id)) {
236
237
238
/* We can't do rumble on this device, hid_write() fails, so don't try to open it here */
return SDL_FALSE;
}
239
if (vendor_id == 0x24c6 && product_id == 0x541a) {
240
/* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
241
242
return SDL_FALSE;
}
243
#endif
244
return (SDL_GetJoystickGameControllerType(vendor_id, product_id, name) == SDL_CONTROLLER_TYPE_XBOXONE);
245
246
247
248
249
}
static const char *
HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
{
250
return HIDAPI_XboxControllerName(vendor_id, product_id);
251
252
253
}
static SDL_bool
254
HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
255
256
257
258
259
260
261
262
{
SDL_DriverXboxOne_Context *ctx;
ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
SDL_OutOfMemory();
return SDL_FALSE;
}
263
*context = ctx;
264
265
266
267
ctx->vendor_id = vendor_id;
ctx->product_id = product_id;
ctx->start_time = SDL_GetTicks();
268
269
270
271
272
273
274
275
276
277
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
}
static int
278
HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
279
{
280
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
281
282
Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
283
284
285
286
if (!ctx->initialized) {
return 0;
}
287
/* Magnitude is 1..100 so scale the 16-bit input here */
288
rumble_packet[2] = ctx->sequence++;
289
290
rumble_packet[8] = low_frequency_rumble / 655;
rumble_packet[9] = high_frequency_rumble / 655;
291
292
if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
return SDL_SetError("Couldn't send rumble packet");
}
if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
} else {
ctx->rumble_expiration = 0;
}
return 0;
}
static void
HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
if (ctx->last_state[4] != data[4]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[5] != data[5]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
330
331
332
if (axis == 32704) {
axis = 32767;
}
333
334
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
335
336
337
if (axis == 32704) {
axis = 32767;
}
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
axis = *(Sint16*)(&data[10]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
axis = *(Sint16*)(&data[12]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
axis = *(Sint16*)(&data[14]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
axis = *(Sint16*)(&data[16]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static void
HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
if (data[1] == 0x30) {
/* The Xbox One S controller needs acks for mode reports */
const Uint8 seqnum = data[2];
const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
hid_write(dev, ack, sizeof(ack));
}
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
364
static SDL_bool
365
HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
366
{
367
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
368
369
370
Uint8 data[USB_PACKET_LENGTH];
int size;
371
372
373
374
375
376
377
378
379
if (!ctx->initialized) {
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->start_time + CONTROLLER_INIT_DELAY_MS)) {
if (!SendControllerInit(dev, ctx)) {
return SDL_FALSE;
}
ctx->initialized = SDL_TRUE;
}
}
380
while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
381
382
383
384
385
386
387
388
389
390
#ifdef DEBUG_XBOX_PROTOCOL
SDL_Log("Xbox One packet: size = %d\n"
" 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
" 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
" 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
size,
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
data[16], data[17], data[18], data[19]);
#endif
391
392
switch (data[0]) {
case 0x20:
393
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
394
395
break;
case 0x07:
396
HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
397
398
399
400
401
402
403
404
405
406
407
408
break;
default:
#ifdef DEBUG_JOYSTICK
SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
#endif
break;
}
}
if (ctx->rumble_expiration) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
409
HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
410
411
}
}
412
413
return (size >= 0);
414
415
}
416
417
418
419
420
421
static void
HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
{
SDL_free(context);
}
422
423
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
{
424
SDL_HINT_JOYSTICK_HIDAPI_XBOX,
425
426
427
SDL_TRUE,
HIDAPI_DriverXboxOne_IsSupportedDevice,
HIDAPI_DriverXboxOne_GetDeviceName,
428
429
430
431
HIDAPI_DriverXboxOne_Init,
HIDAPI_DriverXboxOne_Rumble,
HIDAPI_DriverXboxOne_Update,
HIDAPI_DriverXboxOne_Quit
432
433
434
435
436
437
438
};
#endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
#endif /* SDL_JOYSTICK_HIDAPI */
/* vi: set ts=4 sw=4 expandtab: */