Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH v2 06/17] HID: pidff: Better quirk assigment when searching for fields
From: Tomasz Pakuła @ 2025-08-13 20:09 UTC (permalink / raw)
  To: jikos, bentiss; +Cc: oleg, linux-input
In-Reply-To: <20250813201005.17819-1-tomasz.pakula.oficjalny@gmail.com>

Assign quirks directly when they're discovered. Way easier to understand
without relying on return values.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/hid/usbhid/hid-pidff.c | 59 +++++++++++-----------------------
 1 file changed, 18 insertions(+), 41 deletions(-)

diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index cff79e76c211..c88442a087f1 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -943,7 +943,8 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
  * Find fields from a report and fill a pidff_usage
  */
 static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
-			     struct hid_report *report, int count, int strict)
+			     struct hid_report *report, int count, int strict,
+			     u32 *quirks)
 {
 	if (!report) {
 		pr_debug("%s, null report\n", __func__);
@@ -951,7 +952,6 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
 	}
 
 	int i, j, k, found;
-	int return_value = 0;
 
 	for (k = 0; k < count; k++) {
 		found = 0;
@@ -979,17 +979,17 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
 		if (!found && table[k] == pidff_set_effect[PID_START_DELAY]) {
 			pr_debug("Delay field not found, but that's OK\n");
 			pr_debug("Setting MISSING_DELAY quirk\n");
-			return_value |= HID_PIDFF_QUIRK_MISSING_DELAY;
+			*quirks |= HID_PIDFF_QUIRK_MISSING_DELAY;
 		} else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) {
 			pr_debug("PBO field not found, but that's OK\n");
 			pr_debug("Setting MISSING_PBO quirk\n");
-			return_value |= HID_PIDFF_QUIRK_MISSING_PBO;
+			*quirks |= HID_PIDFF_QUIRK_MISSING_PBO;
 		} else if (!found && strict) {
 			pr_debug("failed to locate %d\n", k);
 			return -1;
 		}
 	}
-	return return_value;
+	return 0;
 }
 
 /*
@@ -1258,26 +1258,17 @@ static int pidff_find_effects(struct pidff_device *pidff,
 #define PIDFF_FIND_FIELDS(name, report, strict) \
 	pidff_find_fields(pidff->name, pidff_ ## name, \
 		pidff->reports[report], \
-		ARRAY_SIZE(pidff_ ## name), strict)
+		ARRAY_SIZE(pidff_ ## name), strict, &pidff->quirks)
 
 /*
  * Fill and check the pidff_usages
  */
 static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
 {
-	int status = 0;
-
-	/* Save info about the device not having the DELAY ffb field. */
-	status = PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1);
-	if (status == -1) {
+	if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
 		hid_err(pidff->hid, "unknown set_effect report layout\n");
 		return -ENODEV;
 	}
-	pidff->quirks |= status;
-
-	if (status & HID_PIDFF_QUIRK_MISSING_DELAY)
-		hid_dbg(pidff->hid, "Adding MISSING_DELAY quirk\n");
-
 
 	PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
 	if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
@@ -1311,39 +1302,25 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
 				 "has periodic effect but no envelope\n");
 	}
 
-	if (test_bit(FF_CONSTANT, dev->ffbit) &&
-	    PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
+	if (PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1) &&
+	    test_and_clear_bit(FF_CONSTANT, dev->ffbit))
 		hid_warn(pidff->hid, "unknown constant effect layout\n");
-		clear_bit(FF_CONSTANT, dev->ffbit);
-	}
 
-	if (test_bit(FF_RAMP, dev->ffbit) &&
-	    PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
+	if (PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1) &&
+	    test_and_clear_bit(FF_RAMP, dev->ffbit))
 		hid_warn(pidff->hid, "unknown ramp effect layout\n");
-		clear_bit(FF_RAMP, dev->ffbit);
-	}
-
-	if (test_bit(FF_SPRING, dev->ffbit) ||
-	    test_bit(FF_DAMPER, dev->ffbit) ||
-	    test_bit(FF_FRICTION, dev->ffbit) ||
-	    test_bit(FF_INERTIA, dev->ffbit)) {
-		status = PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1);
 
-		if (status < 0) {
+	if (PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
+		if (test_and_clear_bit(FF_SPRING, dev->ffbit)   ||
+		    test_and_clear_bit(FF_DAMPER, dev->ffbit)   ||
+		    test_and_clear_bit(FF_FRICTION, dev->ffbit) ||
+		    test_and_clear_bit(FF_INERTIA, dev->ffbit))
 			hid_warn(pidff->hid, "unknown condition effect layout\n");
-			clear_bit(FF_SPRING, dev->ffbit);
-			clear_bit(FF_DAMPER, dev->ffbit);
-			clear_bit(FF_FRICTION, dev->ffbit);
-			clear_bit(FF_INERTIA, dev->ffbit);
-		}
-		pidff->quirks |= status;
 	}
 
-	if (test_bit(FF_PERIODIC, dev->ffbit) &&
-	    PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
+	if (PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1) &&
+	    test_and_clear_bit(FF_PERIODIC, dev->ffbit))
 		hid_warn(pidff->hid, "unknown periodic effect layout\n");
-		clear_bit(FF_PERIODIC, dev->ffbit);
-	}
 
 	PIDFF_FIND_FIELDS(pool, PID_POOL, 0);
 
-- 
2.50.1


^ permalink raw reply related

* [PATCH v2 05/17] HID: pidff: Treat PID_REQUIRED_REPORTS as count, not max
From: Tomasz Pakuła @ 2025-08-13 20:09 UTC (permalink / raw)
  To: jikos, bentiss; +Cc: oleg, linux-input
In-Reply-To: <20250813201005.17819-1-tomasz.pakula.oficjalny@gmail.com>

It's naming suggests it's a count of the records required by the USB PID
standard and this driver.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Oleg Makarenko <oleg@makarenk.ooo>
---
 drivers/hid/usbhid/hid-pidff.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 2f9fbe4c52d7..cff79e76c211 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -33,7 +33,7 @@
 #define PID_DEVICE_CONTROL	6
 #define PID_CREATE_NEW_EFFECT	7
 
-#define PID_REQUIRED_REPORTS	7
+#define PID_REQUIRED_REPORTS	8
 
 #define PID_SET_ENVELOPE	8
 #define PID_SET_CONDITION	9
@@ -1056,7 +1056,7 @@ static int pidff_reports_ok(struct pidff_device *pidff)
 {
 	int i;
 
-	for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
+	for (i = 0; i < PID_REQUIRED_REPORTS; i++) {
 		if (!pidff->reports[i]) {
 			hid_dbg(pidff->hid, "%d missing\n", i);
 			return 0;
-- 
2.50.1


^ permalink raw reply related

* [PATCH v2 04/17] HID: pidff: Use ARRAY_SIZE macro instead of sizeof
From: Tomasz Pakuła @ 2025-08-13 20:09 UTC (permalink / raw)
  To: jikos, bentiss; +Cc: oleg, linux-input
In-Reply-To: <20250813201005.17819-1-tomasz.pakula.oficjalny@gmail.com>

Could lead to issues when arrays won't be 8 bit fields

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Oleg Makarenko <oleg@makarenk.ooo>
---
 drivers/hid/usbhid/hid-pidff.c | 46 +++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 75fc6dbe435c..2f9fbe4c52d7 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -158,20 +158,20 @@ struct pidff_usage {
 struct pidff_device {
 	struct hid_device *hid;
 
-	struct hid_report *reports[sizeof(pidff_reports)];
+	struct hid_report *reports[ARRAY_SIZE(pidff_reports)];
 
-	struct pidff_usage set_effect[sizeof(pidff_set_effect)];
-	struct pidff_usage set_envelope[sizeof(pidff_set_envelope)];
-	struct pidff_usage set_condition[sizeof(pidff_set_condition)];
-	struct pidff_usage set_periodic[sizeof(pidff_set_periodic)];
-	struct pidff_usage set_constant[sizeof(pidff_set_constant)];
-	struct pidff_usage set_ramp[sizeof(pidff_set_ramp)];
+	struct pidff_usage set_effect[ARRAY_SIZE(pidff_set_effect)];
+	struct pidff_usage set_envelope[ARRAY_SIZE(pidff_set_envelope)];
+	struct pidff_usage set_condition[ARRAY_SIZE(pidff_set_condition)];
+	struct pidff_usage set_periodic[ARRAY_SIZE(pidff_set_periodic)];
+	struct pidff_usage set_constant[ARRAY_SIZE(pidff_set_constant)];
+	struct pidff_usage set_ramp[ARRAY_SIZE(pidff_set_ramp)];
 
-	struct pidff_usage device_gain[sizeof(pidff_device_gain)];
-	struct pidff_usage block_load[sizeof(pidff_block_load)];
-	struct pidff_usage pool[sizeof(pidff_pool)];
-	struct pidff_usage effect_operation[sizeof(pidff_effect_operation)];
-	struct pidff_usage block_free[sizeof(pidff_block_free)];
+	struct pidff_usage device_gain[ARRAY_SIZE(pidff_device_gain)];
+	struct pidff_usage block_load[ARRAY_SIZE(pidff_block_load)];
+	struct pidff_usage pool[ARRAY_SIZE(pidff_pool)];
+	struct pidff_usage effect_operation[ARRAY_SIZE(pidff_effect_operation)];
+	struct pidff_usage block_free[ARRAY_SIZE(pidff_block_free)];
 
 	/*
 	 * Special field is a field that is not composed of
@@ -194,10 +194,10 @@ struct pidff_device {
 	/* Special field in effect_operation */
 	struct hid_field *effect_operation_status;
 
-	int control_id[sizeof(pidff_device_control)];
-	int type_id[sizeof(pidff_effect_types)];
-	int status_id[sizeof(pidff_block_load_status)];
-	int operation_id[sizeof(pidff_effect_operation_status)];
+	int control_id[ARRAY_SIZE(pidff_device_control)];
+	int type_id[ARRAY_SIZE(pidff_effect_types)];
+	int status_id[ARRAY_SIZE(pidff_block_load_status)];
+	int operation_id[ARRAY_SIZE(pidff_effect_operation_status)];
 
 	int pid_id[PID_EFFECTS_MAX];
 
@@ -583,7 +583,7 @@ static void pidff_set_device_control(struct pidff_device *pidff, int field)
 		hid_dbg(pidff->hid, "DEVICE_CONTROL is a bitmask\n");
 
 		/* Clear current bitmask */
-		for (i = 0; i < sizeof(pidff_device_control); i++) {
+		for (i = 0; i < ARRAY_SIZE(pidff_device_control); i++) {
 			index = pidff->control_id[i];
 			if (index < 1)
 				continue;
@@ -999,7 +999,7 @@ static int pidff_check_usage(int usage)
 {
 	int i;
 
-	for (i = 0; i < sizeof(pidff_reports); i++)
+	for (i = 0; i < ARRAY_SIZE(pidff_reports); i++)
 		if (usage == (HID_UP_PID | pidff_reports[i]))
 			return i;
 
@@ -1117,7 +1117,7 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld,
 
 #define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \
 	pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \
-		sizeof(pidff_ ## name))
+		ARRAY_SIZE(pidff_ ## name))
 
 /*
  * Find and check the special fields
@@ -1184,7 +1184,7 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
 
 	if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
 				    block_load_status) !=
-			sizeof(pidff_block_load_status)) {
+			ARRAY_SIZE(pidff_block_load_status)) {
 		hid_err(pidff->hid,
 			"block load status identifiers not found\n");
 		return -1;
@@ -1192,7 +1192,7 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
 
 	if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
 				    effect_operation_status) !=
-			sizeof(pidff_effect_operation_status)) {
+			ARRAY_SIZE(pidff_effect_operation_status)) {
 		hid_err(pidff->hid, "effect operation identifiers not found\n");
 		return -1;
 	}
@@ -1208,7 +1208,7 @@ static int pidff_find_effects(struct pidff_device *pidff,
 {
 	int i;
 
-	for (i = 0; i < sizeof(pidff_effect_types); i++) {
+	for (i = 0; i < ARRAY_SIZE(pidff_effect_types); i++) {
 		int pidff_type = pidff->type_id[i];
 
 		if (pidff->set_effect_type->usage[pidff_type].hid !=
@@ -1258,7 +1258,7 @@ static int pidff_find_effects(struct pidff_device *pidff,
 #define PIDFF_FIND_FIELDS(name, report, strict) \
 	pidff_find_fields(pidff->name, pidff_ ## name, \
 		pidff->reports[report], \
-		sizeof(pidff_ ## name), strict)
+		ARRAY_SIZE(pidff_ ## name), strict)
 
 /*
  * Fill and check the pidff_usages
-- 
2.50.1


^ permalink raw reply related

* [PATCH v2 03/17] HID: pidff: Remove unneeded debug
From: Tomasz Pakuła @ 2025-08-13 20:09 UTC (permalink / raw)
  To: jikos, bentiss; +Cc: oleg, linux-input
In-Reply-To: <20250813201005.17819-1-tomasz.pakula.oficjalny@gmail.com>

All the envelope settings work correctly and even if we wanted to debug
something about the envelope report, we would not only need the attack
level but it's length and fade properties to have a full image.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Oleg Makarenko <oleg@makarenk.ooo>
---
 drivers/hid/usbhid/hid-pidff.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 3cf844f7ad4a..75fc6dbe435c 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -339,10 +339,6 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
 	pidff_set_time(&pidff->set_envelope[PID_FADE_TIME],
 			envelope->fade_length);
 
-	hid_dbg(pidff->hid, "attack %u => %d\n",
-		envelope->attack_level,
-		pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
-
 	hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
 			HID_REQ_SET_REPORT);
 }
-- 
2.50.1


^ permalink raw reply related

* [PATCH v2 02/17] HID: pidff: Remove unhelpful pidff_set_actuators helper
From: Tomasz Pakuła @ 2025-08-13 20:09 UTC (permalink / raw)
  To: jikos, bentiss; +Cc: oleg, linux-input
In-Reply-To: <20250813201005.17819-1-tomasz.pakula.oficjalny@gmail.com>

Abstracts away too little of the functionality and replaces a nice,
defined value with a magic bool. There's no actual need for it.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Oleg Makarenko <oleg@makarenk.ooo>
---
 drivers/hid/usbhid/hid-pidff.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index c6b4f61e535d..3cf844f7ad4a 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -605,16 +605,6 @@ static void pidff_set_device_control(struct pidff_device *pidff, int field)
 	hid_hw_wait(pidff->hid);
 }
 
-/*
- * Modify actuators state
- */
-static void pidff_set_actuators(struct pidff_device *pidff, bool enable)
-{
-	hid_dbg(pidff->hid, "%s actuators\n", enable ? "Enable" : "Disable");
-	pidff_set_device_control(pidff,
-		enable ? PID_ENABLE_ACTUATORS : PID_DISABLE_ACTUATORS);
-}
-
 /*
  * Reset the device, stop all effects, enable actuators
  */
@@ -626,7 +616,7 @@ static void pidff_reset(struct pidff_device *pidff)
 	pidff->effect_count = 0;
 
 	pidff_set_device_control(pidff, PID_STOP_ALL_EFFECTS);
-	pidff_set_actuators(pidff, 1);
+	pidff_set_device_control(pidff, PID_ENABLE_ACTUATORS);
 }
 
 /*
-- 
2.50.1


^ permalink raw reply related

* [PATCH v2 01/17] HID: pidff: Use direction fix only for conditional effects
From: Tomasz Pakuła @ 2025-08-13 20:09 UTC (permalink / raw)
  To: jikos, bentiss; +Cc: oleg, linux-input
In-Reply-To: <20250813201005.17819-1-tomasz.pakula.oficjalny@gmail.com>

The already fixed bug in SDL only affected conditional effects. This
should fix FFB in Forza Horizion 4/5 on Moza Devices as Forza Horizon
flips the constant force direction instead of using negative magnitude
values.

Changing the direction in the effect directly in pidff_upload_effect()
would affect it's value in further operations like comparing to the old
effect and/or just reading the effect values in the user application.

This, in turn, would lead to constant PID_SET_EFFECT spam as the effect
direction would constantly not match the value that's set by the
application.

This way, it's still transparent to any software/API.

Only affects conditional effects now so it's better for it to explicitly
state that in the name. If any HW ever needs fixed direction for other
effects, we'll add more quirks.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Oleg Makarenko <oleg@makarenk.ooo>
---
 drivers/hid/hid-universal-pidff.c | 20 ++++++++++----------
 drivers/hid/usbhid/hid-pidff.c    | 28 +++++++++++++++++++++++-----
 drivers/hid/usbhid/hid-pidff.h    |  2 +-
 3 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c
index 554a6559aeb7..70fce0f88e82 100644
--- a/drivers/hid/hid-universal-pidff.c
+++ b/drivers/hid/hid-universal-pidff.c
@@ -144,25 +144,25 @@ static int universal_pidff_input_configured(struct hid_device *hdev,
 
 static const struct hid_device_id universal_pidff_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_2),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_2),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_2),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_2),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_2),
-		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP),
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 614a20b62023..c6b4f61e535d 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -205,6 +205,14 @@ struct pidff_device {
 	u8 effect_count;
 };
 
+static int pidff_is_effect_conditional(struct ff_effect *effect)
+{
+	return effect->type == FF_SPRING  ||
+	       effect->type == FF_DAMPER  ||
+	       effect->type == FF_INERTIA ||
+	       effect->type == FF_FRICTION;
+}
+
 /*
  * Clamp value for a given field
  */
@@ -294,6 +302,20 @@ static void pidff_set_duration(struct pidff_usage *usage, u16 duration)
 	pidff_set_time(usage, duration);
 }
 
+static void pidff_set_effect_direction(struct pidff_device *pidff,
+				       struct ff_effect *effect)
+{
+	u16 direction = effect->direction;
+
+	/* Use fixed direction if needed */
+	if (pidff->quirks & HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION &&
+	    pidff_is_effect_conditional(effect))
+		direction = PIDFF_FIXED_WHEEL_DIRECTION;
+
+	pidff->effect_direction->value[0] =
+		pidff_rescale(direction, U16_MAX, pidff->effect_direction);
+}
+
 /*
  * Send envelope report to the device
  */
@@ -395,11 +417,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
 		pidff->set_effect[PID_GAIN].field->logical_maximum;
 	pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
 
-	/* Use fixed direction if needed */
-	pidff->effect_direction->value[0] = pidff_rescale(
-		pidff->quirks & HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION ?
-		PIDFF_FIXED_WHEEL_DIRECTION : effect->direction,
-		U16_MAX, pidff->effect_direction);
+	pidff_set_effect_direction(pidff, effect);
 
 	/* Omit setting delay field if it's missing */
 	if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY))
diff --git a/drivers/hid/usbhid/hid-pidff.h b/drivers/hid/usbhid/hid-pidff.h
index a53a8b436baa..f321f675e131 100644
--- a/drivers/hid/usbhid/hid-pidff.h
+++ b/drivers/hid/usbhid/hid-pidff.h
@@ -16,7 +16,7 @@
 #define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL	BIT(2)
 
 /* Use fixed 0x4000 direction during SET_EFFECT report upload */
-#define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION	BIT(3)
+#define HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION	BIT(3)
 
 /* Force all periodic effects to be uploaded as SINE */
 #define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY	BIT(4)
-- 
2.50.1


^ permalink raw reply related

* [PATCH v2 00/17] Further hid-pidff improvements and fixes
From: Tomasz Pakuła @ 2025-08-13 20:09 UTC (permalink / raw)
  To: jikos, bentiss; +Cc: oleg, linux-input

Another batch of improvements/fixes/updates to the hid-pidff driver. A lot of
code quality improvements with probably more to come as we better understand the
driver and strive to simplify it's inner workings. I think we're currently past
75% of touchups + Oleg is working on some compatibility changes for Simagic
support in a "pass-through" mode.

Direction fix only for conditional effects fixes FFB in Forza games on Moza.

I removed Anssi's email from the "welcome message" that appears on succesful
PID init to make sure people will look for LKML to send in bug reports.

Changes in v2:
- Added changelogs to commits changing debug messages

Tomasz Pakuła (17):
  HID: pidff: Use direction fix only for conditional effects
  HID: pidff: Remove unhelpful pidff_set_actuators helper
  HID: pidff: Remove unneeded debug
  HID: pidff: Use ARRAY_SIZE macro instead of sizeof
  HID: pidff: Treat PID_REQUIRED_REPORTS as count, not max
  HID: pidff: Better quirk assigment when searching for fields
  HID: pidff: Simplify HID field/usage searching logic
  HID: pidff: Add support for AXES_ENABLE field
  HID: pidff: Update debug messages
  HID: pidff: Rework pidff_upload_effect
  HID: pidff: Separate check for infinite duration
  HID: pidff: PERMISSIVE_CONTROL quirk autodetection
  HID: pidff: Remove Anssi's email address from info msg
  HID: pidff: Define all cardinal directions
  HID: pidff: clang-format pass
  HID: universal-pidff: clang-format pass
  HID: pidff: Reduce PID_EFFECT_OPERATION spam

 drivers/hid/hid-universal-pidff.c |  57 +--
 drivers/hid/usbhid/hid-pidff.c    | 711 +++++++++++++++++-------------
 drivers/hid/usbhid/hid-pidff.h    |   2 +-
 3 files changed, 439 insertions(+), 331 deletions(-)

-- 
2.50.1


^ permalink raw reply

* [PATCH 06/21] Input: remove unneeded 'fast_io' parameter in regmap_config
From: Wolfram Sang @ 2025-08-13 16:14 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Brown, Wolfram Sang, Dmitry Torokhov, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, linux-input,
	imx, linux-arm-kernel
In-Reply-To: <20250813161517.4746-1-wsa+renesas@sang-engineering.com>

When using MMIO with regmap, fast_io is implied. No need to set it
again.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
No dependencies, can be applied directly to the subsystem tree. Buildbot is
happy, too.

 drivers/input/touchscreen/fsl-imx25-tcq.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
index a32708652d10..ff270b3b8572 100644
--- a/drivers/input/touchscreen/fsl-imx25-tcq.c
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -39,7 +39,6 @@ struct mx25_tcq_priv {
 };
 
 static const struct regmap_config mx25_tcq_regconfig = {
-	.fast_io = true,
 	.max_register = 0x5c,
 	.reg_bits = 32,
 	.val_bits = 32,
-- 
2.47.2


^ permalink raw reply related

* [PATCH 00/21] treewide: remove unneeded 'fast_io' parameter in regmap_config
From: Wolfram Sang @ 2025-08-13 16:14 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Brown, Wolfram Sang, Adrian Hunter, Alexandre Belloni,
	Alexandre Torgue, Alim Akhtar, Andrea della Porta,
	Andreas Färber, Andrzej Hajda, Andy Shevchenko, Andy Yan,
	Avi Fishman, Bartosz Golaszewski, Benjamin Fair, Bjorn Andersson,
	Chen-Yu Tsai, Daniel Lezcano, David Airlie, David Lechner,
	Dmitry Torokhov, Drew Fustini, dri-devel, Fabio Estevam,
	Fabrice Gasnier, Fu Wei, Guo Ren, Hans Verkuil,
	Heiko Stübner, imx, Iwona Winiarska, Jaroslav Kysela,
	Jassi Brar, Jernej Skrabec, Jerome Brunet, Jonas Karlman,
	Jonathan Cameron, Kevin Hilman, Kishon Vijay Abraham I,
	Konrad Dybcio, Krzysztof Kozlowski, Laurent Pinchart, Lee Jones,
	Liam Girdwood, Linus Walleij, linux-actions, linux-amlogic,
	linux-arm-kernel, linux-arm-msm, linux-clk, linux-gpio, linux-iio,
	linux-input, linux-media, linux-mmc, linux-phy, linux-pm,
	linuxppc-dev, linux-pwm, linux-riscv, linux-rockchip, linux-rtc,
	linux-samsung-soc, linux-sound, linux-spi, linux-stm32,
	linux-sunxi, Liu Ying, Lukasz Luba, Maarten Lankhorst,
	Manivannan Sadhasivam, Martin Blumenstingl, Mauro Carvalho Chehab,
	Maxime Coquelin, Maxime Ripard, Michael Turquette, Miquel Raynal,
	Nancy Yuen, Neil Armstrong, Nicolin Chen, Nuno Sá, openbmc,
	Patrick Venture, Paul Walmsley, Pengutronix Kernel Team,
	Philipp Zabel, Piotr Wojtaszczyk, Rafael J. Wysocki, Robert Foss,
	Samuel Holland, Samuel Holland, Sandy Huang, Sascha Hauer,
	Shawn Guo, Shengjiu Wang, Simona Vetter, Stephen Boyd,
	Takashi Iwai, Tali Perry, Thomas Zimmermann, Tomer Maimon,
	Ulf Hansson, Uwe Kleine-König, Vasily Khoruzhick, Vinod Koul,
	Vladimir Zapolskiy, Xiubo Li, Yangtao Li, Zhang Rui

While working on a driver using regmap with MMIO, I wondered if I need
to set 'fast_io' in the config. Turned out I don't need to, so I added
documentation for it with commit ffc72771ff6e ("regmap: Annotate that
MMIO implies fast IO").

This series fixes the existing users in the tree which needlessly set
the flag. They have been found using this coccinelle script:

===

@ match @
expression dev, clk, regs;
identifier config;
@@

(
	regmap_init_mmio(dev, regs, &config)
|
	devm_regmap_init_mmio(dev, regs, &config)
|
	regmap_init_mmio_clk(dev, clk, regs, &config)
|
	devm_regmap_init_mmio_clk(dev, clk, regs, &config)
)

@ fix depends on match @
identifier match.config;
@@

	struct regmap_config config = {
-	.fast_io = true,
	};

===

It misses occasions where 'config' is an expression and not an
identifier. These are rare, though, I can fix them manually later. The
advantage of this approach is that it produces no false positives to the
best of my knowledge.

Please apply individually per subsystem. There are no dependencies and
buildbot is happy. Patches are based on 6.17-rc1

Happy hacking,

   Wolfram


Wolfram Sang (21):
  bus: remove unneeded 'fast_io' parameter in regmap_config
  clk: remove unneeded 'fast_io' parameter in regmap_config
  gpio: remove unneeded 'fast_io' parameter in regmap_config
  drm: remove unneeded 'fast_io' parameter in regmap_config
  iio: remove unneeded 'fast_io' parameter in regmap_config
  Input: remove unneeded 'fast_io' parameter in regmap_config
  mailbox: remove unneeded 'fast_io' parameter in regmap_config
  media: remove unneeded 'fast_io' parameter in regmap_config
  mfd: remove unneeded 'fast_io' parameter in regmap_config
  mmc: remove unneeded 'fast_io' parameter in regmap_config
  peci: remove unneeded 'fast_io' parameter in regmap_config
  phy: remove unneeded 'fast_io' parameter in regmap_config
  pinctrl: remove unneeded 'fast_io' parameter in regmap_config
  pmdomain: remove unneeded 'fast_io' parameter in regmap_config
  regulator: remove unneeded 'fast_io' parameter in regmap_config
  reset: remove unneeded 'fast_io' parameter in regmap_config
  rtc: remove unneeded 'fast_io' parameter in regmap_config
  soc: remove unneeded 'fast_io' parameter in regmap_config
  spi: remove unneeded 'fast_io' parameter in regmap_config
  thermal: remove unneeded 'fast_io' parameter in regmap_config
  ASoC: remove unneeded 'fast_io' parameter in regmap_config

 drivers/bus/bt1-apb.c                             | 1 -
 drivers/clk/actions/owl-common.c                  | 1 -
 drivers/clk/clk-axm5516.c                         | 1 -
 drivers/clk/nxp/clk-lpc32xx.c                     | 1 -
 drivers/clk/qcom/a53-pll.c                        | 1 -
 drivers/clk/qcom/a7-pll.c                         | 1 -
 drivers/clk/qcom/apss-ipq-pll.c                   | 1 -
 drivers/clk/qcom/clk-cbf-8996.c                   | 1 -
 drivers/clk/qcom/clk-cpu-8996.c                   | 1 -
 drivers/clk/qcom/hfpll.c                          | 1 -
 drivers/clk/qcom/ipq-cmn-pll.c                    | 1 -
 drivers/clk/thead/clk-th1520-ap.c                 | 1 -
 drivers/gpio/gpio-mvebu.c                         | 1 -
 drivers/gpio/gpio-sifive.c                        | 1 -
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c    | 1 -
 drivers/gpu/drm/imx/dc/dc-cf.c                    | 1 -
 drivers/gpu/drm/imx/dc/dc-de.c                    | 1 -
 drivers/gpu/drm/imx/dc/dc-ed.c                    | 2 --
 drivers/gpu/drm/imx/dc/dc-fg.c                    | 1 -
 drivers/gpu/drm/imx/dc/dc-fl.c                    | 1 -
 drivers/gpu/drm/imx/dc/dc-fw.c                    | 2 --
 drivers/gpu/drm/imx/dc/dc-ic.c                    | 1 -
 drivers/gpu/drm/imx/dc/dc-lb.c                    | 2 --
 drivers/gpu/drm/imx/dc/dc-tc.c                    | 1 -
 drivers/gpu/drm/imx/ipuv3/imx-tve.c               | 2 --
 drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c  | 1 -
 drivers/iio/adc/sun4i-gpadc-iio.c                 | 1 -
 drivers/input/touchscreen/fsl-imx25-tcq.c         | 1 -
 drivers/mailbox/qcom-apcs-ipc-mailbox.c           | 1 -
 drivers/media/cec/platform/stm32/stm32-cec.c      | 1 -
 drivers/mfd/exynos-lpass.c                        | 1 -
 drivers/mfd/fsl-imx25-tsadc.c                     | 1 -
 drivers/mfd/stm32-lptimer.c                       | 1 -
 drivers/mfd/sun4i-gpadc.c                         | 1 -
 drivers/mmc/host/sdhci_am654.c                    | 1 -
 drivers/peci/controller/peci-npcm.c               | 1 -
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 1 -
 drivers/phy/rockchip/phy-rockchip-usbdp.c         | 1 -
 drivers/phy/ti/phy-am654-serdes.c                 | 1 -
 drivers/phy/ti/phy-j721e-wiz.c                    | 1 -
 drivers/pinctrl/pinctrl-rp1.c                     | 1 -
 drivers/pmdomain/imx/gpc.c                        | 1 -
 drivers/regulator/qcom-refgen-regulator.c         | 1 -
 drivers/reset/reset-intel-gw.c                    | 1 -
 drivers/reset/reset-qcom-pdc.c                    | 1 -
 drivers/reset/reset-th1520.c                      | 1 -
 drivers/rtc/rtc-meson.c                           | 1 -
 drivers/soc/qcom/llcc-qcom.c                      | 1 -
 drivers/soc/qcom/ramp_controller.c                | 1 -
 drivers/spi/spi-altera-platform.c                 | 1 -
 drivers/thermal/armada_thermal.c                  | 1 -
 drivers/thermal/sun8i_thermal.c                   | 1 -
 sound/soc/fsl/fsl_sai.c                           | 1 -
 53 files changed, 57 deletions(-)

-- 
2.47.2


^ permalink raw reply

* Re: [PATCH v2 11/11] HID: multitouch: add haptic multitouch support
From: Jonathan Denose @ 2025-08-13 15:52 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Jiri Kosina, Dmitry Torokhov, Jonathan Corbet, Henrik Rydberg,
	linux-input, linux-kernel, linux-doc, Angela Czubak,
	Sean O'Brien
In-Reply-To: <kmjgxgsdh26okjvhbezl7uskedv3ybio2v6qk3zynlswkxaw4e@dhb43oyrxp44>

On Wed, Aug 13, 2025 at 4:22 AM Benjamin Tissoires <bentiss@kernel.org> wrote:
>
> On Aug 04 2025, Jonathan Denose wrote:
> > 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.
>
> Why creating a new option? It seems it'll add unwanted work from
> distributions when we should have something that "just works" no?
>
> It makes sense to depend on FF, but adding a new option is probably
> useless IMO.
>
> >
> > 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
>
> There is something wrong with your ifdef usages:
> - here, you define the functions below conditionally to
>         CONFIG_MULTITOUCH_HAPTIC, which is fine
> - but in hid-multitouch, you also check for CONFIG_MULTITOUCH_HAPTIC
>         before calling the same set of functions.
>
> Either only define the haptic functions when CONFIG_MULTITOUCH_HAPTIC is
> set, and in multitouch check for that define, or define it conditionally
> and remove the checks in hid-multitouch (but probably add a comment).
> >  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 */
> > -
>
> unrelated change (line removed).
>
> >       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);
>
> Please make use of the devm api, you are leaking the allocated memory in
> the regular case (AFAICT).
>
> > +     if (!td->haptic)
> > +             return -ENOMEM;
>
> One extra blank line wouldn't hurt here :)
>
> > +     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
> >
>
> Cheers,
> Benjamin
I'll make the changes and send out a new version.

Thanks for your review!
-- 
Jonathan

^ permalink raw reply

* [PATCH v5] platform/x86: Add WMI driver for Redmibook keyboard.
From: Gladyshev Ilya @ 2025-08-13 15:31 UTC (permalink / raw)
  To: foxido
  Cc: w_armin, linux-input, nikita.nikita.krasnov, Armin Wolf,
	Hans de Goede, Ilpo Järvinen, linux-kernel,
	platform-driver-x86

This driver implements support for various Fn keys (like Cut) and Xiaomi
specific AI button.

Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Gladyshev Ilya <foxido@foxido.dev>
---
Changes since v4:
- Cosmetic fixes from Ilpo's review (posted on v3)

Link to v4: https://lore.kernel.org/platform-driver-x86/20250801120321.9742-1-foxido@foxido.dev
---
 MAINTAINERS                      |   6 ++
 drivers/platform/x86/Kconfig     |  12 +++
 drivers/platform/x86/Makefile    |   1 +
 drivers/platform/x86/redmi-wmi.c | 128 +++++++++++++++++++++++++++++++
 4 files changed, 147 insertions(+)
 create mode 100644 drivers/platform/x86/redmi-wmi.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c0b444e5fd5a..eb25fb10e751 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20965,6 +20965,12 @@ S:	Maintained
 T:	git https://github.com/pkshih/rtw.git
 F:	drivers/net/wireless/realtek/rtw89/
 
+REDMIBOOK WMI DRIVERS
+M:	Gladyshev Ilya <foxido@foxido.dev>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/redmi-wmi.c
+
 REDPINE WIRELESS DRIVER
 L:	linux-wireless@vger.kernel.org
 S:	Orphan
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index e5cbd58a99f3..9f98a7042e43 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -109,6 +109,18 @@ config XIAOMI_WMI
 	  To compile this driver as a module, choose M here: the module will
 	  be called xiaomi-wmi.
 
+config REDMI_WMI
+	tristate "Redmibook WMI key driver"
+	depends on ACPI_WMI
+	depends on INPUT
+	select INPUT_SPARSEKMAP
+	help
+	  Say Y here if you want support for WMI-based hotkey events on
+	  Xiaomi Redmibook devices.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called redmi-wmi.
+
 config GIGABYTE_WMI
 	tristate "Gigabyte WMI temperature driver"
 	depends on ACPI_WMI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index bea87a85ae75..406dd0807ba7 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_HUAWEI_WMI)		+= huawei-wmi.o
 obj-$(CONFIG_MXM_WMI)			+= mxm-wmi.o
 obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT)	+= nvidia-wmi-ec-backlight.o
 obj-$(CONFIG_XIAOMI_WMI)		+= xiaomi-wmi.o
+obj-$(CONFIG_REDMI_WMI)			+= redmi-wmi.o
 obj-$(CONFIG_GIGABYTE_WMI)		+= gigabyte-wmi.o
 
 # Acer
diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c
new file mode 100644
index 000000000000..104c4953d67d
--- /dev/null
+++ b/drivers/platform/x86/redmi-wmi.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/* WMI driver for Xiaomi Redmibooks */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/unaligned.h>
+#include <linux/wmi.h>
+
+#include <uapi/linux/input-event-codes.h>
+
+#define WMI_REDMIBOOK_KEYBOARD_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF"
+
+#define AI_KEY_VALUE_MASK 0x00000100
+
+static const struct key_entry redmi_wmi_keymap[] = {
+	{KE_KEY, 0x00000201,	{KEY_SELECTIVE_SCREENSHOT}},
+	{KE_KEY, 0x00000301,	{KEY_ALL_APPLICATIONS}},
+	{KE_KEY, 0x00001b01,	{KEY_SETUP}},
+
+	/* AI button has code for each position */
+	{KE_KEY, 0x00011801,	{KEY_ASSISTANT}},
+	{KE_KEY, 0x00011901,	{KEY_ASSISTANT}},
+
+	/* Keyboard backlight */
+	{KE_IGNORE, 0x00000501, {}},
+	{KE_IGNORE, 0x00800501, {}},
+	{KE_IGNORE, 0x00050501, {}},
+	{KE_IGNORE, 0x000a0501, {}},
+
+	{KE_END}
+};
+
+struct redmi_wmi {
+	struct input_dev *input_dev;
+	/* Protects the key event sequence */
+	struct mutex key_lock;
+};
+
+static int redmi_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+	struct redmi_wmi *data;
+	int err;
+
+	/* Init dev */
+	data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	dev_set_drvdata(&wdev->dev, data);
+
+	err = devm_mutex_init(&wdev->dev, &data->key_lock);
+	if (err)
+		return err;
+
+	data->input_dev = devm_input_allocate_device(&wdev->dev);
+	if (!data->input_dev)
+		return -ENOMEM;
+
+	data->input_dev->name = "Redmibook WMI keys";
+	data->input_dev->phys = "wmi/input0";
+
+	err = sparse_keymap_setup(data->input_dev, redmi_wmi_keymap, NULL);
+	if (err)
+		return err;
+
+	return input_register_device(data->input_dev);
+}
+
+static void redmi_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)
+{
+	struct redmi_wmi *data = dev_get_drvdata(&wdev->dev);
+	bool autorelease = true;
+	u32 payload;
+	int value = 1;
+
+	if (obj->type != ACPI_TYPE_BUFFER) {
+		dev_err(&wdev->dev, "Bad response type %u\n", obj->type);
+		return;
+	}
+
+	if (obj->buffer.length < 32) {
+		dev_err(&wdev->dev, "Invalid buffer length %u\n", obj->buffer.length);
+		return;
+	}
+
+	payload = get_unaligned_le32(obj->buffer.pointer);
+	struct key_entry *entry = sparse_keymap_entry_from_scancode(data->input_dev, payload);
+
+	if (!entry) {
+		dev_dbg(&wdev->dev, "Unknown WMI event with payload %u", payload);
+		return;
+	}
+
+	/* AI key quirk */
+	if (entry->keycode == KEY_ASSISTANT) {
+		value = !(payload & AI_KEY_VALUE_MASK);
+		autorelease = false;
+	}
+
+	guard(mutex)(&data->key_lock);
+	sparse_keymap_report_entry(data->input_dev, entry, value, autorelease);
+}
+
+static const struct wmi_device_id redmi_wmi_id_table[] = {
+	{ WMI_REDMIBOOK_KEYBOARD_EVENT_GUID, NULL },
+	{ }
+};
+
+static struct wmi_driver redmi_wmi_driver = {
+	.driver = {
+		.name = "redmi-wmi",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.id_table = redmi_wmi_id_table,
+	.probe = redmi_wmi_probe,
+	.notify = redmi_wmi_notify,
+	.no_singleton = true,
+};
+module_wmi_driver(redmi_wmi_driver);
+
+MODULE_DEVICE_TABLE(wmi, redmi_wmi_id_table);
+MODULE_AUTHOR("Gladyshev Ilya <foxido@foxido.dev>");
+MODULE_DESCRIPTION("Redmibook WMI driver");
+MODULE_LICENSE("GPL");
-- 
2.50.0


^ permalink raw reply related

* [PATCH] Input: gpio-keys - do not print gpio number if using gpiod
From: Andrew Davis @ 2025-08-13 15:10 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Andrew Davis

The value in button->gpio is not valid when in this branch which is for
the case of gpiod. Do not print this out as it will always be 0 here.

While here, there is no reason to assign irq to error, use irq directly.
Lastly, dev_err_probe() returns the given error value, so we can return
directly the result of dev_err_probe() making this a single line.

Signed-off-by: Andrew Davis <afd@ti.com>
---
 drivers/input/keyboard/gpio_keys.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index f9db86da0818b..05f8ccdfba920 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -580,13 +580,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 			bdata->irq = button->irq;
 		} else {
 			irq = gpiod_to_irq(bdata->gpiod);
-			if (irq < 0) {
-				error = irq;
-				dev_err_probe(dev, error,
-					      "Unable to get irq number for GPIO %d\n",
-					      button->gpio);
-				return error;
-			}
+			if (irq < 0)
+				return dev_err_probe(dev, irq, "Unable to get irq from GPIO\n");
 			bdata->irq = irq;
 		}
 
-- 
2.39.2


^ permalink raw reply related

* Re: [syzbot] [input?] [usb?] [io-uring?] INFO: task hung in io_wq_put_and_exit (5)
From: Jens Axboe @ 2025-08-13 14:32 UTC (permalink / raw)
  To: syzbot
  Cc: anna-maria, asml.silence, frederic, io-uring, linux-input,
	linux-kernel, linux-usb, syzkaller-bugs, tglx
In-Reply-To: <6880f54c.050a0220.248954.0000.GAE@google.com>

On Wed, Jul 23, 2025 at 8:44?AM syzbot <syzbot+e328767eafd849df0a78@syzkaller.appspotmail.com> wrote:
>
> Hello,
>
> syzbot found the following issue on:
>
> HEAD commit:    bf61759db409 Merge tag 'sched_ext-for-6.16-rc6-fixes' of g..
> git tree:       upstream
> console+strace: https://syzkaller.appspot.com/x/log.txt?x=12b877d4580000
> kernel config:  https://syzkaller.appspot.com/x/.config?x=415e83411fefd73f
> dashboard link: https://syzkaller.appspot.com/bug?extid=e328767eafd849df0a78
> compiler:       gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
> syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=110b938c580000
> C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=1622a38c580000
>
> Downloadable assets:
> disk image: https://storage.googleapis.com/syzbot-assets/22c5f1286a72/disk-bf61759d.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/cc79af4d966c/vmlinux-bf61759d.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/b2e6d621f424/bzImage-bf61759d.xz
>
> The issue was bisected to:
>
> commit e5598d6ae62626d261b046a2f19347c38681ff51
> Author: Pavel Begunkov <asml.silence@gmail.com>
> Date:   Thu Aug 24 22:53:31 2023 +0000
>
>     io_uring: compact SQ/CQ heads/tails
>
> bisection log:  https://syzkaller.appspot.com/x/bisect.txt?x=12c92b82580000
> final oops:     https://syzkaller.appspot.com/x/report.txt?x=11c92b82580000
> console output: https://syzkaller.appspot.com/x/log.txt?x=16c92b82580000
>
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+e328767eafd849df0a78@syzkaller.appspotmail.com
> Fixes: e5598d6ae626 ("io_uring: compact SQ/CQ heads/tails")
>
> INFO: task syz-executor971:5849 blocked for more than 143 seconds.
>       Not tainted 6.16.0-rc6-syzkaller-00279-gbf61759db409 #0
>       Blocked by coredump.
> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> task:syz-executor971 state:D stack:26488 pid:5849  tgid:5849  ppid:5844   task_flags:0x400148 flags:0x00024002
> Call Trace:
>  <TASK>
>  context_switch kernel/sched/core.c:5397 [inline]
>  __schedule+0x116a/0x5de0 kernel/sched/core.c:6786
>  __schedule_loop kernel/sched/core.c:6864 [inline]
>  schedule+0xe7/0x3a0 kernel/sched/core.c:6879
>  schedule_timeout+0x257/0x290 kernel/time/sleep_timeout.c:75
>  do_wait_for_common kernel/sched/completion.c:95 [inline]
>  __wait_for_common+0x2ff/0x4e0 kernel/sched/completion.c:116
>  io_wq_exit_workers io_uring/io-wq.c:1319 [inline]
>  io_wq_put_and_exit+0x271/0x8d0 io_uring/io-wq.c:1347
>  io_uring_clean_tctx+0x10d/0x190 io_uring/tctx.c:203
>  io_uring_cancel_generic+0x69c/0x9a0 io_uring/io_uring.c:3212
>  io_uring_files_cancel include/linux/io_uring.h:19 [inline]
>  do_exit+0x2ce/0x2bd0 kernel/exit.c:911
>  do_group_exit+0xd3/0x2a0 kernel/exit.c:1105
>  __do_sys_exit_group kernel/exit.c:1116 [inline]
>  __se_sys_exit_group kernel/exit.c:1114 [inline]
>  __x64_sys_exit_group+0x3e/0x50 kernel/exit.c:1114
>  x64_sys_call+0x1530/0x1730 arch/x86/include/generated/asm/syscalls_64.h:232
>  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
>  do_syscall_64+0xcd/0x4c0 arch/x86/entry/syscall_64.c:94
>  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7f141ec08e39
> RSP: 002b:00007ffcd1b0b6e8 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7
> RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f141ec08e39
> RDX: 000000000000003c RSI: 00000000000000e7 RDI: 0000000000000000
> RBP: 00007f141ec843b0 R08: ffffffffffffffb8 R09: 0000000000000000
> R10: 000000000000000e R11: 0000000000000246 R12: 00007f141ec843b0
> R13: 0000000000000000 R14: 00007f141ec880c0 R15: 00007f141ebd7020
>  </TASK>
> INFO: task syz-executor971:5850 blocked for more than 143 seconds.
>       Not tainted 6.16.0-rc6-syzkaller-00279-gbf61759db409 #0
>       Blocked by coredump.

I took a look at this one, and it's simply waiting on nullb0 timeouts
that it's flooded the queue with. Since it's flooding the nullb0 device
which has been configured to time out IO, we'll have a lot of io-wq
workers that are sitting blocked waiting on making progress. That can
obviously take a long time, which then in turn triggers the io_uring
cancelation/exit warning because of that. It all seems to be working as
it should.

I don't think there's a bug here because of that, the only thing that's
"stuck" is because each timeout takes 30s to trigger and there are tons
of them.

#syz invalid

-- 
Jens Axboe


^ permalink raw reply

* [PATCH v2 2/2] HID: Make elan touch controllers power on after panel is enabled
From: Pin-yen Lin @ 2025-08-13 12:51 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jiri Kosina,
	Benjamin Tissoires
  Cc: dri-devel, Douglas Anderson, linux-kernel, linux-input,
	Chen-Yu Tsai, Pin-yen Lin
In-Reply-To: <20250813125132.1319482-1-treapking@chromium.org>

Introduce a new HID quirk to indicate that this device has to be enabled
after the panel's backlight is enabled, and update the driver data for
the elan devices to enable this quirk. This cannot be a I2C HID quirk
because the kernel needs to acknowledge this before powering up the
device and read the VID/PID. When this quirk is enabled, register
.panel_enabled()/.panel_disabling() instead for the panel follower.

Also rename the *panel_prepare* functions into *panel_follower* because
they could be called in other situations now.

Signed-off-by: Pin-yen Lin <treapking@chromium.org>

---

Changes in v2:
- Rename *panel_prepare* functions to *panel_follower*
- Replace after_panel_enabled flag with enabled/disabling callbacks

 drivers/hid/i2c-hid/i2c-hid-core.c    | 46 ++++++++++++++++-----------
 drivers/hid/i2c-hid/i2c-hid-of-elan.c | 11 ++++++-
 include/linux/hid.h                   |  2 ++
 3 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index d3912e3f2f13a..99ce6386176c6 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -112,9 +112,9 @@ struct i2c_hid {
 
 	struct i2chid_ops	*ops;
 	struct drm_panel_follower panel_follower;
-	struct work_struct	panel_follower_prepare_work;
+	struct work_struct	panel_follower_work;
 	bool			is_panel_follower;
-	bool			prepare_work_finished;
+	bool			panel_follower_work_finished;
 };
 
 static const struct i2c_hid_quirks {
@@ -1110,10 +1110,10 @@ static int i2c_hid_core_probe_panel_follower(struct i2c_hid *ihid)
 	return ret;
 }
 
-static void ihid_core_panel_prepare_work(struct work_struct *work)
+static void ihid_core_panel_follower_work(struct work_struct *work)
 {
 	struct i2c_hid *ihid = container_of(work, struct i2c_hid,
-					    panel_follower_prepare_work);
+					    panel_follower_work);
 	struct hid_device *hid = ihid->hid;
 	int ret;
 
@@ -1130,7 +1130,7 @@ static void ihid_core_panel_prepare_work(struct work_struct *work)
 	if (ret)
 		dev_warn(&ihid->client->dev, "Power on failed: %d\n", ret);
 	else
-		WRITE_ONCE(ihid->prepare_work_finished, true);
+		WRITE_ONCE(ihid->panel_follower_work_finished, true);
 
 	/*
 	 * The work APIs provide a number of memory ordering guarantees
@@ -1139,12 +1139,12 @@ static void ihid_core_panel_prepare_work(struct work_struct *work)
 	 * guarantee that a write that happened in the work is visible after
 	 * cancel_work_sync(). We'll add a write memory barrier here to match
 	 * with i2c_hid_core_panel_unpreparing() to ensure that our write to
-	 * prepare_work_finished is visible there.
+	 * panel_follower_work_finished is visible there.
 	 */
 	smp_wmb();
 }
 
-static int i2c_hid_core_panel_prepared(struct drm_panel_follower *follower)
+static int i2c_hid_core_panel_follower_resume(struct drm_panel_follower *follower)
 {
 	struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower);
 
@@ -1152,29 +1152,36 @@ static int i2c_hid_core_panel_prepared(struct drm_panel_follower *follower)
 	 * Powering on a touchscreen can be a slow process. Queue the work to
 	 * the system workqueue so we don't block the panel's power up.
 	 */
-	WRITE_ONCE(ihid->prepare_work_finished, false);
-	schedule_work(&ihid->panel_follower_prepare_work);
+	WRITE_ONCE(ihid->panel_follower_work_finished, false);
+	schedule_work(&ihid->panel_follower_work);
 
 	return 0;
 }
 
-static int i2c_hid_core_panel_unpreparing(struct drm_panel_follower *follower)
+static int i2c_hid_core_panel_follower_suspend(struct drm_panel_follower *follower)
 {
 	struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower);
 
-	cancel_work_sync(&ihid->panel_follower_prepare_work);
+	cancel_work_sync(&ihid->panel_follower_work);
 
-	/* Match with ihid_core_panel_prepare_work() */
+	/* Match with ihid_core_panel_follower_work() */
 	smp_rmb();
-	if (!READ_ONCE(ihid->prepare_work_finished))
+	if (!READ_ONCE(ihid->panel_follower_work_finished))
 		return 0;
 
 	return i2c_hid_core_suspend(ihid, true);
 }
 
-static const struct drm_panel_follower_funcs i2c_hid_core_panel_follower_funcs = {
-	.panel_prepared = i2c_hid_core_panel_prepared,
-	.panel_unpreparing = i2c_hid_core_panel_unpreparing,
+static const struct drm_panel_follower_funcs
+				i2c_hid_core_panel_follower_prepare_funcs = {
+	.panel_prepared = i2c_hid_core_panel_follower_resume,
+	.panel_unpreparing = i2c_hid_core_panel_follower_suspend,
+};
+
+static const struct drm_panel_follower_funcs
+				i2c_hid_core_panel_follower_enable_funcs = {
+	.panel_enabled = i2c_hid_core_panel_follower_resume,
+	.panel_disabling = i2c_hid_core_panel_follower_suspend,
 };
 
 static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
@@ -1182,7 +1189,10 @@ static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
 	struct device *dev = &ihid->client->dev;
 	int ret;
 
-	ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_funcs;
+	if (ihid->hid->initial_quirks | HID_QUIRK_POWER_ON_AFTER_BACKLIGHT)
+		ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_enable_funcs;
+	else
+		ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_prepare_funcs;
 
 	/*
 	 * If we're not in control of our own power up/power down then we can't
@@ -1237,7 +1247,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
 	init_waitqueue_head(&ihid->wait);
 	mutex_init(&ihid->cmd_lock);
 	mutex_init(&ihid->reset_lock);
-	INIT_WORK(&ihid->panel_follower_prepare_work, ihid_core_panel_prepare_work);
+	INIT_WORK(&ihid->panel_follower_work, ihid_core_panel_follower_work);
 
 	/* we need to allocate the command buffer without knowing the maximum
 	 * size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the
diff --git a/drivers/hid/i2c-hid/i2c-hid-of-elan.c b/drivers/hid/i2c-hid/i2c-hid-of-elan.c
index 3fcff6daa0d3a..0215f217f6d86 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of-elan.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of-elan.c
@@ -8,6 +8,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
+#include <linux/hid.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -23,6 +24,7 @@ struct elan_i2c_hid_chip_data {
 	unsigned int post_power_delay_ms;
 	u16 hid_descriptor_address;
 	const char *main_supply_name;
+	bool power_after_backlight;
 };
 
 struct i2c_hid_of_elan {
@@ -97,6 +99,7 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client)
 {
 	struct i2c_hid_of_elan *ihid_elan;
 	int ret;
+	u32 quirks = 0;
 
 	ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL);
 	if (!ihid_elan)
@@ -131,8 +134,12 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client)
 		}
 	}
 
+	if (ihid_elan->chip_data->power_after_backlight)
+		quirks = HID_QUIRK_POWER_ON_AFTER_BACKLIGHT;
+
 	ret = i2c_hid_core_probe(client, &ihid_elan->ops,
-				 ihid_elan->chip_data->hid_descriptor_address, 0);
+				 ihid_elan->chip_data->hid_descriptor_address,
+				 quirks);
 	if (ret)
 		goto err_deassert_reset;
 
@@ -150,6 +157,7 @@ static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = {
 	.post_gpio_reset_on_delay_ms = 300,
 	.hid_descriptor_address = 0x0001,
 	.main_supply_name = "vcc33",
+	.power_after_backlight = true,
 };
 
 static const struct elan_i2c_hid_chip_data elan_ekth6a12nay_chip_data = {
@@ -157,6 +165,7 @@ static const struct elan_i2c_hid_chip_data elan_ekth6a12nay_chip_data = {
 	.post_gpio_reset_on_delay_ms = 300,
 	.hid_descriptor_address = 0x0001,
 	.main_supply_name = "vcc33",
+	.power_after_backlight = true,
 };
 
 static const struct elan_i2c_hid_chip_data ilitek_ili9882t_chip_data = {
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 2cc4f1e4ea963..c32425b5d0119 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -364,6 +364,7 @@ struct hid_item {
  * | @HID_QUIRK_HAVE_SPECIAL_DRIVER:
  * | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
  * | @HID_QUIRK_IGNORE_SPECIAL_DRIVER
+ * | @HID_QUIRK_POWER_ON_AFTER_BACKLIGHT
  * | @HID_QUIRK_FULLSPEED_INTERVAL:
  * | @HID_QUIRK_NO_INIT_REPORTS:
  * | @HID_QUIRK_NO_IGNORE:
@@ -391,6 +392,7 @@ struct hid_item {
 #define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE	BIT(20)
 #define HID_QUIRK_NOINVERT			BIT(21)
 #define HID_QUIRK_IGNORE_SPECIAL_DRIVER		BIT(22)
+#define HID_QUIRK_POWER_ON_AFTER_BACKLIGHT	BIT(23)
 #define HID_QUIRK_FULLSPEED_INTERVAL		BIT(28)
 #define HID_QUIRK_NO_INIT_REPORTS		BIT(29)
 #define HID_QUIRK_NO_IGNORE			BIT(30)
-- 
2.51.0.rc0.205.g4a044479a3-goog


^ permalink raw reply related

* [PATCH v2 1/2] drm/panel: Allow powering on panel follower after panel is enabled
From: Pin-yen Lin @ 2025-08-13 12:51 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jiri Kosina,
	Benjamin Tissoires
  Cc: dri-devel, Douglas Anderson, linux-kernel, linux-input,
	Chen-Yu Tsai, Pin-yen Lin

Some touch controllers have to be powered on after the panel's backlight
is enabled. To support these controllers, introduce .panel_enabled() and
.panel_disabling() to panel_follower_funcs and use them to power on the
device after the panel and its backlight are enabled.

Signed-off-by: Pin-yen Lin <treapking@chromium.org>

---

Changes in v2:
- Replace after_panel_enabled flag with enabled/disabling callbacks

 drivers/gpu/drm/drm_panel.c | 57 ++++++++++++++++++++++++++++++++++---
 include/drm/drm_panel.h     | 14 +++++++++
 2 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index c8bb28dccdc1b..e3682c22c4dd2 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -134,6 +134,9 @@ void drm_panel_prepare(struct drm_panel *panel)
 	panel->prepared = true;
 
 	list_for_each_entry(follower, &panel->followers, list) {
+		if (!follower->funcs->panel_prepared)
+			continue;
+
 		ret = follower->funcs->panel_prepared(follower);
 		if (ret < 0)
 			dev_info(panel->dev, "%ps failed: %d\n",
@@ -179,6 +182,9 @@ void drm_panel_unprepare(struct drm_panel *panel)
 	mutex_lock(&panel->follower_lock);
 
 	list_for_each_entry(follower, &panel->followers, list) {
+		if (!follower->funcs->panel_unpreparing)
+			continue;
+
 		ret = follower->funcs->panel_unpreparing(follower);
 		if (ret < 0)
 			dev_info(panel->dev, "%ps failed: %d\n",
@@ -209,6 +215,7 @@ EXPORT_SYMBOL(drm_panel_unprepare);
  */
 void drm_panel_enable(struct drm_panel *panel)
 {
+	struct drm_panel_follower *follower;
 	int ret;
 
 	if (!panel)
@@ -219,10 +226,12 @@ void drm_panel_enable(struct drm_panel *panel)
 		return;
 	}
 
+	mutex_lock(&panel->follower_lock);
+
 	if (panel->funcs && panel->funcs->enable) {
 		ret = panel->funcs->enable(panel);
 		if (ret < 0)
-			return;
+			goto exit;
 	}
 	panel->enabled = true;
 
@@ -230,6 +239,18 @@ void drm_panel_enable(struct drm_panel *panel)
 	if (ret < 0)
 		DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n",
 			     ret);
+
+	list_for_each_entry(follower, &panel->followers, list) {
+		if (!follower->funcs->panel_enabled)
+			continue;
+
+		ret = follower->funcs->panel_enabled(follower);
+		if (ret < 0)
+			dev_info(panel->dev, "%ps failed: %d\n",
+				 follower->funcs->panel_enabled, ret);
+	}
+exit:
+	mutex_unlock(&panel->follower_lock);
 }
 EXPORT_SYMBOL(drm_panel_enable);
 
@@ -243,6 +264,7 @@ EXPORT_SYMBOL(drm_panel_enable);
  */
 void drm_panel_disable(struct drm_panel *panel)
 {
+	struct drm_panel_follower *follower;
 	int ret;
 
 	if (!panel)
@@ -262,6 +284,18 @@ void drm_panel_disable(struct drm_panel *panel)
 		return;
 	}
 
+	mutex_lock(&panel->follower_lock);
+
+	list_for_each_entry(follower, &panel->followers, list) {
+		if (!follower->funcs->panel_disabling)
+			continue;
+
+		ret = follower->funcs->panel_disabling(follower);
+		if (ret < 0)
+			dev_info(panel->dev, "%ps failed: %d\n",
+				 follower->funcs->panel_disabling, ret);
+	}
+
 	ret = backlight_disable(panel->backlight);
 	if (ret < 0)
 		DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
@@ -270,9 +304,12 @@ void drm_panel_disable(struct drm_panel *panel)
 	if (panel->funcs && panel->funcs->disable) {
 		ret = panel->funcs->disable(panel);
 		if (ret < 0)
-			return;
+			goto exit;
 	}
 	panel->enabled = false;
+
+exit:
+	mutex_unlock(&panel->follower_lock);
 }
 EXPORT_SYMBOL(drm_panel_disable);
 
@@ -569,12 +606,18 @@ int drm_panel_add_follower(struct device *follower_dev,
 	mutex_lock(&panel->follower_lock);
 
 	list_add_tail(&follower->list, &panel->followers);
-	if (panel->prepared) {
+	if (panel->prepared && follower->funcs->panel_prepared) {
 		ret = follower->funcs->panel_prepared(follower);
 		if (ret < 0)
 			dev_info(panel->dev, "%ps failed: %d\n",
 				 follower->funcs->panel_prepared, ret);
 	}
+	if (panel->enabled && follower->funcs->panel_enabled) {
+		ret = follower->funcs->panel_enabled(follower);
+		if (ret < 0)
+			dev_info(panel->dev, "%ps failed: %d\n",
+				 follower->funcs->panel_enabled, ret);
+	}
 
 	mutex_unlock(&panel->follower_lock);
 
@@ -598,12 +641,18 @@ void drm_panel_remove_follower(struct drm_panel_follower *follower)
 
 	mutex_lock(&panel->follower_lock);
 
-	if (panel->prepared) {
+	if (panel->prepared && follower->funcs->panel_unpreparing) {
 		ret = follower->funcs->panel_unpreparing(follower);
 		if (ret < 0)
 			dev_info(panel->dev, "%ps failed: %d\n",
 				 follower->funcs->panel_unpreparing, ret);
 	}
+	if (panel->enabled && follower->funcs->panel_disabling) {
+		ret = follower->funcs->panel_disabling(follower);
+		if (ret < 0)
+			dev_info(panel->dev, "%ps failed: %d\n",
+				 follower->funcs->panel_disabling, ret);
+	}
 	list_del_init(&follower->list);
 
 	mutex_unlock(&panel->follower_lock);
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 843fb756a2950..2407bfa60236f 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -160,6 +160,20 @@ struct drm_panel_follower_funcs {
 	 * Called before the panel is powered off.
 	 */
 	int (*panel_unpreparing)(struct drm_panel_follower *follower);
+
+	/**
+	 * @panel_enabled:
+	 *
+	 * Called after the panel and the backlight have been enabled.
+	 */
+	int (*panel_enabled)(struct drm_panel_follower *follower);
+
+	/**
+	 * @panel_disabling:
+	 *
+	 * Called before the panel and the backlight are disabled.
+	 */
+	int (*panel_disabling)(struct drm_panel_follower *follower);
 };
 
 struct drm_panel_follower {
-- 
2.51.0.rc0.205.g4a044479a3-goog


^ permalink raw reply related

* Re: [PATCH] Hid: Intel-thc-hid: Intel-quicki2c: Enhance driver re-install flow
From: Jiri Kosina @ 2025-08-13 11:56 UTC (permalink / raw)
  To: Even Xu; +Cc: bentiss, srinivas.pandruvada, linux-input, linux-kernel,
	Rui Zhang
In-Reply-To: <20250806002332.1487447-1-even.xu@intel.com>

On Wed, 6 Aug 2025, Even Xu wrote:

> After driver module is removed and during re-install stage, if there
> is continueous user touching on the screen, it is a risk impacting
> THC hardware initialization which causes driver installation failure.
> 
> This patch enhances this flow by quiescing the external touch
> interrupt after driver is removed which keeps THC hardware
> ignore external interrupt during this remove and re-install stage.
> 
> Signed-off-by: Even Xu <even.xu@intel.com>
> Tested-by: Rui Zhang <rui1.zhang@intel.com>
> Fixes: 66b59bfce6d9 ("HID: intel-thc-hid: intel-quicki2c: Complete THC QuickI2C driver")

(please use the uppercase/lowercase in shortlog consistently with how HID 
subsystem has been using it ... I've fixed that manually for this one).

Applied to hid.git#for-6.17/upstream-fixes, thanks.

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH v2] HID: hid-ntrig: fix unable to handle page fault in ntrig_report_version()
From: Benjamin Tissoires @ 2025-08-13 11:53 UTC (permalink / raw)
  To: Jiri Kosina, Minjong Kim; +Cc: linux-input, linux-kernel
In-Reply-To: <20250813-hid-ntrig-page-fault-fix-v2-1-f98581f35106@samsung.com>

On Wed, 13 Aug 2025 19:30:22 +0900, Minjong Kim wrote:
> in ntrig_report_version(), hdev parameter passed from hid_probe().
> sending descriptor to /dev/uhid can make hdev->dev.parent->parent to null
> if hdev->dev.parent->parent is null, usb_dev has
> invalid address(0xffffffffffffff58) that hid_to_usb_dev(hdev) returned
> when usb_rcvctrlpipe() use usb_dev,it trigger
> page fault error for address(0xffffffffffffff58)
> 
> [...]

Applied to hid/hid.git (for-6.17/upstream-fixes), thanks!

[1/1] HID: hid-ntrig: fix unable to handle page fault in ntrig_report_version()
      https://git.kernel.org/hid/hid/c/185c926283da

Cheers,
-- 
Benjamin Tissoires <bentiss@kernel.org>


^ permalink raw reply

* Re: [PATCH 09/17] HID: pidff: Update debug messages
From: Jiri Kosina @ 2025-08-13 11:47 UTC (permalink / raw)
  To: Tomasz Pakuła; +Cc: bentiss, oleg, linux-input
In-Reply-To: <20250803181354.60034-10-tomasz.pakula.oficjalny@gmail.com>

On Sun, 3 Aug 2025, Tomasz Pakuła wrote:

> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> ---
>  drivers/hid/usbhid/hid-pidff.c | 15 +++++++++++----
>  1 file changed, 11 insertions(+), 4 deletions(-)

At least some changelog (what motivates the update, how is this making 
anything better?) would be nice here as well.

Thanks,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH 03/17] HID: pidff: Remove unneeded debug
From: Jiri Kosina @ 2025-08-13 11:44 UTC (permalink / raw)
  To: Tomasz Pakuła; +Cc: bentiss, oleg, linux-input
In-Reply-To: <20250803181354.60034-4-tomasz.pakula.oficjalny@gmail.com>

On Sun, 3 Aug 2025, Tomasz Pakuła wrote:

> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> Reviewed-by: Oleg Makarenko <oleg@makarenk.ooo>

Could you please provided rationale in the changelog what makes this debug 
'unneeded', so that it's properly recorded in the history?

Thanks,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* [PATCH v2] HID: hid-ntrig: fix unable to handle page fault in ntrig_report_version()
From: Minjong Kim @ 2025-08-13 10:30 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel, Minjong Kim
In-Reply-To: <CGME20250813103051epcas1p39a9dacf48770020ca234e0c648bb01d2@epcas1p3.samsung.com>

in ntrig_report_version(), hdev parameter passed from hid_probe().
sending descriptor to /dev/uhid can make hdev->dev.parent->parent to null
if hdev->dev.parent->parent is null, usb_dev has
invalid address(0xffffffffffffff58) that hid_to_usb_dev(hdev) returned
when usb_rcvctrlpipe() use usb_dev,it trigger
page fault error for address(0xffffffffffffff58)

add null check logic to ntrig_report_version()
before calling hid_to_usb_dev()

Signed-off-by: Minjong Kim <minbell.kim@samsung.com>
---
 drivers/hid/hid-ntrig.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 2738ce947434f904f32e9a1979b1681c66972ff9..0f76e241e0afb4adb38885a008a05edb24169ea9 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev)
 	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
 	unsigned char *data = kmalloc(8, GFP_KERNEL);
 
+	if (!hid_is_usb(hdev))
+		return;
+
 	if (!data)
 		goto err_free;
 

---
base-commit: 347e9f5043c89695b01e66b3ed111755afcf1911
change-id: 20250717-hid-ntrig-page-fault-fix-d13c49c86473

Best regards,
-- 
Minjong Kim <minbell.kim@samsung.com>


^ permalink raw reply related

* Re: [PATCH v3] HID: hid-ntrig: fix unable to handle page fault in ntrig_report_version()
From: Benjamin Tissoires @ 2025-08-13 10:06 UTC (permalink / raw)
  To: Minjong Kim; +Cc: Jiri Kosina, linux-input, linux-kernel
In-Reply-To: <20250813092234.ja5qfpvkxocfnchd@minbellkim-500TGA-500SGA>

On Aug 13 2025, Minjong Kim wrote:
> On Wed, Aug 13, 2025 at 10:39:37AM +0200, Benjamin Tissoires wrote:
> > On Aug 13 2025, Minjong Kim wrote:
> > > 
> > > From 75e52defd4b2fd138285c5ad953942e2e6cf2fbb Mon Sep 17 00:00:00 2001
> > > From: Minjong Kim <minbell.kim@samsung.com>
> > > Date: Thu, 17 Jul 2025 14:37:47 +0900
> > > Subject: [PATCH v2] HID: hid-ntrig: fix unable to handle page fault in
> > >  ntrig_report_version()
> > > 
> > > in ntrig_report_version(), hdev parameter passed from hid_probe().
> > > sending descriptor to /dev/uhid can make hdev->dev.parent->parent to null
> > > if hdev->dev.parent->parent is null, usb_dev has
> > > invalid address(0xffffffffffffff58) that hid_to_usb_dev(hdev) returned
> > > when usb_rcvctrlpipe() use usb_dev,it trigger
> > > page fault error for address(0xffffffffffffff58)
> > > 
> > > add null check logic to ntrig_report_version()
> > > before calling hid_to_usb_dev()
> > > 
> > > Signed-off-by: Minjong Kim <minbell.kim@samsung.com>
> > > ---
> > >  drivers/hid/hid-ntrig.c | 3 +++
> > >  1 file changed, 3 insertions(+)
> > > 
> > > diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
> > > index 2738ce947434..fa948d9e236c 100644
> > > --- a/drivers/hid/hid-ntrig.c
> > > +++ b/drivers/hid/hid-ntrig.c
> > > @@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev)
> > >  	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
> > >  	unsigned char *data = kmalloc(8, GFP_KERNEL);
> > > 
> > > +	if (!hdev->dev.parent->parent)
> > 
> > Why simply not use if(!hid_is_usb(hdev)) instead?
> > 
> > Cheers,
> > Benjamin
> >
> 
> From 61818c85614ad40beab53cee421272814576836d Mon Sep 17 00:00:00 2001
> From: Minjong Kim <minbell.kim@samsung.com>
> Date: Thu, 17 Jul 2025 14:37:47 +0900
> Subject: [PATCH v3] HID: hid-ntrig: fix unable to handle page fault in
>  ntrig_report_version()
> 
> in ntrig_report_version(), hdev parameter passed from hid_probe().
> sending descriptor to /dev/uhid can make hdev->dev.parent->parent to null
> if hdev->dev.parent->parent is null, usb_dev has
> invalid address(0xffffffffffffff58) that hid_to_usb_dev(hdev) returned
> when usb_rcvctrlpipe() use usb_dev,it trigger
> page fault error for address(0xffffffffffffff58)
> 
> add null check logic to ntrig_report_version()
> before calling hid_to_usb_dev()
> 
> Signed-off-by: Minjong Kim <minbell.kim@samsung.com>
> ---
>  drivers/hid/hid-ntrig.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
> index 2738ce947434..0f76e241e0af 100644
> --- a/drivers/hid/hid-ntrig.c
> +++ b/drivers/hid/hid-ntrig.c
> @@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev)
>  	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
>  	unsigned char *data = kmalloc(8, GFP_KERNEL);
>  
> +	if (!hid_is_usb(hdev))
> +		return;
> +
>  	if (!data)
>  		goto err_free;
>  
> -- 
> 2.34.1
> 
> 
> I checked that crashes didn't occuered this patch
> then, I'm just wondering why it is effective?
> could you explain me about this?
> 
> Best regards,

Could you please properly resend the patch, without replying to the
thread? I can't seem to make b4 happy to apply the patch directly so
there is something wrong with your submission here.

Cheers,
Benjamin


^ permalink raw reply

* Re: [PATCH RESEND] HID: asus: fix UAF via HID_CLAIMED_INPUT validation
From: Benjamin Tissoires @ 2025-08-13  9:43 UTC (permalink / raw)
  To: jikos, linux-input, linux-kernel, Qasim Ijaz; +Cc: stable
In-Reply-To: <20250810181041.44874-1-qasdev00@gmail.com>

On Sun, 10 Aug 2025 19:10:41 +0100, Qasim Ijaz wrote:
> After hid_hw_start() is called hidinput_connect() will eventually be
> called to set up the device with the input layer since the
> HID_CONNECT_DEFAULT connect mask is used. During hidinput_connect()
> all input and output reports are processed and corresponding hid_inputs
> are allocated and configured via hidinput_configure_usages(). This
> process involves slot tagging report fields and configuring usages
> by setting relevant bits in the capability bitmaps. However it is possible
> that the capability bitmaps are not set at all leading to the subsequent
> hidinput_has_been_populated() check to fail leading to the freeing of the
> hid_input and the underlying input device.
> 
> [...]

Applied to hid/hid.git (for-6.17/upstream-fixes), thanks!

[1/1] HID: asus: fix UAF via HID_CLAIMED_INPUT validation
      https://git.kernel.org/hid/hid/c/d3af6ca9a8c3

Cheers,
-- 
Benjamin Tissoires <bentiss@kernel.org>


^ permalink raw reply

* Re: [PATCH] hid: fix I2C read buffer overflow in raw_event() for mcp2221
From: Benjamin Tissoires @ 2025-08-13  9:43 UTC (permalink / raw)
  To: Rishi Gupta, Arnaud Lecomte
  Cc: Jiri Kosina, linux-i2c, linux-input, linux-kernel,
	syzbot+52c1a7d3e5b361ccd346
In-Reply-To: <20250726220931.7126-1-contact@arnaud-lcm.com>

On Sat, 26 Jul 2025 23:09:31 +0100, Arnaud Lecomte wrote:
> As reported by syzbot, mcp2221_raw_event lacked
> validation of incoming I2C read data sizes, risking buffer
> overflows in mcp->rxbuf during multi-part transfers.
> As highlighted in the DS20005565B spec, p44, we have:
> "The number of read-back data bytes to follow in this packet:
> from 0 to a maximum of 60 bytes of read-back bytes."
> This patch enforces we don't exceed this limit.
> 
> [...]

Applied to hid/hid.git (for-6.17/upstream-fixes), thanks!

[1/1] hid: fix I2C read buffer overflow in raw_event() for mcp2221
      https://git.kernel.org/hid/hid/c/b56cc41a3ae7

Cheers,
-- 
Benjamin Tissoires <bentiss@kernel.org>


^ permalink raw reply

* Re: [PATCH v3] HID: hid-ntrig: fix unable to handle page fault in ntrig_report_version()
From: Benjamin Tissoires @ 2025-08-13  9:41 UTC (permalink / raw)
  To: Minjong Kim; +Cc: Jiri Kosina, linux-input, linux-kernel
In-Reply-To: <20250813092234.ja5qfpvkxocfnchd@minbellkim-500TGA-500SGA>

On Aug 13 2025, Minjong Kim wrote:
> On Wed, Aug 13, 2025 at 10:39:37AM +0200, Benjamin Tissoires wrote:
> > On Aug 13 2025, Minjong Kim wrote:
> > > 
> > > From 75e52defd4b2fd138285c5ad953942e2e6cf2fbb Mon Sep 17 00:00:00 2001
> > > From: Minjong Kim <minbell.kim@samsung.com>
> > > Date: Thu, 17 Jul 2025 14:37:47 +0900
> > > Subject: [PATCH v2] HID: hid-ntrig: fix unable to handle page fault in
> > >  ntrig_report_version()
> > > 
> > > in ntrig_report_version(), hdev parameter passed from hid_probe().
> > > sending descriptor to /dev/uhid can make hdev->dev.parent->parent to null
> > > if hdev->dev.parent->parent is null, usb_dev has
> > > invalid address(0xffffffffffffff58) that hid_to_usb_dev(hdev) returned
> > > when usb_rcvctrlpipe() use usb_dev,it trigger
> > > page fault error for address(0xffffffffffffff58)
> > > 
> > > add null check logic to ntrig_report_version()
> > > before calling hid_to_usb_dev()
> > > 
> > > Signed-off-by: Minjong Kim <minbell.kim@samsung.com>
> > > ---
> > >  drivers/hid/hid-ntrig.c | 3 +++
> > >  1 file changed, 3 insertions(+)
> > > 
> > > diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
> > > index 2738ce947434..fa948d9e236c 100644
> > > --- a/drivers/hid/hid-ntrig.c
> > > +++ b/drivers/hid/hid-ntrig.c
> > > @@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev)
> > >  	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
> > >  	unsigned char *data = kmalloc(8, GFP_KERNEL);
> > > 
> > > +	if (!hdev->dev.parent->parent)
> > 
> > Why simply not use if(!hid_is_usb(hdev)) instead?
> > 
> > Cheers,
> > Benjamin
> >
> 
> From 61818c85614ad40beab53cee421272814576836d Mon Sep 17 00:00:00 2001
> From: Minjong Kim <minbell.kim@samsung.com>
> Date: Thu, 17 Jul 2025 14:37:47 +0900
> Subject: [PATCH v3] HID: hid-ntrig: fix unable to handle page fault in
>  ntrig_report_version()
> 
> in ntrig_report_version(), hdev parameter passed from hid_probe().
> sending descriptor to /dev/uhid can make hdev->dev.parent->parent to null
> if hdev->dev.parent->parent is null, usb_dev has
> invalid address(0xffffffffffffff58) that hid_to_usb_dev(hdev) returned
> when usb_rcvctrlpipe() use usb_dev,it trigger
> page fault error for address(0xffffffffffffff58)
> 
> add null check logic to ntrig_report_version()
> before calling hid_to_usb_dev()
> 
> Signed-off-by: Minjong Kim <minbell.kim@samsung.com>
> ---
>  drivers/hid/hid-ntrig.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
> index 2738ce947434..0f76e241e0af 100644
> --- a/drivers/hid/hid-ntrig.c
> +++ b/drivers/hid/hid-ntrig.c
> @@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev)
>  	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
>  	unsigned char *data = kmalloc(8, GFP_KERNEL);
>  
> +	if (!hid_is_usb(hdev))
> +		return;
> +
>  	if (!data)
>  		goto err_free;
>  
> -- 
> 2.34.1
> 
> 
> I checked that crashes didn't occuered this patch
> then, I'm just wondering why it is effective?
> could you explain me about this?

You are basically trying to detect if a device is connected through uhid
or usb. uhid doesn't set the hdev->dev.parent->parent field, which is
only available when connected over an actual USB port.

So instead of relying on struct internals, I just told you to use the
proper mechanism to ensure that the function which will call usb
specifics will actually work on usb connected devices only, not emulated
devices.

Cheers,
Benjamin

> 
> Best regards,



^ permalink raw reply

* Re: [PATCH v2 11/11] HID: multitouch: add haptic multitouch support
From: Benjamin Tissoires @ 2025-08-13  9:22 UTC (permalink / raw)
  To: Jonathan Denose
  Cc: Jiri Kosina, Dmitry Torokhov, Jonathan Corbet, Henrik Rydberg,
	linux-input, linux-kernel, linux-doc, Angela Czubak,
	Sean O'Brien
In-Reply-To: <20250804-support-forcepads-v2-11-138ca980261d@google.com>

On Aug 04 2025, Jonathan Denose wrote:
> 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.

Why creating a new option? It seems it'll add unwanted work from
distributions when we should have something that "just works" no?

It makes sense to depend on FF, but adding a new option is probably
useless IMO.


> 
> 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

There is something wrong with your ifdef usages:
- here, you define the functions below conditionally to
	CONFIG_MULTITOUCH_HAPTIC, which is fine
- but in hid-multitouch, you also check for CONFIG_MULTITOUCH_HAPTIC
	before calling the same set of functions.

Either only define the haptic functions when CONFIG_MULTITOUCH_HAPTIC is
set, and in multitouch check for that define, or define it conditionally
and remove the checks in hid-multitouch (but probably add a comment).

>  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 */
> -

unrelated change (line removed).

>  	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);

Please make use of the devm api, you are leaking the allocated memory in
the regular case (AFAICT).

> +	if (!td->haptic)
> +		return -ENOMEM;

One extra blank line wouldn't hurt here :)

> +	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
> 

Cheers,
Benjamin

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox