Aric Stewart : winebus.sys: Support adding and removing SDL devices.

Alexandre Julliard julliard at winehq.org
Wed Feb 21 18:39:41 CST 2018


Module: wine
Branch: master
Commit: 752de1b56607b84c712e79ab34c507a3e8d96c4b
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=752de1b56607b84c712e79ab34c507a3e8d96c4b

Author: Aric Stewart <aric at codeweavers.com>
Date:   Wed Feb 21 06:55:50 2018 -0600

winebus.sys: Support adding and removing SDL devices.

Signed-off-by: Aric Stewart <aric at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winebus.sys/bus_sdl.c | 290 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 289 insertions(+), 1 deletion(-)

diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c
index 8486a0f..05443f5 100644
--- a/dlls/winebus.sys/bus_sdl.c
+++ b/dlls/winebus.sys/bus_sdl.c
@@ -19,10 +19,17 @@
  */
 
 #include "config.h"
+#include "wine/port.h"
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SDL2_SDL_H
+# include <SDL2/SDL.h>
+#endif
 
 #define NONAMELESSUNION
 
@@ -33,7 +40,17 @@
 #include "winnls.h"
 #include "winternl.h"
 #include "ddk/wdm.h"
+#include "ddk/hidtypes.h"
+#include "wine/library.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
+#include "hidusage.h"
+
+#ifdef WORDS_BIGENDIAN
+# define LE_WORD(x) RtlUshortByteSwap(x)
+#else
+# define LE_WORD(x) (x)
+#endif
 
 #include "bus.h"
 
@@ -41,9 +58,280 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
 
 #ifdef SONAME_LIBSDL2
 
+WINE_DECLARE_DEBUG_CHANNEL(hid_report);
+
+static DRIVER_OBJECT *sdl_driver_obj = NULL;
+
+static const WCHAR sdl_busidW[] = {'S','D','L','J','O','Y',0};
+
+#include "initguid.h"
+DEFINE_GUID(GUID_DEVCLASS_SDL, 0x463d60b5,0x802b,0x4bb2,0x8f,0xdb,0x7d,0xa9,0xb9,0x96,0x04,0xd8);
+
+static void *sdl_handle = NULL;
+
+#ifdef SONAME_LIBSDL2
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
+MAKE_FUNCPTR(SDL_GetError);
+MAKE_FUNCPTR(SDL_Init);
+MAKE_FUNCPTR(SDL_JoystickEventState);
+MAKE_FUNCPTR(SDL_JoystickGetGUID);
+MAKE_FUNCPTR(SDL_JoystickGetGUIDString);
+MAKE_FUNCPTR(SDL_JoystickInstanceID);
+MAKE_FUNCPTR(SDL_JoystickName);
+MAKE_FUNCPTR(SDL_JoystickNumAxes);
+MAKE_FUNCPTR(SDL_JoystickOpen);
+MAKE_FUNCPTR(SDL_WaitEvent);
+#endif
+static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick);
+static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick);
+static Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick);
+
+struct platform_private
+{
+    SDL_Joystick *sdl_joystick;
+    SDL_JoystickID id;
+};
+
+static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
+{
+    return (struct platform_private *)get_platform_private(device);
+}
+
+static int compare_platform_device(DEVICE_OBJECT *device, void *platform_dev)
+{
+    SDL_JoystickID id1 = impl_from_DEVICE_OBJECT(device)->id;
+    SDL_JoystickID id2 = PtrToUlong(platform_dev);
+    return (id1 != id2);
+}
+
+static NTSTATUS get_reportdescriptor(DEVICE_OBJECT *device, BYTE *buffer, DWORD length, DWORD *out_length)
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS get_string(DEVICE_OBJECT *device, DWORD index, WCHAR *buffer, DWORD length)
+{
+    struct platform_private *ext = impl_from_DEVICE_OBJECT(device);
+    const char* str = NULL;
+
+    switch (index)
+    {
+        case HID_STRING_ID_IPRODUCT:
+            str = pSDL_JoystickName(ext->sdl_joystick);
+            break;
+        case HID_STRING_ID_IMANUFACTURER:
+            str = "SDL";
+            break;
+        case HID_STRING_ID_ISERIALNUMBER:
+            str = "000000";
+            break;
+        default:
+            ERR("Unhandled string index %i\n", index);
+    }
+
+    if (str && str[0])
+        MultiByteToWideChar(CP_ACP, 0, str, -1, buffer, length);
+    else
+        buffer[0] = 0;
+
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS begin_report_processing(DEVICE_OBJECT *device)
+{
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS set_output_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *written)
+{
+    *written = 0;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS get_feature_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *read)
+{
+    *read = 0;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS set_feature_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *written)
+{
+    *written = 0;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+static const platform_vtbl sdl_vtbl =
+{
+    compare_platform_device,
+    get_reportdescriptor,
+    get_string,
+    begin_report_processing,
+    set_output_report,
+    get_feature_report,
+    set_feature_report,
+};
+
+static void try_remove_device(SDL_JoystickID index)
+{
+    DEVICE_OBJECT *device = NULL;
+
+    device = bus_find_hid_device(&sdl_vtbl, ULongToPtr(index));
+    if (!device) return;
+
+    IoInvalidateDeviceRelations(device, RemovalRelations);
+
+    bus_remove_hid_device(device);
+}
+
+static void try_add_device(SDL_JoystickID index)
+{
+    DWORD vid = 0, pid = 0, version = 0;
+    DEVICE_OBJECT *device = NULL;
+    WCHAR serial[34] = {0};
+    char guid_str[34];
+    BOOL is_xbox_gamepad;
+    int button_count, axis_count;
+
+    SDL_Joystick* joystick;
+    SDL_JoystickID id;
+    SDL_JoystickGUID guid;
+
+    if ((joystick = pSDL_JoystickOpen(index)) == NULL)
+    {
+        WARN("Unable to open sdl device %i: %s\n", index, pSDL_GetError());
+        return;
+    }
+
+    id = index;
+    if (pSDL_JoystickGetProductVersion != NULL) {
+        vid = pSDL_JoystickGetVendor(joystick);
+        pid = pSDL_JoystickGetProduct(joystick);
+        version = pSDL_JoystickGetProductVersion(joystick);
+    }
+    else
+    {
+        vid = 0x01;
+        pid = pSDL_JoystickInstanceID(joystick) + 1;
+        version = 0;
+    }
+
+    guid = pSDL_JoystickGetGUID(joystick);
+    pSDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
+    MultiByteToWideChar(CP_ACP, 0, guid_str, -1, serial, sizeof(guid_str));
+
+    TRACE("Found sdl device %i (vid %04x, pid %04x, version %u, serial %s)\n",
+          index, vid, pid, version, debugstr_w(serial));
+
+    axis_count = pSDL_JoystickNumAxes(joystick);
+    button_count = pSDL_JoystickNumAxes(joystick);
+    is_xbox_gamepad = (axis_count == 6  && button_count >= 14);
+
+    device = bus_create_hid_device(sdl_driver_obj, sdl_busidW, vid, pid, version, 0, serial, is_xbox_gamepad, &GUID_DEVCLASS_SDL, &sdl_vtbl, sizeof(struct platform_private));
+
+    if (device)
+    {
+        struct platform_private *private = impl_from_DEVICE_OBJECT(device);
+        private->sdl_joystick = joystick;
+        private->id = id;
+        IoInvalidateDeviceRelations(device, BusRelations);
+    }
+    else
+    {
+        WARN("Ignoring device %i\n", index);
+    }
+}
+
+static void process_device_event(SDL_Event *event)
+{
+    TRACE_(hid_report)("Received action %x\n", event->type);
+
+    if (event->type == SDL_JOYDEVICEADDED)
+        try_add_device(((SDL_JoyDeviceEvent*)event)->which);
+    else if (event->type == SDL_JOYDEVICEREMOVED)
+        try_remove_device(((SDL_JoyDeviceEvent*)event)->which);
+}
+
+static DWORD CALLBACK deviceloop_thread(void *args)
+{
+    HANDLE init_done = args;
+    SDL_Event event;
+
+    if (pSDL_Init(SDL_INIT_JOYSTICK) < 0)
+    {
+        ERR("Can't Init SDL\n");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    pSDL_JoystickEventState(SDL_ENABLE);
+
+    SetEvent(init_done);
+
+    while (1)
+        while (pSDL_WaitEvent(&event) != 0)
+            process_device_event(&event);
+
+    TRACE("Device thread exiting\n");
+    return 0;
+}
+
 NTSTATUS WINAPI sdl_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_path)
 {
-    FIXME("STUB: (%p, %s)\n", driver, debugstr_w(registry_path->Buffer));
+    HANDLE events[2];
+    DWORD result;
+
+    TRACE("(%p, %s)\n", driver, debugstr_w(registry_path->Buffer));
+    if (sdl_handle == NULL)
+    {
+        sdl_handle = wine_dlopen(SONAME_LIBSDL2, RTLD_NOW, NULL, 0);
+        if (!sdl_handle) {
+            WARN("could not load %s\n", SONAME_LIBSDL2);
+            sdl_driver_obj = NULL;
+            return STATUS_UNSUCCESSFUL;
+        }
+#define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(sdl_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
+        LOAD_FUNCPTR(SDL_GetError);
+        LOAD_FUNCPTR(SDL_Init);
+        LOAD_FUNCPTR(SDL_JoystickEventState);
+        LOAD_FUNCPTR(SDL_JoystickGetGUID);
+        LOAD_FUNCPTR(SDL_JoystickGetGUIDString);
+        LOAD_FUNCPTR(SDL_JoystickInstanceID);
+        LOAD_FUNCPTR(SDL_JoystickName);
+        LOAD_FUNCPTR(SDL_JoystickNumAxes);
+        LOAD_FUNCPTR(SDL_JoystickOpen);
+        LOAD_FUNCPTR(SDL_WaitEvent);
+#undef LOAD_FUNCPTR
+        pSDL_JoystickGetProduct = wine_dlsym(sdl_handle, "SDL_JoystickGetProduct", NULL, 0);
+        pSDL_JoystickGetProductVersion = wine_dlsym(sdl_handle, "SDL_JoystickGetProductVersion", NULL, 0);
+        pSDL_JoystickGetVendor = wine_dlsym(sdl_handle, "SDL_JoystickGetVendor", NULL, 0);
+    }
+
+    sdl_driver_obj = driver;
+    driver->MajorFunction[IRP_MJ_PNP] = common_pnp_dispatch;
+    driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = hid_internal_dispatch;
+
+    if (!(events[0] = CreateEventW(NULL, TRUE, FALSE, NULL)))
+        goto error;
+    if (!(events[1] = CreateThread(NULL, 0, deviceloop_thread, events[0], 0, NULL)))
+    {
+        CloseHandle(events[0]);
+        goto error;
+    }
+
+    result = WaitForMultipleObjects(2, events, FALSE, INFINITE);
+    CloseHandle(events[0]);
+    CloseHandle(events[1]);
+    if (result == WAIT_OBJECT_0)
+    {
+        TRACE("Initialization successful\n");
+        return STATUS_SUCCESS;
+    }
+
+error:
+    sdl_driver_obj = NULL;
+    return STATUS_UNSUCCESSFUL;
+sym_not_found:
+    wine_dlclose(sdl_handle, NULL, 0);
+    sdl_handle = NULL;
     return STATUS_UNSUCCESSFUL;
 }
 




More information about the wine-cvs mailing list