From 12d91995fd054ce9de0879cb8d03597da452c8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Oct 2021 08:43:22 +0200 Subject: [PATCH] winebus.sys: Add a PID effect update output report. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Advertising support of the periodic effect types only for now. Signed-off-by: RĂ©mi Bernon Signed-off-by: Alexandre Julliard --- dlls/winebus.sys/bus_sdl.c | 20 ++++- dlls/winebus.sys/bus_udev.c | 19 +++- dlls/winebus.sys/hid.c | 151 +++++++++++++++++++++++++++++++- dlls/winebus.sys/unix_private.h | 21 ++++- dlls/winebus.sys/unixlib.c | 14 +++ 5 files changed, 220 insertions(+), 5 deletions(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 33386a80a34..9c2112f8e56 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -174,7 +174,8 @@ static void set_hat_value(struct unix_device *iface, int index, int value) static BOOL descriptor_add_haptic(struct sdl_device *impl) { - USHORT i; + USHORT i, count = 0; + USAGE usages[16]; if (!pSDL_JoystickIsHaptic(impl->sdl_joystick) || !(impl->sdl_haptic = pSDL_HapticOpenFromJoystick(impl->sdl_joystick))) @@ -200,7 +201,13 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) if ((impl->effect_support & EFFECT_SUPPORT_PHYSICAL)) { - if (!hid_device_add_physical(&impl->unix_device)) + /* SDL_HAPTIC_SQUARE doesn't exist */ + if (impl->effect_support & SDL_HAPTIC_SINE) usages[count++] = PID_USAGE_ET_SINE; + if (impl->effect_support & SDL_HAPTIC_TRIANGLE) usages[count++] = PID_USAGE_ET_TRIANGLE; + if (impl->effect_support & SDL_HAPTIC_SAWTOOTHUP) usages[count++] = PID_USAGE_ET_SAWTOOTH_UP; + if (impl->effect_support & SDL_HAPTIC_SAWTOOTHDOWN) usages[count++] = PID_USAGE_ET_SAWTOOTH_DOWN; + + if (!hid_device_add_physical(&impl->unix_device, usages, count)) return FALSE; } @@ -471,6 +478,14 @@ static NTSTATUS sdl_device_physical_effect_control(struct unix_device *iface, BY return STATUS_SUCCESS; } +static NTSTATUS sdl_device_physical_effect_update(struct unix_device *iface, BYTE index, + struct effect_params *params) +{ + FIXME("iface %p, index %u, params %p stub!\n", iface, index, params); + + return STATUS_NOT_IMPLEMENTED; +} + static const struct hid_device_vtbl sdl_device_vtbl = { sdl_device_destroy, @@ -479,6 +494,7 @@ static const struct hid_device_vtbl sdl_device_vtbl = sdl_device_haptics_start, sdl_device_physical_device_control, sdl_device_physical_effect_control, + sdl_device_physical_effect_update, }; static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *event) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 3db261b2404..d63c9aab589 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -567,6 +567,8 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d BYTE ffbits[(FF_MAX+7)/8]; struct ff_effect effect; USAGE_AND_PAGE usage; + USHORT count = 0; + USAGE usages[16]; INT i, button_count, abs_count, rel_count, hat_count; const BYTE *device_usage = what_am_I(dev); struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); @@ -664,7 +666,13 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d for (i = 0; i < FF_MAX; ++i) if (test_bit(ffbits, i)) break; if (i != FF_MAX) { - if (!hid_device_add_physical(iface)) + if (test_bit(ffbits, FF_SINE)) usages[count++] = PID_USAGE_ET_SINE; + if (test_bit(ffbits, FF_SQUARE)) usages[count++] = PID_USAGE_ET_SQUARE; + if (test_bit(ffbits, FF_TRIANGLE)) usages[count++] = PID_USAGE_ET_TRIANGLE; + if (test_bit(ffbits, FF_SAW_UP)) usages[count++] = PID_USAGE_ET_SAWTOOTH_UP; + if (test_bit(ffbits, FF_SAW_DOWN)) usages[count++] = PID_USAGE_ET_SAWTOOTH_DOWN; + + if (!hid_device_add_physical(iface, usages, count)) return STATUS_NO_MEMORY; } @@ -916,6 +924,14 @@ static NTSTATUS lnxev_device_physical_effect_control(struct unix_device *iface, return STATUS_SUCCESS; } +static NTSTATUS lnxev_device_physical_effect_update(struct unix_device *iface, BYTE index, + struct effect_params *params) +{ + FIXME("iface %p, index %u, params %p stub!\n", iface, index, params); + + return STATUS_NOT_IMPLEMENTED; +} + static const struct hid_device_vtbl lnxev_device_vtbl = { lnxev_device_destroy, @@ -924,6 +940,7 @@ static const struct hid_device_vtbl lnxev_device_vtbl = lnxev_device_haptics_start, lnxev_device_physical_device_control, lnxev_device_physical_effect_control, + lnxev_device_physical_effect_update, }; #endif /* HAS_PROPER_INPUT_HEADER */ diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 4ddee27cff9..72d358e6ad7 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -426,12 +426,27 @@ static const USAGE pid_effect_control_usages[] = PID_USAGE_OP_EFFECT_START_SOLO, PID_USAGE_OP_EFFECT_STOP, }; + +struct pid_effect_update +{ + BYTE index; + BYTE type_index; + UINT16 duration; + UINT16 trigger_repeat_interval; + UINT16 sample_period; + UINT16 start_delay; + BYTE gain; + BYTE trigger_button; + BYTE enable_bits; + BYTE direction[2]; +}; #include "poppack.h" -BOOL hid_device_add_physical(struct unix_device *iface) +BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT count) { struct hid_report_descriptor *desc = &iface->hid_report_descriptor; const BYTE device_control_report = ++desc->next_report_id[HidP_Output]; + struct hid_device_state *state = &iface->hid_device_state; const BYTE device_control_header[] = { USAGE_PAGE(1, HID_USAGE_PAGE_PID), @@ -488,6 +503,95 @@ BOOL hid_device_add_physical(struct unix_device *iface) OUTPUT(1, Data|Var|Abs), END_COLLECTION, }; + + const BYTE effect_update_report = ++desc->next_report_id[HidP_Output]; + const BYTE effect_update_header[] = + { + /* Set effect properties */ + USAGE(1, PID_USAGE_SET_EFFECT_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, effect_update_report), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MAXIMUM(1, 0x7f), + LOGICAL_MINIMUM(1, 0x00), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_TYPE), + COLLECTION(1, Logical), + }; + const BYTE effect_update_footer[] = + { + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, count), + REPORT_SIZE(1, 8), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_DURATION), + USAGE(1, PID_USAGE_TRIGGER_REPEAT_INTERVAL), + USAGE(1, PID_USAGE_SAMPLE_PERIOD), + USAGE(1, PID_USAGE_START_DELAY), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 4), + OUTPUT(1, Data|Var|Abs), + PHYSICAL_MAXIMUM(1, 0), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), /* None */ + + USAGE(1, PID_USAGE_GAIN), + LOGICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_TRIGGER_BUTTON), + LOGICAL_MAXIMUM(2, state->button_count), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs|Null), + + USAGE(1, PID_USAGE_AXES_ENABLE), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_GENERIC<<16)|HID_USAGE_GENERIC_X), + USAGE(4, (HID_USAGE_PAGE_GENERIC<<16)|HID_USAGE_GENERIC_Y), + LOGICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + USAGE(1, PID_USAGE_DIRECTION_ENABLE), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 5), + OUTPUT(1, Cnst|Var|Abs), /* 5-bit pad */ + + USAGE(1, PID_USAGE_DIRECTION), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL<<16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL<<16)|2), + UNIT(1, 0x14), /* Eng Rot:Angular Pos */ + UNIT_EXPONENT(1, -2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MAXIMUM(4, 36000), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + PHYSICAL_MAXIMUM(1, 0), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), /* None */ + END_COLLECTION, + }; ULONG i; if (!hid_report_descriptor_append(desc, device_control_header, sizeof(device_control_header))) @@ -510,8 +614,22 @@ BOOL hid_device_add_physical(struct unix_device *iface) if (!hid_report_descriptor_append(desc, effect_control_footer, sizeof(effect_control_footer))) return FALSE; + if (!hid_report_descriptor_append(desc, effect_update_header, sizeof(effect_update_header))) + return FALSE; + for (i = 0; i < count; ++i) + { + if (!hid_report_descriptor_append_usage(desc, usages[i])) + return FALSE; + } + if (!hid_report_descriptor_append(desc, effect_update_footer, sizeof(effect_update_footer))) + return FALSE; + + /* HID nary collection indexes start at 1 */ + memcpy(iface->hid_physical.effect_types + 1, usages, count * sizeof(*usages)); + iface->hid_physical.device_control_report = device_control_report; iface->hid_physical.effect_control_report = effect_control_report; + iface->hid_physical.effect_update_report = effect_update_report; return TRUE; } @@ -602,6 +720,37 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC else io->Status = iface->hid_vtbl->physical_effect_control(iface, report->index, control, report->iterations); } + else if (packet->reportId == physical->effect_update_report) + { + struct pid_effect_update *report = (struct pid_effect_update *)(packet->reportBuffer + 1); + struct effect_params *params = iface->hid_physical.effect_params + report->index; + USAGE effect_type; + + io->Information = sizeof(*report) + 1; + if (packet->reportBufferLen < io->Information) + io->Status = STATUS_BUFFER_TOO_SMALL; + else if (report->type_index >= ARRAY_SIZE(iface->hid_physical.effect_types)) + io->Status = STATUS_INVALID_PARAMETER; + else if (!(effect_type = iface->hid_physical.effect_types[report->type_index])) + io->Status = STATUS_INVALID_PARAMETER; + else + { + params->effect_type = effect_type; + params->duration = report->duration; + params->trigger_repeat_interval = report->trigger_repeat_interval; + params->sample_period = report->sample_period; + params->start_delay = report->start_delay; + params->gain = report->gain; + params->trigger_button = report->trigger_button == 0xff ? 0 : report->trigger_button; + params->axis_enabled[0] = (report->enable_bits & 1) != 0; + params->axis_enabled[1] = (report->enable_bits & 2) != 0; + params->direction_enabled = (report->enable_bits & 4) != 0; + params->direction[0] = report->direction[0]; + params->direction[1] = report->direction[1]; + + io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); + } + } else { io->Information = 0; diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 2446b8de4a7..125ee600eb6 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -29,6 +29,20 @@ #include "wine/list.h" +struct effect_params +{ + USAGE effect_type; + UINT16 duration; + UINT16 trigger_repeat_interval; + UINT16 sample_period; + UINT16 start_delay; + BYTE gain; + BYTE trigger_button; + BOOL axis_enabled[2]; + BOOL direction_enabled; + BYTE direction[2]; +}; + struct raw_device_vtbl { void (*destroy)(struct unix_device *iface); @@ -49,6 +63,7 @@ struct hid_device_vtbl USHORT rumble_intensity, USHORT buzz_intensity); NTSTATUS (*physical_device_control)(struct unix_device *iface, USAGE control); NTSTATUS (*physical_effect_control)(struct unix_device *iface, BYTE index, USAGE control, BYTE iterations); + NTSTATUS (*physical_effect_update)(struct unix_device *iface, BYTE index, struct effect_params *params); }; struct hid_report_descriptor @@ -91,8 +106,12 @@ struct hid_haptics struct hid_physical { + USAGE effect_types[32]; + struct effect_params effect_params[256]; + BYTE device_control_report; BYTE effect_control_report; + BYTE effect_update_report; }; struct hid_device_state @@ -161,7 +180,7 @@ extern BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usa const USAGE *usages, BOOL rel, LONG min, LONG max) DECLSPEC_HIDDEN; extern BOOL hid_device_add_haptics(struct unix_device *iface) DECLSPEC_HIDDEN; -extern BOOL hid_device_add_physical(struct unix_device *iface) DECLSPEC_HIDDEN; +extern BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT count) DECLSPEC_HIDDEN; extern BOOL hid_device_set_abs_axis(struct unix_device *iface, ULONG index, LONG value) DECLSPEC_HIDDEN; extern BOOL hid_device_set_rel_axis(struct unix_device *iface, ULONG index, LONG value) DECLSPEC_HIDDEN; diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 29537170df7..c9d5fa5fd43 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -99,6 +99,12 @@ static NTSTATUS mouse_physical_effect_control(struct unix_device *iface, BYTE in return STATUS_NOT_SUPPORTED; } +static NTSTATUS mouse_physical_effect_update(struct unix_device *iface, BYTE index, + struct effect_params *params) +{ + return STATUS_NOT_SUPPORTED; +} + static const struct hid_device_vtbl mouse_vtbl = { mouse_destroy, @@ -107,6 +113,7 @@ static const struct hid_device_vtbl mouse_vtbl = mouse_haptics_start, mouse_physical_device_control, mouse_physical_effect_control, + mouse_physical_effect_update, }; static const struct device_desc mouse_device_desc = @@ -169,6 +176,12 @@ static NTSTATUS keyboard_physical_effect_control(struct unix_device *iface, BYTE return STATUS_NOT_SUPPORTED; } +static NTSTATUS keyboard_physical_effect_update(struct unix_device *iface, BYTE index, + struct effect_params *params) +{ + return STATUS_NOT_SUPPORTED; +} + static const struct hid_device_vtbl keyboard_vtbl = { keyboard_destroy, @@ -177,6 +190,7 @@ static const struct hid_device_vtbl keyboard_vtbl = keyboard_haptics_start, keyboard_physical_device_control, keyboard_physical_effect_control, + keyboard_physical_effect_update, }; static const struct device_desc keyboard_device_desc =