Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
With this series we should have all non-custom force feedback effect types supported in the dinput HID joystick through PID reports, as well as down in the SDL and UDEV lnxev devices.
Any raw device, like UDEV hidraw or IOHID may be supported too, as long as they use the standard PID reports, although it's quite untested. They may expect slightly different usage of the reports.
What remains after that is a effect status input report, in order to implement force feedback status functions, and then dropping the other backends to convert dinput(8) to PE.
dlls/winebus.sys/bus_sdl.c | 4 ++ dlls/winebus.sys/bus_udev.c | 4 ++ dlls/winebus.sys/hid.c | 107 ++++++++++++++++++++++++++++++++ dlls/winebus.sys/unix_private.h | 13 ++++ 4 files changed, 128 insertions(+)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 4eab51b5cb2..1bec3661757 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -549,6 +549,10 @@ static NTSTATUS sdl_device_physical_effect_update(struct unix_device *iface, BYT effect.periodic.direction.type = SDL_HAPTIC_SPHERICAL; effect.periodic.direction.dir[0] = params->direction[0] * 36000 / 256; effect.periodic.direction.dir[1] = params->direction[1] * 36000 / 256; + effect.periodic.period = params->periodic.period; + effect.periodic.magnitude = params->periodic.magnitude * 128; + effect.periodic.offset = params->periodic.offset; + effect.periodic.phase = params->periodic.phase; break;
case PID_USAGE_ET_SPRING: diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index f780aac2785..e60891c2244 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1001,6 +1001,10 @@ static NTSTATUS lnxev_device_physical_effect_update(struct unix_device *iface, B case PID_USAGE_ET_SAWTOOTH_UP: case PID_USAGE_ET_SAWTOOTH_DOWN: FIXME("periodic effect semi-stub!"); + effect.u.periodic.period = params->periodic.period; + effect.u.periodic.magnitude = params->periodic.magnitude * 128; + effect.u.periodic.offset = params->periodic.offset; + effect.u.periodic.phase = params->periodic.phase; break;
case PID_USAGE_ET_SPRING: diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 72d358e6ad7..10e9316eb6c 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -440,8 +440,85 @@ struct pid_effect_update BYTE enable_bits; BYTE direction[2]; }; + +struct pid_set_periodic +{ + BYTE index; + BYTE magnitude; + BYTE offset; + BYTE phase; + UINT16 period; +}; #include "poppack.h"
+static BOOL hid_descriptor_add_set_periodic(struct unix_device *iface) +{ + struct hid_report_descriptor *desc = &iface->hid_report_descriptor; + const BYTE report_id = ++desc->next_report_id[HidP_Output]; + const BYTE template[] = + { + /* Periodic Report Definition */ + USAGE(1, PID_USAGE_SET_PERIODIC_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, report_id), + + 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_MAGNITUDE), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 10000), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_OFFSET), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, -10000), + PHYSICAL_MAXIMUM(2, 10000), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_PHASE), + UNIT(1, 0x14), /* Eng Rot:Angular Pos */ + UNIT_EXPONENT(1, -2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0xff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(4, 36000), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_PERIOD), + 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, 1), + OUTPUT(1, Data|Var|Abs), + + PHYSICAL_MAXIMUM(1, 0), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), /* None */ + END_COLLECTION, + }; + + iface->hid_physical.set_periodic_report = report_id; + return hid_report_descriptor_append(desc, template, sizeof(template)); +} + BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT count) { struct hid_report_descriptor *desc = &iface->hid_report_descriptor; @@ -592,6 +669,7 @@ BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT co UNIT(1, 0), /* None */ END_COLLECTION, }; + BOOL periodic = FALSE; ULONG i;
if (!hid_report_descriptor_append(desc, device_control_header, sizeof(device_control_header))) @@ -624,6 +702,19 @@ BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT co if (!hid_report_descriptor_append(desc, effect_update_footer, sizeof(effect_update_footer))) return FALSE;
+ for (i = 0; i < count; ++i) + { + if (usages[i] == PID_USAGE_ET_SINE || + usages[i] == PID_USAGE_ET_SQUARE || + usages[i] == PID_USAGE_ET_TRIANGLE || + usages[i] == PID_USAGE_ET_SAWTOOTH_UP || + usages[i] == PID_USAGE_ET_SAWTOOTH_DOWN) + periodic = TRUE; + } + + if (periodic && !hid_descriptor_add_set_periodic(iface)) + return FALSE; + /* HID nary collection indexes start at 1 */ memcpy(iface->hid_physical.effect_types + 1, usages, count * sizeof(*usages));
@@ -751,6 +842,22 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); } } + else if (packet->reportId == physical->set_periodic_report) + { + struct pid_set_periodic *report = (struct pid_set_periodic *)(packet->reportBuffer + 1); + struct effect_params *params = iface->hid_physical.effect_params + report->index; + + io->Information = sizeof(*report) + 1; + if (packet->reportBufferLen < io->Information) + io->Status = STATUS_BUFFER_TOO_SMALL; + else + { + params->periodic.magnitude = report->magnitude; + params->periodic.offset = report->offset; + params->periodic.phase = report->phase; + params->periodic.period = report->period; + } + } else { io->Information = 0; diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 125ee600eb6..5962de7fb10 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -29,6 +29,14 @@
#include "wine/list.h"
+struct effect_periodic +{ + BYTE magnitude; + BYTE offset; + BYTE phase; + UINT16 period; +}; + struct effect_params { USAGE effect_type; @@ -41,6 +49,10 @@ struct effect_params BOOL axis_enabled[2]; BOOL direction_enabled; BYTE direction[2]; + union + { + struct effect_periodic periodic; + }; };
struct raw_device_vtbl @@ -112,6 +124,7 @@ struct hid_physical BYTE device_control_report; BYTE effect_control_report; BYTE effect_update_report; + BYTE set_periodic_report; };
struct hid_device_state