Signed-off-by: Rémi Bernon rbernon@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, ¶ms, 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 */