Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH] HID: multitouch: stop the release timer from being rearmed on remove
From: sashiko-bot @ 2026-07-24  0:24 UTC (permalink / raw)
  To: Aldo Ariel Panzardo; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260724000958.938675-1-qwe.aldo@gmail.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Out-of-bounds write via set_bit() leading to memory corruption by malicious HID devices.
- [High] Use-After-Free of report buffers in hid_haptic_destroy during device teardown.
- [High] Race condition during probe leading to NULL pointer dereference in mt_sync_frame.
- [High] Sleeping in atomic context when processing unmapped HID reports.
- [Medium] Data race modifying td->applications list without synchronization.
--

--- Patch [1]: [PATCH] HID: multitouch: stop the release timer from being rearmed on remove ---
commit b618d8ab09924436537bc4c4c724c79da532672e
Author: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
Subject: HID: multitouch: stop the release timer from being rearmed on remove

mt_remove() quiesces the sticky-finger timer before stopping the
hardware. timer_delete_sync() waits for a running callback and
dequeues the timer, but it does not stop the timer from being armed
again. Use timer_shutdown_sync() instead.

Cc: stable@vger.kernel.org
Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260723224211.613112-1-you@example.com?part=1
Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com>

> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index 0495152091e3b..f25065b9ec66e 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -2233,7 +2233,7 @@ static void mt_remove(struct hid_device *hdev)
>  {
>  	struct mt_device *td = hid_get_drvdata(hdev);
>  
> -	timer_delete_sync(&td->release_timer);
> +	timer_shutdown_sync(&td->release_timer);
>  
>  	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
>  	hid_hw_stop(hdev);
>  }

[ ... ]

drivers/hid/hid-haptic.c:hid_haptic_destroy() {
    ...
	kfree(haptic->stop_effect.report_buf);
	haptic->stop_effect.report_buf = NULL;

	if (haptic->effect) {
		for (r = 0; r < ff->max_effects; r++)
			kfree(haptic->effect[r].report_buf);
		kfree(haptic->effect);
	}
	haptic->effect = NULL;

	destroy_workqueue(haptic->wq);
    ...
}

[Severity: High]
This isn't a bug introduced by this patch, but could this lead to a
use-after-free during device teardown?

When an input device is destroyed, input_ff_flush() queues
stop_effect.work on the workqueue. If the work is still pending,
destroy_workqueue() will wait for it to finish. However, the report
buffers are freed before the workqueue is drained.

When haptic_work_handler() executes, it calls play_effect() which uses
the freed effect->report_buf.

Should destroy_workqueue() be called before freeing the report buffers?

drivers/hid/hid-multitouch.c:mt_probe() {
    ...
	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
	if (ret)
		return ret;
    ...
	if (td->is_haptic_touchpad) {
		if (hid_haptic_init(hdev, &td->haptic)) {
			dev_warn(&hdev->dev, "Cannot allocate haptic for %s\n",
				 hdev->name);
			td->is_haptic_touchpad = false;
			devm_kfree(&hdev->dev, td->haptic);
		}
    ...
}

[Severity: High]
This is a pre-existing issue, but does this create a race condition if
hid_haptic_init() fails?

Since hid_hw_start() enables hardware interrupts earlier in mt_probe(),
an interrupt could arrive after hid_haptic_init() fails (setting td->haptic
to NULL) but before td->is_haptic_touchpad is set to false.

If mt_sync_frame() runs in this window, it will see td->is_haptic_touchpad
as true and call hid_haptic_pressure_reset(td->haptic), dereferencing a
NULL pointer.

Should the interrupt enablement or error handling order be adjusted?

drivers/hid/hid-multitouch.c:struct mt_device {
    ...
	unsigned long mt_io_flags;
	__u8 inputmode_value;
    ...
	struct list_head applications;
    ...
}

drivers/hid/hid-multitouch.c:mt_process_slot() {
    ...
	set_bit(slotnum, &td->mt_io_flags);
    ...
}

[Severity: Critical]
This is a pre-existing issue, but does this set_bit() call allow an
out-of-bounds write?

A malicious USB HID device could declare a contact max up to 250, resulting
in a slotnum up to 249. Since mt_io_flags is a single unsigned long, calling
set_bit(249, ...) overflows the variable by up to 31 bytes.

This would corrupt adjacent fields in the mt_device struct, including the
inputmode_value and the applications list pointers.

Can the slot index be constrained or the storage for mt_io_flags be expanded?

drivers/hid/hid-multitouch.c:mt_allocate_report_data() {
    ...
	rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL);
    ...
}

[Severity: High]
This isn't a bug introduced by this patch, but can this sleep in atomic
context?

If a device sends an unmapped report ID dynamically over the interrupt
endpoint, the URB completion handler runs in atomic context and calls
hid_report_raw_event(), which eventually calls mt_report().

mt_report() then calls mt_find_report_data() and mt_allocate_report_data().
Since devm_kzalloc() is called with GFP_KERNEL here, it could fault when
processing these unmapped reports in atomic context.

Should this use GFP_ATOMIC instead?

drivers/hid/hid-multitouch.c:mt_set_quirks() {
    ...
	list_for_each_entry(application, &td->applications, list) {
    ...
}

drivers/hid/hid-multitouch.c:mt_allocate_application() {
    ...
	list_add_tail(&mt_application->list, &td->applications);
    ...
}

[Severity: Medium]
This is a pre-existing issue, but is there a data race on the
td->applications list?

mt_set_quirks() iterates over td->applications without locking.
Concurrently, if the device receives an unmapped report, mt_report() can
call mt_allocate_application() from the interrupt path, which adds to the
same list using list_add_tail().

Could this concurrent modification without synchronization corrupt the
linked list?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724000958.938675-1-qwe.aldo@gmail.com?part=1

^ permalink raw reply

* [PATCH] HID: multitouch: stop the release timer from being rearmed on remove
From: Aldo Ariel Panzardo @ 2026-07-24  0:09 UTC (permalink / raw)
  To: linux-input
  Cc: jikos, bentiss, linux-kernel, Aldo Ariel Panzardo, stable,
	Sashiko AI review

mt_remove() quiesces the sticky-finger timer before stopping the
hardware:

    timer_delete_sync(&td->release_timer);

    sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
    hid_hw_stop(hdev);

timer_delete_sync() waits for a running callback and dequeues the timer,
but it does not stop the timer from being armed again. The transport is
still delivering reports at that point, and the report path rearms it:

    if (app->quirks & MT_QUIRK_STICKY_FINGERS) {
        if (td->mt_io_flags & MT_IO_SLOTS_MASK)
            mod_timer(&td->release_timer,
                      jiffies + msecs_to_jiffies(100));

A report that arrives after timer_delete_sync() has returned therefore
leaves the timer queued. td is allocated with devm_kzalloc() against
hdev->dev, so it is freed when the driver is unbound, after mt_remove()
returns. When the timer fires afterwards, mt_expired_timeout()
dereferences the freed td:

    struct mt_device *td = timer_container_of(td, t, release_timer);
    struct hid_device *hdev = td->hdev;

    if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))

Simply moving the teardown after hid_hw_stop() does not fix this on its
own, because mt_expired_timeout() calls mt_release_contacts(), which
walks hdev->inputs; the timer still has to be quiesced before
hid_hw_stop() tears the input devices down.

Use timer_shutdown_sync() instead, which additionally makes any later
mod_timer() a no-op, so neither ordering constraint has to be traded off
against the other. This is the final-teardown pattern the function was
introduced for, and hid-wiimote already uses it for the same reason.

Fixes: 4f4001bc76fd ("HID: multitouch: fix rare Win 8 cases when the touch up event gets missing")
Cc: stable@vger.kernel.org
Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260723224211.613112-1-you@example.com?part=1
Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
---
Found by code inspection after Sashiko AI review flagged the teardown
ordering while reviewing an unrelated patch of mine. I have not
reproduced the use-after-free at runtime: it needs a report to land in
the window between timer_delete_sync() returning and the device being
unbound, which I have no way to drive reliably on the hardware I have.
The window and the rearm path are visible in the code, and the fix does
not depend on the race being hit.

 drivers/hid/hid-multitouch.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 0495152091e3..f25065b9ec66 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -2233,7 +2233,7 @@ static void mt_remove(struct hid_device *hdev)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
 
-	timer_delete_sync(&td->release_timer);
+	timer_shutdown_sync(&td->release_timer);
 
 	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
 	hid_hw_stop(hdev);
-- 
2.43.0


^ permalink raw reply related

* [PATCH] HID: multitouch: keep MT_IO_FLAGS_RUNNING inside the flags word
From: Aldo Ariel Panzardo @ 2026-07-24  0:08 UTC (permalink / raw)
  To: linux-input
  Cc: jikos, bentiss, linux-kernel, Aldo Ariel Panzardo, stable,
	Sashiko AI review

MT_IO_FLAGS_RUNNING is bit 32 of td->mt_io_flags, which is a single
unsigned long. On 32-bit architectures a long is 32 bits wide, so the
valid bit indices are 0-31 and bit 32 falls in the next word. Both users
take and release the flag with atomic bitops:

    test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
    clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);

so on a 32-bit build every report and every sticky-finger timer expiry
reads and writes the four bytes that follow mt_io_flags in struct
mt_device -- inputmode_value, maxcontacts and the is_* flags -- instead
of the flags word itself.

Before commit 46f781e0d151 ("HID: multitouch: fix sticky fingers") the
flag was bit 0 and the word only had to hold three flags. That commit
reserved the low eight bits for per-slot state (MT_IO_SLOTS_MASK) and
moved the flag out to bit 32, one word too far on 32-bit builds.

Put it at MT_IO_SLOTS_BITS, the first bit above the reserved slot range.
The value is only ever used as a bit index, so nothing else has to
change.

Fixes: 46f781e0d151 ("HID: multitouch: fix sticky fingers")
Cc: stable@vger.kernel.org
Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260723224211.613112-1-you@example.com?part=1
Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
---
This applies on top of "HID: multitouch: bound the slot index before
touching mt_io_flags", which introduces MT_IO_SLOTS_BITS. The two are
separate defects with the same Fixes: tag, so they should backport
together.

 drivers/hid/hid-multitouch.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index a75c821f7758..e7d811ed4123 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -99,7 +99,7 @@ enum report_mode {
 
 #define MT_IO_SLOTS_MASK		GENMASK(7, 0) /* reserve first 8 bits for slot tracking */
 #define MT_IO_SLOTS_BITS		8 /* bits covered by MT_IO_SLOTS_MASK */
-#define MT_IO_FLAGS_RUNNING		32
+#define MT_IO_FLAGS_RUNNING		MT_IO_SLOTS_BITS
 
 static const bool mtrue = true;		/* default for true */
 static const bool mfalse;		/* default for false */
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH 02/10] iio: gyro: hid-sensor-gyro-3d: use local struct device
From: Jonathan Cameron @ 2026-07-23 23:51 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Sanjay Chitroda, Jiri Kosina, Srinivas Pandruvada, David Lechner,
	Nuno Sá, Andy Shevchenko, linux-input, linux-iio,
	linux-kernel
In-Reply-To: <al54b953O6JXcbU6@ashevche-desk.local>

On Mon, 20 Jul 2026 22:35:11 +0300
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:

> On Mon, Jul 20, 2026 at 10:20:28PM +0530, Sanjay Chitroda wrote:
> > On 20 July 2026 5:24:33 pm IST, Andy Shevchenko <andriy.shevchenko@intel.com> wrote:  
> > >On Mon, Jul 20, 2026 at 03:10:14PM +0530, Sanjay Chitroda via B4 Relay wrote:  
> 
> ...
> 
> > >> -		dev_err(&pdev->dev, "failed to setup common attributes\n");
> > >> +		dev_err(dev, "failed to setup common attributes\n");
> > >>  		return ret;  
> > >
> > >Nope, First one (to eliminate a lot of churn) should be to convert this and
> > >similar to use
> > >
> > >		return dev_err_probe(...);  
> > 
> > Thank you for your input.
> > 
> > I'm planning to have a incremental series: first introduce a local "dev"
> > pointer, then convert the resource management to "devm_*", and finally
> > replace the remaining error reporting with "dev_err_probe()".
> > 
> > This keeps each series focused and avoids introducing intermediate patterns such as:
> > 
> >    ret = dev_err_probe(dev, ret, ...);
> >    goto error;
> > 
> > Once the cleanup paths are removed, those sites naturally become:
> > 
> >    return dev_err_probe(dev, ret, ...);
> > 
> > Does this approach sound reasonable?  
> 
> 
> No. First you should drop the dead code for sure (see above).
> Second, try to convert to dev_err_probe() as many drivers as you can without an
> intermediate change. If the driver requires an intermediate thing like the above
> it means it requires bigger refactoring. So, you should not have intermediate
> churn. With your current approach there are drivers that will have it, and for
> them you need to have different strategy (see my proposal in the above lines).

Note it is fine to bring in struct device *dev = ... as part of any
other cleanup change where it shortens things. 

Once you have done the more significant changes, chase them with a patch
in the same series to make use of dev in any remaining places.

The trick is to do all cleanup that is trampling on same lines in one
series so things like leaving a few cases to sweep up at the end in
a trivial patch look sensible.   Give you are working on a lot of
drivers, perhaps to keep things manageable you should clean up one or
two completely in a series then follow up with additional series to make
similar changes in the rest.

Jonathan


> 


^ permalink raw reply

* Re: [PATCH] HID: multitouch: bound the slot index before touching mt_io_flags
From: sashiko-bot @ 2026-07-23 22:54 UTC (permalink / raw)
  To: Your Name; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260723224211.613112-1-you@example.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Out-of-bounds memory access / State corruption on 32-bit platforms due to `MT_IO_FLAGS_RUNNING` being 32.
- [High] Use-After-Free (UAF) race condition in `mt_remove` due to incorrect timer teardown ordering.
--

--- Patch [1]: [PATCH] HID: multitouch: bound the slot index before touching mt_io_flags ---
commit 876ccafb8bbdeb9e57250cb530c345252c4de7d6
Author: Aldo Ariel Panzardo <qwe.aldo@gmail.com>

HID: multitouch: bound the slot index before touching mt_io_flags

This commit prevents out-of-bounds writes to mt_io_flags by checking that
the slot index is within the reserved bit range. It introduces mt_io_slot_set()
and mt_io_slot_clear() to enforce this bound before calling set_bit() or
clear_bit().

Cc: stable@vger.kernel.org

> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index 0495152091e3b..463eab9f73cdb 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -98,6 +98,7 @@ enum report_mode {
>  };
>  
>  #define MT_IO_SLOTS_MASK		GENMASK(7, 0) /* reserve first 8 bits for slot tracking */
> +#define MT_IO_SLOTS_BITS		8 /* bits covered by MT_IO_SLOTS_MASK */
>  #define MT_IO_FLAGS_RUNNING		32

[Severity: High]
This is a pre-existing issue, but does using bit index 32 cause out-of-bounds
memory access on 32-bit platforms?

Because mt_io_flags is a single unsigned long, valid bit indices are 0-31
on 32-bit architectures.

Calling test_and_set_bit_lock() with bit 32 will read and write to the memory
immediately following mt_io_flags.

Could this silently corrupt adjacent device state fields like inputmode_value
and maxcontacts in struct mt_device?

>  static const bool mtrue = true;		/* default for true */
> @@ -175,9 +176,10 @@ struct mt_device {
>  	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_RUNNING)
> -					 * first 8 bits are reserved for keeping the slot
> -					 * states, this is fine because we only support up
> -					 * to 250 slots (MT_MAX_MAXCONTACT)
> +					 * the first MT_IO_SLOTS_BITS bits are reserved
> +					 * for keeping the slot states; higher slot
> +					 * numbers are not tracked here, see
> +					 * mt_io_slot_set()
>  					 */
>  	__u8 inputmode_value;	/* InputMode HID feature value */
>  	__u8 maxcontacts;

[ ... ]

[Severity: High]
This is another pre-existing issue not introduced by this patch, but is there
a use-after-free race condition during device removal?

In mt_remove(), timer_delete_sync() is called before the hardware is stopped:

drivers/hid/hid-multitouch.c:mt_remove() {
    ...
	timer_delete_sync(&td->release_timer);

	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
	hid_hw_stop(hdev);
    ...
}

Since the hardware transport is still active, could an incoming HID report
trigger mt_touch_report() and re-arm the timer?

drivers/hid/hid-multitouch.c:mt_touch_report() {
    ...
			mod_timer(&td->release_timer,
				  jiffies + msecs_to_jiffies(100));
    ...
}

If the timer is re-armed after timer_delete_sync(), mt_remove() will complete
and free the devm-managed td structure.

When the timer later fires, won't mt_expired_timeout() access the freed memory?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260723224211.613112-1-you@example.com?part=1

^ permalink raw reply

* [PATCH] HID: multitouch: bound the slot index before touching mt_io_flags
From: Your Name @ 2026-07-23 22:42 UTC (permalink / raw)
  To: linux-input; +Cc: jikos, bentiss, linux-kernel, Aldo Ariel Panzardo, stable

From: Aldo Ariel Panzardo <qwe.aldo@gmail.com>

td->mt_io_flags is a single unsigned long.  Its first MT_IO_SLOTS_BITS
bits track per-slot state, read back through MT_IO_SLOTS_MASK, while bit
32 holds MT_IO_FLAGS_RUNNING, which the report path and the sticky-finger
timer take and release with test_and_set_bit_lock() and
clear_bit_unlock().

set_bit()/clear_bit() are called on that word with the slot number as the
bit index:

	set_bit(slotnum, &td->mt_io_flags);

slotnum is bounded only by td->maxcontacts, which is taken from the HID
CONTACTMAX feature value and can reach MT_MAX_MAXCONTACT (250).  Two
things go wrong once a device reports a slot number of 8 or more:

 - a slot number of 32 sets MT_IO_FLAGS_RUNNING from the data path.
   mt_expired_timeout() then finds the flag already set and returns
   early, so sticky fingers are never released, and the
   clear_bit_unlock() in the other path drops a lock it does not hold.
   Several in-tree classes declare .maxcontacts of 40 and 60, so this is
   reachable with ordinary hardware.

 - a slot number of BITS_PER_LONG or more writes past the end of the word
   altogether, corrupting the struct mt_device fields that follow it.

The same unchecked index is used in mt_release_pending_palms(), where
slotnum comes from a for_each_set_bit() bounded by td->maxcontacts, and
in mt_release_contacts(), where it is bounded by mt->num_slots.

Bound the index to the reserved slot range in one place and use that for
every set_bit()/clear_bit() on mt_io_flags.  Dropping the out-of-range
slots is not a functional change: both readers of the slot state mask
with MT_IO_SLOTS_MASK, so bits at or above MT_IO_SLOTS_BITS were never
observable to begin with.

Also correct the comment on the field, which claimed that eight bits were
sufficient because at most 250 slots are supported.

Fixes: 46f781e0d151 ("HID: multitouch: fix sticky fingers")
Cc: stable@vger.kernel.org
Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
---
 drivers/hid/hid-multitouch.c | 35 ++++++++++++++++++++++++++++-------
 1 file changed, 28 insertions(+), 7 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 0495152091e3..463eab9f73cd 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -98,6 +98,7 @@ enum report_mode {
 };
 
 #define MT_IO_SLOTS_MASK		GENMASK(7, 0) /* reserve first 8 bits for slot tracking */
+#define MT_IO_SLOTS_BITS		8 /* bits covered by MT_IO_SLOTS_MASK */
 #define MT_IO_FLAGS_RUNNING		32
 
 static const bool mtrue = true;		/* default for true */
@@ -175,9 +176,10 @@ struct mt_device {
 	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_RUNNING)
-					 * first 8 bits are reserved for keeping the slot
-					 * states, this is fine because we only support up
-					 * to 250 slots (MT_MAX_MAXCONTACT)
+					 * the first MT_IO_SLOTS_BITS bits are reserved
+					 * for keeping the slot states; higher slot
+					 * numbers are not tracked here, see
+					 * mt_io_slot_set()
 					 */
 	__u8 inputmode_value;	/* InputMode HID feature value */
 	__u8 maxcontacts;
@@ -1027,6 +1029,25 @@ static int mt_compute_slot(struct mt_dev
 	return input_mt_get_slot_by_key(input, *slot->contactid);
 }
 
+/*
+ * Only the first MT_IO_SLOTS_BITS bits of mt_io_flags track slot state; the
+ * rest of the word holds unrelated flags such as MT_IO_FLAGS_RUNNING.  Slot
+ * numbers are bounded by td->maxcontacts, which is taken from the HID
+ * CONTACTMAX feature and can be much larger, so the index has to be checked
+ * before touching the word.
+ */
+static void mt_io_slot_set(struct mt_device *td, int slotnum)
+{
+	if (slotnum < MT_IO_SLOTS_BITS)
+		set_bit(slotnum, &td->mt_io_flags);
+}
+
+static void mt_io_slot_clear(struct mt_device *td, int slotnum)
+{
+	if (slotnum < MT_IO_SLOTS_BITS)
+		clear_bit(slotnum, &td->mt_io_flags);
+}
+
 static void mt_release_pending_palms(struct mt_device *td,
 				     struct mt_application *app,
 				     struct input_dev *input)
@@ -1036,7 +1057,7 @@ static void mt_release_pending_palms(str
 
 	for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) {
 		clear_bit(slotnum, app->pending_palm_slots);
-		clear_bit(slotnum, &td->mt_io_flags);
+		mt_io_slot_clear(td, slotnum);
 
 		input_mt_slot(input, slotnum);
 		input_mt_report_slot_inactive(input);
@@ -1247,9 +1268,9 @@ static int mt_process_slot(struct mt_dev
 		input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
 		input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
 
-		set_bit(slotnum, &td->mt_io_flags);
+		mt_io_slot_set(td, slotnum);
 	} else {
-		clear_bit(slotnum, &td->mt_io_flags);
+		mt_io_slot_clear(td, slotnum);
 	}
 
 	return 0;
@@ -2062,7 +2083,7 @@ static void mt_release_contacts(struct h
 			for (i = 0; i < mt->num_slots; i++) {
 				input_mt_slot(input_dev, i);
 				input_mt_report_slot_inactive(input_dev);
-				clear_bit(i, &td->mt_io_flags);
+				mt_io_slot_clear(td, i);
 			}
 			input_mt_sync_frame(input_dev);
 			input_sync(input_dev);
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH 07/12] Input: adp5585: use devm_blocking_notifier_chain_register()
From: Dmitry Torokhov @ 2026-07-23 21:58 UTC (permalink / raw)
  To: Eliav Farber
  Cc: rafael, tony.luck, bp, guohanjun, mchehab, xueshuai, lenb,
	laurent.pinchart, linusw, brgl, orsonzhai, baolin.wang,
	zhang.lyra, jic23, dlechner, nuno.sa, andy, hansg, ilpo.jarvinen,
	W_Armin, ukleinek, fabio.m.de.francesco, kaihengf, ankita, leitao,
	jason, pedro.pbg, paulmck, frederic, kees, linux-acpi,
	linux-kernel, linux-gpio, linux-pwm, linux-iio, linux-input,
	platform-driver-x86
In-Reply-To: <20260723175513.39849-3-farbere@amazon.com>

On Thu, Jul 23, 2026 at 05:55:08PM +0000, Eliav Farber wrote:
> Replace the blocking_notifier_chain_register() +
> devm_add_action_or_reset() pattern with a single call to
> devm_blocking_notifier_chain_register(), removing the
> adp5585_keys_unreg_notifier() callback.
> 
> Signed-off-by: Eliav Farber <farbere@amazon.com>

Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

Feel free to merge with the rest of the series.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH 1/5] Input: zinitix - check all available fingers for every touch event
From: sashiko-bot @ 2026-07-23 19:33 UTC (permalink / raw)
  To: Kaustabh Chakraborty
  Cc: dmitry.torokhov, devicetree, linux-input, robh, conor+dt
In-Reply-To: <20260724-zinitix-modes-v1-1-f6df7d86a878@disroot.org>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] The patch reintroduces the 'shadow fingers' bug on BT404 touchscreens by reverting the core logic of commit e941dc13fd37.

Pre-existing issues:
- [High] The driver passes stack-allocated variables as buffers to I2C transfer functions (`i2c_master_send`, `i2c_master_recv`), which violates the I2C API contract and is unsafe if the subsystem uses DMA.
--

--- Patch [1]: [PATCH 1/5] Input: zinitix - check all available fingers for every touch event ---
commit 3c2f3ba29bf59a45063f7eee69e37d4b205c7c37
Author: Kaustabh Chakraborty <kauschluss@disroot.org>

Input: zinitix - check all available fingers for every touch event

This commit modifies the zinitix touchscreen driver to unconditionally iterate
over all available finger slots up to MAX_SUPPORTED_FINGER_NUM. It relies
only on SUB_BIT_EXIST instead of using the finger_mask field.

Link: https://android.googlesource.com/kernel/bcm/+/23d376ef33aa4c500a5ea24a290f029d5f8e2de3/drivers/input/touchscreen/zinitix_touch.c#1942 [1]

> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index 0c36765bd79f8..3421b8ffb19b2 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
> @@ -445,7 +445,6 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
>  	struct bt541_ts_data *bt541 = bt541_handler;
>  	struct i2c_client *client = bt541->client;
>  	struct touch_event touch_event;

[Severity: High]
This isn't a bug introduced by this patch, but does passing this
stack-allocated touch_event directly to zinitix_read_data() cause problems
with I2C DMA transfers?

Since zinitix_read_data() wraps i2c_master_recv() and passes this buffer:

zinitix_ts_irq_handler() {
    ...
    error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
                              &touch_event, sizeof(struct touch_event));
    ...
}

Could this lead to memory corruption or kernel panics when CONFIG_VMAP_STACK
is enabled, as stack memory isn't physically contiguous for DMA? This same
pattern appears with local variables passed to i2c_master_send() in
zinitix_read_data() and zinitix_write_u16().

> -	unsigned long finger_mask;
>  	__le16 icon_events;
>  	int error;
>  	int i;

[ ... ]

> @@ -470,8 +469,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
>  		zinitix_report_keys(bt541, le16_to_cpu(icon_events));
>  	}
>  
> -	finger_mask = touch_event.finger_mask;
> -	for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
> +	for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {

[Severity: High]
Does this change reintroduce the shadow fingers regression on BT404
touchscreens?

By unconditionally iterating over all slots and relying solely on
SUB_BIT_EXIST instead of the finger_mask:

zinitix_ts_irq_handler() {
    ...
    for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {
        const struct point_coord *p = &touch_event.point_coord[i];

        if (p->sub_status & SUB_BIT_EXIST)
            zinitix_report_finger(bt541, i, p);
    ...
}

Won't this break functionality on BT404 firmwares which erroneously populate
multiple slots with SUB_BIT_EXIST set for a single physical touch? This
appears to revert the core logic explicitly introduced in commit
e941dc13fd37 to filter out those phantom fingers.

>  		const struct point_coord *p = &touch_event.point_coord[i];
>  
>  		/* Only process contacts that are actually reported */

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org?part=1

^ permalink raw reply

* Re: [PATCH 3/5] Input: zinitix - add support for modes 0 and 1
From: sashiko-bot @ 2026-07-23 19:33 UTC (permalink / raw)
  To: Kaustabh Chakraborty
  Cc: devicetree, robh, linux-input, conor+dt, dmitry.torokhov
In-Reply-To: <20260724-zinitix-modes-v1-3-f6df7d86a878@disroot.org>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] The input device is registered and exposed to userspace before its driver private data (`zinitix_mode`) is fully parsed and initialized, creating a race condition.
- [High] Stack-allocated buffers are passed to I2C transfer functions, which is unsafe and can lead to memory corruption or kernel panics if the I2C adapter relies on DMA.
--

--- Patch [3]: [PATCH 3/5] Input: zinitix - add support for modes 0 and 1 ---
commit 0a0b84e68f36f7bf2e3b751801c1b10ca100ae2e
Author: Kaustabh Chakraborty <kauschluss@disroot.org>

Input: zinitix - add support for modes 0 and 1

This commit implements support for touchscreen modes 0 and 1 in the zinitix
driver by introducing mode-specific event structures. It maintains a common
canonical event structure and adds functions to convert mode-specific event
data into this common format.

> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index fdcb80f52c917..42010f23445e3 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c

[ ... ]

> @@ -440,6 +470,103 @@ static void zinitix_report_keys(struct bt541_ts_data *bt541, u16 icon_events)
>  				 bt541->keycodes[i], icon_events & BIT(i));
>  }
>  
> +static int zinitix_read_point_status_mode0(struct bt541_ts_data *bt541,
> +					   struct touch_event *event)
> +{
> +	struct touch_event_mode0 event_mode0;
> +	int ret;
> +	int i;
> +
> +	ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
> +				&event_mode0, sizeof(struct touch_event_mode0));

[Severity: High]
This isn't a bug introduced by this patch, but does passing stack-allocated
buffers to I2C transfer functions risk memory corruption?

Looking at zinitix_read_point_status_mode0(), the stack-allocated
event_mode0 structure is passed via zinitix_read_data() to i2c_master_recv().
Because kernel stacks are typically virtually mapped with CONFIG_VMAP_STACK
and are not physically contiguous, if the underlying I2C controller driver
attempts to DMA-map this memory, it can lead to memory corruption or kernel
panics.

This pattern is pre-existing in the driver, but the new mode implementations
continue to use it.

> +	if (ret)
> +		return ret;

[ ... ]

> @@ -682,13 +808,9 @@ static int zinitix_ts_probe(struct i2c_client *client)
>  		bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
>  	}
>  
> -	if (bt541->zinitix_mode != 2) {
> -		/*
> -		 * If there are devices that don't support mode 2, support
> -		 * for other modes (0, 1) will be needed.
> -		 */
> +	if (bt541->zinitix_mode > 2) {
>  		dev_err(&client->dev,
> -			"Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
> +			"Malformed zinitix,mode property, must be 0, 1, or 2 (supplied: %d)\n",
>  			bt541->zinitix_mode);

[Severity: High]
This is a pre-existing issue, but could parsing and validating zinitix_mode
after the input device is registered cause a race condition with userspace?

In zinitix_ts_probe(), zinitix_init_input_dev() is called earlier, which
registers the input device and makes it available to userspace. If userspace
opens the device immediately (e.g., via udev uevents), the hardware might
be initialized with an uninitialized zinitix_mode (0 instead of the intended
mode) before this device property parsing executes. This can lead to the
interrupt handler processing garbage data.

Would it be better to read and validate the "zinitix,mode" property before
calling zinitix_init_input_dev()?

>  		return -EINVAL;
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org?part=3

^ permalink raw reply

* Re: [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers
From: sashiko-bot @ 2026-07-23 19:32 UTC (permalink / raw)
  To: Kaustabh Chakraborty
  Cc: devicetree, robh, dmitry.torokhov, conor+dt, linux-input
In-Reply-To: <20260724-zinitix-modes-v1-2-f6df7d86a878@disroot.org>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Low] The validation check in `zinitix_report_finger()` is mathematically impossible to trigger, turning the validation block into dead code and bypassing all event validation.

Pre-existing issues:
- [High] The input device is registered before all driver private data is fully initialized, exposing incomplete state to userspace and violating subsystem rules.
- [High] Regulators enabled in `zinitix_start()` are not disabled on initialization failure paths, leading to a leaked reference count.
- [High] I2C transfers are performed using stack-allocated buffers, which violates kernel safety guidelines for DMA-mapped memory.
--

--- Patch [2]: [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers ---
commit 014178afb268830e3c3cda63dc0ca293fa9a9335
Author: Kaustabh Chakraborty <kauschluss@disroot.org>

Input: zinitix - do not ignore non-moving fingers

This commit addresses an issue with the ZT7548 touchscreen where non-moving
fingers are ignored. It updates the validation mask in zinitix_report_finger()
to include the SUB_BIT_EXIST flag. This ensures fingers that haven't moved
since the last interrupt are properly recognized.

> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index 3421b8ffb19b2..fdcb80f52c917 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
> @@ -406,7 +406,7 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
>  	u16 x, y;
>  
>  	if (unlikely(!(p->sub_status &
> -		       (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
> +		       (SUB_BIT_EXIST | SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
[Severity: Low]
Is this validation check mathematically impossible to trigger now?

The caller zinitix_ts_irq_handler() already verifies if SUB_BIT_EXIST is set:

zinitix_ts_irq_handler() {
    ...
    if (p->sub_status & SUB_BIT_EXIST)
        zinitix_report_finger(bt541, i, p);
    ...
}

Since SUB_BIT_EXIST is strictly guaranteed to be present when this function
is called, the bitwise AND always evaluates to a non-zero value.

This means the negated condition will always evaluate to false, rendering
the entire event validation block and its debug log dead code.

>  		dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
>  			p->sub_status);
>  		return;

[Severity: High]
This isn't a bug introduced by this patch, but does the input device
registration happen before all driver private data is fully initialized?

In zinitix_ts_probe():
    ...
    error = zinitix_init_input_dev(bt541);
    ...
    error = device_property_read_u32(&client->dev, "zinitix,mode",
                                     &bt541->zinitix_mode);
    ...

If a userspace process opens the input device immediately upon registration
in zinitix_init_input_dev(), the driver could configure the hardware using
an uninitialized bt541->zinitix_mode.

Could this place the touchscreen into an unsupported mode?

[Severity: High]
This is a pre-existing issue, but are the regulators enabled in
zinitix_start() correctly disabled on initialization failure paths?

zinitix_start() {
    ...
    error = regulator_bulk_enable(ARRAY_SIZE(bt541->supplies),
                                  bt541->supplies);
    ...
    error = zinitix_send_power_on_sequence(bt541);
    if (error) {
        dev_err(&bt541->client->dev,
                "Error while sending power-on sequence: %d\n", error);
        return error;
    }
    ...
}

If zinitix_send_power_on_sequence() or zinitix_init_touch() fail, the
function returns without disabling the regulators.

Since the input subsystem considers the device closed on open failure, it
will not call zinitix_input_close().

Could repeated open attempts leak the regulator references?

[Severity: High]
This is a pre-existing issue, but do the I2C transfers use stack-allocated
buffers?

zinitix_write_cmd() {
    __le16 reg_le = cpu_to_le16(reg);
    int ret;

    ret = i2c_master_send(client, (u8 *)&reg_le, sizeof(reg_le));
    ...
}

zinitix_ts_irq_handler() {
    struct touch_event touch_event;
    ...
    error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
                              &touch_event, sizeof(struct touch_event));
    ...
}

Passing stack-allocated buffers to I2C transfer functions can lead to
memory corruption or DMA API warnings if the underlying I2C controller
driver attempts to use DMA.

Are these buffers safe given that stack memory is not guaranteed to be
DMA-coherent?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org?part=2

^ permalink raw reply

* [PATCH 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
  Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
	linux-samsung-soc, Kaustabh Chakraborty
In-Reply-To: <20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org>

The ZT7548 chip in the Galaxy J6 is actually able to support mode 2 (the
recommended mode) just fine.

However, the downstream kernel driver utilizes mode 0. This creates a
problem in the aftermarket world where fake touch digitizers only
implement the bare minimum functionality, as used by the downstream
driver, to compromise on cost, which leads to such chips implementing
mode 0 only. To ensure touch works on those devices, set the default
mode to 0.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
index de30d0970336..bd8f798c9810 100644
--- a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
+++ b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
@@ -424,6 +424,8 @@ touchscreen@20 {
 		touchscreen-size-y = <1480>;
 
 		vdd-supply = <&vdd_ldo34>;
+
+		zinitix,mode = <0>;
 	};
 };
 

-- 
2.54.0


^ permalink raw reply related

* [PATCH 4/5] dt-bindings: input/ts/zinitix: document mode 0
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
  Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
	linux-samsung-soc, Kaustabh Chakraborty
In-Reply-To: <20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org>

Zinitix touchscreens support three modes, numbered 0 to 2. These modes
differ based on their event report schema.

The devicetree schema does not mention mode 0, thus does not consider it
as a valid state. Add it.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 .../devicetree/bindings/input/touchscreen/zinitix,bt400.yaml          | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml b/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
index f1ce837b16df..9b51212ea9b9 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
@@ -76,9 +76,9 @@ properties:
   zinitix,mode:
     description: Mode of reporting touch points. Some modes may not work
       with a particular ts firmware for unknown reasons. Available modes are
-      1 and 2. Mode 2 is the default and preferred.
+      0, 1, and 2. Mode 2 is the default and preferred.
     $ref: /schemas/types.yaml#/definitions/uint32
-    enum: [1, 2]
+    enum: [0, 1, 2]
 
   linux,keycodes:
     description:

-- 
2.54.0


^ permalink raw reply related

* [PATCH 3/5] Input: zinitix - add support for modes 0 and 1
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
  Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
	linux-samsung-soc, Kaustabh Chakraborty
In-Reply-To: <20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org>

Zinitix touchscreens have three modes, numbered 0 to 2. The driver
implements mode 2, and leaves out modes 0 and 1. The difference in the
touchscreen modes is the schema of the event data.

Implement modes 0 and 1 in the driver, along with their event structs.
Maintain a common, canonical event struct which is to be the superset of
the mode-specific structs. With that, introduce functions to convert the
mode event info to the canonical format.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 drivers/input/touchscreen/zinitix.c | 138 +++++++++++++++++++++++++++++++++---
 1 file changed, 130 insertions(+), 8 deletions(-)

diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index fdcb80f52c91..42010f23445e 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -145,7 +145,37 @@ struct point_coord {
 	u8	angle;
 };
 
+struct point_coord_mode0 {
+	__le16	x;
+	__le16	y;
+	u8	width;
+	u8	sub_status;
+};
+
 struct touch_event {
+	__le16	status;
+	__le16	event_flag;
+	u8	finger_mask;
+	u8	time_stamp;
+	struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode0 {
+	__le16	status;
+	u8	finger_mask;
+	u8	time_stamp;
+	struct point_coord_mode0 point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode1 {
+	__le16	status;
+	__le16	event_flag;
+	u8	finger_mask;
+	u8	time_stamp;
+	struct point_coord_mode0 point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode2 {
 	__le16	status;
 	u8	finger_mask;
 	u8	time_stamp;
@@ -440,6 +470,103 @@ static void zinitix_report_keys(struct bt541_ts_data *bt541, u16 icon_events)
 				 bt541->keycodes[i], icon_events & BIT(i));
 }
 
+static int zinitix_read_point_status_mode0(struct bt541_ts_data *bt541,
+					   struct touch_event *event)
+{
+	struct touch_event_mode0 event_mode0;
+	int ret;
+	int i;
+
+	ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+				&event_mode0, sizeof(struct touch_event_mode0));
+	if (ret)
+		return ret;
+
+	event->status = event_mode0.status;
+	event->finger_mask = event_mode0.finger_mask;
+	event->time_stamp = event_mode0.time_stamp;
+
+	for (i = 0; i < ARRAY_SIZE(event_mode0.point_coord); i++) {
+		event->point_coord[i].x = event_mode0.point_coord[i].x;
+		event->point_coord[i].y = event_mode0.point_coord[i].y;
+		event->point_coord[i].width = event_mode0.point_coord[i].width;
+		event->point_coord[i].sub_status = event_mode0.point_coord[i].sub_status;
+	}
+
+	return 0;
+}
+
+static int zinitix_read_point_status_mode1(struct bt541_ts_data *bt541,
+					   struct touch_event *event)
+{
+	struct touch_event_mode1 event_mode1;
+	int ret;
+	int i;
+
+	ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+				&event_mode1, sizeof(struct touch_event_mode1));
+	if (ret)
+		return ret;
+
+	event->status = event_mode1.status;
+	event->event_flag = event_mode1.event_flag;
+	event->finger_mask = event_mode1.finger_mask;
+	event->time_stamp = event_mode1.time_stamp;
+
+	for (i = 0; i < ARRAY_SIZE(event_mode1.point_coord); i++) {
+		event->point_coord[i].x = event_mode1.point_coord[i].x;
+		event->point_coord[i].y = event_mode1.point_coord[i].y;
+		event->point_coord[i].width = event_mode1.point_coord[i].width;
+		event->point_coord[i].sub_status = event_mode1.point_coord[i].sub_status;
+	}
+
+	return 0;
+}
+
+static int zinitix_read_point_status_mode2(struct bt541_ts_data *bt541,
+					   struct touch_event *event)
+{
+	struct touch_event_mode2 event_mode2;
+	int ret;
+	int i;
+
+	ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+				&event_mode2, sizeof(struct touch_event_mode2));
+	if (ret)
+		return ret;
+
+	event->status = event_mode2.status;
+	event->finger_mask = event_mode2.finger_mask;
+	event->time_stamp = event_mode2.time_stamp;
+
+	for (i = 0; i < ARRAY_SIZE(event_mode2.point_coord); i++) {
+		event->point_coord[i].x = event_mode2.point_coord[i].x;
+		event->point_coord[i].y = event_mode2.point_coord[i].y;
+		event->point_coord[i].width = event_mode2.point_coord[i].width;
+		event->point_coord[i].sub_status = event_mode2.point_coord[i].sub_status;
+		event->point_coord[i].minor_width = event_mode2.point_coord[i].minor_width;
+		event->point_coord[i].angle = event_mode2.point_coord[i].angle;
+	}
+
+	return 0;
+}
+static int zinitix_read_point_status(struct bt541_ts_data *bt541,
+				     struct touch_event *event)
+{
+	switch (bt541->zinitix_mode) {
+	case 0:
+		return zinitix_read_point_status_mode0(bt541, event);
+	case 1:
+		return zinitix_read_point_status_mode1(bt541, event);
+	case 2:
+		return zinitix_read_point_status_mode2(bt541, event);
+	default:
+		dev_err(&bt541->client->dev, "Mode %d is unsupported\n",
+			bt541->zinitix_mode);
+		return -EINVAL;
+	}
+}
+
 static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
 {
 	struct bt541_ts_data *bt541 = bt541_handler;
@@ -451,8 +578,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
 
 	memset(&touch_event, 0, sizeof(struct touch_event));
 
-	error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
-				  &touch_event, sizeof(struct touch_event));
+	error = zinitix_read_point_status(bt541, &touch_event);
 	if (error) {
 		dev_err(&client->dev, "Failed to read in touchpoint struct\n");
 		goto out;
@@ -682,13 +808,9 @@ static int zinitix_ts_probe(struct i2c_client *client)
 		bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
 	}
 
-	if (bt541->zinitix_mode != 2) {
-		/*
-		 * If there are devices that don't support mode 2, support
-		 * for other modes (0, 1) will be needed.
-		 */
+	if (bt541->zinitix_mode > 2) {
 		dev_err(&client->dev,
-			"Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
+			"Malformed zinitix,mode property, must be 0, 1, or 2 (supplied: %d)\n",
 			bt541->zinitix_mode);
 		return -EINVAL;
 	}

-- 
2.54.0


^ permalink raw reply related

* [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
  Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
	linux-samsung-soc, Kaustabh Chakraborty
In-Reply-To: <20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org>

With the ZT7548 touchscreen present in the Galaxy J6, multitouch does not
work reliably. This is due to the fact that the driver reports fingers
only when their state is changed, so it's either placed against the
scren, moved, or drawn away from the screen.

The function which is responsible for this is zinitix_report_finger().
This function is called from the IRQ handler, under the following
condition:

		if (p->sub_status & SUB_BIT_EXIST)
			zinitix_report_finger(bt541, i, p);

This implies and ensures that every valid finger must have the
SUB_BIT_EXIST flag.

However, at the beginning of the function, it refuses to recognize any
finger if it has none of SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE. This
excludes fingers in reports which do not move from the position since
the previous interrupt. Add SUB_BIT_EXIST to the list of valid bits.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 drivers/input/touchscreen/zinitix.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 3421b8ffb19b..fdcb80f52c91 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -406,7 +406,7 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
 	u16 x, y;
 
 	if (unlikely(!(p->sub_status &
-		       (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
+		       (SUB_BIT_EXIST | SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
 		dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
 			p->sub_status);
 		return;

-- 
2.54.0


^ permalink raw reply related

* [PATCH 1/5] Input: zinitix - check all available fingers for every touch event
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
  Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
	linux-samsung-soc, Kaustabh Chakraborty
In-Reply-To: <20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org>

When this initial driver was first added to tree, that is, in commit
26822652c85e ("Input: add zinitix touchscreen driver"), the touch_event
struct had a field called finger_cnt. It was supposed to report how many
fingers are touching the screen.

But then, in commit e941dc13fd37 ("Input: zinitix - do not report shadow
fingers"), some touchscreens reportedly exposed a bit mask for the
fingers, instead of the count. So the code was changed to bitwise
iteration.

With my testing on the ZT7548 touchscreen of the Galaxy J6, I find the
former to be true. This shows that there's two valid methods depending
on what hardware the driver is made to work on.

One solution is to implement both methods, and use some flag to select
between the two. However, this introduces more implementation overhead,
and a possibility of regression on devices the driver is expected to work.

Instead, unconditionally check all fingers. The finger_mask field is now
left unused, thus serving as padding bytes in the struct. For each
finger, zinitix_report_finger() is called if the status reports the
SUB_BIT_EXIST bit, so phantom fingers are not going to be a thing.

Moreover, the android driver [1] does exactly that, so it's a tried
method of implementation.

Link: https://android.googlesource.com/kernel/bcm/+/23d376ef33aa4c500a5ea24a290f029d5f8e2de3/drivers/input/touchscreen/zinitix_touch.c#1942 [1]
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 drivers/input/touchscreen/zinitix.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 0c36765bd79f..3421b8ffb19b 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -445,7 +445,6 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
 	struct bt541_ts_data *bt541 = bt541_handler;
 	struct i2c_client *client = bt541->client;
 	struct touch_event touch_event;
-	unsigned long finger_mask;
 	__le16 icon_events;
 	int error;
 	int i;
@@ -470,8 +469,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
 		zinitix_report_keys(bt541, le16_to_cpu(icon_events));
 	}
 
-	finger_mask = touch_event.finger_mask;
-	for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
+	for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {
 		const struct point_coord *p = &touch_event.point_coord[i];
 
 		/* Only process contacts that are actually reported */

-- 
2.54.0


^ permalink raw reply related

* [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte)
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
  Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
	linux-samsung-soc, Kaustabh Chakraborty

The zinitix family of touchscreens support at least three modes, called
0, 1, and 2. At least some digitizers (including, but not limited to
ZT7548) are able to support multiple modes. Currently, the driver in
linux supports mode 2 only. This series aims to add support for modes 0
and 1, accompanied with necessary architectural changes.

Among other things, perhaps the biggest difference between multiple
modes is how the touch report schema is laid out. Modes may skip
reporting certain properties such as touch width and pressure. For more
implementation details, the android driver [1] can be referred to, which
was also the primary reference material for these changes.

The last patch is for the Samsung Galaxy J6 (samsung-j6lte), which has a
zinitix touchscreen digitizer. By default, mode 2 is assumed for the
touchscreen, however the downstream kernel driver [1] for this device
uses mode 0 by default. This creates an issue with aftermarket
digitizers where mode 2 implementation isn't available simply because
it's not required by the driver downstream.

This last patch needs to be accepted into next only when the former
patches are in next.  

[1] https://github.com/samsungexynos7870/android_kernel_samsung_exynos7870/blob/master/drivers/input/touchscreen/zinitix/zinitix_zt75xx_ts.c

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
Kaustabh Chakraborty (5):
      Input: zinitix - check all available fingers for every touch event
      Input: zinitix - do not ignore non-moving fingers
      Input: zinitix - add support for modes 0 and 1
      dt-bindings: input/ts/zinitix: document mode 0
      arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen

 .../bindings/input/touchscreen/zinitix,bt400.yaml  |   4 +-
 arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts    |   2 +
 drivers/input/touchscreen/zinitix.c                | 144 +++++++++++++++++++--
 3 files changed, 136 insertions(+), 14 deletions(-)
---
base-commit: 290aaf24a551d5a0dce037e3fab30820f9113a10
change-id: 20260723-zinitix-modes-9c4d409b9ee3

Best regards,
--  
Kaustabh Chakraborty <kauschluss@disroot.org>


^ permalink raw reply

* [PATCH 16/36] Input: remove conditional return with no effect
From: Sang-Heon Jeon @ 2026-07-23 18:45 UTC (permalink / raw)
  To: Julia.Lawall, Dmitry Torokhov; +Cc: cocci, linux-input, linux-kernel
In-Reply-To: <20260723184538.3888637-1-ekffu200098@gmail.com>

Both branches of the check return the same value, so the check has
no effect. Remove it and return the value directly.

This is the result of running the Coccinelle script from
scripts/coccinelle/misc/cond_return_no_effect.cocci.

Signed-off-by: Sang-Heon Jeon <ekffu200098@gmail.com>
---
 drivers/input/keyboard/pmic8xxx-keypad.c | 8 +-------
 drivers/input/mouse/synaptics_i2c.c      | 6 +-----
 drivers/input/rmi4/rmi_smbus.c           | 7 +------
 3 files changed, 3 insertions(+), 18 deletions(-)

diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 35d1aa2a22a5..c916e80e2f58 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -462,15 +462,9 @@ static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
 
 static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
 {
-	int rc;
-
 	kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
 
-	rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);
-	if (rc < 0)
-		return rc;
-
-	return rc;
+	return regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);
 }
 
 static int pmic8xxx_kp_open(struct input_dev *dev)
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index d4cf982f1263..85e37e2ce45b 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -257,11 +257,7 @@ static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val)
 	if (error)
 		return error;
 
-	error = i2c_smbus_write_byte_data(client, reg & 0xff, val);
-	if (error)
-		return error;
-
-	return error;
+	return i2c_smbus_write_byte_data(client, reg & 0xff, val);
 }
 
 static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg)
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
index 6de68c602558..3160714a514a 100644
--- a/drivers/input/rmi4/rmi_smbus.c
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -177,13 +177,8 @@ static int smb_block_read(struct rmi_transport_dev *xport,
 	struct rmi_smb_xport *rmi_smb =
 		container_of(xport, struct rmi_smb_xport, xport);
 	struct i2c_client *client = rmi_smb->client;
-	int retval;
 
-	retval = i2c_smbus_read_block_data(client, commandcode, buf);
-	if (retval < 0)
-		return retval;
-
-	return retval;
+	return i2c_smbus_read_block_data(client, commandcode, buf);
 }
 
 static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
-- 
2.43.0


^ permalink raw reply related

* [PATCH 00/36] treewide: remove conditional returns with no effect
From: Sang-Heon Jeon @ 2026-07-23 18:45 UTC (permalink / raw)
  To: Julia.Lawall, Alex Deucher, Alexander Shishkin, Alexandre Belloni,
	Andrew Lunn, Andrew Morton, Arkadiusz Kubalewski, Borislav Petkov,
	Christian König, Daniel Lezcano, David Airlie,
	David S. Miller, Dmitry Torokhov, Eric Dumazet, Florian Westphal,
	Greg Kroah-Hartman, Hans de Goede, Hans Verkuil, Heikki Krogerus,
	Herbert Xu, Ilpo Järvinen, Jakub Kicinski,
	James E.J. Bottomley, Jani Nikula, Jaroslav Kysela,
	Jason Gunthorpe, Jiri Pirko, Joerg Roedel (AMD), Johan Hovold,
	Jonathan Cameron, Joonas Lahtinen, Julian Anastasov,
	Leon Romanovsky, Liam Girdwood, Linus Walleij, Maarten Lankhorst,
	Mark Brown, Martin K. Petersen, Matthew Sakai,
	Mauro Carvalho Chehab, Maxime Ripard, Michael Turquette,
	Mike Rapoport, Miri Korenblit, Nicolas Palix, Pablo Neira Ayuso,
	Paolo Abeni, Ping-Ke Shih, Rafael J. Wysocki, Rodrigo Vivi,
	Sebastian Reichel, Shuah Khan, Simona Vetter, Simon Horman,
	Stephen Boyd, Steve French, Takashi Iwai, Thomas Renninger,
	Thomas Zimmermann, Tony Luck, Tvrtko Ursulin, Vadim Fedorenko,
	Vinod Koul, Will Deacon, Yazen Ghannam
  Cc: cocci, amd-gfx, dmaengine, dm-devel, dri-devel, intel-gfx,
	intel-wired-lan, iommu, linux-cifs, linux-clk, linux-crypto,
	linux-edac, linux-gpio, linux-iio, linux-input, linux-kernel,
	linux-media, linux-mm, linux-pm, linux-rdma, linux-rtc,
	linux-s390, linux-scsi, linux-sound, linux-usb, linux-wireless,
	lvs-devel, netdev, netfilter-devel, nouveau, platform-driver-x86

Hello,

While reading mm/memblock, I found a conditional return where both
branches return the same value:

	err = do_something();
	if (err)
		return err;
	return err;

Such code is usually a leftover from removing a statement between
the two returns, and the tree has about a hundred of these.

Patch 1 adds a Coccinelle script that matches the pattern, including
negation and constant-comparison variants. Where a local variable is
assigned right before the check, the assignment and the two returns
turn into a single return of the assigned expression.

Patches 2-36 are generated by the script, with hand fixes to restore
unexpectedly removed comments and to fix the formatting checkpatch.pl
complained about.

The patches are grouped by subsystem instead of split per file. If
you would rather split, merge or drop your part, just let me know
and I will address it in the next version.

All patches are independent and can be applied separately, but for
everyone's convenience, it would be nice if they were merged through
a single tree.

The series is based on next-20260721.

Sang-Heon Jeon (36):
  coccinelle: misc: add cond_return_no_effect.cocci
  drm/amd: remove conditional return with no effect
  drm/radeon: remove conditional return with no effect
  dpll: zl3073x: remove conditional return with no effect
  drm/i915: remove conditional return with no effect
  drm: remove conditional return with no effect
  net: ethernet: remove conditional return with no effect
  net: remove conditional return with no effect
  net: intel: remove conditional return with no effect
  wifi: remove conditional return with no effect
  ipvs: remove conditional return with no effect
  media: remove conditional return with no effect
  ALSA: remove conditional return with no effect
  ASoC: remove conditional return with no effect
  iio: remove conditional return with no effect
  Input: remove conditional return with no effect
  clk: remove conditional return with no effect
  crypto: drivers - remove conditional return with no effect
  dmaengine: qcom_hidma: remove conditional return with no effect
  stm class: remove conditional return with no effect
  RDMA/ocrdma: remove conditional return with no effect
  iommu/s390: remove conditional return with no effect
  dm vdo: remove conditional return with no effect
  pinctrl: mediatek: remove conditional return with no effect
  platform/x86: toshiba_haps: remove conditional return with no effect
  power: supply: pm8916_lbc: remove conditional return with no effect
  RAS/AMD/ATL: remove conditional return with no effect
  regulator: wm831x-isink: remove conditional return with no effect
  rtc: pcf2127: remove conditional return with no effect
  scsi: mpt3sas: remove conditional return with no effect
  thermal/drivers/k3_bandgap: remove conditional return with no effect
  USB: serial: ch341: remove conditional return with no effect
  usb: typec: fusb302: remove conditional return with no effect
  smb: client: remove conditional return with no effect
  cpupower: remove conditional return with no effect
  memblock: remove conditional return with no effect

 drivers/clk/clk-cs2000-cp.c                   |   6 +-
 drivers/clk/clk-lmk04832.c                    |  12 +-
 .../intel/qat/qat_common/adf_gen2_config.c    |   8 +-
 .../marvell/octeontx2/otx2_cpt_mbox_common.c  |   7 +-
 drivers/dma/qcom/hidma_ll.c                   |   6 +-
 drivers/dpll/zl3073x/dpll.c                   |   6 +-
 drivers/dpll/zl3073x/out.c                    |   8 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c         |   6 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c         |   6 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c       |   6 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c      |   6 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c        |   6 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c        |   6 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c        |   6 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c         |   6 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c         |   6 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c         |   6 +-
 drivers/gpu/drm/amd/amdgpu/vce_v4_0.c         |   6 +-
 drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c    |  32 ++---
 drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c    |   6 +-
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c     |   6 +-
 .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c |   6 +-
 .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c   |   6 +-
 .../gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c    |  19 +--
 .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c  |   7 +-
 .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c   |   7 +-
 .../drm/amd/pm/swsmu/smu13/aldebaran_ppt.c    |   6 +-
 .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c    |  19 +--
 .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c  |   6 +-
 .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c  |  10 +-
 .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c  |   6 +-
 .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c    |  19 +--
 .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c  |   6 +-
 .../gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c    |   9 +-
 .../drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c  |  16 +--
 drivers/gpu/drm/i915/display/intel_hdmi.c     |   7 +-
 drivers/gpu/drm/i915/gvt/gtt.c                |   8 +-
 drivers/gpu/drm/imx/ipuv3/imx-drm-core.c      |   6 +-
 drivers/gpu/drm/nouveau/dispnv50/disp.c       |  14 +-
 .../drm/panel/panel-osd-osd101t2587-53ts.c    |   7 +-
 drivers/gpu/drm/radeon/ci_dpm.c               |   6 +-
 drivers/gpu/drm/radeon/kv_dpm.c               |  30 ++---
 drivers/gpu/drm/radeon/si_dpm.c               |  14 +-
 drivers/gpu/drm/tilcdc/tilcdc_drv.c           |   6 +-
 drivers/hwtracing/stm/core.c                  |   8 +-
 drivers/iio/light/isl29028.c                  |   6 +-
 drivers/iio/light/tsl2583.c                   |  14 +-
 drivers/iio/magnetometer/ak8974.c             |   6 +-
 drivers/infiniband/hw/ocrdma/ocrdma_verbs.c   |   7 +-
 drivers/input/keyboard/pmic8xxx-keypad.c      |   8 +-
 drivers/input/mouse/synaptics_i2c.c           |   6 +-
 drivers/input/rmi4/rmi_smbus.c                |   7 +-
 drivers/iommu/s390-iommu.c                    |   8 +-
 drivers/md/dm-vdo/encodings.c                 |   8 +-
 drivers/media/i2c/mt9p031.c                   |   6 +-
 .../microchip/microchip-sama7g5-isc.c         |   7 +-
 .../media/platform/qcom/iris/iris_resources.c |   6 +-
 .../media/platform/qcom/venus/pm_helpers.c    |   7 +-
 drivers/media/platform/renesas/rcar-csi2.c    |   6 +-
 .../platform/samsung/s3c-camif/camif-core.c   |   7 +-
 drivers/media/usb/dvb-usb-v2/mxl111sf.c       |  12 +-
 drivers/media/usb/gspca/jl2005bcd.c           |   7 +-
 drivers/net/ethernet/amazon/ena/ena_netdev.c  |   6 +-
 .../ethernet/aquantia/atlantic/aq_macsec.c    |   6 +-
 .../ethernet/freescale/dpaa2/dpaa2-switch.c   |   6 +-
 drivers/net/ethernet/freescale/gianfar.c      |   6 +-
 drivers/net/ethernet/intel/i40e/i40e_main.c   |   8 +-
 drivers/net/ethernet/intel/igb/e1000_i210.c   |   6 +-
 drivers/net/ethernet/intel/igc/igc_phy.c      |   6 +-
 .../ethernet/qlogic/netxen/netxen_nic_hw.c    |   7 +-
 .../ethernet/qlogic/qlcnic/qlcnic_83xx_init.c |   6 +-
 drivers/net/ethernet/renesas/rtsn.c           |   7 +-
 drivers/net/phy/microchip_t1.c                |   6 +-
 drivers/net/pse-pd/tps23881.c                 |   6 +-
 drivers/net/wireless/ath/ath6kl/init.c        |   6 +-
 drivers/net/wireless/intel/iwlwifi/mvm/link.c |   6 +-
 .../wireless/realtek/rtlwifi/rtl8821ae/hw.c   |   7 +-
 drivers/net/wireless/realtek/rtw89/mac.c      |   6 +-
 drivers/net/wireless/realtek/rtw89/mac_be.c   |   6 +-
 .../pinctrl/mediatek/pinctrl-mtk-common-v2.c  |   6 +-
 drivers/platform/x86/toshiba_haps.c           |   6 +-
 drivers/power/supply/pm8916_lbc.c             |   8 +-
 drivers/ras/amd/atl/map.c                     |   6 +-
 drivers/regulator/wm831x-isink.c              |   6 +-
 drivers/rtc/rtc-pcf2127.c                     |   7 +-
 drivers/scsi/mpt3sas/mpt3sas_base.c           |   6 +-
 drivers/thermal/k3_bandgap.c                  |   7 +-
 drivers/usb/serial/ch341.c                    |   8 +-
 drivers/usb/typec/tcpm/fusb302.c              |  14 +-
 fs/smb/client/smb1maperror.c                  |   6 +-
 mm/memblock.c                                 |   7 +-
 net/netfilter/ipvs/ip_vs_sync.c               |   7 +-
 .../misc/cond_return_no_effect.cocci          | 121 ++++++++++++++++++
 sound/pci/echoaudio/echoaudio_dsp.c           |   6 +-
 sound/pci/echoaudio/layla24_dsp.c             |   6 +-
 sound/pci/riptide/riptide.c                   |   5 +-
 sound/soc/amd/acp/acp-mach-common.c           |  11 +-
 sound/soc/intel/atom/sst-mfld-platform-pcm.c  |   7 +-
 sound/soc/samsung/smdk_spdif.c                |   8 +-
 sound/soc/sof/intel/hda-dsp.c                 |   6 +-
 sound/usb/mixer_scarlett.c                    |  26 ++--
 tools/power/cpupower/utils/powercap-info.c    |   2 -
 102 files changed, 295 insertions(+), 643 deletions(-)
 create mode 100644 scripts/coccinelle/misc/cond_return_no_effect.cocci

--
2.43.0


^ permalink raw reply

* [PATCH v6] Input: gunze: replace deprecated APIs and fix warning style
From: Bivash Kumar Singh @ 2026-07-23 18:40 UTC (permalink / raw)
  To: linux-input; +Cc: dmitry.torokhov, Bivash Kumar Singh
In-Reply-To: <20260718190040.10613-1-bivashraj750@gmail.com>

Replace printk(KERN_WARNING) with dev_warn_ratelimited(), and
simple_strtoul() with sscanf() to parse the coordinate data.
NUL-terminate the receive buffer in gunze_interrupt() so it can
safely be treated as a string.

Enlarge gunze->data by one byte to avoid the NUL terminator
overflowing into the adjacent phys field. Also report BTN_TOUCH
release on a corrupted 'R' packet so touch state can't get stuck
down.

Signed-off-by: Bivash Kumar Singh <bivashraj750@gmail.com>
---
Changes in v6:
  - Enlarge gunze->data[] by one byte (GUNZE_MAX_LENGTH + 1) to fix
    an off-by-one overflow: NUL-terminating a full-length packet at
    gunze->data[gunze->idx] wrote one byte past the array into the
    adjacent phys field. (reported by Sashiko AI review)
  - Restore BTN_TOUCH release reporting when sscanf() fails to parse
    coordinates on a release ('R') packet, so touch state cannot get
    stuck down.

Changes in v5:
  - Switch from kstrtoul() to sscanf() as suggested by Dmitry Torokhov.
    sscanf() naturally handles comma-separated coordinate data without
    needing a local buffer copy or manual NUL termination tricks.
  - NUL-terminate receive buffer in gunze_interrupt() before processing.
  - Use dev_warn_ratelimited() to prevent log spam on noisy serial lines.

Changes in v4:
  - Remove early return on kstrtoul() failure to prevent touch state
    getting permanently stuck if a release packet contains noisy data.
    Initialize x and y to 0 as safe fallback values instead.
    (reported by Sashiko AI review)

Changes in v3:
  - Fix comment style: add space after /* and use NUL instead of NULL
  - Add missing Changes section that was absent in v2

Changes in v2:
  - Copy packet data to a local NUL-terminated buffer before calling
    kstrtoul(), so the comma separator does not cause parsing to fail
    on every valid touch event. (reported by Sashiko AI review)
---
 drivers/input/touchscreen/gunze.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 2baeb4f3b941..e2b1e1d970c6 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -34,22 +34,31 @@ struct gunze {
 	struct input_dev *dev;
 	struct serio *serio;
 	int idx;
-	unsigned char data[GUNZE_MAX_LENGTH];
+	unsigned char data[GUNZE_MAX_LENGTH + 1];
 	char phys[32];
 };
 
 static void gunze_process_packet(struct gunze *gunze)
 {
 	struct input_dev *dev = gunze->dev;
+	unsigned int x, y;
 
-	if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
-		(gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
-		printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data);
+	if (gunze->data[0] != 'T' && gunze->data[0] != 'R') {
+		dev_warn_ratelimited(&gunze->serio->dev, "bad packet: >%s<\n", gunze->data);
 		return;
 	}
 
-	input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
-	input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
+	if (sscanf(gunze->data + 1, "%4u,%4u", &x, &y) != 2) {
+		dev_warn_ratelimited(&gunze->serio->dev, "bad packet: >%s<\n", gunze->data);
+		if (gunze->data[0] == 'R') {
+			input_report_key(dev, BTN_TOUCH, 0);
+			input_sync(dev);
+		}
+		return;
+	}
+
+	input_report_abs(dev, ABS_X, x);
+	input_report_abs(dev, ABS_Y, 1024 - y);
 	input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
 	input_sync(dev);
 }
@@ -60,6 +69,7 @@ static irqreturn_t gunze_interrupt(struct serio *serio,
 	struct gunze *gunze = serio_get_drvdata(serio);
 
 	if (data == '\r') {
+		gunze->data[gunze->idx] = '\0';
 		gunze_process_packet(gunze);
 		gunze->idx = 0;
 	} else {
-- 
2.53.0


^ permalink raw reply related

* [PATCH 12/12] reboot: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:56 UTC (permalink / raw)
  To: rafael, tony.luck, bp, guohanjun, mchehab, xueshuai, lenb,
	laurent.pinchart, linusw, brgl, orsonzhai, baolin.wang,
	zhang.lyra, jic23, dlechner, nuno.sa, andy, dmitry.torokhov,
	hansg, ilpo.jarvinen, W_Armin, ukleinek, fabio.m.de.francesco,
	kaihengf, ankita, leitao, farbere, jason, pedro.pbg, paulmck,
	frederic, kees, linux-acpi, linux-kernel, linux-gpio, linux-pwm,
	linux-iio, linux-input, platform-driver-x86
In-Reply-To: <20260723175632.44812-1-farbere@amazon.com>

Replace the blocking_notifier_chain_register() +
devm_add_action_or_reset() pattern with a single call to
devm_blocking_notifier_chain_register(), removing the
devm_unregister_reboot_notifier() callback.

Signed-off-by: Eliav Farber <farbere@amazon.com>
---
 kernel/reboot.c | 24 ++----------------------
 1 file changed, 2 insertions(+), 22 deletions(-)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index 695c33e75efd..557609419989 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -136,30 +136,10 @@ int unregister_reboot_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_reboot_notifier);
 
-static void devm_unregister_reboot_notifier(struct device *dev, void *res)
-{
-	WARN_ON(unregister_reboot_notifier(*(struct notifier_block **)res));
-}
-
 int devm_register_reboot_notifier(struct device *dev, struct notifier_block *nb)
 {
-	struct notifier_block **rcnb;
-	int ret;
-
-	rcnb = devres_alloc(devm_unregister_reboot_notifier,
-			    sizeof(*rcnb), GFP_KERNEL);
-	if (!rcnb)
-		return -ENOMEM;
-
-	ret = register_reboot_notifier(nb);
-	if (!ret) {
-		*rcnb = nb;
-		devres_add(dev, rcnb);
-	} else {
-		devres_free(rcnb);
-	}
-
-	return ret;
+	return devm_blocking_notifier_chain_register(dev,
+						     &reboot_notifier_list, nb);
 }
 EXPORT_SYMBOL(devm_register_reboot_notifier);
 
-- 
2.47.3


^ permalink raw reply related

* [PATCH 11/12] gpio: gpiolib-kunit: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:56 UTC (permalink / raw)
  To: rafael, tony.luck, bp, guohanjun, mchehab, xueshuai, lenb,
	laurent.pinchart, linusw, brgl, orsonzhai, baolin.wang,
	zhang.lyra, jic23, dlechner, nuno.sa, andy, dmitry.torokhov,
	hansg, ilpo.jarvinen, W_Armin, ukleinek, fabio.m.de.francesco,
	kaihengf, ankita, leitao, farbere, jason, pedro.pbg, paulmck,
	frederic, kees, linux-acpi, linux-kernel, linux-gpio, linux-pwm,
	linux-iio, linux-input, platform-driver-x86
In-Reply-To: <20260723175632.44812-1-farbere@amazon.com>

Replace the blocking_notifier_chain_register() +
devm_add_action_or_reset() pattern with a single call to
devm_blocking_notifier_chain_register(), removing the
gpio_unbind_unregister_notifier() callback.

Signed-off-by: Eliav Farber <farbere@amazon.com>
---
 drivers/gpio/gpiolib-kunit.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/drivers/gpio/gpiolib-kunit.c b/drivers/gpio/gpiolib-kunit.c
index 380b68f879e5..8ce9acc89e29 100644
--- a/drivers/gpio/gpiolib-kunit.c
+++ b/drivers/gpio/gpiolib-kunit.c
@@ -237,13 +237,6 @@ static int gpio_unbind_notify(struct notifier_block *nb, unsigned long action,
 	return NOTIFY_OK;
 }
 
-static void gpio_unbind_unregister_notifier(void *data)
-{
-	struct notifier_block *nb = data;
-
-	blocking_notifier_chain_unregister(&gpio_unbind_notifier, nb);
-}
-
 static int gpio_unbind_consumer_probe(struct platform_device *pdev)
 {
 	struct gpio_unbind_consumer_drvdata *data;
@@ -261,11 +254,8 @@ static int gpio_unbind_consumer_probe(struct platform_device *pdev)
 		return PTR_ERR(data->desc);
 
 	data->nb.notifier_call = gpio_unbind_notify;
-	ret = blocking_notifier_chain_register(&gpio_unbind_notifier, &data->nb);
-	if (ret)
-		return ret;
-
-	ret = devm_add_action_or_reset(dev, gpio_unbind_unregister_notifier, &data->nb);
+	ret = devm_blocking_notifier_chain_register(dev, &gpio_unbind_notifier,
+						    &data->nb);
 	if (ret)
 		return ret;
 
-- 
2.47.3


^ permalink raw reply related

* [PATCH 10/12] gpio: eic-sprd: use devm_atomic_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:56 UTC (permalink / raw)
  To: rafael, tony.luck, bp, guohanjun, mchehab, xueshuai, lenb,
	laurent.pinchart, linusw, brgl, orsonzhai, baolin.wang,
	zhang.lyra, jic23, dlechner, nuno.sa, andy, dmitry.torokhov,
	hansg, ilpo.jarvinen, W_Armin, ukleinek, fabio.m.de.francesco,
	kaihengf, ankita, leitao, farbere, jason, pedro.pbg, paulmck,
	frederic, kees, linux-acpi, linux-kernel, linux-gpio, linux-pwm,
	linux-iio, linux-input, platform-driver-x86

Replace the atomic_notifier_chain_register() +
devm_add_action_or_reset() pattern with a single call to
devm_atomic_notifier_chain_register(), removing the
sprd_eic_unregister_notifier() callback.

Signed-off-by: Eliav Farber <farbere@amazon.com>
---
 drivers/gpio/gpio-eic-sprd.c | 17 ++---------------
 1 file changed, 2 insertions(+), 15 deletions(-)

diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
index 3b7ebcf12fe7..86eb9624d38a 100644
--- a/drivers/gpio/gpio-eic-sprd.c
+++ b/drivers/gpio/gpio-eic-sprd.c
@@ -601,13 +601,6 @@ static const struct irq_chip sprd_eic_irq = {
 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
-static void sprd_eic_unregister_notifier(void *data)
-{
-	struct notifier_block *nb = data;
-
-	atomic_notifier_chain_unregister(&sprd_eic_irq_notifier, nb);
-}
-
 static int sprd_eic_probe(struct platform_device *pdev)
 {
 	const struct sprd_eic_variant_data *pdata;
@@ -690,14 +683,8 @@ static int sprd_eic_probe(struct platform_device *pdev)
 	}
 
 	sprd_eic->irq_nb.notifier_call = sprd_eic_irq_notify;
-	ret = atomic_notifier_chain_register(&sprd_eic_irq_notifier,
-					     &sprd_eic->irq_nb);
-	if (ret)
-		return dev_err_probe(dev, ret,
-				     "Failed to register with the interrupt notifier");
-
-	return devm_add_action_or_reset(dev, sprd_eic_unregister_notifier,
-					&sprd_eic->irq_nb);
+	return devm_atomic_notifier_chain_register(dev, &sprd_eic_irq_notifier,
+						   &sprd_eic->irq_nb);
 }
 
 static const struct of_device_id sprd_eic_of_match[] = {
-- 
2.47.3


^ permalink raw reply related

* [PATCH 09/12] platform/x86: uniwill-wmi: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:55 UTC (permalink / raw)
  To: rafael, tony.luck, bp, guohanjun, mchehab, xueshuai, lenb,
	laurent.pinchart, linusw, brgl, orsonzhai, baolin.wang,
	zhang.lyra, jic23, dlechner, nuno.sa, andy, dmitry.torokhov,
	hansg, ilpo.jarvinen, W_Armin, ukleinek, fabio.m.de.francesco,
	kaihengf, ankita, leitao, farbere, jason, pedro.pbg, paulmck,
	frederic, kees, linux-acpi, linux-kernel, linux-gpio, linux-pwm,
	linux-iio, linux-input, platform-driver-x86
In-Reply-To: <20260723175513.39849-1-farbere@amazon.com>

Replace the blocking_notifier_chain_register() +
devm_add_action_or_reset() pattern with a single call to
devm_blocking_notifier_chain_register(), removing the
devm_uniwill_wmi_unregister_notifier() callback.

Signed-off-by: Eliav Farber <farbere@amazon.com>
---
 drivers/platform/x86/uniwill/uniwill-wmi.c | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.c b/drivers/platform/x86/uniwill/uniwill-wmi.c
index afcbfa4f7552..2ffa29a829ee 100644
--- a/drivers/platform/x86/uniwill/uniwill-wmi.c
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.c
@@ -26,22 +26,11 @@
 
 static BLOCKING_NOTIFIER_HEAD(uniwill_wmi_chain_head);
 
-static void devm_uniwill_wmi_unregister_notifier(void *data)
-{
-	struct notifier_block *nb = data;
-
-	blocking_notifier_chain_unregister(&uniwill_wmi_chain_head, nb);
-}
-
 int devm_uniwill_wmi_register_notifier(struct device *dev, struct notifier_block *nb)
 {
-	int ret;
-
-	ret = blocking_notifier_chain_register(&uniwill_wmi_chain_head, nb);
-	if (ret < 0)
-		return ret;
-
-	return devm_add_action_or_reset(dev, devm_uniwill_wmi_unregister_notifier, nb);
+	return devm_blocking_notifier_chain_register(dev,
+						     &uniwill_wmi_chain_head,
+						     nb);
 }
 
 static void uniwill_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)
-- 
2.47.3


^ permalink raw reply related

* [PATCH 08/12] ACPI: APEI: GHES: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:55 UTC (permalink / raw)
  To: rafael, tony.luck, bp, guohanjun, mchehab, xueshuai, lenb,
	laurent.pinchart, linusw, brgl, orsonzhai, baolin.wang,
	zhang.lyra, jic23, dlechner, nuno.sa, andy, dmitry.torokhov,
	hansg, ilpo.jarvinen, W_Armin, ukleinek, fabio.m.de.francesco,
	kaihengf, ankita, leitao, farbere, jason, pedro.pbg, paulmck,
	frederic, kees, linux-acpi, linux-kernel, linux-gpio, linux-pwm,
	linux-iio, linux-input, platform-driver-x86
In-Reply-To: <20260723175513.39849-1-farbere@amazon.com>

Replace the blocking_notifier_chain_register() +
devm_add_action_or_reset() pattern with a single call to
devm_blocking_notifier_chain_register(), removing the
ghes_vendor_record_notifier_destroy() callback.

Signed-off-by: Eliav Farber <farbere@amazon.com>
---
 drivers/acpi/apei/ghes.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 3236a3ce79d6..3aa29dcd70da 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -689,21 +689,12 @@ void ghes_unregister_vendor_record_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(ghes_unregister_vendor_record_notifier);
 
-static void ghes_vendor_record_notifier_destroy(void *nb)
-{
-	ghes_unregister_vendor_record_notifier(nb);
-}
-
 int devm_ghes_register_vendor_record_notifier(struct device *dev,
 					      struct notifier_block *nb)
 {
-	int ret;
-
-	ret = ghes_register_vendor_record_notifier(nb);
-	if (ret)
-		return ret;
-
-	return devm_add_action_or_reset(dev, ghes_vendor_record_notifier_destroy, nb);
+	return devm_blocking_notifier_chain_register(dev,
+						     &vendor_record_notify_list,
+						     nb);
 }
 EXPORT_SYMBOL_GPL(devm_ghes_register_vendor_record_notifier);
 
-- 
2.47.3


^ permalink raw reply related

* [PATCH 07/12] Input: adp5585: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:55 UTC (permalink / raw)
  To: rafael, tony.luck, bp, guohanjun, mchehab, xueshuai, lenb,
	laurent.pinchart, linusw, brgl, orsonzhai, baolin.wang,
	zhang.lyra, jic23, dlechner, nuno.sa, andy, dmitry.torokhov,
	hansg, ilpo.jarvinen, W_Armin, ukleinek, fabio.m.de.francesco,
	kaihengf, ankita, leitao, farbere, jason, pedro.pbg, paulmck,
	frederic, kees, linux-acpi, linux-kernel, linux-gpio, linux-pwm,
	linux-iio, linux-input, platform-driver-x86
In-Reply-To: <20260723175513.39849-1-farbere@amazon.com>

Replace the blocking_notifier_chain_register() +
devm_add_action_or_reset() pattern with a single call to
devm_blocking_notifier_chain_register(), removing the
adp5585_keys_unreg_notifier() callback.

Signed-off-by: Eliav Farber <farbere@amazon.com>
---
 drivers/input/keyboard/adp5585-keys.c | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/drivers/input/keyboard/adp5585-keys.c b/drivers/input/keyboard/adp5585-keys.c
index 017c95029180..0be4cc234c21 100644
--- a/drivers/input/keyboard/adp5585-keys.c
+++ b/drivers/input/keyboard/adp5585-keys.c
@@ -254,15 +254,6 @@ static int adp5585_keys_ev_handle(struct notifier_block *nb, unsigned long key,
 	return NOTIFY_STOP;
 }
 
-static void adp5585_keys_unreg_notifier(void *data)
-{
-	struct adp5585_kpad *kpad = data;
-	struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent);
-
-	blocking_notifier_chain_unregister(&adp5585->event_notifier,
-					   &kpad->nb);
-}
-
 static int adp5585_keys_probe(struct platform_device *pdev)
 {
 	const struct platform_device_id *id = platform_get_device_id(pdev);
@@ -318,12 +309,9 @@ static int adp5585_keys_probe(struct platform_device *pdev)
 		return error;
 
 	kpad->nb.notifier_call = adp5585_keys_ev_handle;
-	error = blocking_notifier_chain_register(&adp5585->event_notifier,
-						 &kpad->nb);
-	if (error)
-		return error;
-
-	error = devm_add_action_or_reset(dev, adp5585_keys_unreg_notifier, kpad);
+	error = devm_blocking_notifier_chain_register(dev,
+						      &adp5585->event_notifier,
+						      &kpad->nb);
 	if (error)
 		return error;
 
-- 
2.47.3


^ permalink raw reply related


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