* [PATCH 1/2] HID: input: rename hidinput_set_battery_charge_status()
From: José Expósito @ 2025-08-04 9:11 UTC (permalink / raw)
To: jikos
Cc: bentiss, luguohong, linux-input, linux-kernel,
José Expósito
In preparation for a patch fixing a bug affecting
hidinput_set_battery_charge_status(), rename the function to
hidinput_update_battery_charge_status() and move it up so it can be used
by hidinput_update_battery().
Refactor, no functional changes.
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
drivers/hid/hid-input-test.c | 10 +++++-----
drivers/hid/hid-input.c | 38 ++++++++++++++++++------------------
2 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c
index 77c2d45ac62a..6f5c71660d82 100644
--- a/drivers/hid/hid-input-test.c
+++ b/drivers/hid/hid-input-test.c
@@ -7,7 +7,7 @@
#include <kunit/test.h>
-static void hid_test_input_set_battery_charge_status(struct kunit *test)
+static void hid_test_input_update_battery_charge_status(struct kunit *test)
{
struct hid_device *dev;
bool handled;
@@ -15,15 +15,15 @@ static void hid_test_input_set_battery_charge_status(struct kunit *test)
dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
- handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0);
+ handled = hidinput_update_battery_charge_status(dev, HID_DG_HEIGHT, 0);
KUNIT_EXPECT_FALSE(test, handled);
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0);
+ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 0);
KUNIT_EXPECT_TRUE(test, handled);
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1);
+ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 1);
KUNIT_EXPECT_TRUE(test, handled);
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING);
}
@@ -63,7 +63,7 @@ static void hid_test_input_get_battery_property(struct kunit *test)
}
static struct kunit_case hid_input_tests[] = {
- KUNIT_CASE(hid_test_input_set_battery_charge_status),
+ KUNIT_CASE(hid_test_input_update_battery_charge_status),
KUNIT_CASE(hid_test_input_get_battery_property),
{ }
};
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index ff1784b5c2a4..262787e6eb20 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -595,6 +595,20 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
dev->battery = NULL;
}
+static bool hidinput_update_battery_charge_status(struct hid_device *dev,
+ unsigned int usage, int value)
+{
+ switch (usage) {
+ case HID_BAT_CHARGING:
+ dev->battery_charge_status = value ?
+ POWER_SUPPLY_STATUS_CHARGING :
+ POWER_SUPPLY_STATUS_DISCHARGING;
+ return true;
+ }
+
+ return false;
+}
+
static void hidinput_update_battery(struct hid_device *dev, int value)
{
int capacity;
@@ -617,20 +631,6 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
power_supply_changed(dev->battery);
}
}
-
-static bool hidinput_set_battery_charge_status(struct hid_device *dev,
- unsigned int usage, int value)
-{
- switch (usage) {
- case HID_BAT_CHARGING:
- dev->battery_charge_status = value ?
- POWER_SUPPLY_STATUS_CHARGING :
- POWER_SUPPLY_STATUS_DISCHARGING;
- return true;
- }
-
- return false;
-}
#else /* !CONFIG_HID_BATTERY_STRENGTH */
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
struct hid_field *field, bool is_percentage)
@@ -642,14 +642,14 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
{
}
-static void hidinput_update_battery(struct hid_device *dev, int value)
+static bool hidinput_update_battery_charge_status(struct hid_device *dev,
+ unsigned int usage, int value)
{
+ return false;
}
-static bool hidinput_set_battery_charge_status(struct hid_device *dev,
- unsigned int usage, int value)
+static void hidinput_update_battery(struct hid_device *dev, int value)
{
- return false;
}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
@@ -1515,7 +1515,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
if (usage->type == EV_PWR) {
- bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value);
+ bool handled = hidinput_update_battery_charge_status(hid, usage->hid, value);
if (!handled)
hidinput_update_battery(hid, value);
--
2.50.1
^ permalink raw reply related
* [PATCH 2/2] HID: input: report battery status changes immediately
From: José Expósito @ 2025-08-04 9:11 UTC (permalink / raw)
To: jikos
Cc: bentiss, luguohong, linux-input, linux-kernel,
José Expósito
In-Reply-To: <20250804091215.6637-1-jose.exposito89@gmail.com>
When the battery status changes, report the change immediately to user
space.
Fixes: a608dc1c0639 ("HID: input: map battery system charging")
Reported-by: 卢国宏 <luguohong@xiaomi.com>
Closes: https://lore.kernel.org/linux-input/aI49Im0sGb6fpgc8@fedora/T/
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
drivers/hid/hid-input.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 262787e6eb20..277538a17b57 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -609,13 +609,19 @@ static bool hidinput_update_battery_charge_status(struct hid_device *dev,
return false;
}
-static void hidinput_update_battery(struct hid_device *dev, int value)
+static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
+ int value)
{
int capacity;
if (!dev->battery)
return;
+ if (hidinput_update_battery_charge_status(dev, usage, value)) {
+ power_supply_changed(dev->battery);
+ return;
+ }
+
if (value == 0 || value < dev->battery_min || value > dev->battery_max)
return;
@@ -648,7 +654,8 @@ static bool hidinput_update_battery_charge_status(struct hid_device *dev,
return false;
}
-static void hidinput_update_battery(struct hid_device *dev, int value)
+static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
+ int value)
{
}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
@@ -1515,11 +1522,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
if (usage->type == EV_PWR) {
- bool handled = hidinput_update_battery_charge_status(hid, usage->hid, value);
-
- if (!handled)
- hidinput_update_battery(hid, value);
-
+ hidinput_update_battery(hid, usage->hid, value);
return;
}
--
2.50.1
^ permalink raw reply related
* [dtor-input:next 25/25] drivers/input/touch-overlay.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
From: kernel test robot @ 2025-08-04 9:18 UTC (permalink / raw)
To: Lee Jones; +Cc: oe-kbuild-all, linux-input, Dmitry Torokhov
tree: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
head: a7bee4e7f78089c101be2ad51f4b5ec64782053e
commit: a7bee4e7f78089c101be2ad51f4b5ec64782053e [25/25] Merge tag 'ib-mfd-gpio-input-pwm-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into next
config: openrisc-allnoconfig (https://download.01.org/0day-ci/archive/20250804/202508041754.ykl25o1q-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250804/202508041754.ykl25o1q-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508041754.ykl25o1q-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/iio/common/ssp_sensors/ssp_iio.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/common/st_sensors/st_sensors_buffer.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/common/st_sensors/st_sensors_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/common/st_sensors/st_sensors_i2c.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/common/st_sensors/st_sensors_spi.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/common/st_sensors/st_sensors_trigger.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/dac/ad3552r-common.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/dac/ad5592r-base.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/dac/ad5686.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/dummy/iio_dummy_evgen.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/gyro/bmg160_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/gyro/fxas21002c_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/gyro/st_gyro_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/humidity/hts221_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/adis.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/bmi160/bmi160_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/bmi270/bmi270_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/bmi323/bmi323_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/bno055/bno055.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/fxos8700_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/inv_icm42600/inv_icm42600_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/industrialio-backend.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/industrialio-configfs.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/industrialio-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/industrialio-event.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/industrialio-sw-device.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/industrialio-sw-trigger.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/industrialio-trigger.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/light/st_uvis25_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/magnetometer/bmc150_magn.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/magnetometer/hmc5843_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/magnetometer/rm3100-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/magnetometer/st_magn_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/bmp280-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/bmp280-regmap.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/hsc030pa.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/mpl115.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/mprls0025pa.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/ms5611_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/st_pressure_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/pressure/zpa2326.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/trigger/stm32-lptimer-trigger.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iio/trigger/stm32-timer-trigger.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/addr.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/cache.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/cgroup.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/cm.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/cma.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/cq.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/device.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/ib_core_uverbs.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/iwcm.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/mad.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/mr_pool.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/nldev.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/rdma_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/restrack.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/roce_gid_mgmt.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/rw.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/sa_query.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/security.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/sysfs.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/ucaps.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/umem_dmabuf.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/uverbs_cmd.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/uverbs_ioctl.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/uverbs_main.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/core/uverbs_std_types.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/sw/rdmavt/ah.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/sw/rdmavt/cq.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/sw/rdmavt/mcast.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/sw/rdmavt/mr.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/sw/rdmavt/qp.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/sw/rdmavt/rc.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/sw/rdmavt/vt.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/ulp/rtrs/rtrs-clt.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/ulp/rtrs/rtrs-srv.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/infiniband/ulp/rtrs/rtrs.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/ff-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/ff-memless.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/gameport/gameport.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/input-poller.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/input.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/joystick/iforce/iforce-main.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/joystick/iforce/iforce-packets.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/misc/ad714x.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/misc/adxl34x.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/misc/cma3000_d0x.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/rmi4/rmi_2d_sensor.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/rmi4/rmi_bus.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/rmi4/rmi_driver.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/serio/hil_mlc.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/serio/hp_sdc.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/serio/i8042.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/serio/libps2.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/serio/serio.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/sparse-keymap.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
>> drivers/input/touch-overlay.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/ad7879.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/cyttsp_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/goodix_berlin_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/tsc200x-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/wm9705.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/wm9712.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/wm9713.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/input/touchscreen/wm97xx-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/icc-clk.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/imx/imx.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/mediatek/icc-emi.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/qcom/bcm-voter.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/qcom/icc-common.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/qcom/icc-rpm-clocks.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/qcom/icc-rpm.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/qcom/icc-rpmh.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/interconnect/qcom/smd-rpm.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/dma-iommu.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/intel/dmar.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/intel/iommu.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/io-pgfault.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/io-pgtable.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommu-debugfs.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommu-pages.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommu-sva.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommu-sysfs.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommufd/device.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommufd/driver.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommufd/iova_bitmap.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommufd/main.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iommufd/vfio_compat.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/iova.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/irq_remapping.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/iommu/omap-iommu.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/ipack/ipack.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/irqchip/irq-ath79-misc.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/irqchip/irq-renesas-rzv2h.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/irqchip/irq-riscv-imsic-state.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/irqchip/irqchip.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/capi/kcapi.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/hardware/mISDN/isdnhdlc.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/hardware/mISDN/mISDNipac.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/hardware/mISDN/mISDNisar.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/mISDN/core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/mISDN/fsm.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/mISDN/hwchannel.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/isdn/mISDN/layer1.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/led-class-flash.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/led-class-multicolor.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/led-class.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/led-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/leds-lp55xx-common.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/leds-ti-lmu-common.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/simatic/simatic-ipc-leds-gpio-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/trigger/ledtrig-backlight.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/trigger/ledtrig-camera.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/trigger/ledtrig-cpu.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/trigger/ledtrig-disk.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/leds/trigger/ledtrig-mtd.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/adb.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/macio_asic.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/mediabay.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/smu.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/via-cuda.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/via-pmu.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/windfarm_core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/windfarm_pid.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/macintosh/windfarm_smu_sat.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/mailbox/mailbox.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/mailbox/mtk-cmdq-mailbox.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/mailbox/pcc.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/mcb/mcb-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-audit.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-bio-prison-v1.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-bio-prison-v2.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-bufio.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-builtin.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-cache-background-tracker.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-cache-policy.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-exception-store.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-io.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-ioctl.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-kcopyd.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-log.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-path-selector.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-region-hash.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-rq.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-snap.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-table.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-target.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm-zone.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/dm.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/md.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/persistent-data/dm-block-manager.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/raid5-cache.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/md/raid5.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/media/cec/core/cec-adap.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
drivers/media/cec/core/cec-core.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: 答复: [External Mail]Re: 转发: commit?a608dc1c06397dc50ab773498433432fb5938f92 (patch) has a bug
From: José Expósito @ 2025-08-04 9:20 UTC (permalink / raw)
To: 卢国宏
Cc: jikos@kernel.org, bentiss@kernel.org, linux-input@vger.kernel.org,
jkosina@suse.cz
In-Reply-To: <db380722eb484dedbf77ec6304c6ca7c@xiaomi.com>
Hi 卢国宏,
Forwarding your email to the mailing list and answering after it.
The mailing list won't accept your emails unless you send them in
plain text:
On Mon, Aug 04, 2025 at 01:55:37AM +0000, 卢国宏 wrote:
> ________________________________
> 发件人: José Expósito <jose.exposito89@gmail.com>
> 发送时间: 2025年8月3日 0:30
> 收件人: 卢国宏
> 抄送: jikos@kernel.org; bentiss@kernel.org; linux-input@vger.kernel.org; torvalds@linux-foundation.org; linus@linuxfoundation.org; jkosina@suse.cz
> 主题: [External Mail]Re: 转发: commit?a608dc1c06397dc50ab773498433432fb5938f92 (patch) has a bug
>
> [外部邮件] 此邮件来源于小米公司外部,请谨慎处理。若对邮件安全性存疑,请将邮件转发给misec@xiaomi.com进行反馈
>
> Hi 卢国宏,
>
> Thanks a lot for reporting this issue.
>
> On Sat, Aug 02, 2025 at 12:23:54PM +0000, 卢国宏 wrote:
> > Hello, José and Jiri!
> > I've discovered that the patch you submitted to the Linux community,
> > "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-6.3.y&id=a608dc1c06397dc50ab773498433432fb5938f92"
> > contains a bug. Even with your patch, the charging status of HID
> > devices is still not reported to upper layers in a timely manner.
> > The reasons are as follows:
> >
> > [...]
> >
> > if function hidinput_set_battery_charge_status() return true, That is,
> > the charging status of the HID device has changed,This charging status
> > will not be reported,Because, only when handled is false,
> > "hid input update battery(hid, value);" will be called.
>
> I wrote this patch a while ago and I can't remember the exact reason
> why hidinput_update_battery() is only called by hidinput_hid_event()
> when hidinput_set_battery_charge_status() returns false.
>
> The devices I have change their status, for example, discharging to
> charging, when they are connected via Bluetooth and I switch them to
> USB. This reconnection reports the status to user-space, so there is
> no need for additional synchronization.
> Does your device work in the same manner?
>
> --->>> Our device is a pure USB-connected controller with a battery inside. The controller has two USB ports, one for connecting to a mobile phone's data port and the other for connecting to a charger. After the controller is connected to the mobile phone, and then the charger is connected to the controller's charging port, the controller will report the controller's charging status to the mobile phone through the HID protocol (Usage Page: 0x85 - Battery System Page, Usage ID: 0x44).
>
> However, before we try to fix the problem, it would be nice if you
> could provide a reproducer.
>
> What device is affected by this bug?
>
> By using "sudo hid-recorder" and selecting your device, you will be
> able to capture and replay (with "hid-replay") the HID events sent
> by your device.
> Could you share a recording of your device changing from the charging
> to discharging status and back to charging so we can reproduce the
> issue, please?
>
> If the recording is too long, please upload it to a server.
>
> --->>> When I debugged this issue, I checked the charging status of the USB controller device by using the Android uevents bin file in the Linux command line. For example, I executed the command "./uevents | grep AAA", where AAA is the device name. Then, when you unplug the charger, it will print "AAA POWER_SUPPLY_STATUS=Discharging", and when you plug in the charger, it will print "AAA POWER_SUPPLY_STATUS=charging".
> --->>> Because I am not familiar with the use of "hid-recorder" and "hid-replay" for the time being, if it is really necessary later, I will help you capture the reproduction records through these two tools.
> --->>> By the way, we previously approached Google directly to resolve the issue by adding the line "power_supply_changed(dev->battery);" mentioned in my original email to the Google Linux kernel code. We've already built two generations of this product, and this solution has proven to be feasible. However, when we requested this solution again for our third-generation product, Google disagreed. They said we should address the issue directly upstream! In other words, we should approach the Linux community to resolve the issue once and for all. They have a point, so I'm coming to you for help.
>
> > Therefore, the function "hidinput set battery charge status" can be
> > changed to the following:
> >
> > static bool hidinput_set_battery_charge_status(struct hid_device *dev,
> > + unsigned int usage, int value)
> > +{
> > + switch (usage) {
> > + case HID_BAT_CHARGING:
> > + dev->battery_charge_status = value ?
> > + POWER_SUPPLY_STATUS_CHARGING :
> > + POWER_SUPPLY_STATUS_DISCHARGING;
> > + power_supply_changed(dev->battery);
> > + return true;
> > + }
> > +
> > + return false;
> > +}
>
> Could you test if this patch also solves your problem, please?
>
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index 9d80635a91eb..bce580beb5c6 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -1515,11 +1515,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
> return;
>
> if (usage->type == EV_PWR) {
> - bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value);
> -
> - if (!handled)
> - hidinput_update_battery(hid, value);
> -
> + hidinput_set_battery_charge_status(hid, usage->hid, value);
> + hidinput_update_battery(hid, value);
> return;
> }
>
> --->>> I am sure that your patch can also solve our problem, because we have used your method to solve this problem in our previous internal code. If you can submit this patch, our problem will be solved. Thank you very much!
>
> Thanks a lot in advance,
> José Expósito
>
> > Because we have encountered this problem in our project, and this
> > method can solve it.
> > I hope you can solve this problem as soon as possible, otherwise,
> > we will encounter this problem again in our future projects.
> >
> > Thank you so much!
> #/******本邮件及其附件含有小米公司的保密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制、或散发)本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件! This e-mail and its attachments contain confidential information from XIAOMI, which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction, or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this e-mail in error, please notify the sender by phone or email immediately and delete it!******/#
I sent a couple of patches that I think will solve your problem:
https://lore.kernel.org/linux-input/20250804091215.6637-1-jose.exposito89@gmail.com/T/#md9f4924a4a5817fe6c0ff9474f8a5c0e36c9ee3b
Please compile and test them and let us know if the solution works
so we can merge the fix upstream.
If you find any problems, please provide a reproducer so I can debug it.
Thanks a lot in advance,
Jose
^ permalink raw reply
* Re: [PATCH v2 3/3] HID: hid-steam: Use new BTN_GRIP* buttons
From: Jiri Kosina @ 2025-08-04 13:40 UTC (permalink / raw)
To: Vicki Pfau; +Cc: Dmitry Torokhov, Benjamin Tissoires, linux-input
In-Reply-To: <20250717000143.1902875-4-vi@endrift.com>
On Wed, 16 Jul 2025, Vicki Pfau wrote:
> Signed-off-by: Vicki Pfau <vi@endrift.com>
Dmitry,
with
Acked-by: Jiri Kosina <jkosina@suse.com>
can you please take it with the generic and xpad patch through your tree,
to avoid cross-tree dependency?
Thanks!
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH v2 00/11] HID: Implement haptic touchpad support
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
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_hid_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_hid_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:
- change drivers/hid/Makefile to only build hid-haptic when
CONFIG_MULTITOUCH_HAPTIC is defined and not CONFIG_HID_HAPTIC to
resolve build error.
- change cover letter subject from forcepad to touchpad
- Link to v1: https://lore.kernel.org/r/20250714-support-forcepads-v1-0-71c7c05748c9@google.com
---
Angela Czubak (11):
HID: add haptics page defines
Input: add FF_HID 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 | 20 ++
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 | 136 +++++++-
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, 959 insertions(+), 8 deletions(-)
---
base-commit: 86731a2a651e58953fc949573895f2fa6d456841
change-id: 20250625-support-forcepads-0b4f74fd3d0a
Best regards,
--
Jonathan Denose <jdenose@google.com>
^ permalink raw reply
* [PATCH v2 01/11] HID: add haptics page defines
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 02/11] Input: add FF_HID effect type
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
From: Angela Czubak <aczubak@google.com>
FF_HID 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..3ea7c826c6fb2034e46f95cb95b84ef6f5b866df 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_hid_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_hid_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_hid_effect hid;
} u;
};
@@ -471,6 +490,7 @@ struct ff_effect {
* Force feedback effect types
*/
+#define FF_HID 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_HID
#define FF_EFFECT_MAX FF_RAMP
/*
--
2.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 03/11] Input: add INPUT_PROP_HAPTIC_TOUCHPAD
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 04/11] HID: haptic: introduce hid_haptic_device
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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 | 9 ++++++
drivers/hid/Makefile | 1 +
drivers/hid/hid-haptic.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/hid/hid-haptic.h | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 156 insertions(+)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 43859fc757470caf6ad43bd5f72f119e9c36aea7..ad6bcc4248cc111705d7cfde2b1481b46353e2d7 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -92,6 +92,15 @@ 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.
+
+ 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..fc8979772d00e8b3238b26060c5541065a61811d
--- /dev/null
+++ b/drivers/hid/hid-haptic.h
@@ -0,0 +1,74 @@
+/* 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;
+};
+
+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);
--
2.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 05/11] HID: input: allow mapping of haptic output
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 06/11] HID: haptic: initialize haptic device
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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 | 1 +
2 files changed, 439 insertions(+)
diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
index d659a430c1a6b06ded31d49efe4bded909671cb6..923b685f0e1e81b7f95567b11209af264c522373 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_hid_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.hid.hid_usage >= (HID_HP_VENDORWAVEFORMMIN & HID_USAGE) &&
+ effect->u.hid.hid_usage <= (HID_HP_VENDORWAVEFORMMAX & HID_USAGE) &&
+ (effect->u.hid.vendor_id != haptic->vendor_id ||
+ effect->u.hid.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.hid.hid_usage) {
+ ordinal = i;
+ break;
+ }
+ }
+ if (ordinal < 1)
+ return -EINVAL;
+
+ /* Fill the buffer for the effect id */
+ fill_effect_buf(haptic, &effect->u.hid, &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_HID;
+ effect->id = -1;
+ effect->u.hid.hid_usage = HID_HP_WAVEFORMNONE & HID_USAGE;
+ effect->u.hid.intensity = 100;
+ effect->u.hid.retrigger_period = 0;
+ effect->u.hid.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.hid.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) {
+ ordinal = haptic->release_ordinal;
+ if (!ordinal)
+ ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
+ else
+ effect.u.hid.hid_usage = HID_HP_WAVEFORMRELEASE &
+ HID_USAGE;
+ fill_effect_buf(haptic, &effect.u.hid, &haptic->effect[effect_id],
+ ordinal);
+ } else if (effect.u.hid.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE)) {
+ ordinal = haptic->press_ordinal;
+ if (!ordinal)
+ ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
+ else
+ effect.u.hid.hid_usage = HID_HP_WAVEFORMPRESS &
+ HID_USAGE;
+ fill_effect_buf(haptic, &effect.u.hid, &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_hid_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_HID);
+
+ 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 fc8979772d00e8b3238b26060c5541065a61811d..9aa910579d09206a2a882a5f708efd8620428f78 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -72,3 +72,4 @@ 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);
--
2.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 07/11] HID: input: calculate resolution for pressure
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 08/11] HID: haptic: add functions handling events
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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
* [PATCH v2 09/11] Input: MT - add INPUT_MT_TOTAL_FORCE flags
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 10/11] HID: haptic: add hid_haptic_switch_mode
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
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 760dd1d70583489c07e199943ebba361d347bfa4..e83363cad6febb5d3fcd786b76e05bc16a7e4e94 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.hid.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.hid, &haptic->effect[effect->id],
ordinal);
+ if (effect->u.hid.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE) ||
+ effect->u.hid.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.hid.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) {
ordinal = haptic->release_ordinal;
- if (!ordinal)
+ if (!ordinal) {
ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
- else
- effect.u.hid.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.hid.hid_usage = HID_HP_WAVEFORMRELEASE & HID_USAGE;
+ }
fill_effect_buf(haptic, &effect.u.hid, &haptic->effect[effect_id],
ordinal);
} else if (effect.u.hid.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.hid.hid_usage = HID_HP_WAVEFORMPRESS &
- HID_USAGE;
+ effect.u.hid.hid_usage = HID_HP_WAVEFORMPRESS & HID_USAGE;
+
fill_effect_buf(haptic, &effect.u.hid, &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.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* [PATCH v2 11/11] HID: multitouch: add haptic multitouch support
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
In-Reply-To: <20250804-support-forcepads-v2-0-138ca980261d@google.com>
From: Angela Czubak <aczubak@google.com>
Add new option (MULTITOUCH_HAPTIC) to mark whether hid-multitouch
should try and configure simple haptic device.
Once this option is configured, and the device is recognized to have simple
haptic capabilities, 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/Kconfig | 11 ++++
drivers/hid/Makefile | 2 +-
drivers/hid/hid-haptic.h | 52 +++++++++++++++++
drivers/hid/hid-multitouch.c | 136 ++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 199 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ad6bcc4248cc111705d7cfde2b1481b46353e2d7..b7452f11a4f914f92af582ed054d42ecbcd6cb9e 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -817,6 +817,17 @@ config HID_MULTITOUCH
To compile this driver as a module, choose M here: the
module will be called hid-multitouch.
+config MULTITOUCH_HAPTIC
+ bool "Simple haptic multitouch support"
+ depends on HID_MULTITOUCH
+ select HID_HAPTIC
+ default n
+ help
+ Support for simple multitouch haptic devices.
+ Adds extra parsing and FF device for the hid multitouch driver.
+ It can be used for Elan 2703 haptic touchpad.
+ To enable, say Y.
+
config HID_NINTENDO
tristate "Nintendo Joy-Con, NSO, and Pro Controller support"
depends on NEW_LEDS
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 361a7daedeb85454114def8afb5f58caeab58a00..be09b4f13b2058a0a1d7eab79f35def758120fc4 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -4,7 +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
+hid-$(CONFIG_MULTITOUCH_HAPTIC) += hid-haptic.o
obj-$(CONFIG_HID_BPF) += bpf/
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
index 0a34b0c6d706a985630962acc41f7a8eb73cd343..808cec0b4e51eba1f58b839f3e552493655b7899 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -58,6 +58,7 @@ struct hid_haptic_device {
struct hid_haptic_effect stop_effect;
};
+#ifdef CONFIG_MULTITOUCH_HAPTIC
void hid_haptic_feature_mapping(struct hid_device *hdev,
struct hid_haptic_device *haptic,
struct hid_field *field, struct hid_usage
@@ -77,3 +78,54 @@ 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,
+ 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;
+}
+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) {}
+static inline
+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..4ff9ac5022b13a0739dbc7ae5f6ebd84f0114a73 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;
@@ -490,6 +494,95 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
kfree(buf);
}
+#if defined(CONFIG_MULTITOUCH_HAPTIC)
+static int mt_haptic_init(struct hid_device *hdev,
+ struct hid_haptic_device **haptic_ptr)
+{
+ return hid_haptic_init(hdev, haptic_ptr);
+}
+
+static void mt_haptic_feature_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_field *field, struct hid_usage *usage)
+{
+ return hid_haptic_feature_mapping(hdev, haptic, field, usage);
+}
+
+static bool mt_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+ struct hid_input *hi, struct hid_field *field)
+{
+ return hid_haptic_check_pressure_unit(haptic, hi, field);
+}
+
+static void mt_haptic_pressure_reset(struct hid_haptic_device *haptic)
+{
+ return hid_haptic_pressure_reset(haptic);
+}
+
+static void mt_haptic_pressure_increase(struct hid_haptic_device *haptic,
+ __s32 pressure)
+{
+ return hid_haptic_pressure_increase(haptic, pressure);
+}
+
+static int mt_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 hid_haptic_input_mapping(hdev, haptic, hi, field, usage, bit, max);
+}
+
+static int mt_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi)
+{
+ return hid_haptic_input_configured(hdev, haptic, hi);
+}
+#else
+static int mt_haptic_init(struct hid_device *hdev,
+ struct hid_haptic_device **haptic_ptr)
+{
+ return 0;
+}
+
+static void mt_haptic_feature_mapping(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_field *field, struct hid_usage *usage)
+{}
+
+static bool mt_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+ struct hid_input *hi, struct hid_field *field)
+{
+ return 0;
+}
+
+static void mt_haptic_pressure_reset(struct hid_haptic_device *haptic)
+{}
+
+static void mt_haptic_pressure_increase(struct hid_haptic_device *haptic,
+ __s32 pressure)
+{}
+
+static int mt_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 int mt_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic,
+ struct hid_input *hi)
+{
+ return 0;
+}
+#endif
+
+
static void mt_feature_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage)
{
@@ -525,6 +618,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
mt_get_feature(hdev, field->report);
break;
}
+
+ mt_haptic_feature_mapping(hdev, td->haptic, field, usage);
}
static void set_abs(struct input_dev *input, unsigned int code,
@@ -856,6 +951,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 =
+ mt_haptic_check_pressure_unit(td->haptic,
+ hi, field);
MT_STORE_FIELD(p);
return 1;
case HID_DG_SCANTIME:
@@ -980,6 +1078,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)
+ mt_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 +1237,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
minor = minor >> 1;
}
+ if (td->is_haptic_touchpad)
+ mt_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 +1427,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 +1465,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 +1528,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 = mt_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 +1747,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 (mt_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) {
@@ -1764,7 +1884,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
int ret, i;
struct mt_device *td;
const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
-
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
mtclass = &(mt_classes[i]);
@@ -1777,6 +1896,10 @@ 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 = kzalloc(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 +1963,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 (mt_haptic_init(hdev, &td->haptic)) {
+ dev_warn(&hdev->dev, "Cannot allocate haptic for %s\n",
+ hdev->name);
+ td->is_haptic_touchpad = false;
+ kfree(td->haptic);
+ }
+ } else {
+ kfree(td->haptic);
+ }
+
return 0;
}
--
2.50.1.565.gc32cd1483b-goog
^ permalink raw reply related
* Re: [PATCH 2/2] HID: input: report battery status changes immediately
From: kernel test robot @ 2025-08-04 15:34 UTC (permalink / raw)
To: José Expósito, jikos
Cc: oe-kbuild-all, bentiss, luguohong, linux-input, linux-kernel,
José Expósito
In-Reply-To: <20250804091215.6637-2-jose.exposito89@gmail.com>
Hi José,
kernel test robot noticed the following build warnings:
[auto build test WARNING on hid/for-next]
[also build test WARNING on linus/master v6.16 next-20250804]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Jos-Exp-sito/HID-input-report-battery-status-changes-immediately/20250804-171355
base: https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git for-next
patch link: https://lore.kernel.org/r/20250804091215.6637-2-jose.exposito89%40gmail.com
patch subject: [PATCH 2/2] HID: input: report battery status changes immediately
config: arm-randconfig-004-20250804 (https://download.01.org/0day-ci/archive/20250804/202508042305.PBym6Evd-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250804/202508042305.PBym6Evd-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508042305.PBym6Evd-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/hid/hid-input.c:651:13: warning: 'hidinput_update_battery_charge_status' defined but not used [-Wunused-function]
651 | static bool hidinput_update_battery_charge_status(struct hid_device *dev,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/hidinput_update_battery_charge_status +651 drivers/hid/hid-input.c
581c4484769e69 Dmitry Torokhov 2017-08-01 650
133568dfb5acfa José Expósito 2025-08-04 @651 static bool hidinput_update_battery_charge_status(struct hid_device *dev,
133568dfb5acfa José Expósito 2025-08-04 652 unsigned int usage, int value)
581c4484769e69 Dmitry Torokhov 2017-08-01 653 {
133568dfb5acfa José Expósito 2025-08-04 654 return false;
581c4484769e69 Dmitry Torokhov 2017-08-01 655 }
a608dc1c06397d José Expósito 2022-11-24 656
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [dtor-input:next] BUILD SUCCESS WITH WARNING a7bee4e7f78089c101be2ad51f4b5ec64782053e
From: kernel test robot @ 2025-08-04 19:15 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
branch HEAD: a7bee4e7f78089c101be2ad51f4b5ec64782053e Merge tag 'ib-mfd-gpio-input-pwm-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into next
Warning (recently discovered and may have been fixed):
https://lore.kernel.org/oe-kbuild-all/202508041754.ykl25o1q-lkp@intel.com
drivers/input/touch-overlay.c: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
Warning ids grouped by kconfigs:
recent_errors
|-- alpha-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- alpha-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arc-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arc-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arc-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arc-hsdk_defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-keystone_defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-mv78xx0_defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-neponset_defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-randconfig-001-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-randconfig-002-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm-randconfig-003-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm64-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- arm64-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- csky-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- csky-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- csky-randconfig-001-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- hexagon-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- hexagon-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- hexagon-randconfig-001-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- hexagon-randconfig-002-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- i386-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- i386-buildonly-randconfig-006-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- i386-randconfig-141-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- loongarch-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- loongarch-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- m68k-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- m68k-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- microblaze-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- microblaze-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- microblaze-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- mips-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- nios2-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- nios2-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- openrisc-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- openrisc-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- openrisc-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- parisc-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- parisc-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- parisc-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- parisc-randconfig-002-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- parisc64-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc-bluestone_defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc-ppa8548_defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc-randconfig-001-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc64-randconfig-001-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc64-randconfig-002-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- powerpc64-randconfig-003-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- riscv-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- riscv-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- riscv-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- riscv-randconfig-002-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- s390-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- s390-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- s390-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sh-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sh-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sh-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sh-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sh-sh03_defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sparc-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sparc-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- sparc64-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- um-allmodconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- um-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- um-randconfig-001-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- um-randconfig-002-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- x86_64-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- x86_64-allyesconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- x86_64-buildonly-randconfig-006-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- x86_64-defconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- x86_64-randconfig-161-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- x86_64-rhel-9.4-rust
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- xtensa-allnoconfig
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
|-- xtensa-randconfig-001-20250804
| `-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
`-- xtensa-randconfig-002-20250804
`-- drivers-input-touch-overlay.c:warning:EXPORT_SYMBOL()-is-used-but-include-linux-export.h-is-missing
elapsed time: 721m
configs tested: 135
configs skipped: 4
tested configs:
alpha allnoconfig gcc-15.1.0
alpha allyesconfig gcc-15.1.0
arc allmodconfig gcc-15.1.0
arc allnoconfig gcc-15.1.0
arc allyesconfig gcc-15.1.0
arc hsdk_defconfig gcc-15.1.0
arc randconfig-001-20250804 gcc-8.5.0
arc randconfig-002-20250804 gcc-13.4.0
arm allmodconfig gcc-15.1.0
arm allnoconfig clang-22
arm allyesconfig gcc-15.1.0
arm keystone_defconfig gcc-15.1.0
arm mv78xx0_defconfig clang-19
arm neponset_defconfig gcc-15.1.0
arm randconfig-001-20250804 clang-22
arm randconfig-002-20250804 clang-22
arm randconfig-003-20250804 clang-22
arm randconfig-004-20250804 gcc-15.1.0
arm64 allmodconfig clang-19
arm64 allnoconfig gcc-15.1.0
arm64 randconfig-001-20250804 clang-22
arm64 randconfig-002-20250804 clang-19
arm64 randconfig-003-20250804 clang-22
arm64 randconfig-004-20250804 clang-22
csky allnoconfig gcc-15.1.0
csky defconfig gcc-15.1.0
csky randconfig-001-20250804 gcc-12.5.0
csky randconfig-002-20250804 gcc-11.5.0
hexagon allmodconfig clang-17
hexagon allnoconfig clang-22
hexagon allyesconfig clang-22
hexagon randconfig-001-20250804 clang-22
hexagon randconfig-002-20250804 clang-22
i386 allmodconfig gcc-12
i386 allnoconfig gcc-12
i386 allyesconfig gcc-12
i386 buildonly-randconfig-001-20250804 clang-20
i386 buildonly-randconfig-002-20250804 gcc-12
i386 buildonly-randconfig-003-20250804 clang-20
i386 buildonly-randconfig-004-20250804 gcc-12
i386 buildonly-randconfig-005-20250804 gcc-12
i386 buildonly-randconfig-006-20250804 clang-20
i386 defconfig clang-20
loongarch allmodconfig clang-19
loongarch allnoconfig clang-22
loongarch randconfig-001-20250804 gcc-15.1.0
loongarch randconfig-002-20250804 clang-22
m68k allmodconfig gcc-15.1.0
m68k allnoconfig gcc-15.1.0
m68k allyesconfig gcc-15.1.0
m68k atari_defconfig gcc-15.1.0
microblaze allmodconfig gcc-15.1.0
microblaze allnoconfig gcc-15.1.0
microblaze allyesconfig gcc-15.1.0
microblaze defconfig gcc-15.1.0
mips allnoconfig gcc-15.1.0
mips gcw0_defconfig clang-22
nios2 allnoconfig gcc-11.5.0
nios2 defconfig gcc-11.5.0
nios2 randconfig-001-20250804 gcc-10.5.0
nios2 randconfig-002-20250804 gcc-10.5.0
openrisc allnoconfig gcc-15.1.0
openrisc allyesconfig gcc-15.1.0
openrisc defconfig gcc-15.1.0
parisc allmodconfig gcc-15.1.0
parisc allnoconfig gcc-15.1.0
parisc allyesconfig gcc-15.1.0
parisc defconfig gcc-15.1.0
parisc randconfig-001-20250804 gcc-12.5.0
parisc randconfig-002-20250804 gcc-14.3.0
parisc64 defconfig gcc-15.1.0
powerpc allmodconfig gcc-15.1.0
powerpc allnoconfig gcc-15.1.0
powerpc allyesconfig clang-22
powerpc bluestone_defconfig clang-22
powerpc ppa8548_defconfig gcc-15.1.0
powerpc randconfig-001-20250804 gcc-8.5.0
powerpc randconfig-002-20250804 gcc-13.4.0
powerpc randconfig-003-20250804 clang-22
powerpc64 randconfig-001-20250804 clang-22
powerpc64 randconfig-002-20250804 clang-19
powerpc64 randconfig-003-20250804 clang-16
riscv allmodconfig clang-22
riscv allnoconfig gcc-15.1.0
riscv allyesconfig clang-16
riscv defconfig clang-22
riscv randconfig-001-20250804 gcc-8.5.0
riscv randconfig-002-20250804 gcc-13.4.0
s390 allmodconfig clang-18
s390 allnoconfig clang-22
s390 allyesconfig gcc-15.1.0
s390 defconfig clang-22
s390 randconfig-001-20250804 clang-22
s390 randconfig-002-20250804 gcc-8.5.0
sh allmodconfig gcc-15.1.0
sh allnoconfig gcc-15.1.0
sh allyesconfig gcc-15.1.0
sh apsh4ad0a_defconfig gcc-15.1.0
sh defconfig gcc-15.1.0
sh ecovec24_defconfig gcc-15.1.0
sh magicpanelr2_defconfig gcc-15.1.0
sh randconfig-001-20250804 gcc-14.3.0
sh randconfig-002-20250804 gcc-15.1.0
sh se7750_defconfig gcc-15.1.0
sh se7780_defconfig gcc-15.1.0
sh sh03_defconfig gcc-15.1.0
sparc allmodconfig gcc-15.1.0
sparc allnoconfig gcc-15.1.0
sparc defconfig gcc-15.1.0
sparc randconfig-001-20250804 gcc-8.5.0
sparc randconfig-002-20250804 gcc-13.4.0
sparc64 defconfig clang-20
sparc64 randconfig-001-20250804 gcc-10.5.0
sparc64 randconfig-002-20250804 gcc-8.5.0
um allmodconfig clang-19
um allnoconfig clang-22
um allyesconfig gcc-12
um defconfig clang-22
um i386_defconfig gcc-12
um randconfig-001-20250804 clang-22
um randconfig-002-20250804 gcc-12
um x86_64_defconfig clang-22
x86_64 allnoconfig clang-20
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20250804 clang-20
x86_64 buildonly-randconfig-002-20250804 gcc-12
x86_64 buildonly-randconfig-003-20250804 gcc-12
x86_64 buildonly-randconfig-004-20250804 gcc-12
x86_64 buildonly-randconfig-005-20250804 clang-20
x86_64 buildonly-randconfig-006-20250804 gcc-12
x86_64 defconfig gcc-11
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig gcc-15.1.0
xtensa randconfig-001-20250804 gcc-11.5.0
xtensa randconfig-002-20250804 gcc-13.4.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2 02/11] Input: add FF_HID effect type
From: tomasz.pakula.oficjalny @ 2025-08-04 20:34 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
In-Reply-To: <20250804-support-forcepads-v2-2-138ca980261d@google.com>
On Mon, 2025-08-04 at 14:11 +0000, Jonathan Denose wrote:
> From: Angela Czubak <aczubak@google.com>
>
> FF_HID 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..3ea7c826c6fb2034e46f95cb95b84ef6f5b866df 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_hid_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_hid_effect {
> + __u16 hid_usage;
> + __u16 vendor_id;
> + __u8 vendor_waveform_page;
> + __u16 intensity;
> + __u16 repeat_count;
> + __u16 retrigger_period;
> +};
Wouldn't it make more sense to call this new effect ff_haptic_effect?
hid_effect sound generic, too generic. One could say, all ff effect are
hid effects because most ff apis (linux' included) are based on USB PID
spec.
> +
> /**
> * 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_hid_effect hid;
> } u;
> };
>
> @@ -471,6 +490,7 @@ struct ff_effect {
> * Force feedback effect types
> */
>
> +#define FF_HID 0x4f
Again here, FF_HID sounds confusing without having the broader context.
Constant, Sine, Inertia, Spring are way more descriptive. FF_HAPTIC
would be a great name to distinguish such an effect. Or maybe FF_TACTILE
with ff_tactile_effect?
> #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_HID
> #define FF_EFFECT_MAX FF_RAMP
>
> /*
Overall, I'll keep an eye on this as I'm slowly working towards a
proposal for a revamped and extended ff api on Linux that would make it
fully featured (we're lacking things like device control and querying
effects and their status, arbitrary number of axes and arbitrary axes
themselves).
^ permalink raw reply
* RE: [PATCH 1/2] HID: intel-thc-hid: intel-quicki2c: Fix ACPI dsd ICRS/ISUB length
From: Xu, Even @ 2025-08-05 2:14 UTC (permalink / raw)
To: Aaron, Ma, Sun, Xinpeng, jikos@kernel.org, bentiss@kernel.org,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
Aaron, Ma
In-Reply-To: <20250803065726.2895470-1-aaron.ma@canonical.com>
> -----Original Message-----
> From: Aaron Ma <aaron.ma@canonical.com>
> Sent: Sunday, August 3, 2025 2:57 PM
> To: Xu, Even <even.xu@intel.com>; Sun, Xinpeng <xinpeng.sun@intel.com>;
> jikos@kernel.org; bentiss@kernel.org; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org; Aaron, Ma <aaron.ma@canonical.com>
> Subject: [PATCH 1/2] HID: intel-thc-hid: intel-quicki2c: Fix ACPI dsd ICRS/ISUB
> length
>
> The QuickI2C ACPI _DSD methods return ICRS and ISUB data with a trailing byte,
> making the actual length is one more byte than the structs defined.
>
> It caused stack-out-of-bounds and kernel crash:
>
> kernel: BUG: KASAN: stack-out-of-bounds in
> quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0 [intel_quicki2c]
> kernel: Write of size 12 at addr ffff888106d1f900 by task kworker/u33:2/75
> kernel:
> kernel: CPU: 3 UID: 0 PID: 75 Comm: kworker/u33:2 Not tainted 6.16.0+ #3
> PREEMPT(voluntary)
> kernel: Workqueue: async async_run_entry_fn
> kernel: Call Trace:
> kernel: <TASK>
> kernel: dump_stack_lvl+0x76/0xa0
> kernel: print_report+0xd1/0x660
> kernel: ? __pfx__raw_spin_lock_irqsave+0x10/0x10
> kernel: ? __kasan_slab_free+0x5d/0x80
> kernel: ? kasan_addr_to_slab+0xd/0xb0
> kernel: kasan_report+0xe1/0x120
> kernel: ? quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0
> [intel_quicki2c]
> kernel: ? quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0
> [intel_quicki2c]
> kernel: kasan_check_range+0x11c/0x200
> kernel: __asan_memcpy+0x3b/0x80
> kernel: quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0
> [intel_quicki2c]
> kernel: ? __pfx_quicki2c_acpi_get_dsd_property.constprop.0+0x10/0x10
> [intel_quicki2c]
> kernel: quicki2c_get_acpi_resources+0x237/0x730 [intel_quicki2c] [...]
> kernel: </TASK>
> kernel:
> kernel: The buggy address belongs to stack of task kworker/u33:2/75
> kernel: and is located at offset 48 in frame:
> kernel: quicki2c_get_acpi_resources+0x0/0x730 [intel_quicki2c]
> kernel:
> kernel: This frame has 3 objects:
> kernel: [32, 36) 'hid_desc_addr'
> kernel: [48, 59) 'i2c_param'
> kernel: [80, 224) 'i2c_config'
>
> ACPI DSD methods return:
>
> \_SB.PC00.THC0.ICRS Buffer 000000003fdc947b 001 Len 0C = 0A 00 80 1A 06
> 00 00 00 00 00 00 00
> \_SB.PC00.THC0.ISUB Buffer 00000000f2fcbdc4 001 Len 91 = 00 00 00 00 00
> 00 00 00 00 00 00 00
>
> Adding reserved padding to quicki2c_subip_acpi_parameter/config.
Good finding, thanks for the fix!
>
> Fixes: 5282e45ccbfa9 ("HID: intel-thc-hid: intel-quicki2c: Add THC QuickI2C ACPI
> interfaces")
> Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
> ---
> drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> index 6ddb584bd6110..97085a6a7452d 100644
> --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> @@ -71,6 +71,7 @@ struct quicki2c_subip_acpi_parameter {
> u16 device_address;
> u64 connection_speed;
> u8 addressing_mode;
> + u8 reserved;
> } __packed;
>
> /**
> @@ -120,6 +121,7 @@ struct quicki2c_subip_acpi_config {
> u64 HMTD;
> u64 HMRD;
> u64 HMSL;
> + u8 reserved;
> };
Reviewed-by: Even Xu <even.xu@intel.com>
Tested-by: Even Xu <even.xu@intel.com>
>
> struct device;
> --
> 2.43.0
^ permalink raw reply
* RE: [PATCH 2/2] HID: intel-thc-hid: intel-thc: Fix incorrect pointer arithmetic in I2C regs save
From: Xu, Even @ 2025-08-05 2:15 UTC (permalink / raw)
To: Aaron, Ma, Sun, Xinpeng, jikos@kernel.org, bentiss@kernel.org,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
Aaron, Ma
In-Reply-To: <20250803065726.2895470-2-aaron.ma@canonical.com>
> -----Original Message-----
> From: Aaron Ma <aaron.ma@canonical.com>
> Sent: Sunday, August 3, 2025 2:57 PM
> To: Xu, Even <even.xu@intel.com>; Sun, Xinpeng <xinpeng.sun@intel.com>;
> jikos@kernel.org; bentiss@kernel.org; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org; Aaron, Ma <aaron.ma@canonical.com>
> Subject: [PATCH 2/2] HID: intel-thc-hid: intel-thc: Fix incorrect pointer arithmetic
> in I2C regs save
>
> Improper use of secondary pointer (&dev->i2c_subip_regs) caused kernel crash
> and out-of-bounds error:
>
> BUG: KASAN: slab-out-of-bounds in _regmap_bulk_read+0x449/0x510 Write of
> size 4 at addr ffff888136005dc0 by task kworker/u33:5/5107
>
> CPU: 3 UID: 0 PID: 5107 Comm: kworker/u33:5 Not tainted 6.16.0+ #3
> PREEMPT(voluntary)
> Workqueue: async async_run_entry_fn
> Call Trace:
> <TASK>
> dump_stack_lvl+0x76/0xa0
> print_report+0xd1/0x660
> ? __pfx__raw_spin_lock_irqsave+0x10/0x10
> ? kasan_complete_mode_report_info+0x26/0x200
> kasan_report+0xe1/0x120
> ? _regmap_bulk_read+0x449/0x510
> ? _regmap_bulk_read+0x449/0x510
> __asan_report_store4_noabort+0x17/0x30
> _regmap_bulk_read+0x449/0x510
> ? __pfx__regmap_bulk_read+0x10/0x10
> regmap_bulk_read+0x270/0x3d0
> pio_complete+0x1ee/0x2c0 [intel_thc]
> ? __pfx_pio_complete+0x10/0x10 [intel_thc]
> ? __pfx_pio_wait+0x10/0x10 [intel_thc]
> ? regmap_update_bits_base+0x13b/0x1f0
> thc_i2c_subip_pio_read+0x117/0x270 [intel_thc]
> thc_i2c_subip_regs_save+0xc2/0x140 [intel_thc]
> ? __pfx_thc_i2c_subip_regs_save+0x10/0x10 [intel_thc] [...] The buggy address
> belongs to the object at ffff888136005d00
> which belongs to the cache kmalloc-rnd-12-192 of size 192 The buggy address is
> located 0 bytes to the right of
> allocated 192-byte region [ffff888136005d00, ffff888136005dc0)
>
> Replaced with direct array indexing (&dev->i2c_subip_regs[i]) to ensure safe
> memory access.
>
> Fixes: 4228966def884 ("HID: intel-thc-hid: intel-thc: Add THC I2C config
> interfaces")
> Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
> ---
> drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-
> thc-hid/intel-thc/intel-thc-dev.c
> index c105df7f6c873..4698722e0d0a6 100644
> --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c
> +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c
> @@ -1539,7 +1539,7 @@ int thc_i2c_subip_regs_save(struct thc_device *dev)
>
> for (int i = 0; i < ARRAY_SIZE(i2c_subip_regs); i++) {
> ret = thc_i2c_subip_pio_read(dev, i2c_subip_regs[i],
> - &read_size, (u32 *)&dev-
> >i2c_subip_regs + i);
> + &read_size, &dev-
> >i2c_subip_regs[i]);
> if (ret < 0)
> return ret;
> }
> @@ -1562,7 +1562,7 @@ int thc_i2c_subip_regs_restore(struct thc_device
> *dev)
>
> for (int i = 0; i < ARRAY_SIZE(i2c_subip_regs); i++) {
> ret = thc_i2c_subip_pio_write(dev, i2c_subip_regs[i],
> - write_size, (u32 *)&dev-
> >i2c_subip_regs + i);
> + write_size, &dev-
> >i2c_subip_regs[i]);
> if (ret < 0)
> return ret;
> }
Thanks for the fix!
Reviewed-by: Even Xu <even.xu@intel.com>
Tested-by: Even Xu <even.xu@intel.com>
> --
> 2.43.0
^ permalink raw reply
* Re: dev->uniq is not unique for individual USB interfaces
From: Andrey Smirnov @ 2025-08-05 3:11 UTC (permalink / raw)
To: Jiri Kosina; +Cc: Benjamin Tissoires, linux-usb, open list:HID CORE LAYER
In-Reply-To: <03s194q6-n6n7-2p42-5o48-99726p7qp0n0@xreary.bet>
On Mon, Aug 4, 2025 at 12:20 AM Jiri Kosina <jikos@kernel.org> wrote:
>
> On Mon, 21 Jul 2025, Andrey Smirnov wrote:
>
> > Hey folks:
> >
> > I'm working on a custom USB device that presents N battery powered HID
> > interfaces with each interface reporting its own battery life via
> > standard HID Power Device report. The problem I'm running into is that
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/hid/hid-input.c?h=v6.16-rc7#n524
> >
> > assumes that "uniq" field of a "struct hid_device" is always unique, but
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/hid/usbhid/hid-core.c?h=v6.16-rc7#n1415
> >
> > populates "uniq" with iSerialNumber which is only unique per USB
> > device, not per USB interface. At the first glance the right way to
> > fix this would be to change how uniq is generated by usbhid_probe()
> > but that probably would break some userspace assumptions?
>
> Hmm, actually, from top of my head I am not able to come up with any
> userspace breakage this might cause. Do you have anything particular on
> mind?
No, not really. It sounds like we can try to fix this without gating
the change by a quirk. I'll try to put together a path in the next
couple of days, then.
Thanks!
^ permalink raw reply
* Re: 答复: [External Mail][PATCH 2/2] HID: input: report battery status changes immediately
From: José Expósito @ 2025-08-05 8:42 UTC (permalink / raw)
To: 卢国宏
Cc: jikos@kernel.org, bentiss@kernel.org, linux-input@vger.kernel.org,
linux-kernel@vger.kernel.org, Fei1 Jiang 蒋飞
In-Reply-To: <a235549c5cf24205bb7ce7f05737c403@xiaomi.com>
Hi!
On Tue, Aug 05, 2025 at 01:43:30AM +0000, 卢国宏 wrote:
> ________________________________
> 发件人: José Expósito <jose.exposito89@gmail.com>
> 发送时间: 2025年8月4日 17:11
> 收件人: jikos@kernel.org
> 抄送: bentiss@kernel.org; 卢国宏; linux-input@vger.kernel.org; linux-kernel@vger.kernel.org; José Expósito
> 主题: [External Mail][PATCH 2/2] HID: input: report battery status changes immediately
>
> [外部邮件] 此邮件来源于小米公司外部,请谨慎处理。若对邮件安全性存疑,请将邮件转发给misec@xiaomi.com进行反馈
>
> When the battery status changes, report the change immediately to user
> space.
>
> Fixes: a608dc1c0639 ("HID: input: map battery system charging")
> Reported-by: 卢国宏 <luguohong@xiaomi.com>
> Closes: https://lore.kernel.org/linux-input/aI49Im0sGb6fpgc8@fedora/T/
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
> drivers/hid/hid-input.c | 17 ++++++++++-------
> 1 file changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index 262787e6eb20..277538a17b57 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -609,13 +609,19 @@ static bool hidinput_update_battery_charge_status(struct hid_device *dev,
> return false;
> }
>
> -static void hidinput_update_battery(struct hid_device *dev, int value)
> +static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
> + int value)
> {
> int capacity;
>
> if (!dev->battery)
> return;
>
> + if (hidinput_update_battery_charge_status(dev, usage, value)) {
> + power_supply_changed(dev->battery);
> + return;
> + }
> +
>
> > Hi, José. Shouldn't the return statement in this code be removed?
> > Otherwise, if both the battery level and the charging status change
> > simultaneously, the code following the if statement that updates the
> > battery level won't run, and the battery level won't be updated.
> > Thanks!
At least on the hardware I have access to, changes are reported independently.
I added a log at the beginning of this function to illustrate it.
This is the output when the battery of my device goes from 99% to 95%:
New EV_PWR report:
usage = 8716389
value = 99
New EV_PWR report:
usage = 8716356 (HID_BAT_CHARGING)
value = 0 (POWER_SUPPLY_STATUS_DISCHARGING)
[...]
New EV_PWR report:
usage = 8716389
value = 95
New EV_PWR report:
usage = 8716356 (HID_BAT_CHARGING)
value = 0 (POWER_SUPPLY_STATUS_DISCHARGING)
If we remove that return, then "value" (0 or 1) would be used as battery level,
reporting wrong battery levels to user-space.
Isn't your device reporting its battery information in a similar way?
Jose
PS - I'll fix the warning in v2 and add a Tested-by: 卢国宏 tag once
this is confirmed to work on the affected hardware.
>
>
> if (value == 0 || value < dev->battery_min || value > dev->battery_max)
> return;
>
> @@ -648,7 +654,8 @@ static bool hidinput_update_battery_charge_status(struct hid_device *dev,
> return false;
> }
>
> -static void hidinput_update_battery(struct hid_device *dev, int value)
> +static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
> + int value)
> {
> }
> #endif /* CONFIG_HID_BATTERY_STRENGTH */
> @@ -1515,11 +1522,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
> return;
>
> if (usage->type == EV_PWR) {
> - bool handled = hidinput_update_battery_charge_status(hid, usage->hid, value);
> -
> - if (!handled)
> - hidinput_update_battery(hid, value);
> -
> + hidinput_update_battery(hid, usage->hid, value);
> return;
> }
>
> --
> 2.50.1
>
> #/******本邮件及其附件含有小米公司的保密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制、或散发)本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件! This e-mail and its attachments contain confidential information from XIAOMI, which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction, or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this e-mail in error, please notify the sender by phone or email immediately and delete it!******/#
^ permalink raw reply
* [PATCH v2] input: zforce_ts: Remove error print for devm_add_action_or_reset()
From: Waqar Hameed @ 2025-08-05 9:33 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: kernel, linux-input, linux-kernel
When `devm_add_action_or_reset()` fails, it is due to a failed memory
allocation and will thus return `-ENOMEM`. `dev_err_probe()` doesn't do
anything when error is `-ENOMEM`. Therefore, remove the useless call to
`dev_err_probe()` when `devm_add_action_or_reset()` fails, and just
return the value instead.
Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
Changes in v2:
* Split the patch to one seperate patch for each sub-system.
Link to v1: https://lore.kernel.org/all/pnd7c0s6ji2.fsf@axis.com/
drivers/input/touchscreen/zforce_ts.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index df42fdf36ae3..4d000b5b3ae6 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -739,8 +739,7 @@ static int zforce_probe(struct i2c_client *client)
error = devm_add_action_or_reset(&client->dev, zforce_reset, ts);
if (error)
- return dev_err_probe(&client->dev, error,
- "failed to register reset action\n");
+ return error;
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
base-commit: 260f6f4fda93c8485c8037865c941b42b9cba5d2
--
2.39.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox