winebus.sys: Pass a unix_device pointer in every bus event.
Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
8bff437e9d
commit
421a6f53ad
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue