* [PATCH v2 08/11] HID: haptic: add functions handling events
2025-08-04 14:11 Jonathan Denose
@ 2025-08-04 14:11 ` Jonathan Denose
0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-04 14:11 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Implement hid_haptic_handle_press_release() which generates haptic feedback
as well as saves the pressed state of the haptic device.
Add functions to increase and reset the state of the pressure detected by
the device.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/hid-haptic.c | 20 +++++++++++++++++++-
drivers/hid/hid-haptic.h | 4 ++++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
index 923b685f0e1e81b7f95567b11209af264c522373..760dd1d70583489c07e199943ebba361d347bfa4 100644
--- a/drivers/hid/hid-haptic.c
+++ b/drivers/hid/hid-haptic.c
@@ -50,8 +50,13 @@ EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping);
bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
struct hid_input *hi, struct hid_field *field)
{
- if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON)
+ if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON) {
+ haptic->force_logical_minimum = field->logical_minimum;
+ haptic->force_physical_minimum = field->physical_minimum;
+ haptic->force_resolution = input_abs_get_res(hi->input,
+ ABS_MT_PRESSURE);
return true;
+ }
return false;
}
EXPORT_SYMBOL_GPL(hid_haptic_check_pressure_unit);
@@ -508,3 +513,16 @@ int hid_haptic_init(struct hid_device *hdev,
return ret;
}
EXPORT_SYMBOL_GPL(hid_haptic_init);
+
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic)
+{
+ haptic->pressure_sum = 0;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_pressure_reset);
+
+void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
+ __s32 pressure)
+{
+ haptic->pressure_sum += pressure;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_pressure_increase);
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
index 9aa910579d09206a2a882a5f708efd8620428f78..0a34b0c6d706a985630962acc41f7a8eb73cd343 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -73,3 +73,7 @@ int hid_haptic_input_configured(struct hid_device *hdev,
struct hid_haptic_device *haptic,
struct hid_input *hi);
int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr);
+void hid_haptic_handle_press_release(struct hid_haptic_device *haptic);
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic);
+void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
+ __s32 pressure);
--
2.50.1.565.gc32cd1483b-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 00/11] HID: Implement haptic touchpad support
@ 2025-08-18 14:28 Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 01/11] HID: add haptics page defines Jonathan Denose
` (11 more replies)
0 siblings, 12 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
Hello,
This is an updated implementation of the interface for controlling haptic
touchpads.
Below is an updated design proposal for the userspace and HID interfaces,
modified from what one of my colleagues submitted in 2019 [0].
We would appreciate any feedback you might have.
Thank you,
Jonathan Denose
Chromium OS Team
Background
==========
There are multiple independent projects to develop a touchpad with force sensors
and haptic actuators, instead of a traditional button. These haptic touchpads
have several advantages and potential uses; they allow clicking across the
entire touchpad surface, adjusting the force requirement for clicks, haptic
feedback initiated by UI, etc. Supporting these features will potentially
require two new communication channels at the kernel level:
* Control of haptic motor by the host
* Force sensor data from device to host
This document includes two related proposals:
1. HID design proposal, that hardware makers would need to implement
2. Kernel design proposal
Objective
==========
Develop a standard protocol to allow userspace applications to communicate with
haptic touchpads, and minimize duplicated code and effort.
Requirements:
1. Support UI-initiated haptic feedback.
2. Allow userspace to control when button press and button release haptic
effects are triggered. (Useful when detecting a false click, changing force
thresholds, or sending context-dependent effects).
3. Reveal force sensor readings to userspace applications.
4. Only allow OS-controlled haptic feedback for those systems which support it.
Proposal
========
In order to minimize duplicated effort, we propose standardized haptic touchpad
support in the linux kernel.
HID API
-------
Modes
.....
The haptic touchpad should be able to operate under two different modes.
1. Device-controlled mode
The haptic touchpad should start up in "device-controlled mode"
(HID_HAPTIC_MODE_DEVICE), meaning it acts as a normal touchpad. This means it
should perform the press and release haptic feedback autonomously at predefined
force thresholds, and send the appropriate BTN_* events.
2. Host-controlled mode
Once the touchpad has been confirmed as supporting haptics (described in more
detail in the the "Click and release control" section below), the device should
enter "host-controlled mode" (HID_HAPTIC_MODE_HOST). In this mode userspace
should take control. From here, userspace will take control over
press/release haptic feedback, relying on the effects sent by the kernel.
Multitouch
..........
The HID API for multitouch reports should follow the Microsoft precision
touchpad spec [1], with the following changes:
* A tip pressure field [2] should be used to report the force. The physical unit
Type (Newtons or grams), exponent, and limits should be reported in the
report descriptor for the force field.
* The device will always report the button state according to its predefined
force thresholds, even when not in device-controlled mode.
* The device must expose a "simple haptic controller" logical collection
alongside the touchpad collection.
Haptic control
..............
The HID protocol described in HUTRR63[3] must be used.
The following waveforms should be supported:
| WAVEFORMNONE | Implicit waveforms required by protocol |
| WAVEFORMSTOP | |
| ------------------------ | ------------------------------------------------- |
| WAVEFORMPRESS | To be used to simulate button press. In device- |
| | controlled mode, it will also be used to simulate |
| | button release. |
| ------------------------ | ------------------------------------------------- |
| WAVEFORMRELEASE | To be used to simulate button release. |
All waveforms will have an associated duration; continuous waveforms will be
ignored by the kernel.
Triggers & Mode switching
.........................
The “auto trigger waveform” should be set to WAVEFORM_PRESS by default, and the
button from the touchpad collection should be set as the “auto trigger
associated control”.
The kernel can trigger the different modes in the following ways:
* Device-controlled mode can be enabled by setting the “auto trigger waveform” to
WAVEFORM_PRESS.
* Host-controlled mode can be enabled by setting the "auto trigger waveform" to
WAVEFORM_STOP.
The device must also support manual triggering. If intensity modification for
waveforms is supported by the device, the intensity control should be included
in the manual trigger output report. This allows modification of the intensity
on a per-waveform basis. Retriggering does not need to be supported by the
device.
Userspace API
-------------
Multitouch protocol
...................
ABS_MT_PRESSURE will be used to report force. The resolution of ABS_MT_PRESSURE
should also be defined and reported in force units of grams or Newtons.
ABS_PRESSURE should be reported as the total force applied to the touchpad.
When the kernel is in host-controlled mode, it should always forward the button
press and release events to userspace.
Use Force Feedback protocol to request pre-defined effects
..........................................................
The force feedback protocol [4] should be used to control predefined effects.
Typical use of the force feedback protocol requires loading effects to the
driver by describing the output waveform, and then requesting those effects
using an ID provided by the driver. However, for haptic touchpads we do not want
to describe the output waveform explicitly, but use a set of predefined effects,
which are identified by HID usage.
The force feedback protocol will need to be extended to allow requests for HID
haptic effects. This requires a new feedback effect type:
/**
* struct ff_haptic_effect
* @hid_usage: hid_usage according to Haptics page (WAVEFORM_CLICK, etc.)
* @vendor_id: the waveform vendor ID if hid_usage is in the vendor-defined
* range
* @vendor_id: the vendor waveform page if hid_usage is in the vendor-defined
* range
* @intensity: strength of the effect
* @repeat_count: number of times to retrigger effect
* @retrigger_period: time before effect is retriggered (in ms)
*/
struct ff_haptic_effect {
__u16 hid_usage;
__u16 vendor_id;
__u8 vendor_waveform_page;
__s16 intensity;
__u16 repeat_count;
__u16 retrigger_period;
}
Since the standard waveform id namespace does not overlap with the vendor
waveform id namespace, the vendor id and page can be ignored for standard
waveforms.
Click and release control
.........................
Haptic functionality shall be gated behind the HID_MULTITOUCH_HAPTIC kernel
configuration option, and this kernel configuration option should only be
enabled if userspace will support haptic capabilities. Haptic functionality will
only be initialized and used if HID_MULTITOUCH_HAPTIC is enabled, and if the
following conditions have been met:
* ABS_MT_PRESSURE is defined and reporting force units of Newtons or grams.
* The device supports haptic effects according to the hid protocol defined in
HUTRR63 [3].
These checks will happen when the driver probes and initializes the multitouch
device.
In the case when the kernel configuration option has been set and the device
reports pressure and haptic effects as defined above, the kernel will initialize
the haptic device and configure the haptic driver to signal that the touchpad is
haptic-compatible. To signal to userspace that the touchpad is haptic-compatible
the kernel will mark INPUT_PROP_HAPTIC_TOUCHPAD.
With userspace willing and able to take control, the kernel will signal to the
device to exit device-controlled mode once a WAVEFORMPRESS or WAVEFORMRELEASE
event is uploaded. From here, userspace will take control over press/release
haptic feedback, relying on the effects sent by the kernel.
In all other cases, the driver will take no action to enable haptic
functionality.
Summary of normal use-case
1. The kernel waits for userspace to upload WAVEFORMPRESS or
WAVEFORMRELEASE.
2. Userspace determines when a click has been performed based on its own
criteria and tells the touchpad to perform a haptic effect.
3. When userspace erases the WAVEFORMPRESS or WAVEFORMRELEASE effect, signal the
device to return to device-controlled mode.
[0]: https://www.spinics.net/lists/linux-input/msg60938.html
[1]: https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchpad-devices
[2]: Usage ID 0x30 of HID usage table 0x0D. See chapter 16:
https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
[3]: https://www.usb.org/sites/default/files/hutrr63b_-_haptics_page_redline_0.pdf
[4]: https://www.kernel.org/doc/html/v4.20/input/ff.html
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
Changes in v2:
- Rename FF_HID and ff_hid_effect to FF_HAPTIC and ff_haptic_effect
- Add more detail to CONFIG_HID_HAPTIC config option description
- Remove CONFIG_MULTITOUCH_HAPTIC config option
- Utilize devm api in hid-multitouch haptic functions
- Link to v1: https://lore.kernel.org/all/20250714-support-forcepads-v1-0-71c7c05748c9@google.com
---
Angela Czubak (11):
HID: add haptics page defines
Input: add FF_HAPTIC effect type
Input: add INPUT_PROP_HAPTIC_TOUCHPAD
HID: haptic: introduce hid_haptic_device
HID: input: allow mapping of haptic output
HID: haptic: initialize haptic device
HID: input: calculate resolution for pressure
HID: haptic: add functions handling events
Input: MT - add INPUT_MT_TOTAL_FORCE flags
HID: haptic: add hid_haptic_switch_mode
HID: multitouch: add haptic multitouch support
Documentation/input/event-codes.rst | 14 +
drivers/hid/Kconfig | 11 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-haptic.c | 580 +++++++++++++++++++++++++++++++++
drivers/hid/hid-haptic.h | 131 ++++++++
drivers/hid/hid-input.c | 18 +-
drivers/hid/hid-multitouch.c | 47 +++
drivers/input/input-mt.c | 14 +-
include/linux/hid.h | 29 ++
include/linux/input/mt.h | 1 +
include/uapi/linux/input-event-codes.h | 1 +
include/uapi/linux/input.h | 22 +-
12 files changed, 862 insertions(+), 7 deletions(-)
---
base-commit: 86731a2a651e58953fc949573895f2fa6d456841
change-id: 20250625-support-forcepads-0b4f74fd3d0a
Best regards,
--
Jonathan Denose <jdenose@google.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 01/11] HID: add haptics page defines
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 02/11] Input: add FF_HAPTIC effect type Jonathan Denose
` (10 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Introduce haptic usages as defined in HID Usage Tables specification.
Add HID units for newton and gram.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
include/linux/hid.h | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 568a9d8c749bc5547ff78d5abe6db7bce2f62d2b..344ab0e40f29afe55575e5a7544496b7bb48a266 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -156,6 +156,7 @@ struct hid_item {
#define HID_UP_TELEPHONY 0x000b0000
#define HID_UP_CONSUMER 0x000c0000
#define HID_UP_DIGITIZER 0x000d0000
+#define HID_UP_HAPTIC 0x000e0000
#define HID_UP_PID 0x000f0000
#define HID_UP_BATTERY 0x00850000
#define HID_UP_CAMERA 0x00900000
@@ -316,6 +317,28 @@ struct hid_item {
#define HID_DG_TOOLSERIALNUMBER 0x000d005b
#define HID_DG_LATENCYMODE 0x000d0060
+#define HID_HP_SIMPLECONTROLLER 0x000e0001
+#define HID_HP_WAVEFORMLIST 0x000e0010
+#define HID_HP_DURATIONLIST 0x000e0011
+#define HID_HP_AUTOTRIGGER 0x000e0020
+#define HID_HP_MANUALTRIGGER 0x000e0021
+#define HID_HP_AUTOTRIGGERASSOCIATEDCONTROL 0x000e0022
+#define HID_HP_INTENSITY 0x000e0023
+#define HID_HP_REPEATCOUNT 0x000e0024
+#define HID_HP_RETRIGGERPERIOD 0x000e0025
+#define HID_HP_WAVEFORMVENDORPAGE 0x000e0026
+#define HID_HP_WAVEFORMVENDORID 0x000e0027
+#define HID_HP_WAVEFORMCUTOFFTIME 0x000e0028
+#define HID_HP_WAVEFORMNONE 0x000e1001
+#define HID_HP_WAVEFORMSTOP 0x000e1002
+#define HID_HP_WAVEFORMCLICK 0x000e1003
+#define HID_HP_WAVEFORMBUZZCONTINUOUS 0x000e1004
+#define HID_HP_WAVEFORMRUMBLECONTINUOUS 0x000e1005
+#define HID_HP_WAVEFORMPRESS 0x000e1006
+#define HID_HP_WAVEFORMRELEASE 0x000e1007
+#define HID_HP_VENDORWAVEFORMMIN 0x000e2001
+#define HID_HP_VENDORWAVEFORMMAX 0x000e2fff
+
#define HID_BAT_ABSOLUTESTATEOFCHARGE 0x00850065
#define HID_BAT_CHARGING 0x00850044
@@ -423,6 +446,12 @@ struct hid_item {
#define HID_REPORT_PROTOCOL 1
#define HID_BOOT_PROTOCOL 0
+/*
+ * HID units
+ */
+#define HID_UNIT_GRAM 0x0101
+#define HID_UNIT_NEWTON 0xe111
+
/*
* This is the global environment of the parser. This information is
* persistent for main-items. The global environment can be saved and
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 02/11] Input: add FF_HAPTIC effect type
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 01/11] HID: add haptics page defines Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 03/11] Input: add INPUT_PROP_HAPTIC_TOUCHPAD Jonathan Denose
` (9 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
FF_HAPTIC effect type can be used to trigger haptic feedback with HID
simple haptic usages.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
include/uapi/linux/input.h | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 2557eb7b056178b2b8be98d9cea855eba1bd5aaf..a440fafaa018947f4d9ca0a15af2b4c6bd0ae6a0 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -428,6 +428,24 @@ struct ff_rumble_effect {
__u16 weak_magnitude;
};
+/**
+ * struct ff_haptic_effect
+ * @hid_usage: hid_usage according to Haptics page (WAVEFORM_CLICK, etc.)
+ * @vendor_id: the waveform vendor ID if hid_usage is in the vendor-defined range
+ * @vendor_waveform_page: the vendor waveform page if hid_usage is in the vendor-defined range
+ * @intensity: strength of the effect as percentage
+ * @repeat_count: number of times to retrigger effect
+ * @retrigger_period: time before effect is retriggered (in ms)
+ */
+struct ff_haptic_effect {
+ __u16 hid_usage;
+ __u16 vendor_id;
+ __u8 vendor_waveform_page;
+ __u16 intensity;
+ __u16 repeat_count;
+ __u16 retrigger_period;
+};
+
/**
* struct ff_effect - defines force feedback effect
* @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
@@ -464,6 +482,7 @@ struct ff_effect {
struct ff_periodic_effect periodic;
struct ff_condition_effect condition[2]; /* One for each axis */
struct ff_rumble_effect rumble;
+ struct ff_haptic_effect haptic;
} u;
};
@@ -471,6 +490,7 @@ struct ff_effect {
* Force feedback effect types
*/
+#define FF_HAPTIC 0x4f
#define FF_RUMBLE 0x50
#define FF_PERIODIC 0x51
#define FF_CONSTANT 0x52
@@ -480,7 +500,7 @@ struct ff_effect {
#define FF_INERTIA 0x56
#define FF_RAMP 0x57
-#define FF_EFFECT_MIN FF_RUMBLE
+#define FF_EFFECT_MIN FF_HAPTIC
#define FF_EFFECT_MAX FF_RAMP
/*
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 03/11] Input: add INPUT_PROP_HAPTIC_TOUCHPAD
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 01/11] HID: add haptics page defines Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 02/11] Input: add FF_HAPTIC effect type Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 16:31 ` Randy Dunlap
2025-08-18 14:28 ` [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device Jonathan Denose
` (8 subsequent siblings)
11 siblings, 1 reply; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
INPUT_PROP_HAPTIC_TOUCHPAD property is to be set for a device with simple
haptic capabilities.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
Documentation/input/event-codes.rst | 14 ++++++++++++++
include/uapi/linux/input-event-codes.h | 1 +
2 files changed, 15 insertions(+)
diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst
index b4557462edd7b3fef9e9cd6c2c3cb2d05bb531ab..6f7aa9e8207c4aa825d9694ad891f4d105fe8196 100644
--- a/Documentation/input/event-codes.rst
+++ b/Documentation/input/event-codes.rst
@@ -400,6 +400,20 @@ can report through the rotational axes (absolute and/or relative rx, ry, rz).
All other axes retain their meaning. A device must not mix
regular directional axes and accelerometer axes on the same event node.
+INPUT_PROP_HAPTIC_TOUCHPAD
+--------------------------
+
+The INPUT_PROP_HAPTIC_TOUCHPAD property indicates that device:
+- supports simple haptic auto and manual triggering
+- can differentiate between at least 5 fingers
+- uses correct resolution for the X/Y (units and value)
+- report correct force per touch, and correct units for them (newtons or grams)
+- follows the MT protocol type B
+
+Summing up, such devices follow the MS spec for input devices in
+Win8 and Win8.1, and in addition support the Simple haptic controller HID table,
+and report correct units for the pressure.
+
Guidelines
==========
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 3b2524e4b667d1e7cc02ff5cb674e7c2ac069a66..efe8c36d4ee9a938ffb1b0dd0ddd0ec6a3fcb8fe 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -27,6 +27,7 @@
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */
+#define INPUT_PROP_HAPTIC_TOUCHPAD 0x07 /* is a haptic touchpad */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (2 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 03/11] Input: add INPUT_PROP_HAPTIC_TOUCHPAD Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 16:36 ` Randy Dunlap
2025-08-18 14:28 ` [PATCH v2 05/11] HID: input: allow mapping of haptic output Jonathan Denose
` (7 subsequent siblings)
11 siblings, 1 reply; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Define a new structure that contains simple haptic device configuration
as well as current state.
Add functions that recognize auto trigger and manual trigger reports
as well as save their addresses.
Verify that the pressure unit is either grams or newtons.
Mark the input device as a haptic touchpad if the unit is correct and
the reports are found.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/Kconfig | 11 +++++
drivers/hid/Makefile | 1 +
drivers/hid/hid-haptic.c | 72 ++++++++++++++++++++++++++++++++
drivers/hid/hid-haptic.h | 105 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 189 insertions(+)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 43859fc757470caf6ad43bd5f72f119e9c36aea7..cbbe82a0a2ba257e45f77ca014fb5f08b71fc62f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -92,6 +92,17 @@ config HID_GENERIC
If unsure, say Y.
+config HID_HAPTIC
+ bool "Haptic touchpad support"
+ default n
+ help
+ Support for touchpads with force sensors and haptic actuators instead of a
+ traditional button.
+ Adds extra parsing and FF device for the hid multitouch driver.
+ It can be used for Elan 2703 haptic touchpad.
+
+ If unsure, say N.
+
menu "Special HID drivers"
config HID_A4TECH
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 10ae5dedbd84708d988ea1f594d409ccebd85ebb..361a7daedeb85454114def8afb5f58caeab58a00 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -4,6 +4,7 @@
#
hid-y := hid-core.o hid-input.o hid-quirks.o
hid-$(CONFIG_DEBUG_FS) += hid-debug.o
+hid-$(CONFIG_HID_HAPTIC) += hid-haptic.o
obj-$(CONFIG_HID_BPF) += bpf/
diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
new file mode 100644
index 0000000000000000000000000000000000000000..d659a430c1a6b06ded31d49efe4bded909671cb6
--- /dev/null
+++ b/drivers/hid/hid-haptic.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HID Haptic support for Linux
+ *
+ * Copyright (c) 2021 Angela Czubak <acz@semihalf.com>
+ */
+
+#include "hid-haptic.h"
+
+void hid_haptic_feature_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_field *field, struct hid_usage *usage)
+{
+ if (usage->hid == HID_HP_AUTOTRIGGER) {
+ if (usage->usage_index >= field->report_count) {
+ dev_err(&hdev->dev,
+ "HID_HP_AUTOTRIGGER out of range\n");
+ return;
+ }
+
+ hid_device_io_start(hdev);
+ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT);
+ hid_hw_wait(hdev);
+ hid_device_io_stop(hdev);
+ haptic->default_auto_trigger =
+ field->value[usage->usage_index];
+ haptic->auto_trigger_report = field->report;
+ }
+}
+EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping);
+
+bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+ struct hid_input *hi, struct hid_field *field)
+{
+ if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON)
+ return true;
+ return false;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_check_pressure_unit);
+
+int hid_haptic_input_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->hid == HID_HP_MANUALTRIGGER) {
+ haptic->manual_trigger_report = field->report;
+ /* we don't really want to map these fields */
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_input_mapping);
+
+int hid_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi)
+{
+
+ if (hi->application == HID_DG_TOUCHPAD) {
+ if (haptic->auto_trigger_report &&
+ haptic->manual_trigger_report) {
+ __set_bit(INPUT_PROP_HAPTIC_TOUCHPAD, hi->input->propbit);
+ return 1;
+ }
+ return 0;
+ }
+ return -1;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_input_configured);
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
new file mode 100644
index 0000000000000000000000000000000000000000..b729f8245aa60c3d06b79b11846dccf6fcc0c08b
--- /dev/null
+++ b/drivers/hid/hid-haptic.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HID Haptic support for Linux
+ *
+ * Copyright (c) 2021 Angela Czubak <acz@semihalf.com>
+ */
+
+/*
+ */
+
+
+#include <linux/hid.h>
+
+#define HID_HAPTIC_ORDINAL_WAVEFORMNONE 1
+#define HID_HAPTIC_ORDINAL_WAVEFORMSTOP 2
+
+#define HID_HAPTIC_MODE_DEVICE 0
+#define HID_HAPTIC_MODE_HOST 1
+
+struct hid_haptic_effect {
+ u8 *report_buf;
+ struct input_dev *input_dev;
+ struct work_struct work;
+ struct list_head control;
+ struct mutex control_mutex;
+};
+
+struct hid_haptic_effect_node {
+ struct list_head node;
+ struct file *file;
+};
+
+struct hid_haptic_device {
+ struct input_dev *input_dev;
+ struct hid_device *hdev;
+ struct hid_report *auto_trigger_report;
+ struct mutex auto_trigger_mutex;
+ struct workqueue_struct *wq;
+ struct hid_report *manual_trigger_report;
+ struct mutex manual_trigger_mutex;
+ size_t manual_trigger_report_len;
+ int pressed_state;
+ s32 pressure_sum;
+ s32 force_logical_minimum;
+ s32 force_physical_minimum;
+ s32 force_resolution;
+ u32 mode;
+ u32 default_auto_trigger;
+ u32 vendor_page;
+ u32 vendor_id;
+ u32 max_waveform_id;
+ u32 max_duration_id;
+ u16 *hid_usage_map;
+ u32 *duration_map;
+ u16 press_ordinal;
+ u16 release_ordinal;
+ struct hid_haptic_effect *effect;
+ struct hid_haptic_effect stop_effect;
+};
+
+#ifdef CONFIG_HID_HAPTIC
+void hid_haptic_feature_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_field *field, struct hid_usage
+ *usage);
+bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+ struct hid_input *hi, struct hid_field *field);
+int hid_haptic_input_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max);
+int hid_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi);
+#else
+static inline
+void hid_haptic_feature_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_field *field, struct hid_usage
+ *usage)
+{}
+static inline
+bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+ struct hid_input *hi, struct hid_field *field)
+{
+ return false;
+}
+static inline
+int hid_haptic_input_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ return 0;
+}
+static inline
+int hid_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi)
+{
+ return 0;
+}
+#endif
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 05/11] HID: input: allow mapping of haptic output
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (3 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 06/11] HID: haptic: initialize haptic device Jonathan Denose
` (6 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
This change makes it possible to parse output reports by input mapping
functions by HID drivers.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/hid-input.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 9d80635a91ebd8d8bdafaac07b5f85693b179cb4..d42c1fbd20a1cc01c04f93cf10f1d1c18043929c 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -682,9 +682,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if (field->report_count < 1)
goto ignore;
- /* only LED usages are supported in output fields */
+ /* only LED and HAPTIC usages are supported in output fields */
if (field->report_type == HID_OUTPUT_REPORT &&
- (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
+ (usage->hid & HID_USAGE_PAGE) != HID_UP_LED &&
+ (usage->hid & HID_USAGE_PAGE) != HID_UP_HAPTIC) {
goto ignore;
}
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 06/11] HID: haptic: initialize haptic device
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (4 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 05/11] HID: input: allow mapping of haptic output Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 07/11] HID: input: calculate resolution for pressure Jonathan Denose
` (5 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Add hid_haptic_init(). Parse autotrigger report to retrieve ordinals for
press and release waveforms.
Implement force feedback functions.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/hid-haptic.c | 438 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/hid/hid-haptic.h | 5 +
2 files changed, 443 insertions(+)
diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
index d659a430c1a6b06ded31d49efe4bded909671cb6..ef09b4039f33f15d7220e69fbed10bd8b0362bb4 100644
--- a/drivers/hid/hid-haptic.c
+++ b/drivers/hid/hid-haptic.c
@@ -5,12 +5,16 @@
* Copyright (c) 2021 Angela Czubak <acz@semihalf.com>
*/
+#include <linux/module.h>
+
#include "hid-haptic.h"
void hid_haptic_feature_mapping(struct hid_device *hdev,
struct hid_haptic_device *haptic,
struct hid_field *field, struct hid_usage *usage)
{
+ u16 usage_hid;
+
if (usage->hid == HID_HP_AUTOTRIGGER) {
if (usage->usage_index >= field->report_count) {
dev_err(&hdev->dev,
@@ -25,6 +29,20 @@ void hid_haptic_feature_mapping(struct hid_device *hdev,
haptic->default_auto_trigger =
field->value[usage->usage_index];
haptic->auto_trigger_report = field->report;
+ } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ORDINAL) {
+ usage_hid = usage->hid & HID_USAGE;
+ switch (field->logical) {
+ case HID_HP_WAVEFORMLIST:
+ if (usage_hid > haptic->max_waveform_id)
+ haptic->max_waveform_id = usage_hid;
+ break;
+ case HID_HP_DURATIONLIST:
+ if (usage_hid > haptic->max_duration_id)
+ haptic->max_duration_id = usage_hid;
+ break;
+ default:
+ break;
+ }
}
}
EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping);
@@ -70,3 +88,423 @@ int hid_haptic_input_configured(struct hid_device *hdev,
return -1;
}
EXPORT_SYMBOL_GPL(hid_haptic_input_configured);
+
+static void parse_auto_trigger_field(struct hid_haptic_device *haptic,
+ struct hid_field *field)
+{
+ int count = field->report_count;
+ int n;
+ u16 usage_hid;
+
+ for (n = 0; n < count; n++) {
+ switch (field->usage[n].hid & HID_USAGE_PAGE) {
+ case HID_UP_ORDINAL:
+ usage_hid = field->usage[n].hid & HID_USAGE;
+ switch (field->logical) {
+ case HID_HP_WAVEFORMLIST:
+ haptic->hid_usage_map[usage_hid] = field->value[n];
+ if (field->value[n] ==
+ (HID_HP_WAVEFORMPRESS & HID_USAGE)) {
+ haptic->press_ordinal = usage_hid;
+ } else if (field->value[n] ==
+ (HID_HP_WAVEFORMRELEASE & HID_USAGE)) {
+ haptic->release_ordinal = usage_hid;
+ }
+ break;
+ case HID_HP_DURATIONLIST:
+ haptic->duration_map[usage_hid] =
+ field->value[n];
+ break;
+ default:
+ break;
+ }
+ break;
+ case HID_UP_HAPTIC:
+ switch (field->usage[n].hid) {
+ case HID_HP_WAVEFORMVENDORID:
+ haptic->vendor_id = field->value[n];
+ break;
+ case HID_HP_WAVEFORMVENDORPAGE:
+ haptic->vendor_page = field->value[n];
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ /* Should not really happen */
+ break;
+ }
+ }
+}
+
+static void fill_effect_buf(struct hid_haptic_device *haptic,
+ struct ff_haptic_effect *effect,
+ struct hid_haptic_effect *haptic_effect,
+ int waveform_ordinal)
+{
+ struct hid_report *rep = haptic->manual_trigger_report;
+ struct hid_usage *usage;
+ struct hid_field *field;
+ s32 value;
+ int i, j;
+ u8 *buf = haptic_effect->report_buf;
+
+ mutex_lock(&haptic->manual_trigger_mutex);
+ for (i = 0; i < rep->maxfield; i++) {
+ field = rep->field[i];
+ /* Ignore if report count is out of bounds. */
+ if (field->report_count < 1)
+ continue;
+
+ for (j = 0; j < field->maxusage; j++) {
+ usage = &field->usage[j];
+
+ switch (usage->hid) {
+ case HID_HP_INTENSITY:
+ if (effect->intensity > 100) {
+ value = field->logical_maximum;
+ } else {
+ value = field->logical_minimum +
+ effect->intensity *
+ (field->logical_maximum -
+ field->logical_minimum) / 100;
+ }
+ break;
+ case HID_HP_REPEATCOUNT:
+ value = effect->repeat_count;
+ break;
+ case HID_HP_RETRIGGERPERIOD:
+ value = effect->retrigger_period;
+ break;
+ case HID_HP_MANUALTRIGGER:
+ value = waveform_ordinal;
+ break;
+ default:
+ break;
+ }
+
+ field->value[j] = value;
+ }
+ }
+
+ hid_output_report(rep, buf);
+ mutex_unlock(&haptic->manual_trigger_mutex);
+}
+
+static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ struct ff_device *ff = dev->ff;
+ struct hid_haptic_device *haptic = ff->private;
+ int i, ordinal = 0;
+
+ /* If vendor range, check vendor id and page */
+ if (effect->u.haptic.hid_usage >= (HID_HP_VENDORWAVEFORMMIN & HID_USAGE) &&
+ effect->u.haptic.hid_usage <= (HID_HP_VENDORWAVEFORMMAX & HID_USAGE) &&
+ (effect->u.haptic.vendor_id != haptic->vendor_id ||
+ effect->u.haptic.vendor_waveform_page != haptic->vendor_page))
+ return -EINVAL;
+
+ /* Check hid_usage */
+ for (i = 1; i <= haptic->max_waveform_id; i++) {
+ if (haptic->hid_usage_map[i] == effect->u.haptic.hid_usage) {
+ ordinal = i;
+ break;
+ }
+ }
+ if (ordinal < 1)
+ return -EINVAL;
+
+ /* Fill the buffer for the effect id */
+ fill_effect_buf(haptic, &effect->u.haptic, &haptic->effect[effect->id],
+ ordinal);
+
+ return 0;
+}
+
+static int play_effect(struct hid_device *hdev, struct hid_haptic_device *haptic,
+ struct hid_haptic_effect *effect)
+{
+ int ret;
+
+ ret = hid_hw_output_report(hdev, effect->report_buf,
+ haptic->manual_trigger_report_len);
+ if (ret < 0) {
+ ret = hid_hw_raw_request(hdev,
+ haptic->manual_trigger_report->id,
+ effect->report_buf,
+ haptic->manual_trigger_report_len,
+ HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
+ }
+
+ return ret;
+}
+
+static void haptic_work_handler(struct work_struct *work)
+{
+
+ struct hid_haptic_effect *effect = container_of(work,
+ struct hid_haptic_effect,
+ work);
+ struct input_dev *dev = effect->input_dev;
+ struct hid_device *hdev = input_get_drvdata(dev);
+ struct hid_haptic_device *haptic = dev->ff->private;
+
+ mutex_lock(&haptic->manual_trigger_mutex);
+ if (effect != &haptic->stop_effect)
+ play_effect(hdev, haptic, &haptic->stop_effect);
+
+ play_effect(hdev, haptic, effect);
+ mutex_unlock(&haptic->manual_trigger_mutex);
+
+}
+
+static int hid_haptic_playback(struct input_dev *dev, int effect_id, int value)
+{
+ struct hid_haptic_device *haptic = dev->ff->private;
+
+ if (value)
+ queue_work(haptic->wq, &haptic->effect[effect_id].work);
+ else
+ queue_work(haptic->wq, &haptic->stop_effect.work);
+
+ return 0;
+}
+
+static void effect_set_default(struct ff_effect *effect)
+{
+ effect->type = FF_HAPTIC;
+ effect->id = -1;
+ effect->u.haptic.hid_usage = HID_HP_WAVEFORMNONE & HID_USAGE;
+ effect->u.haptic.intensity = 100;
+ effect->u.haptic.retrigger_period = 0;
+ effect->u.haptic.repeat_count = 0;
+}
+
+static int hid_haptic_erase(struct input_dev *dev, int effect_id)
+{
+ struct hid_haptic_device *haptic = dev->ff->private;
+ struct ff_effect effect;
+ int ordinal;
+
+ effect_set_default(&effect);
+
+ if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) {
+ ordinal = haptic->release_ordinal;
+ if (!ordinal)
+ ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
+ else
+ effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE &
+ HID_USAGE;
+ fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id],
+ ordinal);
+ } else if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE)) {
+ ordinal = haptic->press_ordinal;
+ if (!ordinal)
+ ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
+ else
+ effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS &
+ HID_USAGE;
+ fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id],
+ ordinal);
+ }
+
+ return 0;
+}
+
+static void hid_haptic_destroy(struct ff_device *ff)
+{
+ struct hid_haptic_device *haptic = ff->private;
+ struct hid_device *hdev = haptic->hdev;
+ int r;
+
+ if (hdev)
+ put_device(&hdev->dev);
+
+ kfree(haptic->stop_effect.report_buf);
+ haptic->stop_effect.report_buf = NULL;
+
+ if (haptic->effect) {
+ for (r = 0; r < ff->max_effects; r++)
+ kfree(haptic->effect[r].report_buf);
+ kfree(haptic->effect);
+ }
+ haptic->effect = NULL;
+
+ destroy_workqueue(haptic->wq);
+ haptic->wq = NULL;
+
+ kfree(haptic->duration_map);
+ haptic->duration_map = NULL;
+
+ kfree(haptic->hid_usage_map);
+ haptic->hid_usage_map = NULL;
+
+ module_put(THIS_MODULE);
+}
+
+int hid_haptic_init(struct hid_device *hdev,
+ struct hid_haptic_device **haptic_ptr)
+{
+ struct hid_haptic_device *haptic = *haptic_ptr;
+ struct input_dev *dev = NULL;
+ struct hid_input *hidinput;
+ struct ff_device *ff;
+ int ret = 0, r;
+ struct ff_haptic_effect stop_effect = {
+ .hid_usage = HID_HP_WAVEFORMSTOP & HID_USAGE,
+ };
+ const char *prefix = "hid-haptic";
+ char *name;
+ int (*flush)(struct input_dev *dev, struct file *file);
+ int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+
+ haptic->hdev = hdev;
+ haptic->max_waveform_id = max(2u, haptic->max_waveform_id);
+ haptic->max_duration_id = max(2u, haptic->max_duration_id);
+
+ haptic->hid_usage_map = kcalloc(haptic->max_waveform_id + 1,
+ sizeof(u16), GFP_KERNEL);
+ if (!haptic->hid_usage_map) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ haptic->duration_map = kcalloc(haptic->max_duration_id + 1,
+ sizeof(u32), GFP_KERNEL);
+ if (!haptic->duration_map) {
+ ret = -ENOMEM;
+ goto usage_map;
+ }
+
+ if (haptic->max_waveform_id != haptic->max_duration_id)
+ dev_warn(&hdev->dev,
+ "Haptic duration and waveform lists have different max id (%u and %u).\n",
+ haptic->max_duration_id, haptic->max_waveform_id);
+
+ haptic->hid_usage_map[HID_HAPTIC_ORDINAL_WAVEFORMNONE] =
+ HID_HP_WAVEFORMNONE & HID_USAGE;
+ haptic->hid_usage_map[HID_HAPTIC_ORDINAL_WAVEFORMSTOP] =
+ HID_HP_WAVEFORMSTOP & HID_USAGE;
+
+ for (r = 0; r < haptic->auto_trigger_report->maxfield; r++)
+ parse_auto_trigger_field(haptic, haptic->auto_trigger_report->field[r]);
+
+ list_for_each_entry(hidinput, &hdev->inputs, list) {
+ if (hidinput->application == HID_DG_TOUCHPAD) {
+ dev = hidinput->input;
+ break;
+ }
+ }
+
+ if (!dev) {
+ dev_err(&hdev->dev, "Failed to find the input device\n");
+ ret = -ENODEV;
+ goto duration_map;
+ }
+
+ haptic->input_dev = dev;
+ haptic->manual_trigger_report_len =
+ hid_report_len(haptic->manual_trigger_report);
+ mutex_init(&haptic->manual_trigger_mutex);
+ name = kmalloc(strlen(prefix) + strlen(hdev->name) + 2, GFP_KERNEL);
+ if (name) {
+ sprintf(name, "%s %s", prefix, hdev->name);
+ haptic->wq = create_singlethread_workqueue(name);
+ kfree(name);
+ }
+ if (!haptic->wq) {
+ ret = -ENOMEM;
+ goto duration_map;
+ }
+ haptic->effect = kcalloc(FF_MAX_EFFECTS,
+ sizeof(struct hid_haptic_effect), GFP_KERNEL);
+ if (!haptic->effect) {
+ ret = -ENOMEM;
+ goto output_queue;
+ }
+ for (r = 0; r < FF_MAX_EFFECTS; r++) {
+ haptic->effect[r].report_buf =
+ hid_alloc_report_buf(haptic->manual_trigger_report,
+ GFP_KERNEL);
+ if (!haptic->effect[r].report_buf) {
+ dev_err(&hdev->dev,
+ "Failed to allocate a buffer for an effect.\n");
+ ret = -ENOMEM;
+ goto buffer_free;
+ }
+ haptic->effect[r].input_dev = dev;
+ INIT_WORK(&haptic->effect[r].work, haptic_work_handler);
+ }
+ haptic->stop_effect.report_buf =
+ hid_alloc_report_buf(haptic->manual_trigger_report,
+ GFP_KERNEL);
+ if (!haptic->stop_effect.report_buf) {
+ dev_err(&hdev->dev,
+ "Failed to allocate a buffer for stop effect.\n");
+ ret = -ENOMEM;
+ goto buffer_free;
+ }
+ haptic->stop_effect.input_dev = dev;
+ INIT_WORK(&haptic->stop_effect.work, haptic_work_handler);
+ fill_effect_buf(haptic, &stop_effect, &haptic->stop_effect,
+ HID_HAPTIC_ORDINAL_WAVEFORMSTOP);
+
+ input_set_capability(dev, EV_FF, FF_HAPTIC);
+
+ flush = dev->flush;
+ event = dev->event;
+ ret = input_ff_create(dev, FF_MAX_EFFECTS);
+ if (ret) {
+ dev_err(&hdev->dev, "Failed to create ff device.\n");
+ goto stop_buffer_free;
+ }
+
+ ff = dev->ff;
+ ff->private = haptic;
+ ff->upload = hid_haptic_upload_effect;
+ ff->playback = hid_haptic_playback;
+ ff->erase = hid_haptic_erase;
+ ff->destroy = hid_haptic_destroy;
+ if (!try_module_get(THIS_MODULE)) {
+ dev_err(&hdev->dev, "Failed to increase module count.\n");
+ goto input_free;
+ }
+ if (!get_device(&hdev->dev)) {
+ dev_err(&hdev->dev, "Failed to get hdev device.\n");
+ module_put(THIS_MODULE);
+ goto input_free;
+ }
+ return 0;
+
+input_free:
+ input_ff_destroy(dev);
+ /* Do not let double free happen, input_ff_destroy will call
+ * hid_haptic_destroy.
+ */
+ *haptic_ptr = NULL;
+ /* Restore dev flush and event */
+ dev->flush = flush;
+ dev->event = event;
+ return ret;
+stop_buffer_free:
+ kfree(haptic->stop_effect.report_buf);
+ haptic->stop_effect.report_buf = NULL;
+buffer_free:
+ while (--r >= 0)
+ kfree(haptic->effect[r].report_buf);
+ kfree(haptic->effect);
+ haptic->effect = NULL;
+output_queue:
+ destroy_workqueue(haptic->wq);
+ haptic->wq = NULL;
+duration_map:
+ kfree(haptic->duration_map);
+ haptic->duration_map = NULL;
+usage_map:
+ kfree(haptic->hid_usage_map);
+ haptic->hid_usage_map = NULL;
+exit:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_init);
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
index b729f8245aa60c3d06b79b11846dccf6fcc0c08b..402ac66954e315eb5444df277ab2b9a4ec415dd6 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -73,6 +73,7 @@ int hid_haptic_input_mapping(struct hid_device *hdev,
int hid_haptic_input_configured(struct hid_device *hdev,
struct hid_haptic_device *haptic,
struct hid_input *hi);
+int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr);
#else
static inline
void hid_haptic_feature_mapping(struct hid_device *hdev,
@@ -102,4 +103,8 @@ int hid_haptic_input_configured(struct hid_device *hdev,
{
return 0;
}
+int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr)
+{
+ return 0;
+}
#endif
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 07/11] HID: input: calculate resolution for pressure
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (5 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 06/11] HID: haptic: initialize haptic device Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 08/11] HID: haptic: add functions handling events Jonathan Denose
` (4 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Assume that if the pressure is given in newtons it should be normalized
to grams. If the pressure has no unit do not calculate resolution.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/hid-input.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d42c1fbd20a1cc01c04f93cf10f1d1c18043929c..1d59787bd0c0e251698e2a2944dae1c4a96adefe 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -303,6 +303,19 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
}
break;
+ case ABS_PRESSURE:
+ case ABS_MT_PRESSURE:
+ if (field->unit == HID_UNIT_NEWTON) {
+ /* Convert to grams, 1 newton is 101.97 grams */
+ prev = physical_extents;
+ physical_extents *= 10197;
+ if (physical_extents < prev)
+ return 0;
+ unit_exponent -= 2;
+ } else if (field->unit != HID_UNIT_GRAM) {
+ return 0;
+ }
+ break;
default:
return 0;
}
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 08/11] HID: haptic: add functions handling events
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (6 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 07/11] HID: input: calculate resolution for pressure Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 09/11] Input: MT - add INPUT_MT_TOTAL_FORCE flags Jonathan Denose
` (3 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Implement hid_haptic_handle_press_release() which generates haptic feedback
as well as saves the pressed state of the haptic device.
Add functions to increase and reset the state of the pressure detected by
the device.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/hid-haptic.c | 20 +++++++++++++++++++-
drivers/hid/hid-haptic.h | 15 +++++++++++++++
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
index ef09b4039f33f15d7220e69fbed10bd8b0362bb4..c02af820051c22d1c899db84496c5a44b868fe49 100644
--- a/drivers/hid/hid-haptic.c
+++ b/drivers/hid/hid-haptic.c
@@ -50,8 +50,13 @@ EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping);
bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
struct hid_input *hi, struct hid_field *field)
{
- if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON)
+ if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON) {
+ haptic->force_logical_minimum = field->logical_minimum;
+ haptic->force_physical_minimum = field->physical_minimum;
+ haptic->force_resolution = input_abs_get_res(hi->input,
+ ABS_MT_PRESSURE);
return true;
+ }
return false;
}
EXPORT_SYMBOL_GPL(hid_haptic_check_pressure_unit);
@@ -508,3 +513,16 @@ int hid_haptic_init(struct hid_device *hdev,
return ret;
}
EXPORT_SYMBOL_GPL(hid_haptic_init);
+
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic)
+{
+ haptic->pressure_sum = 0;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_pressure_reset);
+
+void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
+ __s32 pressure)
+{
+ haptic->pressure_sum += pressure;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_pressure_increase);
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
index 402ac66954e315eb5444df277ab2b9a4ec415dd6..73601f429de16bae3b1d877445f7eebf41a69d94 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -74,6 +74,10 @@ int hid_haptic_input_configured(struct hid_device *hdev,
struct hid_haptic_device *haptic,
struct hid_input *hi);
int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr);
+void hid_haptic_handle_press_release(struct hid_haptic_device *haptic);
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic);
+void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
+ __s32 pressure);
#else
static inline
void hid_haptic_feature_mapping(struct hid_device *hdev,
@@ -107,4 +111,15 @@ int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_p
{
return 0;
}
+static inline
+void hid_haptic_handle_press_release(struct hid_haptic_device *haptic)
+{}
+static inline
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic)
+{}
+static inline
+void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
+ __s32 pressure)
+{}
#endif
+
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 09/11] Input: MT - add INPUT_MT_TOTAL_FORCE flags
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (7 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 08/11] HID: haptic: add functions handling events Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 10/11] HID: haptic: add hid_haptic_switch_mode Jonathan Denose
` (2 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Add a flag to generate ABS_PRESSURE as sum of ABS_MT_PRESSURE across
all slots.
This flag should be set if one knows a device reports true force and would
like to report total force to the userspace.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/input/input-mt.c | 14 ++++++++++----
include/linux/input/mt.h | 1 +
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 337006dd9dcf72ef2eeb8580e4dd83babf8100be..09f518897d4a71a4a7625367dc2c652ee6035d98 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -198,6 +198,7 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
struct input_mt *mt = dev->mt;
struct input_mt_slot *oldest;
int oldid, count, i;
+ int p, reported_p = 0;
if (!mt)
return;
@@ -216,6 +217,13 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
oldest = ps;
oldid = id;
}
+ if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
+ p = input_mt_get_value(ps, ABS_MT_PRESSURE);
+ if (mt->flags & INPUT_MT_TOTAL_FORCE)
+ reported_p += p;
+ else if (oldid == id)
+ reported_p = p;
+ }
count++;
}
@@ -245,10 +253,8 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
input_event(dev, EV_ABS, ABS_X, x);
input_event(dev, EV_ABS, ABS_Y, y);
- if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
- int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
- input_event(dev, EV_ABS, ABS_PRESSURE, p);
- }
+ if (test_bit(ABS_MT_PRESSURE, dev->absbit))
+ input_event(dev, EV_ABS, ABS_PRESSURE, reported_p);
} else {
if (test_bit(ABS_MT_PRESSURE, dev->absbit))
input_event(dev, EV_ABS, ABS_PRESSURE, 0);
diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h
index 2cf89a538b18bbc7c99c8705c2d22bdc95065238..d30286298a00a356bc9db954ae362f034cdd359b 100644
--- a/include/linux/input/mt.h
+++ b/include/linux/input/mt.h
@@ -17,6 +17,7 @@
#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */
#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */
#define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */
+#define INPUT_MT_TOTAL_FORCE 0x0020 /* calculate total force from slots pressure */
/**
* struct input_mt_slot - represents the state of an input MT slot
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 10/11] HID: haptic: add hid_haptic_switch_mode
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (8 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 09/11] Input: MT - add INPUT_MT_TOTAL_FORCE flags Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 11/11] HID: multitouch: add haptic multitouch support Jonathan Denose
2025-08-18 14:34 ` [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
Function hid_haptic_switch_mode() can be used to switch between
device-controlled mode and host-controlled mode. Uploading a
WAVEFORMPRESS or WAVEFORMRELEASE effect triggers host-controlled mode if
the device is in device-controlled mode.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/hid-haptic.c | 66 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 59 insertions(+), 7 deletions(-)
diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
index c02af820051c22d1c899db84496c5a44b868fe49..aa090684c1f23b61a1ac4e9e7e523b31a8166a21 100644
--- a/drivers/hid/hid-haptic.c
+++ b/drivers/hid/hid-haptic.c
@@ -5,6 +5,7 @@
* Copyright (c) 2021 Angela Czubak <acz@semihalf.com>
*/
+#include <linux/input/mt.h>
#include <linux/module.h>
#include "hid-haptic.h"
@@ -197,12 +198,46 @@ static void fill_effect_buf(struct hid_haptic_device *haptic,
mutex_unlock(&haptic->manual_trigger_mutex);
}
+static void switch_mode(struct hid_device *hdev, struct hid_haptic_device *haptic,
+ int mode)
+{
+ struct hid_report *rep = haptic->auto_trigger_report;
+ struct hid_field *field;
+ s32 value;
+ int i, j;
+
+ if (mode == HID_HAPTIC_MODE_HOST)
+ value = HID_HAPTIC_ORDINAL_WAVEFORMSTOP;
+ else
+ value = haptic->default_auto_trigger;
+
+ mutex_lock(&haptic->auto_trigger_mutex);
+ for (i = 0; i < rep->maxfield; i++) {
+ field = rep->field[i];
+ /* Ignore if report count is out of bounds. */
+ if (field->report_count < 1)
+ continue;
+
+ for (j = 0; j < field->maxusage; j++) {
+ if (field->usage[j].hid == HID_HP_AUTOTRIGGER)
+ field->value[j] = value;
+ }
+ }
+
+ /* send the report */
+ hid_hw_request(hdev, rep, HID_REQ_SET_REPORT);
+ mutex_unlock(&haptic->auto_trigger_mutex);
+ haptic->mode = mode;
+}
+
static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *effect,
struct ff_effect *old)
{
+ struct hid_device *hdev = input_get_drvdata(dev);
struct ff_device *ff = dev->ff;
struct hid_haptic_device *haptic = ff->private;
int i, ordinal = 0;
+ bool switch_modes = false;
/* If vendor range, check vendor id and page */
if (effect->u.haptic.hid_usage >= (HID_HP_VENDORWAVEFORMMIN & HID_USAGE) &&
@@ -225,6 +260,16 @@ static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *eff
fill_effect_buf(haptic, &effect->u.haptic, &haptic->effect[effect->id],
ordinal);
+ if (effect->u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE) ||
+ effect->u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE))
+ switch_modes = true;
+
+ /* If device is in autonomous mode, and the uploaded effect signals userspace
+ * wants control of the device, change modes
+ */
+ if (switch_modes && haptic->mode == HID_HAPTIC_MODE_DEVICE)
+ switch_mode(hdev, haptic, HID_HAPTIC_MODE_HOST);
+
return 0;
}
@@ -290,6 +335,7 @@ static void effect_set_default(struct ff_effect *effect)
static int hid_haptic_erase(struct input_dev *dev, int effect_id)
{
struct hid_haptic_device *haptic = dev->ff->private;
+ struct hid_device *hdev = input_get_drvdata(dev);
struct ff_effect effect;
int ordinal;
@@ -297,20 +343,25 @@ static int hid_haptic_erase(struct input_dev *dev, int effect_id)
if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) {
ordinal = haptic->release_ordinal;
- if (!ordinal)
+ if (!ordinal) {
ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
- else
- effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE &
- HID_USAGE;
+ if (haptic->mode == HID_HAPTIC_MODE_HOST)
+ switch_mode(hdev, haptic, HID_HAPTIC_MODE_DEVICE);
+ } else
+ effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE & HID_USAGE;
+
fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id],
ordinal);
} else if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE)) {
ordinal = haptic->press_ordinal;
- if (!ordinal)
+ if (!ordinal) {
ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
+ if (haptic->mode == HID_HAPTIC_MODE_HOST)
+ switch_mode(hdev, haptic, HID_HAPTIC_MODE_DEVICE);
+ }
else
- effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS &
- HID_USAGE;
+ effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS & HID_USAGE;
+
fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id],
ordinal);
}
@@ -392,6 +443,7 @@ int hid_haptic_init(struct hid_device *hdev,
haptic->hid_usage_map[HID_HAPTIC_ORDINAL_WAVEFORMSTOP] =
HID_HP_WAVEFORMSTOP & HID_USAGE;
+ mutex_init(&haptic->auto_trigger_mutex);
for (r = 0; r < haptic->auto_trigger_report->maxfield; r++)
parse_auto_trigger_field(haptic, haptic->auto_trigger_report->field[r]);
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v2 11/11] HID: multitouch: add haptic multitouch support
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (9 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 10/11] HID: haptic: add hid_haptic_switch_mode Jonathan Denose
@ 2025-08-18 14:28 ` Jonathan Denose
2025-08-18 14:34 ` [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien, Jonathan Denose
From: Angela Czubak <aczubak@google.com>
If CONFIG_HID_HAPTIC is configured, and the device is recognized to have
simple haptic capabilities, try initializing the haptic device, check
input frames for pressure and handle it using hid_haptic_* API.
Signed-off-by: Angela Czubak <aczubak@google.com>
Co-developed-by: Jonathan Denose <jdenose@google.com>
Signed-off-by: Jonathan Denose <jdenose@google.com>
---
drivers/hid/hid-haptic.h | 16 ++++++++++-----
drivers/hid/hid-multitouch.c | 47 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
index 73601f429de16bae3b1d877445f7eebf41a69d94..6fbe07a8df42c2dc77681b013a6f948357253bf8 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -107,19 +107,25 @@ int hid_haptic_input_configured(struct hid_device *hdev,
{
return 0;
}
+static inline
+void hid_haptic_reset(struct hid_device *hdev, struct hid_haptic_device *haptic)
+{}
+static inline
int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr)
{
return 0;
}
static inline
-void hid_haptic_handle_press_release(struct hid_haptic_device *haptic)
-{}
+void hid_haptic_handle_press_release(struct hid_haptic_device *haptic) {}
static inline
-void hid_haptic_pressure_reset(struct hid_haptic_device *haptic)
-{}
+bool hid_haptic_handle_input(struct hid_haptic_device *haptic)
+{
+ return false;
+}
+static inline
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic) {}
static inline
void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
__s32 pressure)
{}
#endif
-
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index b41001e02da7e02d492bd85743b359ed7ec16e7f..bbbd5c49dbd480ecad2a0c074b2f973f099dc054 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -49,6 +49,8 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
+#include "hid-haptic.h"
+
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0)
#define MT_QUIRK_SLOT_IS_CONTACTID BIT(1)
@@ -167,11 +169,13 @@ struct mt_report_data {
struct mt_device {
struct mt_class mtclass; /* our mt device class */
struct timer_list release_timer; /* to release sticky fingers */
+ struct hid_haptic_device *haptic; /* haptic related configuration */
struct hid_device *hdev; /* hid_device we're attached to */
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
__u8 inputmode_value; /* InputMode HID feature value */
__u8 maxcontacts;
bool is_buttonpad; /* is this device a button pad? */
+ bool is_haptic_touchpad; /* is this device a haptic touchpad? */
bool serial_maybe; /* need to check for serial protocol */
struct list_head applications;
@@ -525,6 +529,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
mt_get_feature(hdev, field->report);
break;
}
+
+ hid_haptic_feature_mapping(hdev, td->haptic, field, usage);
}
static void set_abs(struct input_dev *input, unsigned int code,
@@ -856,6 +862,9 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPPRESSURE:
set_abs(hi->input, ABS_MT_PRESSURE, field,
cls->sn_pressure);
+ td->is_haptic_touchpad =
+ hid_haptic_check_pressure_unit(td->haptic,
+ hi, field);
MT_STORE_FIELD(p);
return 1;
case HID_DG_SCANTIME:
@@ -980,6 +989,8 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
app->num_received = 0;
app->left_button_state = 0;
+ if (td->is_haptic_touchpad)
+ hid_haptic_pressure_reset(td->haptic);
if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
@@ -1137,6 +1148,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
minor = minor >> 1;
}
+ if (td->is_haptic_touchpad)
+ hid_haptic_pressure_increase(td->haptic, *slot->p);
+
x = hdev->quirks & HID_QUIRK_X_INVERT ?
input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x :
*slot->x;
@@ -1324,6 +1338,9 @@ static int mt_touch_input_configured(struct hid_device *hdev,
if (cls->is_indirect)
app->mt_flags |= INPUT_MT_POINTER;
+ if (td->is_haptic_touchpad)
+ app->mt_flags |= INPUT_MT_TOTAL_FORCE;
+
if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
app->mt_flags |= INPUT_MT_DROP_UNUSED;
@@ -1359,6 +1376,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_application *application;
struct mt_report_data *rdata;
+ int ret;
rdata = mt_find_report_data(td, field->report);
if (!rdata) {
@@ -1421,6 +1439,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (field->physical == HID_DG_STYLUS)
hi->application = HID_DG_STYLUS;
+ ret = hid_haptic_input_mapping(hdev, td->haptic, hi, field, usage, bit,
+ max);
+ if (ret != 0)
+ return ret;
+
/* let hid-core decide for the others */
return 0;
}
@@ -1635,6 +1658,14 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
struct hid_report *report;
int ret;
+ if (td->is_haptic_touchpad && (td->mtclass.name == MT_CLS_WIN_8 ||
+ td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT)) {
+ if (hid_haptic_input_configured(hdev, td->haptic, hi) == 0)
+ td->is_haptic_touchpad = false;
+ } else {
+ td->is_haptic_touchpad = false;
+ }
+
list_for_each_entry(report, &hi->reports, hidinput_list) {
rdata = mt_find_report_data(td, report);
if (!rdata) {
@@ -1777,6 +1808,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev_err(&hdev->dev, "cannot allocate multitouch data\n");
return -ENOMEM;
}
+ td->haptic = devm_kzalloc(&td->hdev->dev, sizeof(*(td->haptic)), GFP_KERNEL);
+ if (!td->haptic)
+ return -ENOMEM;
+
+ td->haptic->hdev = hdev;
td->hdev = hdev;
td->mtclass = *mtclass;
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
@@ -1840,6 +1876,17 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL);
+ if (td->is_haptic_touchpad) {
+ if (hid_haptic_init(hdev, &td->haptic)) {
+ dev_warn(&hdev->dev, "Cannot allocate haptic for %s\n",
+ hdev->name);
+ td->is_haptic_touchpad = false;
+ devm_kfree(&td->hdev->dev, td->haptic);
+ }
+ } else {
+ devm_kfree(&td->hdev->dev, td->haptic);
+ }
+
return 0;
}
--
2.51.0.rc1.163.g2494970778-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v2 00/11] HID: Implement haptic touchpad support
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
` (10 preceding siblings ...)
2025-08-18 14:28 ` [PATCH v2 11/11] HID: multitouch: add haptic multitouch support Jonathan Denose
@ 2025-08-18 14:34 ` Jonathan Denose
11 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 14:34 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien
On Mon, Aug 18, 2025 at 9:28 AM Jonathan Denose <jdenose@google.com> wrote:
>
> Hello,
>
> This is an updated implementation of the interface for controlling haptic
> touchpads.
>
> Below is an updated design proposal for the userspace and HID interfaces,
> modified from what one of my colleagues submitted in 2019 [0].
>
> We would appreciate any feedback you might have.
>
> Thank you,
>
> Jonathan Denose
> Chromium OS Team
>
> Background
> ==========
>
> There are multiple independent projects to develop a touchpad with force sensors
> and haptic actuators, instead of a traditional button. These haptic touchpads
> have several advantages and potential uses; they allow clicking across the
> entire touchpad surface, adjusting the force requirement for clicks, haptic
> feedback initiated by UI, etc. Supporting these features will potentially
> require two new communication channels at the kernel level:
> * Control of haptic motor by the host
> * Force sensor data from device to host
>
> This document includes two related proposals:
> 1. HID design proposal, that hardware makers would need to implement
> 2. Kernel design proposal
>
> Objective
> ==========
>
> Develop a standard protocol to allow userspace applications to communicate with
> haptic touchpads, and minimize duplicated code and effort.
>
> Requirements:
> 1. Support UI-initiated haptic feedback.
> 2. Allow userspace to control when button press and button release haptic
> effects are triggered. (Useful when detecting a false click, changing force
> thresholds, or sending context-dependent effects).
> 3. Reveal force sensor readings to userspace applications.
> 4. Only allow OS-controlled haptic feedback for those systems which support it.
>
> Proposal
> ========
>
> In order to minimize duplicated effort, we propose standardized haptic touchpad
> support in the linux kernel.
>
> HID API
> -------
>
> Modes
> .....
>
> The haptic touchpad should be able to operate under two different modes.
>
> 1. Device-controlled mode
>
> The haptic touchpad should start up in "device-controlled mode"
> (HID_HAPTIC_MODE_DEVICE), meaning it acts as a normal touchpad. This means it
> should perform the press and release haptic feedback autonomously at predefined
> force thresholds, and send the appropriate BTN_* events.
>
> 2. Host-controlled mode
>
> Once the touchpad has been confirmed as supporting haptics (described in more
> detail in the the "Click and release control" section below), the device should
> enter "host-controlled mode" (HID_HAPTIC_MODE_HOST). In this mode userspace
> should take control. From here, userspace will take control over
> press/release haptic feedback, relying on the effects sent by the kernel.
>
> Multitouch
> ..........
>
> The HID API for multitouch reports should follow the Microsoft precision
> touchpad spec [1], with the following changes:
> * A tip pressure field [2] should be used to report the force. The physical unit
> Type (Newtons or grams), exponent, and limits should be reported in the
> report descriptor for the force field.
> * The device will always report the button state according to its predefined
> force thresholds, even when not in device-controlled mode.
> * The device must expose a "simple haptic controller" logical collection
> alongside the touchpad collection.
>
> Haptic control
> ..............
>
> The HID protocol described in HUTRR63[3] must be used.
>
> The following waveforms should be supported:
>
> | WAVEFORMNONE | Implicit waveforms required by protocol |
> | WAVEFORMSTOP | |
> | ------------------------ | ------------------------------------------------- |
> | WAVEFORMPRESS | To be used to simulate button press. In device- |
> | | controlled mode, it will also be used to simulate |
> | | button release. |
> | ------------------------ | ------------------------------------------------- |
> | WAVEFORMRELEASE | To be used to simulate button release. |
>
> All waveforms will have an associated duration; continuous waveforms will be
> ignored by the kernel.
>
> Triggers & Mode switching
> .........................
>
> The “auto trigger waveform” should be set to WAVEFORM_PRESS by default, and the
> button from the touchpad collection should be set as the “auto trigger
> associated control”.
>
> The kernel can trigger the different modes in the following ways:
> * Device-controlled mode can be enabled by setting the “auto trigger waveform” to
> WAVEFORM_PRESS.
> * Host-controlled mode can be enabled by setting the "auto trigger waveform" to
> WAVEFORM_STOP.
>
> The device must also support manual triggering. If intensity modification for
> waveforms is supported by the device, the intensity control should be included
> in the manual trigger output report. This allows modification of the intensity
> on a per-waveform basis. Retriggering does not need to be supported by the
> device.
>
> Userspace API
> -------------
>
> Multitouch protocol
> ...................
>
> ABS_MT_PRESSURE will be used to report force. The resolution of ABS_MT_PRESSURE
> should also be defined and reported in force units of grams or Newtons.
> ABS_PRESSURE should be reported as the total force applied to the touchpad.
> When the kernel is in host-controlled mode, it should always forward the button
> press and release events to userspace.
>
> Use Force Feedback protocol to request pre-defined effects
> ..........................................................
>
> The force feedback protocol [4] should be used to control predefined effects.
>
> Typical use of the force feedback protocol requires loading effects to the
> driver by describing the output waveform, and then requesting those effects
> using an ID provided by the driver. However, for haptic touchpads we do not want
> to describe the output waveform explicitly, but use a set of predefined effects,
> which are identified by HID usage.
>
> The force feedback protocol will need to be extended to allow requests for HID
> haptic effects. This requires a new feedback effect type:
>
> /**
> * struct ff_haptic_effect
> * @hid_usage: hid_usage according to Haptics page (WAVEFORM_CLICK, etc.)
> * @vendor_id: the waveform vendor ID if hid_usage is in the vendor-defined
> * range
> * @vendor_id: the vendor waveform page if hid_usage is in the vendor-defined
> * range
> * @intensity: strength of the effect
> * @repeat_count: number of times to retrigger effect
> * @retrigger_period: time before effect is retriggered (in ms)
> */
> struct ff_haptic_effect {
> __u16 hid_usage;
> __u16 vendor_id;
> __u8 vendor_waveform_page;
> __s16 intensity;
> __u16 repeat_count;
> __u16 retrigger_period;
> }
>
> Since the standard waveform id namespace does not overlap with the vendor
> waveform id namespace, the vendor id and page can be ignored for standard
> waveforms.
>
> Click and release control
> .........................
>
> Haptic functionality shall be gated behind the HID_MULTITOUCH_HAPTIC kernel
> configuration option, and this kernel configuration option should only be
> enabled if userspace will support haptic capabilities. Haptic functionality will
> only be initialized and used if HID_MULTITOUCH_HAPTIC is enabled, and if the
> following conditions have been met:
> * ABS_MT_PRESSURE is defined and reporting force units of Newtons or grams.
> * The device supports haptic effects according to the hid protocol defined in
> HUTRR63 [3].
> These checks will happen when the driver probes and initializes the multitouch
> device.
>
> In the case when the kernel configuration option has been set and the device
> reports pressure and haptic effects as defined above, the kernel will initialize
> the haptic device and configure the haptic driver to signal that the touchpad is
> haptic-compatible. To signal to userspace that the touchpad is haptic-compatible
> the kernel will mark INPUT_PROP_HAPTIC_TOUCHPAD.
>
> With userspace willing and able to take control, the kernel will signal to the
> device to exit device-controlled mode once a WAVEFORMPRESS or WAVEFORMRELEASE
> event is uploaded. From here, userspace will take control over press/release
> haptic feedback, relying on the effects sent by the kernel.
>
> In all other cases, the driver will take no action to enable haptic
> functionality.
>
> Summary of normal use-case
> 1. The kernel waits for userspace to upload WAVEFORMPRESS or
> WAVEFORMRELEASE.
> 2. Userspace determines when a click has been performed based on its own
> criteria and tells the touchpad to perform a haptic effect.
> 3. When userspace erases the WAVEFORMPRESS or WAVEFORMRELEASE effect, signal the
> device to return to device-controlled mode.
>
> [0]: https://www.spinics.net/lists/linux-input/msg60938.html
> [1]: https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchpad-devices
> [2]: Usage ID 0x30 of HID usage table 0x0D. See chapter 16:
> https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
> [3]: https://www.usb.org/sites/default/files/hutrr63b_-_haptics_page_redline_0.pdf
> [4]: https://www.kernel.org/doc/html/v4.20/input/ff.html
>
> Signed-off-by: Jonathan Denose <jdenose@google.com>
> ---
> Changes in v2:
> - Rename FF_HID and ff_hid_effect to FF_HAPTIC and ff_haptic_effect
> - Add more detail to CONFIG_HID_HAPTIC config option description
> - Remove CONFIG_MULTITOUCH_HAPTIC config option
> - Utilize devm api in hid-multitouch haptic functions
> - Link to v1: https://lore.kernel.org/all/20250714-support-forcepads-v1-0-71c7c05748c9@google.com
>
> ---
> Angela Czubak (11):
> HID: add haptics page defines
> Input: add FF_HAPTIC effect type
> Input: add INPUT_PROP_HAPTIC_TOUCHPAD
> HID: haptic: introduce hid_haptic_device
> HID: input: allow mapping of haptic output
> HID: haptic: initialize haptic device
> HID: input: calculate resolution for pressure
> HID: haptic: add functions handling events
> Input: MT - add INPUT_MT_TOTAL_FORCE flags
> HID: haptic: add hid_haptic_switch_mode
> HID: multitouch: add haptic multitouch support
>
> Documentation/input/event-codes.rst | 14 +
> drivers/hid/Kconfig | 11 +
> drivers/hid/Makefile | 1 +
> drivers/hid/hid-haptic.c | 580 +++++++++++++++++++++++++++++++++
> drivers/hid/hid-haptic.h | 131 ++++++++
> drivers/hid/hid-input.c | 18 +-
> drivers/hid/hid-multitouch.c | 47 +++
> drivers/input/input-mt.c | 14 +-
> include/linux/hid.h | 29 ++
> include/linux/input/mt.h | 1 +
> include/uapi/linux/input-event-codes.h | 1 +
> include/uapi/linux/input.h | 22 +-
> 12 files changed, 862 insertions(+), 7 deletions(-)
> ---
> base-commit: 86731a2a651e58953fc949573895f2fa6d456841
> change-id: 20250625-support-forcepads-0b4f74fd3d0a
>
> Best regards,
> --
> Jonathan Denose <jdenose@google.com>
>
My apologies, I'm using b4 to manage these patches and submission and
I'm not sure why I couldn't get it to increment this version like it
did the last time.
Link to the previous version of this patchset is here:
https://lore.kernel.org/all/20250804-support-forcepads-v2-0-138ca980261d@google.com/
--
Jonathan
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2 03/11] Input: add INPUT_PROP_HAPTIC_TOUCHPAD
2025-08-18 14:28 ` [PATCH v2 03/11] Input: add INPUT_PROP_HAPTIC_TOUCHPAD Jonathan Denose
@ 2025-08-18 16:31 ` Randy Dunlap
0 siblings, 0 replies; 17+ messages in thread
From: Randy Dunlap @ 2025-08-18 16:31 UTC (permalink / raw)
To: Jonathan Denose, Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov,
Jonathan Corbet, Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien
On 8/18/25 7:28 AM, Jonathan Denose wrote:
> From: Angela Czubak <aczubak@google.com>
>
> INPUT_PROP_HAPTIC_TOUCHPAD property is to be set for a device with simple
> haptic capabilities.
>
> Signed-off-by: Angela Czubak <aczubak@google.com>
> Co-developed-by: Jonathan Denose <jdenose@google.com>
> Signed-off-by: Jonathan Denose <jdenose@google.com>
> ---
> Documentation/input/event-codes.rst | 14 ++++++++++++++
> include/uapi/linux/input-event-codes.h | 1 +
> 2 files changed, 15 insertions(+)
>
> diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst
> index b4557462edd7b3fef9e9cd6c2c3cb2d05bb531ab..6f7aa9e8207c4aa825d9694ad891f4d105fe8196 100644
> --- a/Documentation/input/event-codes.rst
> +++ b/Documentation/input/event-codes.rst
> @@ -400,6 +400,20 @@ can report through the rotational axes (absolute and/or relative rx, ry, rz).
> All other axes retain their meaning. A device must not mix
> regular directional axes and accelerometer axes on the same event node.
>
> +INPUT_PROP_HAPTIC_TOUCHPAD
> +--------------------------
> +
> +The INPUT_PROP_HAPTIC_TOUCHPAD property indicates that device:
> +- supports simple haptic auto and manual triggering
> +- can differentiate between at least 5 fingers
> +- uses correct resolution for the X/Y (units and value)
> +- report correct force per touch, and correct units for them (newtons or grams)
reports
> +- follows the MT protocol type B
> +
> +Summing up, such devices follow the MS spec for input devices in
--
~Randy
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device
2025-08-18 14:28 ` [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device Jonathan Denose
@ 2025-08-18 16:36 ` Randy Dunlap
2025-08-18 22:17 ` Jonathan Denose
0 siblings, 1 reply; 17+ messages in thread
From: Randy Dunlap @ 2025-08-18 16:36 UTC (permalink / raw)
To: Jonathan Denose, Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov,
Jonathan Corbet, Henrik Rydberg
Cc: linux-input, linux-kernel, linux-doc, Angela Czubak,
Sean O'Brien
Hi,
On 8/18/25 7:28 AM, Jonathan Denose wrote:
> From: Angela Czubak <aczubak@google.com>
>
> Define a new structure that contains simple haptic device configuration
> as well as current state.
> Add functions that recognize auto trigger and manual trigger reports
> as well as save their addresses.
> Verify that the pressure unit is either grams or newtons.
> Mark the input device as a haptic touchpad if the unit is correct and
> the reports are found.
>
> Signed-off-by: Angela Czubak <aczubak@google.com>
> Co-developed-by: Jonathan Denose <jdenose@google.com>
> Signed-off-by: Jonathan Denose <jdenose@google.com>
> ---
> drivers/hid/Kconfig | 11 +++++
> drivers/hid/Makefile | 1 +
> drivers/hid/hid-haptic.c | 72 ++++++++++++++++++++++++++++++++
> drivers/hid/hid-haptic.h | 105 +++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 189 insertions(+)
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 43859fc757470caf6ad43bd5f72f119e9c36aea7..cbbe82a0a2ba257e45f77ca014fb5f08b71fc62f 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -92,6 +92,17 @@ config HID_GENERIC
>
> If unsure, say Y.
>
> +config HID_HAPTIC
> + bool "Haptic touchpad support"
Why bool instead of tristate?
> + default n
> + help
> + Support for touchpads with force sensors and haptic actuators instead of a
> + traditional button.
> + Adds extra parsing and FF device for the hid multitouch driver.
> + It can be used for Elan 2703 haptic touchpad.
> +
> + If unsure, say N.
> +
I do wish that hid/Kconfig indentation didn't vary so much from coding-style.rst.
> menu "Special HID drivers"
>
> config HID_A4TECH
> diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..b729f8245aa60c3d06b79b11846dccf6fcc0c08b
> --- /dev/null
> +++ b/drivers/hid/hid-haptic.h
> @@ -0,0 +1,105 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * HID Haptic support for Linux
> + *
> + * Copyright (c) 2021 Angela Czubak <acz@semihalf.com>
> + */
> +
> +/*
> + */
eh?
> +
> +
> +#include <linux/hid.h>
?
--
~Randy
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device
2025-08-18 16:36 ` Randy Dunlap
@ 2025-08-18 22:17 ` Jonathan Denose
0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Denose @ 2025-08-18 22:17 UTC (permalink / raw)
To: Randy Dunlap
Cc: Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov, Jonathan Corbet,
Henrik Rydberg, linux-input, linux-kernel, linux-doc,
Angela Czubak, Sean O'Brien
On Mon, Aug 18, 2025 at 11:36 AM Randy Dunlap <rdunlap@infradead.org> wrote:
>
> Hi,
>
> On 8/18/25 7:28 AM, Jonathan Denose wrote:
> > From: Angela Czubak <aczubak@google.com>
> >
> > Define a new structure that contains simple haptic device configuration
> > as well as current state.
> > Add functions that recognize auto trigger and manual trigger reports
> > as well as save their addresses.
> > Verify that the pressure unit is either grams or newtons.
> > Mark the input device as a haptic touchpad if the unit is correct and
> > the reports are found.
> >
> > Signed-off-by: Angela Czubak <aczubak@google.com>
> > Co-developed-by: Jonathan Denose <jdenose@google.com>
> > Signed-off-by: Jonathan Denose <jdenose@google.com>
> > ---
> > drivers/hid/Kconfig | 11 +++++
> > drivers/hid/Makefile | 1 +
> > drivers/hid/hid-haptic.c | 72 ++++++++++++++++++++++++++++++++
> > drivers/hid/hid-haptic.h | 105 +++++++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 189 insertions(+)
> >
> > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> > index 43859fc757470caf6ad43bd5f72f119e9c36aea7..cbbe82a0a2ba257e45f77ca014fb5f08b71fc62f 100644
> > --- a/drivers/hid/Kconfig
> > +++ b/drivers/hid/Kconfig
> > @@ -92,6 +92,17 @@ config HID_GENERIC
> >
> > If unsure, say Y.
> >
> > +config HID_HAPTIC
> > + bool "Haptic touchpad support"
>
> Why bool instead of tristate?
No particular reason, I can change it to tristate.
>
> > + default n
> > + help
> > + Support for touchpads with force sensors and haptic actuators instead of a
> > + traditional button.
> > + Adds extra parsing and FF device for the hid multitouch driver.
> > + It can be used for Elan 2703 haptic touchpad.
> > +
> > + If unsure, say N.
> > +
>
> I do wish that hid/Kconfig indentation didn't vary so much from coding-style.rst.
>
> > menu "Special HID drivers"
> >
> > config HID_A4TECH
>
>
>
> > diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..b729f8245aa60c3d06b79b11846dccf6fcc0c08b
> > --- /dev/null
> > +++ b/drivers/hid/hid-haptic.h
> > @@ -0,0 +1,105 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * HID Haptic support for Linux
> > + *
> > + * Copyright (c) 2021 Angela Czubak <acz@semihalf.com>
> > + */
> > +
> > +/*
> > + */
> eh?
I can clean this up as well.
>
> > +
> > +
> > +#include <linux/hid.h>
> ?
>
> --
> ~Randy
>
I'll also fix the grammatical error you noted on the patch before this
one and resubmit. Thanks for your review!
--
Jonathan
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2025-08-18 22:17 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-18 14:28 [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 01/11] HID: add haptics page defines Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 02/11] Input: add FF_HAPTIC effect type Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 03/11] Input: add INPUT_PROP_HAPTIC_TOUCHPAD Jonathan Denose
2025-08-18 16:31 ` Randy Dunlap
2025-08-18 14:28 ` [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device Jonathan Denose
2025-08-18 16:36 ` Randy Dunlap
2025-08-18 22:17 ` Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 05/11] HID: input: allow mapping of haptic output Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 06/11] HID: haptic: initialize haptic device Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 07/11] HID: input: calculate resolution for pressure Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 08/11] HID: haptic: add functions handling events Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 09/11] Input: MT - add INPUT_MT_TOTAL_FORCE flags Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 10/11] HID: haptic: add hid_haptic_switch_mode Jonathan Denose
2025-08-18 14:28 ` [PATCH v2 11/11] HID: multitouch: add haptic multitouch support Jonathan Denose
2025-08-18 14:34 ` [PATCH v2 00/11] HID: Implement haptic touchpad support Jonathan Denose
-- strict thread matches above, loose matches on Subject: below --
2025-08-04 14:11 Jonathan Denose
2025-08-04 14:11 ` [PATCH v2 08/11] HID: haptic: add functions handling events Jonathan Denose
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).