Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_iohid.c | 38 +++++++++++++++++++++-- dlls/winebus.sys/bus_sdl.c | 4 ++- dlls/winebus.sys/bus_udev.c | 25 ++++++++++------ dlls/winebus.sys/main.c | 53 +++++---------------------------- dlls/winebus.sys/unix_private.h | 2 +- dlls/winebus.sys/unixlib.c | 17 ++++++----- dlls/winebus.sys/unixlib.h | 9 +----- 7 files changed, 75 insertions(+), 73 deletions(-)
diff --git a/dlls/winebus.sys/bus_iohid.c b/dlls/winebus.sys/bus_iohid.c index 8bdd7857ae6..492d5a70ddb 100644 --- a/dlls/winebus.sys/bus_iohid.c +++ b/dlls/winebus.sys/bus_iohid.c @@ -95,9 +95,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay); #ifdef HAVE_IOHIDMANAGERCREATE
+static CRITICAL_SECTION iohid_cs; +static CRITICAL_SECTION_DEBUG iohid_cs_debug = +{ + 0, 0, &iohid_cs, + { &iohid_cs_debug.ProcessLocksList, &iohid_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": iohid_cs") } +}; +static CRITICAL_SECTION iohid_cs = { &iohid_cs_debug, -1, 0, 0, 0, 0 }; + static IOHIDManagerRef hid_manager; static CFRunLoopRef run_loop; static struct list event_queue = LIST_INIT(event_queue); +static struct list device_list = LIST_INIT(device_list);
static const WCHAR busidW[] = {'I','O','H','I','D',0}; static struct iohid_bus_options options; @@ -114,6 +124,16 @@ static inline struct platform_private *impl_from_unix_device(struct unix_device return CONTAINING_RECORD(iface, struct platform_private, unix_device); }
+static struct platform_private *find_device_from_iohid(IOHIDDeviceRef IOHIDDevice) +{ + struct platform_private *private; + + LIST_FOR_EACH_ENTRY(private, &device_list, struct platform_private, unix_device.entry) + if (!private->device == IOHIDDevice) return private; + + return NULL; +} + static void CFStringToWSTR(CFStringRef cstr, LPWSTR wstr, int length) { int len = min(CFStringGetLength(cstr), length-1); @@ -170,6 +190,10 @@ static void iohid_device_stop(struct unix_device *iface) struct platform_private *private = impl_from_unix_device(iface);
IOHIDDeviceRegisterInputReportCallback(private->device, NULL, 0, NULL, NULL); + + EnterCriticalSection(&iohid_cs); + list_remove(&private->unix_device.entry); + LeaveCriticalSection(&iohid_cs); }
static NTSTATUS iohid_device_get_report_descriptor(struct unix_device *iface, BYTE *buffer, @@ -336,6 +360,7 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * TRACE("dev %p, desc %s.\n", IOHIDDevice, debugstr_device_desc(&desc));
if (!(private = unix_device_create(&iohid_device_vtbl, sizeof(struct platform_private)))) return; + list_add_tail(&device_list, &private->unix_device.entry); private->device = IOHIDDevice; private->buffer = NULL;
@@ -344,13 +369,18 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void *
static void handle_RemovalCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef IOHIDDevice) { + struct platform_private *device; + TRACE("OS/X IOHID Device Removed %p\n", IOHIDDevice); IOHIDDeviceRegisterInputReportCallback(IOHIDDevice, NULL, 0, NULL, NULL); /* Note: Yes, we leak the buffer. But according to research there is no safe way to deallocate that buffer. */ IOHIDDeviceUnscheduleFromRunLoop(IOHIDDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); IOHIDDeviceClose(IOHIDDevice, 0); - bus_event_queue_device_removed(&event_queue, busidW, IOHIDDevice); + + device = find_device_from_iohid(IOHIDDevice); + if (device) bus_event_queue_device_removed(&event_queue, &device->unix_device); + else WARN("failed to find device for iohid device %p\n", IOHIDDevice); }
NTSTATUS iohid_bus_init(void *args) @@ -377,6 +407,7 @@ NTSTATUS iohid_bus_init(void *args) NTSTATUS iohid_bus_wait(void *args) { struct bus_event *result = args; + CFRunLoopRunResult ret;
/* cleanup previously returned event */ bus_event_cleanup(result); @@ -384,7 +415,10 @@ NTSTATUS iohid_bus_wait(void *args) do { if (bus_event_queue_pop(&event_queue, result)) return STATUS_PENDING; - } while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, TRUE) != kCFRunLoopRunStopped); + EnterCriticalSection(&iohid_cs); + ret = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, TRUE); + LeaveCriticalSection(&iohid_cs); + } while (ret != kCFRunLoopRunStopped);
TRACE("IOHID main loop exiting\n"); bus_event_queue_destroy(&event_queue); diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 6a6f364edf6..d48f9507abb 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -799,7 +799,9 @@ static void process_device_event(SDL_Event *event) else if (event->type == SDL_JOYDEVICEREMOVED) { id = ((SDL_JoyDeviceEvent *)event)->which; - bus_event_queue_device_removed(&event_queue, sdl_busidW, ULongToPtr(id)); + device = find_device_from_id(id); + if (device) bus_event_queue_device_removed(&event_queue, &device->unix_device); + else WARN("failed to find device with id %d\n", id); } else if (event->type >= SDL_JOYAXISMOTION && event->type <= SDL_JOYBUTTONUP) { diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 23b649ff511..8cbcabf25e8 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -200,6 +200,16 @@ static struct platform_private *find_device_from_syspath(const char *path) return NULL; }
+static struct platform_private *find_device_from_udev(struct udev_device *dev) +{ + struct platform_private *device; + + LIST_FOR_EACH_ENTRY(device, &device_list, struct platform_private, unix_device.entry) + if (device->udev_device == dev) return device; + + return NULL; +} + #ifdef HAS_PROPER_INPUT_HEADER
static const BYTE ABS_TO_HID_MAP[][2] = { @@ -1062,14 +1072,6 @@ static void udev_add_device(struct udev_device *dev) #endif }
-static void try_remove_device(struct udev_device *dev) -{ - bus_event_queue_device_removed(&event_queue, hidraw_busidW, dev); -#ifdef HAS_PROPER_INPUT_HEADER - bus_event_queue_device_removed(&event_queue, lnxev_busidW, dev); -#endif -} - static void build_initial_deviceset(void) { struct udev_enumerate *enumerate; @@ -1161,6 +1163,7 @@ error:
static void process_monitor_event(struct udev_monitor *monitor) { + struct platform_private *device; struct udev_device *dev; const char *action;
@@ -1180,7 +1183,11 @@ static void process_monitor_event(struct udev_monitor *monitor) else if (strcmp(action, "add") == 0) udev_add_device(dev); else if (strcmp(action, "remove") == 0) - try_remove_device(dev); + { + device = find_device_from_udev(dev); + if (device) bus_event_queue_device_removed(&event_queue, &device->unix_device); + else WARN("failed to find device for udev device %p\n", dev); + } else WARN("Unhandled action %s\n", debugstr_a(action));
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 162787c4e4a..a80bd8a186e 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -146,17 +146,6 @@ static void unix_device_remove(DEVICE_OBJECT *device) winebus_call(device_remove, ext->unix_device); }
-static int unix_device_compare(DEVICE_OBJECT *device, void *context) -{ - struct device_extension *ext = (struct device_extension *)device->DeviceExtension; - struct device_compare_params params = - { - .iface = ext->unix_device, - .context = context - }; - return winebus_call(device_compare, ¶ms); -} - static NTSTATUS unix_device_start(DEVICE_OBJECT *device) { struct device_extension *ext = (struct device_extension *)device->DeviceExtension; @@ -359,29 +348,6 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, struct uni return device; }
-static DEVICE_OBJECT *bus_find_hid_device(const WCHAR *bus_id, void *platform_dev) -{ - struct device_extension *ext; - DEVICE_OBJECT *ret = NULL; - - TRACE("bus_id %s, platform_dev %p\n", debugstr_w(bus_id), platform_dev); - - EnterCriticalSection(&device_list_cs); - LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry) - { - if (strcmpW(ext->desc.busid, bus_id)) continue; - if (unix_device_compare(ext->device, platform_dev) == 0) - { - ret = ext->device; - break; - } - } - LeaveCriticalSection(&device_list_cs); - - TRACE("returning %p\n", ret); - return ret; -} - static DEVICE_OBJECT *bus_find_unix_device(struct unix_device *unix_device) { struct device_extension *ext; @@ -625,28 +591,25 @@ static DWORD CALLBACK bus_main_thread(void *args) 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); + device = bus_find_unix_device(event->device); + if (!device) WARN("could not find device for %s bus device %p\n", debugstr_w(bus.name), event->device); + else bus_unlink_hid_device(device); LeaveCriticalSection(&device_list_cs); IoInvalidateDeviceRelations(bus_pdo, BusRelations); break; case BUS_EVENT_TYPE_DEVICE_CREATED: - device = bus_create_hid_device(&event->device_created.desc, event->device_created.device); + device = bus_create_hid_device(&event->device_created.desc, event->device); if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations); else { - WARN("failed to create device for %s bus device %p\n", - debugstr_w(bus.name), event->device_created.device); - winebus_call(device_remove, event->device_created.device); + WARN("failed to create device for %s bus device %p\n", debugstr_w(bus.name), event->device); + winebus_call(device_remove, event->device); } break; case BUS_EVENT_TYPE_INPUT_REPORT: EnterCriticalSection(&device_list_cs); - device = bus_find_unix_device(event->input_report.device); - if (!device) WARN("could not find device for %s bus device %p\n", debugstr_w(bus.name), event->input_report.device); + device = bus_find_unix_device(event->device); + if (!device) WARN("could not find device for %s bus device %p\n", debugstr_w(bus.name), event->device); else process_hid_report(device, event->input_report.buffer, event->input_report.length); LeaveCriticalSection(&device_list_cs); break; diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 3f8d73d033a..9b2c6d81fa2 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -64,7 +64,7 @@ extern NTSTATUS iohid_bus_stop(void *) DECLSPEC_HIDDEN;
extern void bus_event_cleanup(struct bus_event *event) 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_device_removed(struct list *queue, struct unix_device *device) DECLSPEC_HIDDEN; extern BOOL bus_event_queue_device_created(struct list *queue, struct unix_device *device, struct device_desc *desc) DECLSPEC_HIDDEN; extern BOOL bus_event_queue_input_report(struct list *queue, struct unix_device *device, BYTE *report, USHORT length) DECLSPEC_HIDDEN; diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 87cc7de3474..008fb6e77a2 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -343,8 +343,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
void bus_event_cleanup(struct bus_event *event) { - if (event->type == BUS_EVENT_TYPE_INPUT_REPORT) - unix_device_decref(event->input_report.device); + if (event->type == BUS_EVENT_TYPE_NONE) return; + unix_device_decref(event->device); }
void bus_event_queue_destroy(struct list *queue) @@ -358,15 +358,16 @@ void bus_event_queue_destroy(struct list *queue) } }
-BOOL bus_event_queue_device_removed(struct list *queue, const WCHAR *bus_id, void *context) +BOOL bus_event_queue_device_removed(struct list *queue, struct unix_device *device) { ULONG size = sizeof(struct bus_event); struct bus_event *event = HeapAlloc(GetProcessHeap(), 0, size); if (!event) return FALSE;
+ if (unix_device_incref(device) == 1) return FALSE; /* being destroyed */ + event->type = BUS_EVENT_TYPE_DEVICE_REMOVED; - event->device_removed.bus_id = bus_id; - event->device_removed.context = context; + event->device = device; list_add_tail(queue, &event->entry);
return TRUE; @@ -378,8 +379,10 @@ BOOL bus_event_queue_device_created(struct list *queue, struct unix_device *devi struct bus_event *event = HeapAlloc(GetProcessHeap(), 0, size); if (!event) return FALSE;
+ if (unix_device_incref(device) == 1) return FALSE; /* being destroyed */ + event->type = BUS_EVENT_TYPE_DEVICE_CREATED; - event->device_created.device = device; + event->device = device; event->device_created.desc = *desc; list_add_tail(queue, &event->entry);
@@ -395,7 +398,7 @@ BOOL bus_event_queue_input_report(struct list *queue, struct unix_device *device if (unix_device_incref(device) == 1) return FALSE; /* being destroyed */
event->type = BUS_EVENT_TYPE_INPUT_REPORT; - event->input_report.device = device; + event->device = device; event->input_report.length = length; memcpy(event->input_report.buffer, report, length); list_add_tail(queue, &event->entry); diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index 61684d0c0af..cd5f64cbb51 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -76,23 +76,16 @@ struct bus_event enum bus_event_type type; struct list entry;
+ struct unix_device *device; union { struct { - const WCHAR *bus_id; - void *context; - } device_removed; - - struct - { - struct unix_device *device; struct device_desc desc; } device_created;
struct { - struct unix_device *device; USHORT length; BYTE buffer[1]; } input_report;