[PATCH 2/6] winebus.sys: Use the unixlib interface for the SDL bus thread.

Rémi Bernon rbernon at codeweavers.com
Thu Aug 19 02:10:00 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winebus.sys/bus.h          |   2 -
 dlls/winebus.sys/bus_sdl.c      | 142 +++++++++++++-------------------
 dlls/winebus.sys/main.c         | 115 ++++++++++++++++++++------
 dlls/winebus.sys/unix_private.h |  34 ++++++++
 dlls/winebus.sys/unixlib.c      |   5 +-
 dlls/winebus.sys/unixlib.h      |   8 ++
 6 files changed, 192 insertions(+), 114 deletions(-)
 create mode 100644 dlls/winebus.sys/unix_private.h

diff --git a/dlls/winebus.sys/bus.h b/dlls/winebus.sys/bus.h
index 3e53b9c53f1..2c2d26a1525 100644
--- a/dlls/winebus.sys/bus.h
+++ b/dlls/winebus.sys/bus.h
@@ -30,10 +30,8 @@ typedef int(*enum_func)(DEVICE_OBJECT *device, void *context);
 /* Buses */
 NTSTATUS udev_driver_init(void) DECLSPEC_HIDDEN;
 NTSTATUS iohid_driver_init(void) DECLSPEC_HIDDEN;
-NTSTATUS sdl_driver_init(void) DECLSPEC_HIDDEN;
 void udev_driver_unload( void ) DECLSPEC_HIDDEN;
 void iohid_driver_unload( void ) DECLSPEC_HIDDEN;
-void sdl_driver_unload( void ) DECLSPEC_HIDDEN;
 
 /* Native device function table */
 typedef struct
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c
index 84e3ef20664..0cec6e4d981 100644
--- a/dlls/winebus.sys/bus_sdl.c
+++ b/dlls/winebus.sys/bus_sdl.c
@@ -52,18 +52,19 @@
 
 #include "bus.h"
 
+#include "unix_private.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
 
 #ifdef SONAME_LIBSDL2
 
 WINE_DECLARE_DEBUG_CHANNEL(hid_report);
 
-static const WCHAR sdl_busidW[] = {'S','D','L','J','O','Y',0};
+static struct sdl_bus_options options;
 
-static DWORD map_controllers = 0;
+static const WCHAR sdl_busidW[] = {'S','D','L','J','O','Y',0};
 
 static void *sdl_handle = NULL;
-static HANDLE deviceloop_handle;
 static UINT quit_event = -1;
 
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
@@ -748,7 +749,7 @@ static void try_add_device(unsigned int index)
         return;
     }
 
-    if (map_controllers && pSDL_IsGameController(index))
+    if (options.map_controllers && pSDL_IsGameController(index))
         controller = pSDL_GameControllerOpen(index);
 
     id = pSDL_JoystickInstanceID(joystick);
@@ -889,68 +890,32 @@ static void sdl_load_mappings(void)
     }
 }
 
-static DWORD CALLBACK deviceloop_thread(void *args)
+NTSTATUS WINAPI sdl_bus_stop(void)
 {
-    HANDLE init_done = args;
     SDL_Event event;
 
-    if (pSDL_Init(SDL_INIT_GAMECONTROLLER|SDL_INIT_HAPTIC) < 0)
+    if (!sdl_handle) return STATUS_SUCCESS;
+
+    event.type = quit_event;
+    if (pSDL_PushEvent(&event) != 1)
     {
-        ERR("Can't init SDL: %s\n", pSDL_GetError());
+        ERR("error pushing quit event\n");
         return STATUS_UNSUCCESSFUL;
     }
 
-    pSDL_JoystickEventState(SDL_ENABLE);
-    pSDL_GameControllerEventState(SDL_ENABLE);
-
-    /* Process mappings */
-    if (pSDL_GameControllerAddMapping != NULL) sdl_load_mappings();
-
-    SetEvent(init_done);
-
-    while (1) {
-        while (pSDL_WaitEvent(&event) != 0) {
-            if (event.type == quit_event) {
-                TRACE("Device thread exiting\n");
-                return 0;
-            }
-            process_device_event(&event);
-        }
-    }
+    return STATUS_SUCCESS;
 }
 
-void sdl_driver_unload( void )
+NTSTATUS WINAPI sdl_bus_init(void *args)
 {
-    SDL_Event event;
+    TRACE("args %p\n", args);
 
-    TRACE("Unload Driver\n");
+    options = *(struct sdl_bus_options *)args;
 
-    if (!deviceloop_handle)
-        return;
-
-    quit_event = pSDL_RegisterEvents(1);
-    if (quit_event == -1) {
-        ERR("error registering quit event\n");
-        return;
-    }
-
-    event.type = quit_event;
-    if (pSDL_PushEvent(&event) != 1) {
-        ERR("error pushing quit event\n");
-        return;
-    }
-
-    WaitForSingleObject(deviceloop_handle, INFINITE);
-    CloseHandle(deviceloop_handle);
-    dlclose(sdl_handle);
-}
-
-static BOOL sdl_initialize(void)
-{
     if (!(sdl_handle = dlopen(SONAME_LIBSDL2, RTLD_NOW)))
     {
         WARN("could not load %s\n", SONAME_LIBSDL2);
-        return FALSE;
+        return STATUS_UNSUCCESSFUL;
     }
 #define LOAD_FUNCPTR(f)                          \
     if ((p##f = dlsym(sdl_handle, #f)) == NULL)  \
@@ -1000,63 +965,66 @@ static BOOL sdl_initialize(void)
     pSDL_JoystickGetProduct = dlsym(sdl_handle, "SDL_JoystickGetProduct");
     pSDL_JoystickGetProductVersion = dlsym(sdl_handle, "SDL_JoystickGetProductVersion");
     pSDL_JoystickGetVendor = dlsym(sdl_handle, "SDL_JoystickGetVendor");
-    return TRUE;
+
+    if (pSDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) < 0)
+    {
+        ERR("could not init SDL: %s\n", pSDL_GetError());
+        goto failed;
+    }
+
+    if ((quit_event = pSDL_RegisterEvents(1)) == -1)
+    {
+        ERR("error registering quit event\n");
+        goto failed;
+    }
+
+    pSDL_JoystickEventState(SDL_ENABLE);
+    pSDL_GameControllerEventState(SDL_ENABLE);
+
+    /* Process mappings */
+    if (pSDL_GameControllerAddMapping != NULL) sdl_load_mappings();
+    return STATUS_SUCCESS;
 
 failed:
     dlclose(sdl_handle);
     sdl_handle = NULL;
-    return FALSE;
+    return STATUS_UNSUCCESSFUL;
 }
 
-NTSTATUS sdl_driver_init(void)
+NTSTATUS WINAPI sdl_bus_wait(void)
 {
-    static const WCHAR controller_modeW[] = {'M','a','p',' ','C','o','n','t','r','o','l','l','e','r','s',0};
-    static const UNICODE_STRING controller_mode = {sizeof(controller_modeW) - sizeof(WCHAR), sizeof(controller_modeW), (WCHAR*)controller_modeW};
-
-    HANDLE events[2];
-    DWORD result;
-
-    if (!sdl_handle && !sdl_initialize()) return STATUS_UNSUCCESSFUL;
-
-    map_controllers = check_bus_option(&controller_mode, 1);
-
-    if (!(events[0] = CreateEventW(NULL, TRUE, FALSE, NULL)))
-    {
-        WARN("CreateEvent failed\n");
-        return STATUS_UNSUCCESSFUL;
-    }
-    if (!(events[1] = CreateThread(NULL, 0, deviceloop_thread, events[0], 0, NULL)))
-    {
-        WARN("CreateThread failed\n");
-        CloseHandle(events[0]);
-        return STATUS_UNSUCCESSFUL;
-    }
+    SDL_Event event;
 
-    result = WaitForMultipleObjects(2, events, FALSE, INFINITE);
-    CloseHandle(events[0]);
-    if (result == WAIT_OBJECT_0)
+    do
     {
-        TRACE("Initialization successful\n");
-        deviceloop_handle = events[1];
-        return STATUS_SUCCESS;
-    }
-    CloseHandle(events[1]);
+        if (pSDL_WaitEvent(&event) != 0) process_device_event(&event);
+        else WARN("SDL_WaitEvent failed: %s\n", pSDL_GetError());
+    } while (event.type != quit_event);
 
+    TRACE("SDL main loop exiting\n");
     dlclose(sdl_handle);
     sdl_handle = NULL;
-    return STATUS_UNSUCCESSFUL;
+    return STATUS_SUCCESS;
 }
 
 #else
 
-NTSTATUS sdl_driver_init(void)
+NTSTATUS WINAPI sdl_bus_init(void *args)
 {
+    WARN("SDL support not compiled in!\n");
     return STATUS_NOT_IMPLEMENTED;
 }
 
-void sdl_driver_unload( void )
+NTSTATUS WINAPI sdl_bus_wait(void)
 {
-    TRACE("Stub: Unload Driver\n");
+    WARN("SDL support not compiled in!\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS WINAPI sdl_bus_stop(void)
+{
+    WARN("SDL support not compiled in!\n");
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 #endif /* SONAME_LIBSDL2 */
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c
index fe0f6dc60cc..a4b236cecb7 100644
--- a/dlls/winebus.sys/main.c
+++ b/dlls/winebus.sys/main.c
@@ -408,6 +408,20 @@ static NTSTATUS build_device_relations(DEVICE_RELATIONS **devices)
     return STATUS_SUCCESS;
 }
 
+DWORD check_bus_option(const UNICODE_STRING *option, DWORD default_value)
+{
+    char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[sizeof(DWORD)])];
+    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
+    DWORD size;
+
+    if (NtQueryValueKey(driver_key, option, KeyValuePartialInformation, info, sizeof(buffer), &size) == STATUS_SUCCESS)
+    {
+        if (info->Type == REG_DWORD) return *(DWORD *)info->Data;
+    }
+
+    return default_value;
+}
+
 static NTSTATUS handle_IRP_MN_QUERY_DEVICE_RELATIONS(IRP *irp)
 {
     NTSTATUS status = irp->IoStatus.Status;
@@ -622,6 +636,75 @@ static void keyboard_device_create(void)
     IoInvalidateDeviceRelations(bus_pdo, BusRelations);
 }
 
+static DWORD bus_count;
+static HANDLE bus_thread[16];
+
+struct bus_main_params
+{
+    const WCHAR *name;
+    HANDLE init;
+
+    NTSTATUS (WINAPI *bus_init)(void *args);
+    NTSTATUS (WINAPI *bus_wait)(void);
+    void *bus_params;
+};
+
+static DWORD CALLBACK bus_main_thread(void *args)
+{
+    struct bus_main_params bus = *(struct bus_main_params *)args;
+    NTSTATUS status;
+
+    TRACE("%s main loop starting\n", debugstr_w(bus.name));
+    status = bus.bus_init(bus.bus_params);
+    SetEvent(bus.init);
+    TRACE("%s main loop started\n", debugstr_w(bus.name));
+
+    if (status) WARN("%s bus init returned status %#x\n", debugstr_w(bus.name), status);
+    else while ((status = bus.bus_wait()) == STATUS_PENDING) {}
+
+    if (status) WARN("%s bus wait returned status %#x\n", debugstr_w(bus.name), status);
+    else TRACE("%s main loop exited\n", debugstr_w(bus.name));
+    return status;
+}
+
+static NTSTATUS sdl_driver_init(void)
+{
+    static const WCHAR sdl_bus_name[] = {'S','D','L',0};
+    static const WCHAR controller_modeW[] = {'M','a','p',' ','C','o','n','t','r','o','l','l','e','r','s',0};
+    static const UNICODE_STRING controller_mode = {sizeof(controller_modeW) - sizeof(WCHAR), sizeof(controller_modeW), (WCHAR*)controller_modeW};
+    struct sdl_bus_options sdl_params;
+    struct bus_main_params params =
+    {
+        .name = sdl_bus_name,
+        .bus_init = unix_funcs->sdl_bus_init,
+        .bus_wait = unix_funcs->sdl_bus_wait,
+        .bus_params = &sdl_params,
+    };
+    DWORD i = bus_count++;
+
+    if (!(params.init = CreateEventW(NULL, FALSE, FALSE, NULL)))
+    {
+        ERR("failed to create SDL bus event.\n");
+        bus_count--;
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    sdl_params.map_controllers = check_bus_option(&controller_mode, 1);
+    if (!sdl_params.map_controllers) TRACE("SDL controller to XInput HID gamepad mapping disabled\n");
+
+    if (!(bus_thread[i] = CreateThread(NULL, 0, bus_main_thread, &params, 0, NULL)))
+    {
+        ERR("failed to create SDL bus thread.\n");
+        CloseHandle(params.init);
+        bus_count--;
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    WaitForSingleObject(params.init, INFINITE);
+    CloseHandle(params.init);
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
 {
     static const WCHAR SDL_enabledW[] = {'E','n','a','b','l','e',' ','S','D','L',0};
@@ -638,16 +721,12 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
         mouse_device_create();
         keyboard_device_create();
 
-        if (check_bus_option(&SDL_enabled, 1))
+        if (!check_bus_option(&SDL_enabled, 1) || sdl_driver_init())
         {
-            if (sdl_driver_init() == STATUS_SUCCESS)
-            {
-                irp->IoStatus.Status = STATUS_SUCCESS;
-                break;
-            }
+            udev_driver_init();
+            iohid_driver_init();
         }
-        udev_driver_init();
-        iohid_driver_init();
+
         irp->IoStatus.Status = STATUS_SUCCESS;
         break;
     case IRP_MN_SURPRISE_REMOVAL:
@@ -656,7 +735,10 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
     case IRP_MN_REMOVE_DEVICE:
         udev_driver_unload();
         iohid_driver_unload();
-        sdl_driver_unload();
+        unix_funcs->sdl_bus_stop();
+
+        WaitForMultipleObjects(bus_count, bus_thread, TRUE, INFINITE);
+        while (bus_count--) CloseHandle(bus_thread[bus_count]);
 
         irp->IoStatus.Status = STATUS_SUCCESS;
         IoSkipCurrentIrpStackLocation(irp);
@@ -1025,21 +1107,6 @@ void process_hid_report(DEVICE_OBJECT *device, BYTE *report, DWORD length)
     LeaveCriticalSection(&ext->cs);
 }
 
-DWORD check_bus_option(const UNICODE_STRING *option, DWORD default_value)
-{
-    char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[sizeof(DWORD)])];
-    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION*)buffer;
-    DWORD size;
-
-    if (NtQueryValueKey(driver_key, option, KeyValuePartialInformation, info, sizeof(buffer), &size) == STATUS_SUCCESS)
-    {
-        if (info->Type == REG_DWORD)
-            return *(DWORD*)info->Data;
-    }
-
-    return default_value;
-}
-
 BOOL is_xbox_gamepad(WORD vid, WORD pid)
 {
     int i;
diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h
new file mode 100644
index 00000000000..7ac882a03b2
--- /dev/null
+++ b/dlls/winebus.sys/unix_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINEBUS_UNIX_PRIVATE_H
+#define __WINEBUS_UNIX_PRIVATE_H
+
+#include <stdarg.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <winternl.h>
+
+#include "unixlib.h"
+
+extern NTSTATUS WINAPI sdl_bus_init(void *args) DECLSPEC_HIDDEN;
+extern NTSTATUS WINAPI sdl_bus_wait(void) DECLSPEC_HIDDEN;
+extern NTSTATUS WINAPI sdl_bus_stop(void) DECLSPEC_HIDDEN;
+
+#endif /* __WINEBUS_UNIX_PRIVATE_H */
diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c
index 1be740b34b8..832a20372d6 100644
--- a/dlls/winebus.sys/unixlib.c
+++ b/dlls/winebus.sys/unixlib.c
@@ -27,12 +27,15 @@
 
 #include "wine/debug.h"
 
-#include "unixlib.h"
+#include "unix_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
 
 static const struct unix_funcs unix_funcs =
 {
+    sdl_bus_init,
+    sdl_bus_wait,
+    sdl_bus_stop,
 };
 
 NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out)
diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h
index c220629ea87..a5cd57867e4 100644
--- a/dlls/winebus.sys/unixlib.h
+++ b/dlls/winebus.sys/unixlib.h
@@ -27,8 +27,16 @@
 #include <ddk/wdm.h>
 #include <hidusage.h>
 
+struct sdl_bus_options
+{
+    BOOL map_controllers;
+};
+
 struct unix_funcs
 {
+    NTSTATUS (WINAPI *sdl_bus_init)(void *);
+    NTSTATUS (WINAPI *sdl_bus_wait)(void);
+    NTSTATUS (WINAPI *sdl_bus_stop)(void);
 };
 
 #endif /* __WINEBUS_UNIXLIB_H */
-- 
2.32.0




More information about the wine-devel mailing list