src/joystick/hidapi/SDL_hidapi_xboxone.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 15 Aug 2018 23:35:54 -0700
changeset 12119 648377d0e573
parent 12117 8cbdc9b8b055
child 12161 12a877a0ccb5
permissions -rw-r--r--
Use a single hint for both Xbox 360 and Xbox One controllers, since they are often the same driver.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #ifdef SDL_JOYSTICK_HIDAPI
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_log.h"
    27 #include "SDL_events.h"
    28 #include "SDL_timer.h"
    29 #include "SDL_joystick.h"
    30 #include "SDL_gamecontroller.h"
    31 #include "../SDL_sysjoystick.h"
    32 #include "SDL_hidapijoystick_c.h"
    33 
    34 
    35 #ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
    36 
    37 #define USB_PACKET_LENGTH   64
    38 
    39 /*
    40  * This packet is required for all Xbox One pads with 2015
    41  * or later firmware installed (or present from the factory).
    42  */
    43 static const Uint8 xboxone_fw2015_init[] = {
    44     0x05, 0x20, 0x00, 0x01, 0x00
    45 };
    46 
    47 /*
    48  * This packet is required for the Titanfall 2 Xbox One pads
    49  * (0x0e6f:0x0165) to finish initialization and for Hori pads
    50  * (0x0f0d:0x0067) to make the analog sticks work.
    51  */
    52 static const Uint8 xboxone_hori_init[] = {
    53     0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
    54     0x00, 0x00, 0x00, 0x80, 0x00
    55 };
    56 
    57 /*
    58  * This packet is required for some of the PDP pads to start
    59  * sending input reports. These pads include: (0x0e6f:0x02ab),
    60  * (0x0e6f:0x02a4).
    61  */
    62 static const Uint8 xboxone_pdp_init1[] = {
    63     0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
    64 };
    65 
    66 /*
    67  * This packet is required for some of the PDP pads to start
    68  * sending input reports. These pads include: (0x0e6f:0x02ab),
    69  * (0x0e6f:0x02a4).
    70  */
    71 static const Uint8 xboxone_pdp_init2[] = {
    72     0x06, 0x20, 0x00, 0x02, 0x01, 0x00
    73 };
    74 
    75 /*
    76  * A specific rumble packet is required for some PowerA pads to start
    77  * sending input reports. One of those pads is (0x24c6:0x543a).
    78  */
    79 static const Uint8 xboxone_rumblebegin_init[] = {
    80     0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
    81     0x1D, 0x1D, 0xFF, 0x00, 0x00
    82 };
    83 
    84 /*
    85  * A rumble packet with zero FF intensity will immediately
    86  * terminate the rumbling required to init PowerA pads.
    87  * This should happen fast enough that the motors don't
    88  * spin up to enough speed to actually vibrate the gamepad.
    89  */
    90 static const Uint8 xboxone_rumbleend_init[] = {
    91     0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
    92     0x00, 0x00, 0x00, 0x00, 0x00
    93 };
    94 
    95 /*
    96  * This specifies the selection of init packets that a gamepad
    97  * will be sent on init *and* the order in which they will be
    98  * sent. The correct sequence number will be added when the
    99  * packet is going to be sent.
   100  */
   101 typedef struct {
   102     Uint16 vendor_id;
   103     Uint16 product_id;
   104     const Uint8 *data;
   105     int size;
   106 } SDL_DriverXboxOne_InitPacket;
   107 
   108 static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
   109     { 0x0e6f, 0x0165, xboxone_hori_init, sizeof(xboxone_hori_init) },
   110     { 0x0f0d, 0x0067, xboxone_hori_init, sizeof(xboxone_hori_init) },
   111     { 0x0000, 0x0000, xboxone_fw2015_init, sizeof(xboxone_fw2015_init) },
   112     { 0x0e6f, 0x0246, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
   113     { 0x0e6f, 0x0246, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
   114     { 0x0e6f, 0x02ab, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
   115     { 0x0e6f, 0x02ab, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
   116     { 0x0e6f, 0x02a4, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
   117     { 0x0e6f, 0x02a4, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
   118     { 0x24c6, 0x541a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
   119     { 0x24c6, 0x542a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
   120     { 0x24c6, 0x543a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
   121     { 0x24c6, 0x541a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
   122     { 0x24c6, 0x542a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
   123     { 0x24c6, 0x543a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
   124 };
   125 
   126 typedef struct {
   127     Uint8 sequence;
   128     Uint8 last_state[USB_PACKET_LENGTH];
   129     Uint32 rumble_expiration;
   130 } SDL_DriverXboxOne_Context;
   131 
   132 
   133 static SDL_bool
   134 HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, Uint16 usage_page, Uint16 usage)
   135 {
   136     return SDL_IsJoystickXboxOne(vendor_id, product_id);
   137 }
   138 
   139 static const char *
   140 HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   141 {
   142     return HIDAPI_XboxControllerName(vendor_id, product_id);
   143 }
   144 
   145 static SDL_bool
   146 HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
   147 {
   148     SDL_DriverXboxOne_Context *ctx;
   149     int i;
   150     Uint8 init_packet[USB_PACKET_LENGTH];
   151 
   152     ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
   153     if (!ctx) {
   154         SDL_OutOfMemory();
   155         return SDL_FALSE;
   156     }
   157     *context = ctx;
   158 
   159     /* Send the controller init data */
   160     for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
   161         const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
   162         if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
   163             SDL_memcpy(init_packet, packet->data, packet->size);
   164             init_packet[2] = ctx->sequence++;
   165             if (hid_write(dev, init_packet, packet->size) != packet->size) {
   166                 SDL_SetError("Couldn't write Xbox One initialization packet");
   167                 SDL_free(ctx);
   168                 return SDL_FALSE;
   169             }
   170         }
   171     }
   172 
   173     /* Initialize the joystick capabilities */
   174     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   175     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   176     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   177 
   178     return SDL_TRUE;
   179 }
   180 
   181 static int
   182 HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   183 {
   184     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
   185     Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
   186 
   187     /* The Rock Candy Xbox One Controller limits the range of
   188          low frequency rumble strength in the range of [0 - 0x99]
   189          high frequency rumble strength in the range of [0 - 0x82]
   190 
   191        I think the valid range of rumble at the firmware level is [0 - 0x7F]
   192     */
   193     rumble_packet[2] = ctx->sequence++;
   194     rumble_packet[8] = (low_frequency_rumble >> 9);
   195     rumble_packet[9] = (high_frequency_rumble >> 9);
   196 
   197     if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   198         return SDL_SetError("Couldn't send rumble packet");
   199     }
   200 
   201     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   202         ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
   203     } else {
   204         ctx->rumble_expiration = 0;
   205     }
   206     return 0;
   207 }
   208 
   209 static void
   210 HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   211 {
   212     Sint16 axis;
   213 
   214     if (ctx->last_state[4] != data[4]) {
   215         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   216         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   217         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   218         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   219         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   220         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   221     }
   222 
   223     if (ctx->last_state[5] != data[5]) {
   224         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   225         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   226         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   227         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   228         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   229         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   230         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   231         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   232     }
   233 
   234     axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
   235     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   236     axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
   237     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   238     axis = *(Sint16*)(&data[10]);
   239     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   240     axis = *(Sint16*)(&data[12]);
   241     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
   242     axis = *(Sint16*)(&data[14]);
   243     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   244     axis = *(Sint16*)(&data[16]);
   245     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
   246 
   247     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   248 }
   249 
   250 static void
   251 HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   252 {
   253     if (data[1] == 0x30) {
   254         /* The Xbox One S controller needs acks for mode reports */
   255         const Uint8 seqnum = data[2];
   256         const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
   257         hid_write(dev, ack, sizeof(ack));
   258     }
   259 
   260     SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   261 }
   262 
   263 static SDL_bool
   264 HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
   265 {
   266     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
   267     Uint8 data[USB_PACKET_LENGTH];
   268     int size;
   269 
   270     while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
   271         switch (data[0]) {
   272         case 0x20:
   273             HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
   274             break;
   275         case 0x07:
   276             HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
   277             break;
   278         default:
   279 #ifdef DEBUG_JOYSTICK
   280             SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
   281 #endif
   282             break;
   283         }
   284     }
   285 
   286     if (ctx->rumble_expiration) {
   287         Uint32 now = SDL_GetTicks();
   288         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   289             HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
   290         }
   291     }
   292 
   293 	return (size >= 0);
   294 }
   295 
   296 static void
   297 HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
   298 {
   299     SDL_free(context);
   300 }
   301 
   302 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
   303 {
   304     SDL_HINT_JOYSTICK_HIDAPI_XBOX,
   305     SDL_TRUE,
   306     HIDAPI_DriverXboxOne_IsSupportedDevice,
   307     HIDAPI_DriverXboxOne_GetDeviceName,
   308     HIDAPI_DriverXboxOne_Init,
   309     HIDAPI_DriverXboxOne_Rumble,
   310     HIDAPI_DriverXboxOne_Update,
   311     HIDAPI_DriverXboxOne_Quit
   312 };
   313 
   314 #endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
   315 
   316 #endif /* SDL_JOYSTICK_HIDAPI */
   317 
   318 /* vi: set ts=4 sw=4 expandtab: */