Added missing files from previous commit
diff --git a/src/joystick/hidapi/SDL_hidapi_rumble.c b/src/joystick/hidapi/SDL_hidapi_rumble.c
new file mode 100644
index 0000000..c15f1c1
--- /dev/null
+++ b/src/joystick/hidapi/SDL_hidapi_rumble.c
@@ -0,0 +1,188 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  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
+
+/* Handle rumble on a separate thread so it doesn't block the application */
+
+#include "SDL_assert.h"
+#include "SDL_thread.h"
+#include "SDL_hidapijoystick_c.h"
+#include "SDL_hidapi_rumble.h"
+
+
+typedef struct SDL_HIDAPI_RumbleRequest
+{
+    SDL_HIDAPI_Device *device;
+    Uint8 data[USB_PACKET_LENGTH];
+    int size;
+    struct SDL_HIDAPI_RumbleRequest *prev;
+
+} SDL_HIDAPI_RumbleRequest;
+
+typedef struct SDL_HIDAPI_RumbleContext
+{
+    volatile SDL_bool running;
+    SDL_Thread *thread;
+    SDL_mutex *lock;
+    SDL_sem *request_sem;
+    SDL_HIDAPI_RumbleRequest *requests_head;
+    SDL_HIDAPI_RumbleRequest *requests_tail;
+} SDL_HIDAPI_RumbleContext;
+
+static SDL_HIDAPI_RumbleContext rumble_context;
+
+static int SDL_HIDAPI_RumbleThread(void *data)
+{
+    SDL_HIDAPI_RumbleContext *ctx = (SDL_HIDAPI_RumbleContext *)data;
+
+    SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
+
+    while (ctx->running) {
+        SDL_HIDAPI_RumbleRequest *request = NULL;
+
+        SDL_SemWait(ctx->request_sem);
+
+        SDL_LockMutex(ctx->lock);
+        request = ctx->requests_tail;
+        if (request) {
+            if (request == ctx->requests_head) {
+                ctx->requests_head = NULL;
+            }
+            ctx->requests_tail = request->prev;
+        }
+        SDL_UnlockMutex(ctx->lock);
+
+        if (request) {
+            SDL_LockMutex(request->device->dev_lock);
+            hid_write(request->device->dev, request->data, request->size);
+            SDL_UnlockMutex(request->device->dev_lock);
+            (void)SDL_AtomicDecRef(&request->device->rumble_pending);
+            SDL_free(request);
+        }
+    }
+    return 0;
+}
+
+static void
+SDL_HIDAPI_StopRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
+{
+    ctx->running = SDL_FALSE;
+
+    if (ctx->thread) {
+        int result;
+
+        SDL_SemPost(ctx->request_sem);
+        SDL_WaitThread(ctx->thread, &result);
+        ctx->thread = NULL;
+    }
+
+    /* This should always be called with an empty queue */
+    SDL_assert(!ctx->requests_head);
+    SDL_assert(!ctx->requests_tail);
+
+    if (ctx->request_sem) {
+        SDL_DestroySemaphore(ctx->request_sem);
+        ctx->request_sem = NULL;
+    }
+
+    if (ctx->lock) {
+        SDL_DestroyMutex(ctx->lock);
+        ctx->lock = NULL;
+    }
+}
+
+static int
+SDL_HIDAPI_StartRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
+{
+    ctx->lock = SDL_CreateMutex();
+    if (!ctx->lock) {
+        SDL_HIDAPI_StopRumbleThread(ctx);
+        return -1;
+    }
+
+    ctx->request_sem = SDL_CreateSemaphore(0);
+    if (!ctx->request_sem) {
+        SDL_HIDAPI_StopRumbleThread(ctx);
+        return -1;
+    }
+
+    ctx->running = SDL_TRUE;
+    ctx->thread = SDL_CreateThread(SDL_HIDAPI_RumbleThread, "HIDAPI Rumble", ctx);
+    if (!ctx->thread) {
+        SDL_HIDAPI_StopRumbleThread(ctx);
+        return -1;
+    }
+    return 0;
+}
+
+int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size)
+{
+    SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
+    SDL_HIDAPI_RumbleRequest *request;
+
+    if (size > sizeof(request->data)) {
+        return SDL_SetError("Couldn't send rumble, size %d is greater than %d", size, sizeof(request->data));
+    }
+
+    if (!ctx->running) {
+        if (SDL_HIDAPI_StartRumbleThread(ctx) < 0) {
+            return -1;
+        }
+    }
+
+    request = (SDL_HIDAPI_RumbleRequest *)SDL_calloc(1, sizeof(*request));
+    if (!request) {
+        return SDL_OutOfMemory();
+    }
+    request->device = device;
+    SDL_memcpy(request->data, data, size);
+    request->size = size;
+
+    SDL_AtomicIncRef(&device->rumble_pending);
+    
+    SDL_LockMutex(ctx->lock);
+    if (ctx->requests_head) {
+        ctx->requests_head->prev = request;
+    } else {
+        ctx->requests_tail = request;
+    }
+    ctx->requests_head = request;
+    SDL_UnlockMutex(ctx->lock);
+
+    SDL_SemPost(ctx->request_sem);
+
+    return size;
+}
+
+void SDL_HIDAPI_QuitRumble()
+{
+    SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
+
+    if (ctx->running) {
+        SDL_HIDAPI_StopRumbleThread(ctx);
+    }
+}
+
+#endif /* SDL_JOYSTICK_HIDAPI */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/joystick/hidapi/SDL_hidapi_rumble.h b/src/joystick/hidapi/SDL_hidapi_rumble.h
new file mode 100644
index 0000000..1ce67ba
--- /dev/null
+++ b/src/joystick/hidapi/SDL_hidapi_rumble.h
@@ -0,0 +1,31 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  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
+
+/* Handle rumble on a separate thread so it doesn't block the application */
+int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size);
+void SDL_HIDAPI_QuitRumble();
+
+#endif /* SDL_JOYSTICK_HIDAPI */
+
+/* vi: set ts=4 sw=4 expandtab: */