winebus.sys: Return an event from SDL bus wait on input report.
Instead of calling process_hid_report. This adds a reference count on unix devices to make sure they are kept alive until all their input report events have been processed. This also uses a bus-specific device list, to be able to find devices from joystick ids without having to call back to the win32 side. Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5380167ca0
commit
8b434bdc7f
|
@ -59,12 +59,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
|
|||
|
||||
WINE_DECLARE_DEBUG_CHANNEL(hid_report);
|
||||
|
||||
static CRITICAL_SECTION sdl_cs;
|
||||
static CRITICAL_SECTION_DEBUG sdl_cs_debug =
|
||||
{
|
||||
0, 0, &sdl_cs,
|
||||
{ &sdl_cs_debug.ProcessLocksList, &sdl_cs_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": sdl_cs") }
|
||||
};
|
||||
static CRITICAL_SECTION sdl_cs = { &sdl_cs_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
static const WCHAR sdl_busidW[] = {'S','D','L','J','O','Y',0};
|
||||
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);
|
||||
static struct list device_list = LIST_INIT(device_list);
|
||||
|
||||
#define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
|
||||
MAKE_FUNCPTR(SDL_GetError);
|
||||
|
@ -136,9 +146,14 @@ static inline struct platform_private *impl_from_unix_device(struct unix_device
|
|||
return CONTAINING_RECORD(iface, struct platform_private, unix_device);
|
||||
}
|
||||
|
||||
static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
|
||||
static struct platform_private *find_device_from_id(SDL_JoystickID id)
|
||||
{
|
||||
return impl_from_unix_device(get_unix_device(device));
|
||||
struct platform_private *device;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(device, &device_list, struct platform_private, unix_device.entry)
|
||||
if (device->id == id) return device;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define CONTROLLER_NUM_BUTTONS 11
|
||||
|
@ -501,6 +516,10 @@ static void sdl_device_stop(struct unix_device *iface)
|
|||
pSDL_JoystickClose(private->sdl_joystick);
|
||||
if (private->sdl_controller) pSDL_GameControllerClose(private->sdl_controller);
|
||||
if (private->sdl_haptic) pSDL_HapticClose(private->sdl_haptic);
|
||||
|
||||
EnterCriticalSection(&sdl_cs);
|
||||
list_remove(&private->unix_device.entry);
|
||||
LeaveCriticalSection(&sdl_cs);
|
||||
}
|
||||
|
||||
static NTSTATUS sdl_device_get_reportdescriptor(struct unix_device *iface, BYTE *buffer,
|
||||
|
@ -586,11 +605,11 @@ static const struct unix_device_vtbl sdl_device_vtbl =
|
|||
sdl_device_set_feature_report,
|
||||
};
|
||||
|
||||
static BOOL set_report_from_event(DEVICE_OBJECT *device, SDL_Event *event)
|
||||
static BOOL set_report_from_event(struct platform_private *device, SDL_Event *event)
|
||||
{
|
||||
struct platform_private *private;
|
||||
private = impl_from_DEVICE_OBJECT(device);
|
||||
if (private->sdl_controller)
|
||||
struct unix_device *iface = &device->unix_device;
|
||||
|
||||
if (device->sdl_controller)
|
||||
{
|
||||
/* We want mapped events */
|
||||
return TRUE;
|
||||
|
@ -603,9 +622,9 @@ static BOOL set_report_from_event(DEVICE_OBJECT *device, SDL_Event *event)
|
|||
{
|
||||
SDL_JoyButtonEvent *ie = &event->jbutton;
|
||||
|
||||
set_button_value(private, ie->button, ie->state);
|
||||
set_button_value(device, ie->button, ie->state);
|
||||
|
||||
process_hid_report(device, private->report_buffer, private->buffer_length);
|
||||
bus_event_queue_input_report(&event_queue, iface, device->report_buffer, device->buffer_length);
|
||||
break;
|
||||
}
|
||||
case SDL_JOYAXISMOTION:
|
||||
|
@ -614,8 +633,8 @@ static BOOL set_report_from_event(DEVICE_OBJECT *device, SDL_Event *event)
|
|||
|
||||
if (ie->axis < 6)
|
||||
{
|
||||
set_axis_value(private, ie->axis, ie->value, FALSE);
|
||||
process_hid_report(device, private->report_buffer, private->buffer_length);
|
||||
set_axis_value(device, ie->axis, ie->value, FALSE);
|
||||
bus_event_queue_input_report(&event_queue, iface, device->report_buffer, device->buffer_length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -623,16 +642,16 @@ static BOOL set_report_from_event(DEVICE_OBJECT *device, SDL_Event *event)
|
|||
{
|
||||
SDL_JoyBallEvent *ie = &event->jball;
|
||||
|
||||
set_ball_value(private, ie->ball, ie->xrel, ie->yrel);
|
||||
process_hid_report(device, private->report_buffer, private->buffer_length);
|
||||
set_ball_value(device, ie->ball, ie->xrel, ie->yrel);
|
||||
bus_event_queue_input_report(&event_queue, iface, device->report_buffer, device->buffer_length);
|
||||
break;
|
||||
}
|
||||
case SDL_JOYHATMOTION:
|
||||
{
|
||||
SDL_JoyHatEvent *ie = &event->jhat;
|
||||
|
||||
set_hat_value(private, ie->hat, ie->value);
|
||||
process_hid_report(device, private->report_buffer, private->buffer_length);
|
||||
set_hat_value(device, ie->hat, ie->value);
|
||||
bus_event_queue_input_report(&event_queue, iface, device->report_buffer, device->buffer_length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -641,10 +660,9 @@ static BOOL set_report_from_event(DEVICE_OBJECT *device, SDL_Event *event)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL set_mapped_report_from_event(DEVICE_OBJECT *device, SDL_Event *event)
|
||||
static BOOL set_mapped_report_from_event(struct platform_private *device, SDL_Event *event)
|
||||
{
|
||||
struct platform_private *private;
|
||||
private = impl_from_DEVICE_OBJECT(device);
|
||||
struct unix_device *iface = &device->unix_device;
|
||||
|
||||
switch(event->type)
|
||||
{
|
||||
|
@ -672,8 +690,8 @@ static BOOL set_mapped_report_from_event(DEVICE_OBJECT *device, SDL_Event *event
|
|||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||
set_hat_value(private, 0, compose_dpad_value(private->sdl_controller));
|
||||
process_hid_report(device, private->report_buffer, private->buffer_length);
|
||||
set_hat_value(device, 0, compose_dpad_value(device->sdl_controller));
|
||||
bus_event_queue_input_report(&event_queue, iface, device->report_buffer, device->buffer_length);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -682,8 +700,8 @@ static BOOL set_mapped_report_from_event(DEVICE_OBJECT *device, SDL_Event *event
|
|||
|
||||
if (usage >= 0)
|
||||
{
|
||||
set_button_value(private, usage, ie->state);
|
||||
process_hid_report(device, private->report_buffer, private->buffer_length);
|
||||
set_button_value(device, usage, ie->state);
|
||||
bus_event_queue_input_report(&event_queue, iface, device->report_buffer, device->buffer_length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -691,8 +709,8 @@ static BOOL set_mapped_report_from_event(DEVICE_OBJECT *device, SDL_Event *event
|
|||
{
|
||||
SDL_ControllerAxisEvent *ie = &event->caxis;
|
||||
|
||||
set_axis_value(private, ie->axis, ie->value, TRUE);
|
||||
process_hid_report(device, private->report_buffer, private->buffer_length);
|
||||
set_axis_value(device, ie->axis, ie->value, TRUE);
|
||||
bus_event_queue_input_report(&event_queue, iface, device->report_buffer, device->buffer_length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -759,6 +777,7 @@ static void sdl_add_device(unsigned int index)
|
|||
TRACE("%s id %d, desc %s.\n", controller ? "controller" : "joystick", id, debugstr_device_desc(&desc));
|
||||
|
||||
if (!(private = unix_device_create(&sdl_device_vtbl, sizeof(struct platform_private)))) return;
|
||||
list_add_tail(&device_list, &private->unix_device.entry);
|
||||
private->sdl_joystick = joystick;
|
||||
private->sdl_controller = controller;
|
||||
private->id = id;
|
||||
|
@ -768,11 +787,13 @@ static void sdl_add_device(unsigned int index)
|
|||
|
||||
static void process_device_event(SDL_Event *event)
|
||||
{
|
||||
DEVICE_OBJECT *device;
|
||||
struct platform_private *device;
|
||||
SDL_JoystickID id;
|
||||
|
||||
TRACE_(hid_report)("Received action %x\n", event->type);
|
||||
|
||||
EnterCriticalSection(&sdl_cs);
|
||||
|
||||
if (event->type == SDL_JOYDEVICEADDED)
|
||||
sdl_add_device(((SDL_JoyDeviceEvent *)event)->which);
|
||||
else if (event->type == SDL_JOYDEVICEREMOVED)
|
||||
|
@ -783,17 +804,19 @@ static void process_device_event(SDL_Event *event)
|
|||
else if (event->type >= SDL_JOYAXISMOTION && event->type <= SDL_JOYBUTTONUP)
|
||||
{
|
||||
id = ((SDL_JoyButtonEvent *)event)->which;
|
||||
device = bus_find_hid_device(sdl_busidW, ULongToPtr(id));
|
||||
device = find_device_from_id(id);
|
||||
if (device) set_report_from_event(device, event);
|
||||
else WARN("failed to find device with id %d\n", id);
|
||||
}
|
||||
else if (event->type >= SDL_CONTROLLERAXISMOTION && event->type <= SDL_CONTROLLERBUTTONUP)
|
||||
{
|
||||
id = ((SDL_ControllerButtonEvent *)event)->which;
|
||||
device = bus_find_hid_device(sdl_busidW, ULongToPtr(id));
|
||||
device = find_device_from_id(id);
|
||||
if (device) set_mapped_report_from_event(device, event);
|
||||
else WARN("failed to find device with id %d\n", id);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&sdl_cs);
|
||||
}
|
||||
|
||||
static void sdl_load_mappings(void)
|
||||
|
@ -938,6 +961,9 @@ NTSTATUS sdl_bus_wait(void *args)
|
|||
struct bus_event *result = args;
|
||||
SDL_Event event;
|
||||
|
||||
/* cleanup previously returned event */
|
||||
bus_event_cleanup(result);
|
||||
|
||||
do
|
||||
{
|
||||
if (bus_event_queue_pop(&event_queue, result)) return STATUS_PENDING;
|
||||
|
|
|
@ -393,6 +393,25 @@ DEVICE_OBJECT *bus_find_hid_device(const WCHAR *bus_id, void *platform_dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_OBJECT *bus_find_unix_device(struct unix_device *unix_device)
|
||||
{
|
||||
struct device_extension *ext;
|
||||
DEVICE_OBJECT *ret = NULL;
|
||||
|
||||
EnterCriticalSection(&device_list_cs);
|
||||
LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry)
|
||||
{
|
||||
if (ext->unix_device == unix_device)
|
||||
{
|
||||
ret = ext->device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&device_list_cs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bus_unlink_hid_device(DEVICE_OBJECT *device)
|
||||
{
|
||||
struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
|
||||
|
@ -635,6 +654,13 @@ static DWORD CALLBACK bus_main_thread(void *args)
|
|||
winebus_call(device_remove, event->device_created.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);
|
||||
else process_hid_report(device, event->input_report.buffer, event->input_report.length);
|
||||
LeaveCriticalSection(&device_list_cs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -646,7 +672,7 @@ static DWORD CALLBACK bus_main_thread(void *args)
|
|||
|
||||
static NTSTATUS bus_main_thread_start(struct bus_main_params *bus)
|
||||
{
|
||||
DWORD i = bus_count++;
|
||||
DWORD i = bus_count++, max_size;
|
||||
|
||||
if (!(bus->init_done = CreateEventW(NULL, FALSE, FALSE, NULL)))
|
||||
{
|
||||
|
@ -655,7 +681,8 @@ static NTSTATUS bus_main_thread_start(struct bus_main_params *bus)
|
|||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if (!(bus->bus_event = HeapAlloc(GetProcessHeap(), 0, sizeof(struct bus_event))))
|
||||
max_size = offsetof(struct bus_event, input_report.buffer[0x10000]);
|
||||
if (!(bus->bus_event = HeapAlloc(GetProcessHeap(), 0, max_size)))
|
||||
{
|
||||
ERR("failed to allocate %s bus event.\n", debugstr_w(bus->name));
|
||||
CloseHandle(bus->init_done);
|
||||
|
|
|
@ -45,6 +45,7 @@ struct unix_device
|
|||
{
|
||||
const struct unix_device_vtbl *vtbl;
|
||||
struct list entry;
|
||||
LONG ref;
|
||||
};
|
||||
|
||||
extern void *unix_device_create(const struct unix_device_vtbl *vtbl, SIZE_T size) DECLSPEC_HIDDEN;
|
||||
|
@ -61,9 +62,12 @@ 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_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_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;
|
||||
extern BOOL bus_event_queue_pop(struct list *queue, struct bus_event *event) DECLSPEC_HIDDEN;
|
||||
|
||||
struct hid_descriptor
|
||||
|
|
|
@ -248,16 +248,30 @@ void *unix_device_create(const struct unix_device_vtbl *vtbl, SIZE_T size)
|
|||
|
||||
if (!(iface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size))) return NULL;
|
||||
iface->vtbl = vtbl;
|
||||
iface->ref = 1;
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
static void unix_device_decref(struct unix_device *iface)
|
||||
{
|
||||
if (!InterlockedDecrement(&iface->ref))
|
||||
{
|
||||
iface->vtbl->destroy(iface);
|
||||
HeapFree(GetProcessHeap(), 0, iface);
|
||||
}
|
||||
}
|
||||
|
||||
static ULONG unix_device_incref(struct unix_device *iface)
|
||||
{
|
||||
return InterlockedIncrement(&iface->ref);
|
||||
}
|
||||
|
||||
static NTSTATUS unix_device_remove(void *args)
|
||||
{
|
||||
struct unix_device *iface = args;
|
||||
iface->vtbl->stop(iface);
|
||||
iface->vtbl->destroy(iface);
|
||||
HeapFree(GetProcessHeap(), 0, iface);
|
||||
unix_device_decref(iface);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -328,12 +342,21 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
|
|||
unix_device_set_feature_report,
|
||||
};
|
||||
|
||||
void bus_event_cleanup(struct bus_event *event)
|
||||
{
|
||||
if (event->type == BUS_EVENT_TYPE_INPUT_REPORT)
|
||||
unix_device_decref(event->input_report.device);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bus_event_cleanup(event);
|
||||
HeapFree(GetProcessHeap(), 0, event);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL bus_event_queue_device_removed(struct list *queue, const WCHAR *bus_id, void *context)
|
||||
|
@ -364,17 +387,38 @@ BOOL bus_event_queue_device_created(struct list *queue, struct unix_device *devi
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL bus_event_queue_input_report(struct list *queue, struct unix_device *device, BYTE *report, USHORT length)
|
||||
{
|
||||
ULONG size = offsetof(struct bus_event, input_report.buffer[length]);
|
||||
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_INPUT_REPORT;
|
||||
event->input_report.device = device;
|
||||
event->input_report.length = length;
|
||||
memcpy(event->input_report.buffer, report, length);
|
||||
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;
|
||||
ULONG size;
|
||||
|
||||
if (!entry) return FALSE;
|
||||
|
||||
tmp = LIST_ENTRY(entry, struct bus_event, entry);
|
||||
list_remove(entry);
|
||||
|
||||
memcpy(event, tmp, sizeof(*event));
|
||||
if (event->type != BUS_EVENT_TYPE_INPUT_REPORT) size = sizeof(*event);
|
||||
else size = offsetof(struct bus_event, input_report.buffer[event->input_report.length]);
|
||||
|
||||
memcpy(event, tmp, size);
|
||||
HeapFree(GetProcessHeap(), 0, tmp);
|
||||
|
||||
return TRUE;
|
||||
|
|
|
@ -69,6 +69,7 @@ enum bus_event_type
|
|||
BUS_EVENT_TYPE_NONE,
|
||||
BUS_EVENT_TYPE_DEVICE_REMOVED,
|
||||
BUS_EVENT_TYPE_DEVICE_CREATED,
|
||||
BUS_EVENT_TYPE_INPUT_REPORT,
|
||||
};
|
||||
|
||||
struct bus_event
|
||||
|
@ -89,6 +90,13 @@ struct bus_event
|
|||
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