Rémi Bernon : winebus.sys: Add a new rumble report using HID haptics.

Alexandre Julliard julliard at winehq.org
Fri Sep 24 15:31:59 CDT 2021


Module: wine
Branch: master
Commit: cb4d378fa9d3b264357b0bf19f6980f40d81d67e
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=cb4d378fa9d3b264357b0bf19f6980f40d81d67e

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Fri Sep 24 11:51:54 2021 +0200

winebus.sys: Add a new rumble report using HID haptics.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winebus.sys/hid.c          | 150 +++++++++++++++++++++++++++++++++++++---
 dlls/winebus.sys/unix_private.h |  26 +++++++
 2 files changed, 167 insertions(+), 9 deletions(-)

diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c
index c1dd75f77c4..2a02a660f03 100644
--- a/dlls/winebus.sys/hid.c
+++ b/dlls/winebus.sys/hid.c
@@ -24,6 +24,7 @@
 
 #include <stdarg.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -316,12 +317,12 @@ BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usage_page
 BOOL hid_device_add_haptics(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[] =
+    const BYTE vendor_report = ++desc->next_report_id[HidP_Output];
+    const BYTE vendor_template[] =
     {
         USAGE_PAGE(2, HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN),
         COLLECTION(1, Report),
-            REPORT_ID(1, report_id),
+            REPORT_ID(1, vendor_report),
             /* padding */
             REPORT_COUNT(1, 0x02),
             REPORT_SIZE(1, 0x08),
@@ -342,8 +343,86 @@ BOOL hid_device_add_haptics(struct unix_device *iface)
         END_COLLECTION,
     };
 
-    iface->hid_haptics.vendor_report = report_id;
-    return hid_report_descriptor_append(desc, template, sizeof(template));
+    const BYTE haptics_features_report = ++desc->next_report_id[HidP_Feature];
+    const BYTE haptics_waveform_report = ++desc->next_report_id[HidP_Output];
+    const BYTE haptics_template[] =
+    {
+        USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS),
+        USAGE(1, HID_USAGE_HAPTICS_SIMPLE_CONTROLLER),
+        COLLECTION(1, Logical),
+            REPORT_ID(1, haptics_features_report),
+
+            USAGE(1, HID_USAGE_HAPTICS_WAVEFORM_LIST),
+            COLLECTION(1, NamedArray),
+                USAGE_PAGE(1, HID_USAGE_PAGE_ORDINAL),
+                USAGE(1, 3), /* HID_USAGE_HAPTICS_WAVEFORM_RUMBLE */
+                USAGE(1, 4), /* HID_USAGE_HAPTICS_WAVEFORM_BUZZ */
+                REPORT_COUNT(1, 2),
+                REPORT_SIZE(1, 16),
+                FEATURE(1, Data|Var|Abs|Null),
+            END_COLLECTION,
+
+            USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS),
+            USAGE(1, HID_USAGE_HAPTICS_DURATION_LIST),
+            COLLECTION(1, NamedArray),
+                USAGE_PAGE(1, HID_USAGE_PAGE_ORDINAL),
+                USAGE(1, 3), /* 0 (HID_USAGE_HAPTICS_WAVEFORM_RUMBLE) */
+                USAGE(1, 4), /* 0 (HID_USAGE_HAPTICS_WAVEFORM_BUZZ) */
+                REPORT_COUNT(1, 2),
+                REPORT_SIZE(1, 16),
+                FEATURE(1, Data|Var|Abs|Null),
+            END_COLLECTION,
+
+            USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS),
+            USAGE(1, HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME),
+            UNIT(2, 0x1001), /* seconds */
+            UNIT_EXPONENT(1, -3), /* 10^-3 */
+            LOGICAL_MINIMUM(4, 0x00000000),
+            LOGICAL_MAXIMUM(4, 0x7fffffff),
+            PHYSICAL_MINIMUM(4, 0x00000000),
+            PHYSICAL_MAXIMUM(4, 0x7fffffff),
+            REPORT_SIZE(1, 32),
+            REPORT_COUNT(1, 1),
+            FEATURE(1, Data|Var|Abs),
+            /* reset global items */
+            UNIT(1, 0), /* None */
+            UNIT_EXPONENT(1, 0),
+
+            REPORT_ID(1, haptics_waveform_report),
+            USAGE(1, HID_USAGE_HAPTICS_MANUAL_TRIGGER),
+            LOGICAL_MINIMUM(1, 1),
+            LOGICAL_MAXIMUM(1, 4),
+            PHYSICAL_MINIMUM(1, 1),
+            PHYSICAL_MAXIMUM(1, 4),
+            REPORT_SIZE(1, 16),
+            REPORT_COUNT(1, 1),
+            OUTPUT(1, Data|Var|Abs),
+
+            USAGE(1, HID_USAGE_HAPTICS_INTENSITY),
+            LOGICAL_MINIMUM(4, 0x00000000),
+            LOGICAL_MAXIMUM(4, 0x0000ffff),
+            PHYSICAL_MINIMUM(4, 0x00000000),
+            PHYSICAL_MAXIMUM(4, 0x0000ffff),
+            REPORT_SIZE(1, 16),
+            REPORT_COUNT(1, 1),
+            OUTPUT(1, Data|Var|Abs),
+        END_COLLECTION,
+    };
+
+    iface->hid_haptics.vendor_report = vendor_report;
+
+    iface->hid_haptics.features_report = haptics_features_report;
+    iface->hid_haptics.waveform_report = haptics_waveform_report;
+    iface->hid_haptics.features.waveform_list[0] = HID_USAGE_HAPTICS_WAVEFORM_RUMBLE;
+    iface->hid_haptics.features.waveform_list[1] = HID_USAGE_HAPTICS_WAVEFORM_BUZZ;
+    iface->hid_haptics.features.duration_list[0] = 0;
+    iface->hid_haptics.features.duration_list[1] = 0;
+    iface->hid_haptics.features.waveform_cutoff_time_ms = 1000;
+
+    if (!hid_report_descriptor_append(desc, vendor_template, sizeof(vendor_template)))
+        return FALSE;
+
+    return hid_report_descriptor_append(desc, haptics_template, sizeof(haptics_template));
 }
 
 #include "pop_hid_macros.h"
@@ -386,6 +465,29 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC
         io->Information = packet->reportBufferLen;
         io->Status = iface->hid_vtbl->haptics_start(iface, -1, left, right);
     }
+    else if (packet->reportId == haptics->waveform_report)
+    {
+        struct hid_haptics_waveform *waveform = (struct hid_haptics_waveform *)(packet->reportBuffer + 1);
+        struct hid_haptics_waveform *rumble = haptics->waveforms + HAPTICS_WAVEFORM_RUMBLE_INDEX;
+        struct hid_haptics_waveform *buzz = haptics->waveforms + HAPTICS_WAVEFORM_BUZZ_INDEX;
+        ULONG duration_ms;
+
+        io->Information = sizeof(*waveform) + 1;
+        assert(packet->reportBufferLen == io->Information);
+
+        if (waveform->manual_trigger == 0 || waveform->manual_trigger > HAPTICS_WAVEFORM_LAST_INDEX)
+            io->Status = STATUS_INVALID_PARAMETER;
+        else
+        {
+            if (waveform->manual_trigger == HAPTICS_WAVEFORM_STOP_INDEX)
+                memset(haptics->waveforms, 0, sizeof(haptics->waveforms));
+            else
+                haptics->waveforms[waveform->manual_trigger] = *waveform;
+
+            duration_ms = haptics->features.waveform_cutoff_time_ms;
+            io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, rumble->intensity, buzz->intensity);
+        }
+    }
     else
     {
         io->Information = 0;
@@ -395,14 +497,44 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC
 
 static void hid_device_get_feature_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)
 {
-    io->Information = 0;
-    io->Status = STATUS_NOT_IMPLEMENTED;
+    struct hid_haptics *haptics = &iface->hid_haptics;
+
+    if (packet->reportId == haptics->features_report)
+    {
+        struct hid_haptics_features *features = (struct hid_haptics_features *)(packet->reportBuffer + 1);
+
+        io->Information = sizeof(*features) + 1;
+        assert(packet->reportBufferLen == io->Information);
+
+        *features = haptics->features;
+        io->Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        io->Information = 0;
+        io->Status = STATUS_NOT_IMPLEMENTED;
+    }
 }
 
 static void hid_device_set_feature_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)
 {
-    io->Information = 0;
-    io->Status = STATUS_NOT_IMPLEMENTED;
+    struct hid_haptics *haptics = &iface->hid_haptics;
+
+    if (packet->reportId == haptics->features_report)
+    {
+        struct hid_haptics_features *features = (struct hid_haptics_features *)(packet->reportBuffer + 1);
+
+        io->Information = sizeof(*features) + 1;
+        assert(packet->reportBufferLen == io->Information);
+
+        haptics->features.waveform_cutoff_time_ms = features->waveform_cutoff_time_ms;
+        io->Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        io->Information = 0;
+        io->Status = STATUS_NOT_IMPLEMENTED;
+    }
 }
 
 static const struct raw_device_vtbl raw_device_vtbl =
diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h
index 9684ac47067..5da5ca58e7f 100644
--- a/dlls/winebus.sys/unix_private.h
+++ b/dlls/winebus.sys/unix_private.h
@@ -57,9 +57,35 @@ struct hid_report_descriptor
     BYTE next_report_id[3];
 };
 
+enum haptics_waveform_index
+{
+    HAPTICS_WAVEFORM_STOP_INDEX = 1,
+    HAPTICS_WAVEFORM_NULL_INDEX = 2,
+    HAPTICS_WAVEFORM_RUMBLE_INDEX = 3,
+    HAPTICS_WAVEFORM_BUZZ_INDEX = 4,
+    HAPTICS_WAVEFORM_LAST_INDEX = HAPTICS_WAVEFORM_BUZZ_INDEX,
+};
+
+struct hid_haptics_features
+{
+    WORD  waveform_list[HAPTICS_WAVEFORM_LAST_INDEX - HAPTICS_WAVEFORM_NULL_INDEX];
+    WORD  duration_list[HAPTICS_WAVEFORM_LAST_INDEX - HAPTICS_WAVEFORM_NULL_INDEX];
+    DWORD waveform_cutoff_time_ms;
+};
+
+struct hid_haptics_waveform
+{
+    WORD manual_trigger;
+    WORD intensity;
+};
+
 struct hid_haptics
 {
+    struct hid_haptics_features features;
+    struct hid_haptics_waveform waveforms[HAPTICS_WAVEFORM_LAST_INDEX + 1];
     BYTE vendor_report;
+    BYTE features_report;
+    BYTE waveform_report;
 };
 
 struct hid_device_state




More information about the wine-cvs mailing list