winebus.sys: Factor out HID report buffers allocation.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-09-23 08:55:26 +02:00 committed by Alexandre Julliard
parent 5990f19bdc
commit c6df23fed3
4 changed files with 59 additions and 76 deletions

View File

@ -123,9 +123,6 @@ struct sdl_device
SDL_GameController *sdl_controller;
SDL_JoystickID id;
int buffer_length;
BYTE *report_buffer;
SDL_Haptic *sdl_haptic;
int haptic_effect_id;
};
@ -153,8 +150,8 @@ static void set_button_value(struct sdl_device *impl, int index, int value)
int bit_index = index % 8;
BYTE mask = 1 << bit_index;
if (index >= state->button_count) return;
if (value) impl->report_buffer[byte_index] |= mask;
else impl->report_buffer[byte_index] &= ~mask;
if (value) state->report_buf[byte_index] |= mask;
else state->report_buf[byte_index] &= ~mask;
}
static void set_axis_value(struct sdl_device *impl, int index, short value)
@ -163,7 +160,7 @@ static void set_axis_value(struct sdl_device *impl, int index, short value)
USHORT offset = state->abs_axis_start;
if (index >= state->abs_axis_count) return;
offset += index * sizeof(DWORD);
*(DWORD *)&impl->report_buffer[offset] = LE_DWORD(value);
*(DWORD *)&state->report_buf[offset] = LE_DWORD(value);
}
static void set_ball_value(struct sdl_device *impl, int index, int value1, int value2)
@ -172,8 +169,8 @@ static void set_ball_value(struct sdl_device *impl, int index, int value1, int v
USHORT offset = state->rel_axis_start;
if (index >= state->rel_axis_count) return;
offset += index * sizeof(DWORD);
*(DWORD *)&impl->report_buffer[offset] = LE_DWORD(value1);
*(DWORD *)&impl->report_buffer[offset + sizeof(DWORD)] = LE_DWORD(value2);
*(DWORD *)&state->report_buf[offset] = LE_DWORD(value1);
*(DWORD *)&state->report_buf[offset + sizeof(DWORD)] = LE_DWORD(value2);
}
static void set_hat_value(struct sdl_device *impl, int index, int value)
@ -202,7 +199,7 @@ static void set_hat_value(struct sdl_device *impl, int index, int value)
default: return;
}
impl->report_buffer[offset] = val;
state->report_buf[offset] = val;
}
static BOOL descriptor_add_haptic(struct sdl_device *impl)
@ -287,9 +284,6 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface)
if (!hid_device_end_report_descriptor(iface))
return STATUS_NO_MEMORY;
impl->buffer_length = iface->hid_device_state.report_len;
if (!(impl->report_buffer = calloc(1, impl->buffer_length))) goto failed;
/* Initialize axis in the report */
for (i = 0; i < axis_count; i++)
set_axis_value(impl, i, pSDL_JoystickGetAxis(impl->sdl_joystick, i));
@ -297,10 +291,6 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface)
set_hat_value(impl, i, pSDL_JoystickGetHat(impl->sdl_joystick, i));
return STATUS_SUCCESS;
failed:
free(impl->report_buffer);
return STATUS_NO_MEMORY;
}
static SHORT compose_dpad_value(SDL_GameController *joystick)
@ -366,19 +356,12 @@ static NTSTATUS build_controller_report_descriptor(struct unix_device *iface)
if (!hid_device_end_report_descriptor(iface))
return STATUS_NO_MEMORY;
impl->buffer_length = impl->unix_device.hid_device_state.report_len;
if (!(impl->report_buffer = calloc(1, impl->buffer_length))) goto failed;
/* Initialize axis in the report */
for (i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++)
set_axis_value(impl, i, pSDL_GameControllerGetAxis(impl->sdl_controller, i));
set_hat_value(impl, 0, compose_dpad_value(impl->sdl_controller));
return STATUS_SUCCESS;
failed:
free(impl->report_buffer);
return STATUS_NO_MEMORY;
}
static void sdl_device_destroy(struct unix_device *iface)
@ -477,6 +460,7 @@ static const struct hid_device_vtbl sdl_device_vtbl =
static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *event)
{
struct unix_device *iface = &impl->unix_device;
struct hid_device_state *state = &iface->hid_device_state;
if (impl->sdl_controller) return TRUE; /* use controller events instead */
@ -488,8 +472,7 @@ static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *e
SDL_JoyButtonEvent *ie = &event->jbutton;
set_button_value(impl, ie->button, ie->state);
bus_event_queue_input_report(&event_queue, iface, impl->report_buffer, impl->buffer_length);
bus_event_queue_input_report(&event_queue, iface, state->report_buf, state->report_len);
break;
}
case SDL_JOYAXISMOTION:
@ -499,7 +482,7 @@ static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *e
if (ie->axis < 6)
{
set_axis_value(impl, ie->axis, ie->value);
bus_event_queue_input_report(&event_queue, iface, impl->report_buffer, impl->buffer_length);
bus_event_queue_input_report(&event_queue, iface, state->report_buf, state->report_len);
}
break;
}
@ -508,7 +491,7 @@ static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *e
SDL_JoyBallEvent *ie = &event->jball;
set_ball_value(impl, ie->ball, ie->xrel, ie->yrel);
bus_event_queue_input_report(&event_queue, iface, impl->report_buffer, impl->buffer_length);
bus_event_queue_input_report(&event_queue, iface, state->report_buf, state->report_len);
break;
}
case SDL_JOYHATMOTION:
@ -516,7 +499,7 @@ static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *e
SDL_JoyHatEvent *ie = &event->jhat;
set_hat_value(impl, ie->hat, ie->value);
bus_event_queue_input_report(&event_queue, iface, impl->report_buffer, impl->buffer_length);
bus_event_queue_input_report(&event_queue, iface, state->report_buf, state->report_len);
break;
}
default:
@ -528,6 +511,7 @@ static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *e
static BOOL set_report_from_controller_event(struct sdl_device *impl, SDL_Event *event)
{
struct unix_device *iface = &impl->unix_device;
struct hid_device_state *state = &iface->hid_device_state;
switch(event->type)
{
@ -555,7 +539,7 @@ static BOOL set_report_from_controller_event(struct sdl_device *impl, SDL_Event
}
set_button_value(impl, button, ie->state);
bus_event_queue_input_report(&event_queue, iface, impl->report_buffer, impl->buffer_length);
bus_event_queue_input_report(&event_queue, iface, state->report_buf, state->report_len);
break;
}
case SDL_CONTROLLERAXISMOTION:
@ -563,7 +547,7 @@ static BOOL set_report_from_controller_event(struct sdl_device *impl, SDL_Event
SDL_ControllerAxisEvent *ie = &event->caxis;
set_axis_value(impl, ie->axis, ie->value);
bus_event_queue_input_report(&event_queue, iface, impl->report_buffer, impl->buffer_length);
bus_event_queue_input_report(&event_queue, iface, state->report_buf, state->report_len);
break;
}
default:

View File

@ -122,11 +122,6 @@ struct lnxev_device
{
struct base_device base;
int buffer_length;
BYTE *last_report_buffer;
BYTE *current_report_buffer;
enum { FIRST, NORMAL, DROPPED } report_state;
BYTE abs_map[HID_ABS_MAX];
BYTE rel_map[HID_REL_MAX];
BYTE hat_map[8];
@ -338,8 +333,8 @@ static void set_button_value(struct lnxev_device *impl, int index, int value)
int bit_index = index % 8;
BYTE mask = 1 << bit_index;
if (index >= state->button_count) return;
if (value) impl->current_report_buffer[byte_index] |= mask;
else impl->current_report_buffer[byte_index] &= ~mask;
if (value) state->report_buf[byte_index] |= mask;
else state->report_buf[byte_index] &= ~mask;
}
static void set_abs_axis_value(struct lnxev_device *impl, int code, int value)
@ -387,7 +382,7 @@ static void set_abs_axis_value(struct lnxev_device *impl, int code, int value)
offset = state->hatswitch_start;
if (index >= state->hatswitch_count) return;
offset += index;
impl->current_report_buffer[offset] = value;
state->report_buf[offset] = value;
}
else if (code < HID_ABS_MAX && ABS_TO_HID_MAP[code][0] != 0)
{
@ -395,7 +390,7 @@ static void set_abs_axis_value(struct lnxev_device *impl, int code, int value)
offset = state->abs_axis_start;
if (index >= state->abs_axis_count) return;
offset += index * sizeof(DWORD);
*(DWORD *)&impl->current_report_buffer[offset] = LE_DWORD(value);
*(DWORD *)&state->report_buf[offset] = LE_DWORD(value);
}
}
@ -409,7 +404,7 @@ static void set_rel_axis_value(struct lnxev_device *impl, int code, int value)
offset = state->rel_axis_start;
if (index >= state->rel_axis_count) return;
offset += index * sizeof(DWORD);
*(DWORD *)&impl->current_report_buffer[offset] = LE_DWORD(value);
*(DWORD *)&state->report_buf[offset] = LE_DWORD(value);
}
}
@ -530,48 +525,25 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d
if (!hid_device_end_report_descriptor(iface))
return STATUS_NO_MEMORY;
impl->buffer_length = iface->hid_device_state.report_len;
if (!(impl->current_report_buffer = calloc(1, impl->buffer_length))) goto failed;
if (!(impl->last_report_buffer = calloc(1, impl->buffer_length))) goto failed;
impl->report_state = FIRST;
/* Initialize axis in the report */
for (i = 0; i < HID_ABS_MAX; i++)
if (test_bit(absbits, i))
set_abs_axis_value(impl, i, abs_info[i].value);
return STATUS_SUCCESS;
failed:
free(impl->current_report_buffer);
free(impl->last_report_buffer);
return STATUS_NO_MEMORY;
}
static BOOL set_report_from_event(struct lnxev_device *impl, struct input_event *ie)
static BOOL set_report_from_event(struct unix_device *iface, struct input_event *ie)
{
struct lnxev_device *impl = lnxev_impl_from_unix_device(iface);
switch(ie->type)
{
#ifdef EV_SYN
case EV_SYN:
switch (ie->code)
{
case SYN_REPORT:
if (impl->report_state == NORMAL)
{
memcpy(impl->last_report_buffer, impl->current_report_buffer, impl->buffer_length);
return TRUE;
}
else
{
if (impl->report_state == DROPPED)
memcpy(impl->current_report_buffer, impl->last_report_buffer, impl->buffer_length);
impl->report_state = NORMAL;
}
break;
case SYN_DROPPED:
TRACE_(hid_report)("received SY_DROPPED\n");
impl->report_state = DROPPED;
case SYN_REPORT: return hid_device_sync_report(iface);
case SYN_DROPPED: hid_device_drop_report(iface); break;
}
return FALSE;
#endif
@ -785,10 +757,6 @@ static const struct raw_device_vtbl hidraw_device_vtbl =
static void lnxev_device_destroy(struct unix_device *iface)
{
struct lnxev_device *impl = lnxev_impl_from_unix_device(iface);
free(impl->current_report_buffer);
free(impl->last_report_buffer);
udev_device_unref(impl->base.udev_device);
}
@ -818,20 +786,20 @@ static void lnxev_device_stop(struct unix_device *iface)
static void lnxev_device_read_report(struct unix_device *iface)
{
struct hid_device_state *state = &iface->hid_device_state;
struct lnxev_device *impl = lnxev_impl_from_unix_device(iface);
struct input_event ie;
int size;
if (!impl->current_report_buffer || impl->buffer_length == 0)
return;
if (!state->report_buf || !state->report_len) return;
size = read(impl->base.device_fd, &ie, sizeof(ie));
if (size == -1)
TRACE_(hid_report)("Read failed. Likely an unplugged device\n");
else if (size == 0)
TRACE_(hid_report)("Failed to read report\n");
else if (set_report_from_event(impl, &ie))
bus_event_queue_input_report(&event_queue, iface, impl->current_report_buffer, impl->buffer_length);
else if (set_report_from_event(iface, &ie))
bus_event_queue_input_report(&event_queue, iface, state->report_buf, state->report_len);
}
static void lnxev_device_set_output_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)

View File

@ -89,12 +89,15 @@ BOOL hid_device_begin_report_descriptor(struct unix_device *iface, USAGE usage_p
BOOL hid_device_end_report_descriptor(struct unix_device *iface)
{
struct hid_report_descriptor *desc = &iface->hid_report_descriptor;
struct hid_device_state *state = &iface->hid_device_state;
static const BYTE template[] =
{
END_COLLECTION,
};
iface->hid_device_state.report_len = (iface->hid_device_state.bit_size + 7) / 8;
state->report_len = (state->bit_size + 7) / 8;
if (!(state->report_buf = calloc(1, state->report_len))) return FALSE;
if (!(state->last_report_buf = calloc(1, state->report_len))) return FALSE;
return hid_report_descriptor_append(desc, template, sizeof(template));
}
@ -307,6 +310,8 @@ static void hid_device_destroy(struct unix_device *iface)
{
iface->hid_vtbl->destroy(iface);
free(iface->hid_report_descriptor.data);
free(iface->hid_device_state.report_buf);
free(iface->hid_device_state.last_report_buf);
}
static NTSTATUS hid_device_start(struct unix_device *iface)
@ -363,3 +368,23 @@ void *hid_device_create(const struct hid_device_vtbl *vtbl, SIZE_T size)
return impl;
}
BOOL hid_device_sync_report(struct unix_device *iface)
{
BOOL dropped;
if (!(dropped = iface->hid_device_state.dropped))
memcpy(iface->hid_device_state.last_report_buf, iface->hid_device_state.report_buf,
iface->hid_device_state.report_len);
else
memcpy(iface->hid_device_state.report_buf, iface->hid_device_state.last_report_buf,
iface->hid_device_state.report_len);
iface->hid_device_state.dropped = FALSE;
return !dropped;
}
void hid_device_drop_report(struct unix_device *iface)
{
iface->hid_device_state.dropped = TRUE;
}

View File

@ -69,6 +69,9 @@ struct hid_device_state
USHORT button_start;
USHORT button_count;
USHORT report_len;
BYTE *report_buf;
BYTE *last_report_buf;
BOOL dropped;
};
struct unix_device
@ -116,6 +119,9 @@ extern BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usa
extern BOOL hid_device_add_haptics(struct unix_device *iface) DECLSPEC_HIDDEN;
extern BOOL hid_device_sync_report(struct unix_device *iface) DECLSPEC_HIDDEN;
extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN;
BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN;
#endif /* __WINEBUS_UNIX_PRIVATE_H */