diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 8259531779b..e8ae69633c0 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -64,6 +64,7 @@ static struct sdl_bus_options options; static void *sdl_handle = NULL; static UINT quit_event = -1; +static struct list event_queue = LIST_INIT(event_queue); #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL MAKE_FUNCPTR(SDL_GetError); @@ -730,12 +731,6 @@ static BOOL set_mapped_report_from_event(DEVICE_OBJECT *device, SDL_Event *event return FALSE; } -static void try_remove_device(DEVICE_OBJECT *device) -{ - bus_unlink_hid_device(device); - IoInvalidateDeviceRelations(bus_pdo, BusRelations); -} - static void try_add_device(unsigned int index) { DWORD vid = 0, pid = 0, version = 0; @@ -821,9 +816,7 @@ static void process_device_event(SDL_Event *event) else if (event->type == SDL_JOYDEVICEREMOVED) { id = ((SDL_JoyDeviceEvent *)event)->which; - device = bus_find_hid_device(sdl_busidW, ULongToPtr(id)); - if (device) try_remove_device(device); - else WARN("failed to find device with id %d\n", id); + bus_event_queue_device_removed(&event_queue, sdl_busidW, ULongToPtr(id)); } else if (event->type >= SDL_JOYAXISMOTION && event->type <= SDL_JOYBUTTONUP) { @@ -980,15 +973,18 @@ failed: NTSTATUS sdl_bus_wait(void *args) { + struct bus_event *result = args; SDL_Event event; do { + if (bus_event_queue_pop(&event_queue, result)) return STATUS_PENDING; 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"); + bus_event_queue_destroy(&event_queue); dlclose(sdl_handle); sdl_handle = NULL; return STATUS_SUCCESS; diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 4c8c84ffe9b..ec5e7715488 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -654,6 +654,7 @@ struct bus_main_params static DWORD CALLBACK bus_main_thread(void *args) { struct bus_main_params bus = *(struct bus_main_params *)args; + DEVICE_OBJECT *device; NTSTATUS status; TRACE("%s main loop starting\n", debugstr_w(bus.name)); @@ -663,7 +664,24 @@ static DWORD CALLBACK bus_main_thread(void *args) bus.bus_event->type = BUS_EVENT_TYPE_NONE; if (status) WARN("%s bus init returned status %#x\n", debugstr_w(bus.name), status); - else while ((status = winebus_call(bus.wait_code, bus.bus_event)) == STATUS_PENDING) {} + else while ((status = winebus_call(bus.wait_code, bus.bus_event)) == STATUS_PENDING) + { + struct bus_event *event = bus.bus_event; + switch (event->type) + { + case BUS_EVENT_TYPE_NONE: break; + case BUS_EVENT_TYPE_DEVICE_REMOVED: + EnterCriticalSection(&device_list_cs); + if (!(device = bus_find_hid_device(event->device_removed.bus_id, event->device_removed.context))) + WARN("could not find removed device matching bus %s, context %p\n", + debugstr_w(event->device_removed.bus_id), event->device_removed.context); + else + bus_unlink_hid_device(device); + LeaveCriticalSection(&device_list_cs); + IoInvalidateDeviceRelations(bus_pdo, BusRelations); + break; + } + } 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)); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index aff1e86263a..f3edef83cb7 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -27,6 +27,8 @@ #include "unixlib.h" +#include "wine/list.h" + struct unix_device { }; @@ -43,4 +45,8 @@ extern NTSTATUS iohid_bus_init(void *) DECLSPEC_HIDDEN; extern NTSTATUS iohid_bus_wait(void *) DECLSPEC_HIDDEN; extern NTSTATUS iohid_bus_stop(void *) DECLSPEC_HIDDEN; +extern void bus_event_queue_destroy(struct list *queue) DECLSPEC_HIDDEN; +extern BOOL bus_event_queue_device_removed(struct list *queue, const WCHAR *bus_id, void *context) DECLSPEC_HIDDEN; +extern BOOL bus_event_queue_pop(struct list *queue, struct bus_event *event) DECLSPEC_HIDDEN; + #endif /* __WINEBUS_UNIX_PRIVATE_H */ diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index c4090861675..13e2729e0c2 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -26,6 +26,7 @@ #include "winternl.h" #include "wine/debug.h" +#include "wine/list.h" #include "wine/unixlib.h" #include "unix_private.h" @@ -42,3 +43,41 @@ const unixlib_entry_t __wine_unix_call_funcs[] = iohid_bus_wait, iohid_bus_stop, }; + +void bus_event_queue_destroy(struct list *queue) +{ + struct bus_event *event, *next; + + LIST_FOR_EACH_ENTRY_SAFE(event, next, queue, struct bus_event, entry) + HeapFree(GetProcessHeap(), 0, event); +} + +BOOL bus_event_queue_device_removed(struct list *queue, const WCHAR *bus_id, void *context) +{ + ULONG size = sizeof(struct bus_event); + struct bus_event *event = HeapAlloc(GetProcessHeap(), 0, size); + if (!event) return FALSE; + + event->type = BUS_EVENT_TYPE_DEVICE_REMOVED; + event->device_removed.bus_id = bus_id; + event->device_removed.context = context; + list_add_tail(queue, &event->entry); + + return TRUE; +} + +BOOL bus_event_queue_pop(struct list *queue, struct bus_event *event) +{ + struct list *entry = list_head(queue); + struct bus_event *tmp; + + if (!entry) return FALSE; + + tmp = LIST_ENTRY(entry, struct bus_event, entry); + list_remove(entry); + + memcpy(event, tmp, sizeof(*event)); + HeapFree(GetProcessHeap(), 0, tmp); + + return TRUE; +} diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index e6abd98601f..d9097ba9ca7 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -27,6 +27,7 @@ #include #include +#include "wine/list.h" #include "wine/unixlib.h" struct sdl_bus_options @@ -49,11 +50,22 @@ struct unix_device; enum bus_event_type { BUS_EVENT_TYPE_NONE, + BUS_EVENT_TYPE_DEVICE_REMOVED, }; struct bus_event { enum bus_event_type type; + struct list entry; + + union + { + struct + { + const WCHAR *bus_id; + void *context; + } device_removed; + }; }; enum unix_funcs