[PATCH 02/10] winebus.sys: Add a PID device control output report.

Rémi Bernon rbernon at codeweavers.com
Fri Oct 1 02:31:00 CDT 2021


And include it in the HID report descriptor when SDL device has support
for any haptic effect, or when UDEV lnxev device has any FF bit set.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winebus.sys/bus_sdl.c      | 21 +++++++--
 dlls/winebus.sys/bus_udev.c     | 15 +++++++
 dlls/winebus.sys/hid.c          | 75 +++++++++++++++++++++++++++++++++
 dlls/winebus.sys/unix_private.h |  8 ++++
 dlls/winebus.sys/unixlib.c      | 12 ++++++
 5 files changed, 128 insertions(+), 3 deletions(-)

diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c
index 17032e1dba9..bd06717165d 100644
--- a/dlls/winebus.sys/bus_sdl.c
+++ b/dlls/winebus.sys/bus_sdl.c
@@ -115,6 +115,9 @@ static Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick);
 #define WINE_SDL_HAPTIC_RUMBLE    0x80000000 /* using SDL_HapticRumble API */
 
 #define EFFECT_SUPPORT_HAPTICS  (SDL_HAPTIC_LEFTRIGHT|WINE_SDL_HAPTIC_RUMBLE|WINE_SDL_JOYSTICK_RUMBLE)
+#define EFFECT_SUPPORT_PHYSICAL (SDL_HAPTIC_CONSTANT|SDL_HAPTIC_RAMP|SDL_HAPTIC_SINE|SDL_HAPTIC_TRIANGLE| \
+                                 SDL_HAPTIC_SAWTOOTHUP|SDL_HAPTIC_SAWTOOTHDOWN|SDL_HAPTIC_SPRING|SDL_HAPTIC_DAMPER|SDL_HAPTIC_INERTIA| \
+                                 SDL_HAPTIC_FRICTION|SDL_HAPTIC_CUSTOM)
 
 struct sdl_device
 {
@@ -165,14 +168,12 @@ static void set_hat_value(struct unix_device *iface, int index, int value)
 
 static BOOL descriptor_add_haptic(struct sdl_device *impl)
 {
-    unsigned int haptics_mask = SDL_HAPTIC_LEFTRIGHT;
-
     if (!pSDL_JoystickIsHaptic(impl->sdl_joystick) ||
         !(impl->sdl_haptic = pSDL_HapticOpenFromJoystick(impl->sdl_joystick)))
         impl->effect_support = 0;
     else
     {
-        impl->effect_support = pSDL_HapticQuery(impl->sdl_haptic) & haptics_mask;
+        impl->effect_support = pSDL_HapticQuery(impl->sdl_haptic);
         if (pSDL_HapticRumbleSupported(impl->sdl_haptic))
             impl->effect_support |= WINE_SDL_HAPTIC_RUMBLE;
 
@@ -189,6 +190,12 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl)
             return FALSE;
     }
 
+    if ((impl->effect_support & EFFECT_SUPPORT_PHYSICAL))
+    {
+        if (!hid_device_add_physical(&impl->unix_device))
+            return FALSE;
+    }
+
     impl->haptic_effect_id = -1;
     return TRUE;
 }
@@ -391,12 +398,20 @@ NTSTATUS sdl_device_haptics_start(struct unix_device *iface, DWORD duration_ms,
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, USAGE control)
+{
+    FIXME("iface %p, control %#04x stub\n", iface, control);
+
+    return STATUS_NOT_SUPPORTED;
+}
+
 static const struct hid_device_vtbl sdl_device_vtbl =
 {
     sdl_device_destroy,
     sdl_device_start,
     sdl_device_stop,
     sdl_device_haptics_start,
+    sdl_device_physical_device_control,
 };
 
 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 909d91667e1..e4c0103b270 100644
--- a/dlls/winebus.sys/bus_udev.c
+++ b/dlls/winebus.sys/bus_udev.c
@@ -658,6 +658,13 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d
             impl->haptic_effect_id = effect.id;
     }
 
+    for (i = 0; i < FF_MAX; ++i) if (test_bit(ffbits, i)) break;
+    if (i != FF_MAX)
+    {
+        if (!hid_device_add_physical(iface))
+            return STATUS_NO_MEMORY;
+    }
+
     if (!hid_device_end_report_descriptor(iface))
         return STATUS_NO_MEMORY;
 
@@ -802,12 +809,20 @@ static NTSTATUS lnxev_device_haptics_start(struct unix_device *iface, DWORD dura
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, USAGE control)
+{
+    FIXME("iface %p, control %#04x stub!\n", iface, control);
+
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 static const struct hid_device_vtbl lnxev_device_vtbl =
 {
     lnxev_device_destroy,
     lnxev_device_start,
     lnxev_device_stop,
     lnxev_device_haptics_start,
+    lnxev_device_physical_device_control,
 };
 #endif /* HAS_PROPER_INPUT_HEADER */
 
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c
index 0c8e85dfc5f..12db1706ede 100644
--- a/dlls/winebus.sys/hid.c
+++ b/dlls/winebus.sys/hid.c
@@ -35,6 +35,7 @@
 #include "ddk/hidsdi.h"
 
 #include "wine/debug.h"
+#include "wine/hid.h"
 
 #include "unix_private.h"
 
@@ -394,6 +395,64 @@ BOOL hid_device_add_haptics(struct unix_device *iface)
     return hid_report_descriptor_append(desc, haptics_template, sizeof(haptics_template));
 }
 
+#include "pshpack1.h"
+struct pid_device_control
+{
+    BYTE control_index;
+};
+
+static const USAGE pid_device_control_usages[] =
+{
+    0, /* HID nary collection indexes start at 1 */
+    PID_USAGE_DC_ENABLE_ACTUATORS,
+    PID_USAGE_DC_DISABLE_ACTUATORS,
+    PID_USAGE_DC_STOP_ALL_EFFECTS,
+    PID_USAGE_DC_DEVICE_RESET,
+    PID_USAGE_DC_DEVICE_PAUSE,
+    PID_USAGE_DC_DEVICE_CONTINUE,
+};
+#include "poppack.h"
+
+BOOL hid_device_add_physical(struct unix_device *iface)
+{
+    struct hid_report_descriptor *desc = &iface->hid_report_descriptor;
+    const BYTE device_control_report = ++desc->next_report_id[HidP_Output];
+    const BYTE device_control_header[] =
+    {
+        USAGE_PAGE(1, HID_USAGE_PAGE_PID),
+        USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT),
+        COLLECTION(1, Logical),
+            REPORT_ID(1, device_control_report),
+
+            USAGE(1, PID_USAGE_DEVICE_CONTROL),
+            COLLECTION(1, Logical),
+    };
+    const BYTE device_control_footer[] =
+    {
+                LOGICAL_MINIMUM(1, 1),
+                LOGICAL_MAXIMUM(1, 6),
+                REPORT_SIZE(1, 8),
+                REPORT_COUNT(1, 1),
+                OUTPUT(1, Data|Ary|Abs),
+            END_COLLECTION,
+        END_COLLECTION,
+    };
+    ULONG i;
+
+    if (!hid_report_descriptor_append(desc, device_control_header, sizeof(device_control_header)))
+        return FALSE;
+    for (i = 1; i < ARRAY_SIZE(pid_device_control_usages); ++i)
+    {
+        if (!hid_report_descriptor_append_usage(desc, pid_device_control_usages[i]))
+            return FALSE;
+    }
+    if (!hid_report_descriptor_append(desc, device_control_footer, sizeof(device_control_footer)))
+        return FALSE;
+
+    iface->hid_physical.device_control_report = device_control_report;
+    return TRUE;
+}
+
 #include "pop_hid_macros.h"
 
 static void hid_device_destroy(struct unix_device *iface)
@@ -425,6 +484,7 @@ NTSTATUS hid_device_get_report_descriptor(struct unix_device *iface, BYTE *buffe
 
 static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)
 {
+    struct hid_physical *physical = &iface->hid_physical;
     struct hid_haptics *haptics = &iface->hid_haptics;
 
     if (packet->reportId == haptics->waveform_report)
@@ -450,6 +510,21 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC
             io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, rumble->intensity, buzz->intensity);
         }
     }
+    else if (packet->reportId == physical->device_control_report)
+    {
+        struct pid_device_control *report = (struct pid_device_control *)(packet->reportBuffer + 1);
+        USAGE control;
+
+        io->Information = sizeof(*report) + 1;
+        if (packet->reportBufferLen < io->Information)
+            io->Status = STATUS_BUFFER_TOO_SMALL;
+        else if (report->control_index >= ARRAY_SIZE(pid_device_control_usages))
+            io->Status = STATUS_INVALID_PARAMETER;
+        else if (!(control = pid_device_control_usages[report->control_index]))
+            io->Status = STATUS_INVALID_PARAMETER;
+        else
+            io->Status = iface->hid_vtbl->physical_device_control(iface, control);
+    }
     else
     {
         io->Information = 0;
diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h
index 01638bf19fc..c62e4c9d0ab 100644
--- a/dlls/winebus.sys/unix_private.h
+++ b/dlls/winebus.sys/unix_private.h
@@ -47,6 +47,7 @@ struct hid_device_vtbl
     void (*stop)(struct unix_device *iface);
     NTSTATUS (*haptics_start)(struct unix_device *iface, DWORD duration_ms,
                               USHORT rumble_intensity, USHORT buzz_intensity);
+    NTSTATUS (*physical_device_control)(struct unix_device *iface, USAGE control);
 };
 
 struct hid_report_descriptor
@@ -87,6 +88,11 @@ struct hid_haptics
     BYTE waveform_report;
 };
 
+struct hid_physical
+{
+    BYTE device_control_report;
+};
+
 struct hid_device_state
 {
     ULONG bit_size;
@@ -115,6 +121,7 @@ struct unix_device
     struct hid_report_descriptor hid_report_descriptor;
     struct hid_device_state hid_device_state;
     struct hid_haptics hid_haptics;
+    struct hid_physical hid_physical;
 };
 
 extern void *raw_device_create(const struct raw_device_vtbl *vtbl, SIZE_T size) DECLSPEC_HIDDEN;
@@ -152,6 +159,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_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 5cf23badf88..49a42ea04ad 100644
--- a/dlls/winebus.sys/unixlib.c
+++ b/dlls/winebus.sys/unixlib.c
@@ -88,12 +88,18 @@ static NTSTATUS mouse_haptics_start(struct unix_device *iface, DWORD duration,
     return STATUS_NOT_SUPPORTED;
 }
 
+static NTSTATUS mouse_physical_device_control(struct unix_device *iface, USAGE control)
+{
+    return STATUS_NOT_SUPPORTED;
+}
+
 static const struct hid_device_vtbl mouse_vtbl =
 {
     mouse_destroy,
     mouse_start,
     mouse_stop,
     mouse_haptics_start,
+    mouse_physical_device_control,
 };
 
 static const struct device_desc mouse_device_desc =
@@ -145,12 +151,18 @@ static NTSTATUS keyboard_haptics_start(struct unix_device *iface, DWORD duration
     return STATUS_NOT_SUPPORTED;
 }
 
+static NTSTATUS keyboard_physical_device_control(struct unix_device *iface, USAGE control)
+{
+    return STATUS_NOT_SUPPORTED;
+}
+
 static const struct hid_device_vtbl keyboard_vtbl =
 {
     keyboard_destroy,
     keyboard_start,
     keyboard_stop,
     keyboard_haptics_start,
+    keyboard_physical_device_control,
 };
 
 static const struct device_desc keyboard_device_desc =
-- 
2.33.0




More information about the wine-devel mailing list