Added missing files from previous commits
authorSam Lantinga <slouken@libsdl.org>
Thu, 19 Dec 2019 15:02:12 -0800
changeset 1335769329f5f992b
parent 13356 6c431d30a6df
child 13358 a6c41c779a86
Added missing files from previous commits
src/joystick/hidapi/SDL_hidapi_gamecube.c
src/joystick/hidapi/SDL_hidapi_xbox360w.c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c	Thu Dec 19 15:02:12 2019 -0800
     1.3 @@ -0,0 +1,343 @@
     1.4 +/*
     1.5 +  Simple DirectMedia Layer
     1.6 +  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     1.7 +
     1.8 +  This software is provided 'as-is', without any express or implied
     1.9 +  warranty.  In no event will the authors be held liable for any damages
    1.10 +  arising from the use of this software.
    1.11 +
    1.12 +  Permission is granted to anyone to use this software for any purpose,
    1.13 +  including commercial applications, and to alter it and redistribute it
    1.14 +  freely, subject to the following restrictions:
    1.15 +
    1.16 +  1. The origin of this software must not be misrepresented; you must not
    1.17 +     claim that you wrote the original software. If you use this software
    1.18 +     in a product, an acknowledgment in the product documentation would be
    1.19 +     appreciated but is not required.
    1.20 +  2. Altered source versions must be plainly marked as such, and must not be
    1.21 +     misrepresented as being the original software.
    1.22 +  3. This notice may not be removed or altered from any source distribution.
    1.23 +*/
    1.24 +#include "../../SDL_internal.h"
    1.25 +
    1.26 +#ifdef SDL_JOYSTICK_HIDAPI
    1.27 +
    1.28 +#include "SDL_hints.h"
    1.29 +#include "SDL_log.h"
    1.30 +#include "SDL_events.h"
    1.31 +#include "SDL_timer.h"
    1.32 +#include "SDL_haptic.h"
    1.33 +#include "SDL_joystick.h"
    1.34 +#include "SDL_gamecontroller.h"
    1.35 +#include "../SDL_sysjoystick.h"
    1.36 +#include "SDL_hidapijoystick_c.h"
    1.37 +
    1.38 +
    1.39 +#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
    1.40 +
    1.41 +typedef struct {
    1.42 +    SDL_JoystickID joysticks[4];
    1.43 +    Uint8 wireless[4];
    1.44 +    Uint8 rumbleAllowed[4];
    1.45 +    Uint8 rumble[5];
    1.46 +    Uint32 rumbleExpiration[4];
    1.47 +    /* Without this variable, hid_write starts to lag a TON */
    1.48 +    SDL_bool rumbleUpdate;
    1.49 +} SDL_DriverGameCube_Context;
    1.50 +
    1.51 +static SDL_bool
    1.52 +HIDAPI_DriverGameCube_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
    1.53 +{
    1.54 +    if (vendor_id == 0x057e && product_id == 0x0337) {
    1.55 +        /* Nintendo Co., Ltd.  Wii U GameCube Controller Adapter */
    1.56 +        return SDL_TRUE;
    1.57 +    }
    1.58 +    return SDL_FALSE;
    1.59 +}
    1.60 +
    1.61 +static const char *
    1.62 +HIDAPI_DriverGameCube_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
    1.63 +{
    1.64 +    return "Nintendo GameCube Controller";
    1.65 +}
    1.66 +
    1.67 +static SDL_bool
    1.68 +HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
    1.69 +{
    1.70 +    SDL_DriverGameCube_Context *ctx;
    1.71 +    Uint8 packet[37];
    1.72 +    Uint8 *curSlot;
    1.73 +    Uint8 i;
    1.74 +    int size;
    1.75 +    Uint8 initMagic = 0x13;
    1.76 +    Uint8 rumbleMagic = 0x11;
    1.77 +
    1.78 +    ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
    1.79 +    if (!ctx) {
    1.80 +        SDL_OutOfMemory();
    1.81 +        return SDL_FALSE;
    1.82 +    }
    1.83 +
    1.84 +    device->dev = hid_open_path(device->path, 0);
    1.85 +    if (!device->dev) {
    1.86 +        SDL_free(ctx);
    1.87 +        SDL_SetError("Couldn't open %s", device->path);
    1.88 +        return SDL_FALSE;
    1.89 +    }
    1.90 +    device->context = ctx;
    1.91 +
    1.92 +    ctx->joysticks[0] = -1;
    1.93 +    ctx->joysticks[1] = -1;
    1.94 +    ctx->joysticks[2] = -1;
    1.95 +    ctx->joysticks[3] = -1;
    1.96 +    ctx->rumble[0] = rumbleMagic;
    1.97 +
    1.98 +    /* This is all that's needed to initialize the device. Really! */
    1.99 +    if (hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
   1.100 +        SDL_SetError("Couldn't initialize WUP-028");
   1.101 +        goto error;
   1.102 +    }
   1.103 +
   1.104 +    /* Add all the applicable joysticks */
   1.105 +    while ((size = hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
   1.106 +        if (size < 37 || packet[0] != 0x21) {
   1.107 +            continue; /* Nothing to do yet...? */
   1.108 +        }
   1.109 +
   1.110 +        /* Go through all 4 slots */
   1.111 +        curSlot = packet + 1;
   1.112 +        for (i = 0; i < 4; i += 1, curSlot += 9) {
   1.113 +            ctx->wireless[i] = (curSlot[0] & 0x20) != 0;
   1.114 +
   1.115 +            /* Only allow rumble if the adapter's second USB cable is connected */
   1.116 +            ctx->rumbleAllowed[i] = (curSlot[0] & 0x04) != 0 && !ctx->wireless[i];
   1.117 +
   1.118 +            if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
   1.119 +                if (ctx->joysticks[i] == -1) {
   1.120 +                    HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
   1.121 +                }
   1.122 +            } else {
   1.123 +                if (ctx->joysticks[i] != -1) {
   1.124 +                    HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
   1.125 +                    ctx->joysticks[i] = -1;
   1.126 +                }
   1.127 +                continue;
   1.128 +            }
   1.129 +        }
   1.130 +    }
   1.131 +
   1.132 +    return SDL_TRUE;
   1.133 +
   1.134 +error:
   1.135 +    if (device->dev) {
   1.136 +        hid_close(device->dev);
   1.137 +        device->dev = NULL;
   1.138 +    }
   1.139 +    if (device->context) {
   1.140 +        SDL_free(device->context);
   1.141 +        device->context = NULL;
   1.142 +    }
   1.143 +    return SDL_FALSE;
   1.144 +}
   1.145 +
   1.146 +static SDL_bool
   1.147 +HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
   1.148 +{
   1.149 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
   1.150 +    SDL_Joystick *joystick;
   1.151 +    Uint8 packet[37];
   1.152 +    Uint8 *curSlot;
   1.153 +    Uint32 now;
   1.154 +    Uint8 i;
   1.155 +    int size;
   1.156 +
   1.157 +    /* Read input packet */
   1.158 +    while ((size = hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
   1.159 +        if (size < 37 || packet[0] != 0x21) {
   1.160 +            continue; /* Nothing to do right now...? */
   1.161 +        }
   1.162 +
   1.163 +        /* Go through all 4 slots */
   1.164 +        curSlot = packet + 1;
   1.165 +        for (i = 0; i < 4; i += 1, curSlot += 9) {
   1.166 +            ctx->wireless[i] = (curSlot[0] & 0x20) != 0;
   1.167 +
   1.168 +            /* Only allow rumble if the adapter's second USB cable is connected */
   1.169 +            ctx->rumbleAllowed[i] = (curSlot[0] & 0x04) != 0 && !ctx->wireless[i];
   1.170 +
   1.171 +            if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
   1.172 +                if (ctx->joysticks[i] == -1) {
   1.173 +                    HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
   1.174 +                }
   1.175 +                joystick = SDL_JoystickFromInstanceID(ctx->joysticks[i]);
   1.176 +
   1.177 +                /* Hasn't been opened yet, skip */
   1.178 +                if (joystick == NULL) {
   1.179 +                    continue;
   1.180 +                }
   1.181 +            } else {
   1.182 +                if (ctx->joysticks[i] != -1) {
   1.183 +                    HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
   1.184 +                    ctx->joysticks[i] = -1;
   1.185 +                }
   1.186 +                continue;
   1.187 +            }
   1.188 +
   1.189 +            #define READ_BUTTON(off, flag, button) \
   1.190 +                SDL_PrivateJoystickButton( \
   1.191 +                    joystick, \
   1.192 +                    button, \
   1.193 +                    (curSlot[off] & flag) ? SDL_PRESSED : SDL_RELEASED \
   1.194 +                );
   1.195 +            READ_BUTTON(1, 0x01, 0) /* A */
   1.196 +            READ_BUTTON(1, 0x02, 1) /* B */
   1.197 +            READ_BUTTON(1, 0x04, 2) /* X */
   1.198 +            READ_BUTTON(1, 0x08, 3) /* Y */
   1.199 +            READ_BUTTON(1, 0x10, 4) /* DPAD_LEFT */
   1.200 +            READ_BUTTON(1, 0x20, 5) /* DPAD_RIGHT */
   1.201 +            READ_BUTTON(1, 0x40, 6) /* DPAD_DOWN */
   1.202 +            READ_BUTTON(1, 0x80, 7) /* DPAD_UP */
   1.203 +            READ_BUTTON(2, 0x01, 8) /* START */
   1.204 +            READ_BUTTON(2, 0x02, 9) /* RIGHTSHOULDER */
   1.205 +            /* These two buttons are for the bottoms of the analog triggers.
   1.206 +             * More than likely, you're going to want to read the axes instead!
   1.207 +             * -flibit
   1.208 +             */
   1.209 +            READ_BUTTON(2, 0x04, 10) /* TRIGGERRIGHT */
   1.210 +            READ_BUTTON(2, 0x08, 11) /* TRIGGERLEFT */
   1.211 +            #undef READ_BUTTON
   1.212 +
   1.213 +            /* Axis math taken from SDL_xinputjoystick.c */
   1.214 +            #define READ_AXIS(off, axis) \
   1.215 +                SDL_PrivateJoystickAxis( \
   1.216 +                    joystick, \
   1.217 +                    axis, \
   1.218 +                    (Sint16)(((int)curSlot[off] * 257) - 32768) \
   1.219 +                );
   1.220 +            READ_AXIS(3, 0) /* LEFTX */
   1.221 +            READ_AXIS(4, 1) /* LEFTY */
   1.222 +            READ_AXIS(5, 2) /* RIGHTX */
   1.223 +            READ_AXIS(6, 3) /* RIGHTY */
   1.224 +            READ_AXIS(7, 4) /* TRIGGERLEFT */
   1.225 +            READ_AXIS(8, 5) /* TRIGGERRIGHT */
   1.226 +            #undef READ_AXIS
   1.227 +        }
   1.228 +    }
   1.229 +
   1.230 +    /* Write rumble packet */
   1.231 +    now = SDL_GetTicks();
   1.232 +    for (i = 0; i < 4; i += 1) {
   1.233 +        if (ctx->rumbleExpiration[i] > 0) {
   1.234 +            if (SDL_TICKS_PASSED(now, ctx->rumbleExpiration[i]) || !ctx->rumbleAllowed[i]) {
   1.235 +                ctx->rumble[1 + i] = 0;
   1.236 +                ctx->rumbleExpiration[i] = 0;
   1.237 +                ctx->rumbleUpdate = SDL_TRUE;
   1.238 +            }
   1.239 +        }
   1.240 +    }
   1.241 +    if (ctx->rumbleUpdate) {
   1.242 +        hid_write(device->dev, ctx->rumble, sizeof(ctx->rumble));
   1.243 +        ctx->rumbleUpdate = SDL_FALSE;
   1.244 +    }
   1.245 +
   1.246 +    /* If we got here, nothing bad happened! */
   1.247 +    return SDL_TRUE;
   1.248 +}
   1.249 +
   1.250 +static SDL_bool
   1.251 +HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
   1.252 +{
   1.253 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
   1.254 +    Uint8 i;
   1.255 +    for (i = 0; i < 4; i += 1) {
   1.256 +        if (joystick->instance_id == ctx->joysticks[i]) {
   1.257 +            joystick->nbuttons = 12;
   1.258 +            joystick->naxes = 6;
   1.259 +            joystick->epowerlevel = ctx->wireless[i] ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
   1.260 +            joystick->player_index = i;
   1.261 +            return SDL_TRUE;
   1.262 +        }
   1.263 +    }
   1.264 +    return SDL_FALSE; /* Should never get here! */
   1.265 +}
   1.266 +
   1.267 +static int
   1.268 +HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   1.269 +{
   1.270 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
   1.271 +    Uint8 i, val;
   1.272 +    for (i = 0; i < 4; i += 1) {
   1.273 +        if (joystick->instance_id == ctx->joysticks[i]) {
   1.274 +            if (ctx->wireless[i]) {
   1.275 +                return SDL_SetError("Ninteno GameCube WaveBird controllers do not support rumble");
   1.276 +            }
   1.277 +            if (!ctx->rumbleAllowed[i]) {
   1.278 +                return SDL_SetError("Second USB cable for WUP-028 not connected");
   1.279 +            }
   1.280 +            val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
   1.281 +            if (val != ctx->rumble[i + 1]) {
   1.282 +                ctx->rumble[i + 1] = val;
   1.283 +                ctx->rumbleUpdate = SDL_TRUE;
   1.284 +            }
   1.285 +            if (val && duration_ms < SDL_HAPTIC_INFINITY) {
   1.286 +                ctx->rumbleExpiration[i] = SDL_GetTicks() + duration_ms;
   1.287 +            } else {
   1.288 +                ctx->rumbleExpiration[i] = 0;
   1.289 +            }
   1.290 +            return 0;
   1.291 +        }
   1.292 +    }
   1.293 +
   1.294 +    /* Should never get here! */
   1.295 +    SDL_SetError("Couldn't find joystick");
   1.296 +    return -1;
   1.297 +}
   1.298 +
   1.299 +static void
   1.300 +HIDAPI_DriverGameCube_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
   1.301 +{
   1.302 +    SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
   1.303 +    Uint8 i;
   1.304 +
   1.305 +    /* Stop rumble activity */
   1.306 +    for (i = 0; i < 4; i += 1) {
   1.307 +        if (joystick->instance_id == ctx->joysticks[i]) {
   1.308 +            if (!ctx->wireless[i] && ctx->rumbleAllowed[i] && ctx->rumble[1 + i] != 0) {
   1.309 +                ctx->rumble[1 + i] = 0;
   1.310 +                ctx->rumbleExpiration[i] = 0;
   1.311 +                hid_write(device->dev, ctx->rumble, sizeof(ctx->rumble));
   1.312 +            }
   1.313 +            break;
   1.314 +        }
   1.315 +    }
   1.316 +}
   1.317 +
   1.318 +static void
   1.319 +HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device)
   1.320 +{
   1.321 +    hid_close(device->dev);
   1.322 +    device->dev = NULL;
   1.323 +
   1.324 +    SDL_free(device->context);
   1.325 +    device->context = NULL;
   1.326 +}
   1.327 +
   1.328 +SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
   1.329 +{
   1.330 +    SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE,
   1.331 +    SDL_TRUE,
   1.332 +    HIDAPI_DriverGameCube_IsSupportedDevice,
   1.333 +    HIDAPI_DriverGameCube_GetDeviceName,
   1.334 +    HIDAPI_DriverGameCube_InitDevice,
   1.335 +    HIDAPI_DriverGameCube_UpdateDevice,
   1.336 +    HIDAPI_DriverGameCube_OpenJoystick,
   1.337 +    HIDAPI_DriverGameCube_RumbleJoystick,
   1.338 +    HIDAPI_DriverGameCube_CloseJoystick,
   1.339 +    HIDAPI_DriverGameCube_FreeDevice
   1.340 +};
   1.341 +
   1.342 +#endif /* SDL_JOYSTICK_HIDAPI_GAMECUBE */
   1.343 +
   1.344 +#endif /* SDL_JOYSTICK_HIDAPI */
   1.345 +
   1.346 +/* vi: set ts=4 sw=4 expandtab: */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c	Thu Dec 19 15:02:12 2019 -0800
     2.3 @@ -0,0 +1,311 @@
     2.4 +/*
     2.5 +  Simple DirectMedia Layer
     2.6 +  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     2.7 +
     2.8 +  This software is provided 'as-is', without any express or implied
     2.9 +  warranty.  In no event will the authors be held liable for any damages
    2.10 +  arising from the use of this software.
    2.11 +
    2.12 +  Permission is granted to anyone to use this software for any purpose,
    2.13 +  including commercial applications, and to alter it and redistribute it
    2.14 +  freely, subject to the following restrictions:
    2.15 +
    2.16 +  1. The origin of this software must not be misrepresented; you must not
    2.17 +     claim that you wrote the original software. If you use this software
    2.18 +     in a product, an acknowledgment in the product documentation would be
    2.19 +     appreciated but is not required.
    2.20 +  2. Altered source versions must be plainly marked as such, and must not be
    2.21 +     misrepresented as being the original software.
    2.22 +  3. This notice may not be removed or altered from any source distribution.
    2.23 +*/
    2.24 +#include "../../SDL_internal.h"
    2.25 +
    2.26 +#ifdef SDL_JOYSTICK_HIDAPI
    2.27 +
    2.28 +#include "SDL_hints.h"
    2.29 +#include "SDL_log.h"
    2.30 +#include "SDL_events.h"
    2.31 +#include "SDL_timer.h"
    2.32 +#include "SDL_joystick.h"
    2.33 +#include "SDL_gamecontroller.h"
    2.34 +#include "../SDL_sysjoystick.h"
    2.35 +#include "SDL_hidapijoystick_c.h"
    2.36 +
    2.37 +
    2.38 +#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
    2.39 +
    2.40 +#define USB_PACKET_LENGTH   64
    2.41 +
    2.42 +
    2.43 +typedef struct {
    2.44 +    SDL_bool connected;
    2.45 +    Uint8 last_state[USB_PACKET_LENGTH];
    2.46 +    Uint32 rumble_expiration;
    2.47 +} SDL_DriverXbox360W_Context;
    2.48 +
    2.49 +
    2.50 +static SDL_bool
    2.51 +HIDAPI_DriverXbox360W_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
    2.52 +{
    2.53 +    const Uint16 MICROSOFT_USB_VID = 0x045e;
    2.54 +
    2.55 +    if (vendor_id == MICROSOFT_USB_VID) {
    2.56 +        return (product_id == 0x0291 || product_id == 0x0719);
    2.57 +    }
    2.58 +    return SDL_FALSE;
    2.59 +}
    2.60 +
    2.61 +static const char *
    2.62 +HIDAPI_DriverXbox360W_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
    2.63 +{
    2.64 +    return "Xbox 360 Wireless Controller";
    2.65 +}
    2.66 +
    2.67 +static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
    2.68 +{
    2.69 +    Uint8 mode = 0x02 + slot;
    2.70 +    const Uint8 led_packet[] = { 0x00, 0x00, 0x08, (0x40 + (mode % 0x0e)), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    2.71 +
    2.72 +    if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
    2.73 +        return SDL_FALSE;
    2.74 +    }
    2.75 +    return SDL_TRUE;
    2.76 +}
    2.77 +
    2.78 +static void
    2.79 +UpdatePowerLevel(SDL_Joystick *joystick, Uint8 level)
    2.80 +{
    2.81 +    float normalized_level = (float)level / 255.0f;
    2.82 +
    2.83 +    if (normalized_level <= 0.05f) {
    2.84 +        joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
    2.85 +    } else if (normalized_level <= 0.20f) {
    2.86 +        joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
    2.87 +    } else if (normalized_level <= 0.70f) {
    2.88 +        joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
    2.89 +    } else {
    2.90 +        joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
    2.91 +    }
    2.92 +}
    2.93 +
    2.94 +static SDL_bool
    2.95 +HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
    2.96 +{
    2.97 +    SDL_DriverXbox360W_Context *ctx;
    2.98 +
    2.99 +    /* Requests controller presence information from the wireless dongle */
   2.100 +	const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
   2.101 +
   2.102 +    ctx = (SDL_DriverXbox360W_Context *)SDL_calloc(1, sizeof(*ctx));
   2.103 +    if (!ctx) {
   2.104 +        SDL_OutOfMemory();
   2.105 +        return SDL_FALSE;
   2.106 +    }
   2.107 +
   2.108 +    device->dev = hid_open_path(device->path, 0);
   2.109 +    if (!device->dev) {
   2.110 +        SDL_free(ctx);
   2.111 +        SDL_SetError("Couldn't open %s", device->path);
   2.112 +        return SDL_FALSE;
   2.113 +    }
   2.114 +    device->context = ctx;
   2.115 +
   2.116 +    if (hid_write(device->dev, init_packet, sizeof(init_packet)) != sizeof(init_packet)) {
   2.117 +        SDL_SetError("Couldn't write init packet");
   2.118 +        return SDL_FALSE;
   2.119 +    }
   2.120 +
   2.121 +    return SDL_TRUE;
   2.122 +}
   2.123 +
   2.124 +static SDL_bool
   2.125 +HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
   2.126 +{
   2.127 +    SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
   2.128 +
   2.129 +    SDL_zeroa(ctx->last_state);
   2.130 +
   2.131 +    /* Initialize the joystick capabilities */
   2.132 +    joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   2.133 +    joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   2.134 +    joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
   2.135 +
   2.136 +    return SDL_TRUE;
   2.137 +}
   2.138 +
   2.139 +static int
   2.140 +HIDAPI_DriverXbox360W_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   2.141 +{
   2.142 +    SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
   2.143 +
   2.144 +    Uint8 rumble_packet[] = { 0x00, 0x01, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
   2.145 +
   2.146 +    rumble_packet[5] = (low_frequency_rumble >> 8);
   2.147 +    rumble_packet[6] = (high_frequency_rumble >> 8);
   2.148 +
   2.149 +    if (hid_write(device->dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   2.150 +        return SDL_SetError("Couldn't send rumble packet");
   2.151 +    }
   2.152 +
   2.153 +    if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   2.154 +        ctx->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
   2.155 +    } else {
   2.156 +        ctx->rumble_expiration = 0;
   2.157 +    }
   2.158 +    return 0;
   2.159 +}
   2.160 +
   2.161 +static void
   2.162 +HIDAPI_DriverXbox360W_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360W_Context *ctx, Uint8 *data, int size)
   2.163 +{
   2.164 +    Sint16 axis;
   2.165 +    const SDL_bool invert_y_axes = SDL_TRUE;
   2.166 +
   2.167 +    if (ctx->last_state[2] != data[2]) {
   2.168 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   2.169 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   2.170 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   2.171 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   2.172 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   2.173 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   2.174 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   2.175 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   2.176 +    }
   2.177 +
   2.178 +    if (ctx->last_state[3] != data[3]) {
   2.179 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   2.180 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   2.181 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   2.182 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   2.183 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   2.184 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   2.185 +        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   2.186 +    }
   2.187 +
   2.188 +    axis = ((int)data[4] * 257) - 32768;
   2.189 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   2.190 +    axis = ((int)data[5] * 257) - 32768;
   2.191 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   2.192 +    axis = *(Sint16*)(&data[6]);
   2.193 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   2.194 +    axis = *(Sint16*)(&data[8]);
   2.195 +    if (invert_y_axes) {
   2.196 +        axis = ~axis;
   2.197 +    }
   2.198 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   2.199 +    axis = *(Sint16*)(&data[10]);
   2.200 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   2.201 +    axis = *(Sint16*)(&data[12]);
   2.202 +    if (invert_y_axes) {
   2.203 +        axis = ~axis;
   2.204 +    }
   2.205 +    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   2.206 +
   2.207 +    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   2.208 +}
   2.209 +
   2.210 +static SDL_bool
   2.211 +HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
   2.212 +{
   2.213 +    SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
   2.214 +    SDL_Joystick *joystick = NULL;
   2.215 +    Uint8 data[USB_PACKET_LENGTH];
   2.216 +    int size;
   2.217 +
   2.218 +    if (device->num_joysticks > 0) {
   2.219 +        joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
   2.220 +    }
   2.221 +
   2.222 +    while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
   2.223 +        if (size == 2 && data[0] == 0x08) {
   2.224 +            SDL_bool connected = (data[1] & 0x80) ? SDL_TRUE : SDL_FALSE;
   2.225 +#ifdef DEBUG_JOYSTICK
   2.226 +            SDL_Log("Connected = %s\n", connected ? "TRUE" : "FALSE");
   2.227 +#endif
   2.228 +            if (connected != ctx->connected) {
   2.229 +                ctx->connected = connected;
   2.230 +
   2.231 +                if (connected) {
   2.232 +                    SDL_JoystickID joystickID;
   2.233 +
   2.234 +                    HIDAPI_JoystickConnected(device, &joystickID);
   2.235 +
   2.236 +                    /* Set the controller LED */
   2.237 +                    SetSlotLED(device->dev, joystickID);
   2.238 +
   2.239 +                } else if (device->num_joysticks > 0) {
   2.240 +                    HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
   2.241 +                }
   2.242 +            }
   2.243 +        } else if (size == 29 && data[0] == 0x00 && data[1] == 0x0f && data[2] == 0x00 && data[3] == 0xf0) {
   2.244 +            /* Serial number is data[7-13] */
   2.245 +#ifdef DEBUG_JOYSTICK
   2.246 +            SDL_Log("Battery status (initial): %d\n", data[17]);
   2.247 +#endif
   2.248 +            if (joystick) {
   2.249 +                UpdatePowerLevel(joystick, data[17]);
   2.250 +            }
   2.251 +        } else if (size == 29 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x13) {
   2.252 +#ifdef DEBUG_JOYSTICK
   2.253 +            SDL_Log("Battery status: %d\n", data[4]);
   2.254 +#endif
   2.255 +            if (joystick) {
   2.256 +                UpdatePowerLevel(joystick, data[4]);
   2.257 +            }
   2.258 +        } else if (size == 29 && data[0] == 0x00 && (data[1] & 0x01) == 0x01) {
   2.259 +            if (joystick) {
   2.260 +                HIDAPI_DriverXbox360W_HandleStatePacket(joystick, device->dev, ctx, data+4, size-4);
   2.261 +            }
   2.262 +        }
   2.263 +    }
   2.264 +
   2.265 +    if (joystick) {
   2.266 +        if (ctx->rumble_expiration) {
   2.267 +            Uint32 now = SDL_GetTicks();
   2.268 +            if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   2.269 +                HIDAPI_DriverXbox360W_RumbleJoystick(device, joystick, 0, 0, 0);
   2.270 +            }
   2.271 +        }
   2.272 +
   2.273 +        if (size < 0) {
   2.274 +            /* Read error, device is disconnected */
   2.275 +            HIDAPI_JoystickDisconnected(device, joystick->instance_id);
   2.276 +        }
   2.277 +    }
   2.278 +    return (size >= 0);
   2.279 +}
   2.280 +
   2.281 +static void
   2.282 +HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
   2.283 +{
   2.284 +}
   2.285 +
   2.286 +static void
   2.287 +HIDAPI_DriverXbox360W_FreeDevice(SDL_HIDAPI_Device *device)
   2.288 +{
   2.289 +    hid_close(device->dev);
   2.290 +    device->dev = NULL;
   2.291 +
   2.292 +    SDL_free(device->context);
   2.293 +    device->context = NULL;
   2.294 +}
   2.295 +
   2.296 +SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
   2.297 +{
   2.298 +    SDL_HINT_JOYSTICK_HIDAPI_XBOX,
   2.299 +    SDL_TRUE,
   2.300 +    HIDAPI_DriverXbox360W_IsSupportedDevice,
   2.301 +    HIDAPI_DriverXbox360W_GetDeviceName,
   2.302 +    HIDAPI_DriverXbox360W_InitDevice,
   2.303 +    HIDAPI_DriverXbox360W_UpdateDevice,
   2.304 +    HIDAPI_DriverXbox360W_OpenJoystick,
   2.305 +    HIDAPI_DriverXbox360W_RumbleJoystick,
   2.306 +    HIDAPI_DriverXbox360W_CloseJoystick,
   2.307 +    HIDAPI_DriverXbox360W_FreeDevice
   2.308 +};
   2.309 +
   2.310 +#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
   2.311 +
   2.312 +#endif /* SDL_JOYSTICK_HIDAPI */
   2.313 +
   2.314 +/* vi: set ts=4 sw=4 expandtab: */