src/joystick/hidapi/SDL_hidapi_xboxone.c
author Ethan Lee <flibitijibibo@flibitijibibo.com>
Tue, 12 Mar 2019 20:27:54 -0400
changeset 12641 64597a7e8771
parent 12503 806492103856
child 12787 0411f841b035
permissions -rw-r--r--
hidapi: Add support for Wii U/Switch USB GameCube controller adapter.

Note that a single USB device is responsible for all 4 joysticks, so a large
rewrite of the DeviceDriver functions was necessary to allow a single device to
produce multiple joysticks.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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     SDL_JoystickID joystickID;
   128     Uint8 sequence;
   129     Uint8 last_state[USB_PACKET_LENGTH];
   130     Uint32 rumble_expiration;
   131 } SDL_DriverXboxOne_Context;
   132 
   133 
   134 static SDL_bool
   135 HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number)
   136 {
   137     return SDL_IsJoystickXboxOne(vendor_id, product_id);
   138 }
   139 
   140 static const char *
   141 HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   142 {
   143     return HIDAPI_XboxControllerName(vendor_id, product_id);
   144 }
   145 
   146 static SDL_bool
   147 HIDAPI_DriverXboxOne_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
   148 {
   149     SDL_DriverXboxOne_Context *ctx;
   150     int i;
   151     Uint8 init_packet[USB_PACKET_LENGTH];
   152 
   153     ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
   154     if (!ctx) {
   155         SDL_OutOfMemory();
   156         return SDL_FALSE;
   157     }
   158     context->context = ctx;
   159 
   160     /* Send the controller init data */
   161     for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
   162         const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
   163         if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
   164             SDL_memcpy(init_packet, packet->data, packet->size);
   165             init_packet[2] = ctx->sequence++;
   166             if (hid_write(context->device, init_packet, packet->size) != packet->size) {
   167                 SDL_SetError("Couldn't write Xbox One initialization packet");
   168                 SDL_free(ctx);
   169                 return SDL_FALSE;
   170             }
   171         }
   172     }
   173 
   174     ctx->joystickID = SDL_GetNextJoystickInstanceID();
   175     *num_joysticks += 1;
   176     SDL_PrivateJoystickAdded(ctx->joystickID);
   177 
   178     return SDL_TRUE;
   179 }
   180 
   181 static SDL_bool
   182 HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
   183 {
   184     /* Initialize the joystick capabilities */
   185     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   186     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   187     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   188 
   189     return SDL_TRUE;
   190 }
   191 
   192 static void
   193 HIDAPI_DriverXboxOne_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
   194 {
   195     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
   196 
   197     *num_joysticks -= 1;
   198     if (send_event) {
   199         SDL_PrivateJoystickRemoved(ctx->joystickID);
   200     }
   201     SDL_free(context->context);
   202 }
   203 
   204 static int
   205 HIDAPI_DriverXboxOne_NumJoysticks(SDL_HIDAPI_DriverData *context)
   206 {
   207     return 1;
   208 }
   209 
   210 static SDL_JoystickID
   211 HIDAPI_DriverXboxOne_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
   212 {
   213     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
   214     return ctx->joystickID;
   215 }
   216 
   217 static int
   218 HIDAPI_DriverXboxOne_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   219 {
   220     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
   221     Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
   222 
   223     /* The Rock Candy Xbox One Controller limits the range of
   224          low frequency rumble strength in the range of [0 - 0x99]
   225          high frequency rumble strength in the range of [0 - 0x82]
   226 
   227        I think the valid range of rumble at the firmware level is [0 - 0x7F]
   228     */
   229     rumble_packet[2] = ctx->sequence++;
   230     rumble_packet[8] = (low_frequency_rumble >> 9);
   231     rumble_packet[9] = (high_frequency_rumble >> 9);
   232 
   233     if (hid_write(context->device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   234         return SDL_SetError("Couldn't send rumble packet");
   235     }
   236 
   237     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   238         ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
   239     } else {
   240         ctx->rumble_expiration = 0;
   241     }
   242     return 0;
   243 }
   244 
   245 static void
   246 HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   247 {
   248     Sint16 axis;
   249 
   250     if (ctx->last_state[4] != data[4]) {
   251         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   252         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   253         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   254         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   255         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   256         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   257     }
   258 
   259     if (ctx->last_state[5] != data[5]) {
   260         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   261         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   262         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   263         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   264         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   265         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   266         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   267         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   268     }
   269 
   270     axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
   271     if (axis == 32704) {
   272         axis = 32767;
   273     }
   274     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   275     axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
   276     if (axis == 32704) {
   277         axis = 32767;
   278     }
   279     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   280     axis = *(Sint16*)(&data[10]);
   281     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   282     axis = *(Sint16*)(&data[12]);
   283     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
   284     axis = *(Sint16*)(&data[14]);
   285     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   286     axis = *(Sint16*)(&data[16]);
   287     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
   288 
   289     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   290 }
   291 
   292 static void
   293 HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   294 {
   295     if (data[1] == 0x30) {
   296         /* The Xbox One S controller needs acks for mode reports */
   297         const Uint8 seqnum = data[2];
   298         const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
   299         hid_write(dev, ack, sizeof(ack));
   300     }
   301 
   302     SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   303 }
   304 
   305 static SDL_bool
   306 HIDAPI_DriverXboxOne_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
   307 {
   308     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
   309     SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
   310     Uint8 data[USB_PACKET_LENGTH];
   311     int size;
   312 
   313     if (joystick == NULL) {
   314         return SDL_TRUE; /* Nothing to do right now! */
   315     }
   316 
   317     while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
   318         switch (data[0]) {
   319         case 0x20:
   320             HIDAPI_DriverXboxOne_HandleStatePacket(joystick, context->device, ctx, data, size);
   321             break;
   322         case 0x07:
   323             HIDAPI_DriverXboxOne_HandleModePacket(joystick, context->device, ctx, data, size);
   324             break;
   325         default:
   326 #ifdef DEBUG_JOYSTICK
   327             SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
   328 #endif
   329             break;
   330         }
   331     }
   332 
   333     if (ctx->rumble_expiration) {
   334         Uint32 now = SDL_GetTicks();
   335         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   336             HIDAPI_DriverXboxOne_Rumble(context, joystick, 0, 0, 0);
   337         }
   338     }
   339 
   340     return (size >= 0);
   341 }
   342 
   343 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
   344 {
   345     SDL_HINT_JOYSTICK_HIDAPI_XBOX,
   346     SDL_TRUE,
   347     HIDAPI_DriverXboxOne_IsSupportedDevice,
   348     HIDAPI_DriverXboxOne_GetDeviceName,
   349     HIDAPI_DriverXboxOne_InitDriver,
   350     HIDAPI_DriverXboxOne_QuitDriver,
   351     HIDAPI_DriverXboxOne_UpdateDriver,
   352     HIDAPI_DriverXboxOne_NumJoysticks,
   353     HIDAPI_DriverXboxOne_InstanceIDForIndex,
   354     HIDAPI_DriverXboxOne_OpenJoystick,
   355     HIDAPI_DriverXboxOne_Rumble
   356 };
   357 
   358 #endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
   359 
   360 #endif /* SDL_JOYSTICK_HIDAPI */
   361 
   362 /* vi: set ts=4 sw=4 expandtab: */