* [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
* [PATCH 06/12] platform/x86: bitland-mifs-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
bitland_notifier_unregister() callback.
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 3a373184519d..2bcd4f692a74 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -623,13 +623,6 @@ static const struct key_entry bitland_mifs_wmi_keymap[] = {
{ KE_END, 0 }
};
-static void bitland_notifier_unregister(void *data)
-{
- struct notifier_block *nb = data;
-
- blocking_notifier_chain_unregister(&bitland_notifier_list, nb);
-}
-
static int bitland_notifier_callback(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -729,13 +722,9 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
return ret;
drv_data->notifier.notifier_call = bitland_notifier_callback;
- ret = blocking_notifier_chain_register(&bitland_notifier_list, &drv_data->notifier);
- if (ret)
- return ret;
-
- return devm_add_action_or_reset(&wdev->dev,
- bitland_notifier_unregister,
- &drv_data->notifier);
+ return devm_blocking_notifier_chain_register(&wdev->dev,
+ &bitland_notifier_list,
+ &drv_data->notifier);
}
static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
--
2.47.3
^ permalink raw reply related
* [PATCH 05/12] gpio: 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
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_gpio_unreg_notifier() callback.
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
drivers/gpio/gpio-adp5585.c | 20 +++-----------------
1 file changed, 3 insertions(+), 17 deletions(-)
diff --git a/drivers/gpio/gpio-adp5585.c b/drivers/gpio/gpio-adp5585.c
index 6f10fc646008..7c04a7e86c8f 100644
--- a/drivers/gpio/gpio-adp5585.c
+++ b/drivers/gpio/gpio-adp5585.c
@@ -390,16 +390,6 @@ static const struct irq_chip adp5585_irq_chip = {
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
-static void adp5585_gpio_unreg_notifier(void *data)
-{
- struct adp5585_gpio_dev *adp5585_gpio = data;
- struct device *dev = adp5585_gpio->gpio_chip.parent;
- struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
-
- blocking_notifier_chain_unregister(&adp5585->event_notifier,
- &adp5585_gpio->nb);
-}
-
static int adp5585_gpio_probe(struct platform_device *pdev)
{
struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent);
@@ -450,13 +440,9 @@ static int adp5585_gpio_probe(struct platform_device *pdev)
girq->threaded = true;
adp5585_gpio->nb.notifier_call = adp5585_gpio_key_event;
- ret = blocking_notifier_chain_register(&adp5585->event_notifier,
- &adp5585_gpio->nb);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, adp5585_gpio_unreg_notifier,
- adp5585_gpio);
+ ret = devm_blocking_notifier_chain_register(dev,
+ &adp5585->event_notifier,
+ &adp5585_gpio->nb);
if (ret)
return ret;
}
--
2.47.3
^ permalink raw reply related
* [PATCH 04/12] iio: position: iqs624: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:53 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: <20260723175325.37397-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
iqs624_pos_notifier_unregister() callback.
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
drivers/iio/position/iqs624-pos.c | 24 +++---------------------
1 file changed, 3 insertions(+), 21 deletions(-)
diff --git a/drivers/iio/position/iqs624-pos.c b/drivers/iio/position/iqs624-pos.c
index 8239239c6ee2..d2aa2df71457 100644
--- a/drivers/iio/position/iqs624-pos.c
+++ b/drivers/iio/position/iqs624-pos.c
@@ -96,19 +96,6 @@ static int iqs624_pos_notifier(struct notifier_block *notifier,
return ret;
}
-static void iqs624_pos_notifier_unregister(void *context)
-{
- struct iqs624_pos_private *iqs624_pos = context;
- struct iio_dev *indio_dev = iqs624_pos->indio_dev;
- int ret;
-
- ret = blocking_notifier_chain_unregister(&iqs624_pos->iqs62x->nh,
- &iqs624_pos->notifier);
- if (ret)
- dev_err(indio_dev->dev.parent,
- "Failed to unregister notifier: %d\n", ret);
-}
-
static int iqs624_pos_angle_get(struct iqs62x_core *iqs62x, unsigned int *val)
{
int ret;
@@ -255,19 +242,14 @@ static int iqs624_pos_probe(struct platform_device *pdev)
mutex_init(&iqs624_pos->lock);
iqs624_pos->notifier.notifier_call = iqs624_pos_notifier;
- ret = blocking_notifier_chain_register(&iqs624_pos->iqs62x->nh,
- &iqs624_pos->notifier);
+ ret = devm_blocking_notifier_chain_register(&pdev->dev,
+ &iqs624_pos->iqs62x->nh,
+ &iqs624_pos->notifier);
if (ret) {
dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
return ret;
}
- ret = devm_add_action_or_reset(&pdev->dev,
- iqs624_pos_notifier_unregister,
- iqs624_pos);
- if (ret)
- return ret;
-
return devm_iio_device_register(&pdev->dev, indio_dev);
}
--
2.47.3
^ permalink raw reply related
* [PATCH 03/12] iio: light: iqs621-als: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:53 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: <20260723175325.37397-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
iqs621_als_notifier_unregister() callback.
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
drivers/iio/light/iqs621-als.c | 24 +++---------------------
1 file changed, 3 insertions(+), 21 deletions(-)
diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c
index cd5843e3e2c3..f9d215ef1970 100644
--- a/drivers/iio/light/iqs621-als.c
+++ b/drivers/iio/light/iqs621-als.c
@@ -179,19 +179,6 @@ static int iqs621_als_notifier(struct notifier_block *notifier,
return NOTIFY_OK;
}
-static void iqs621_als_notifier_unregister(void *context)
-{
- struct iqs621_als_private *iqs621_als = context;
- struct iio_dev *indio_dev = iqs621_als->indio_dev;
- int ret;
-
- ret = blocking_notifier_chain_unregister(&iqs621_als->iqs62x->nh,
- &iqs621_als->notifier);
- if (ret)
- dev_err(indio_dev->dev.parent,
- "Failed to unregister notifier: %d\n", ret);
-}
-
static int iqs621_als_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -563,19 +550,14 @@ static int iqs621_als_probe(struct platform_device *pdev)
mutex_init(&iqs621_als->lock);
iqs621_als->notifier.notifier_call = iqs621_als_notifier;
- ret = blocking_notifier_chain_register(&iqs621_als->iqs62x->nh,
- &iqs621_als->notifier);
+ ret = devm_blocking_notifier_chain_register(&pdev->dev,
+ &iqs621_als->iqs62x->nh,
+ &iqs621_als->notifier);
if (ret) {
dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
return ret;
}
- ret = devm_add_action_or_reset(&pdev->dev,
- iqs621_als_notifier_unregister,
- iqs621_als);
- if (ret)
- return ret;
-
return devm_iio_device_register(&pdev->dev, indio_dev);
}
--
2.47.3
^ permalink raw reply related
* [PATCH 02/12] pwm: iqs620a: use devm_blocking_notifier_chain_register()
From: Eliav Farber @ 2026-07-23 17:53 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: <20260723175325.37397-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
iqs620_pwm_notifier_unregister() callback.
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
drivers/pwm/pwm-iqs620a.c | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)
diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c
index 13e5e138c8e9..12f7b1415ed4 100644
--- a/drivers/pwm/pwm-iqs620a.c
+++ b/drivers/pwm/pwm-iqs620a.c
@@ -173,17 +173,7 @@ static const struct pwm_ops iqs620_pwm_ops = {
.get_state = iqs620_pwm_get_state,
};
-static void iqs620_pwm_notifier_unregister(void *context)
-{
- struct iqs620_pwm_private *iqs620_pwm = context;
- int ret;
- ret = blocking_notifier_chain_unregister(&iqs620_pwm->iqs62x->nh,
- &iqs620_pwm->notifier);
- if (ret)
- dev_err(iqs620_pwm->dev,
- "Failed to unregister notifier: %d\n", ret);
-}
static int iqs620_pwm_probe(struct platform_device *pdev)
{
@@ -218,19 +208,14 @@ static int iqs620_pwm_probe(struct platform_device *pdev)
mutex_init(&iqs620_pwm->lock);
iqs620_pwm->notifier.notifier_call = iqs620_pwm_notifier;
- ret = blocking_notifier_chain_register(&iqs620_pwm->iqs62x->nh,
- &iqs620_pwm->notifier);
+ ret = devm_blocking_notifier_chain_register(&pdev->dev,
+ &iqs620_pwm->iqs62x->nh,
+ &iqs620_pwm->notifier);
if (ret) {
dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
return ret;
}
- ret = devm_add_action_or_reset(&pdev->dev,
- iqs620_pwm_notifier_unregister,
- iqs620_pwm);
- if (ret)
- return ret;
-
ret = devm_pwmchip_add(&pdev->dev, chip);
if (ret)
dev_err(&pdev->dev, "Failed to add device: %d\n", ret);
--
2.47.3
^ permalink raw reply related
* [PATCH 01/12] notifier: add device-managed registration APIs
From: Eliav Farber @ 2026-07-23 17:53 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: <20260723175325.37397-1-farbere@amazon.com>
Add devm_atomic_notifier_chain_register(),
devm_blocking_notifier_chain_register(), and
devm_raw_notifier_chain_register() that automatically unregister the
notifier when the device is unbound.
Many drivers repeat the same boilerplate pattern:
1. Register the notifier with *_notifier_chain_register()
2. Check for error
3. Register a devm action to unregister on teardown
4. Implement a per-driver static unregister callback
With the new devm_*_notifier_chain_register() APIs, this reduces to a
single call with one error path, eliminating per-driver unregister
callbacks entirely.
The implementation follows the established devres pattern used by other
device-managed kernel APIs.
Signed-off-by: Eliav Farber <farbere@amazon.com>
---
include/linux/notifier.h | 10 +++
kernel/notifier.c | 151 +++++++++++++++++++++++++++++++++++++++
2 files changed, 161 insertions(+)
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 01b6c9d9956f..aa3745d7459b 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -46,6 +46,7 @@
* often but notifier_blocks will seldom be removed.
*/
+struct device;
struct notifier_block;
typedef int (*notifier_fn_t)(struct notifier_block *nb,
@@ -145,10 +146,19 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
struct notifier_block *nb);
+extern int devm_atomic_notifier_chain_register(struct device *dev,
+ struct atomic_notifier_head *nh,
+ struct notifier_block *nb);
extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb);
+extern int devm_blocking_notifier_chain_register(struct device *dev,
+ struct blocking_notifier_head *nh,
+ struct notifier_block *nb);
extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *nb);
+extern int devm_raw_notifier_chain_register(struct device *dev,
+ struct raw_notifier_head *nh,
+ struct notifier_block *nb);
extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
struct notifier_block *nb);
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 2f9fe7c30287..b811638aa878 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/device.h>
#include <linux/kdebug.h>
#include <linux/kprobes.h>
#include <linux/export.h>
@@ -197,6 +198,55 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
}
EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
+struct atomic_notifier_chain_devres {
+ struct atomic_notifier_head *nh;
+ struct notifier_block *nb;
+};
+
+static void devm_atomic_notifier_chain_unregister(struct device *dev, void *res)
+{
+ struct atomic_notifier_chain_devres *dr = res;
+
+ atomic_notifier_chain_unregister(dr->nh, dr->nb);
+}
+
+/**
+ * devm_atomic_notifier_chain_register - Device-managed atomic notifier registration
+ * @dev: Device to tie the notifier lifetime to
+ * @nh: Pointer to head of the atomic notifier chain
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to an atomic notifier chain and registers a cleanup
+ * action to automatically unregister it when @dev is unbound.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int devm_atomic_notifier_chain_register(struct device *dev,
+ struct atomic_notifier_head *nh,
+ struct notifier_block *n)
+{
+ struct atomic_notifier_chain_devres *dr;
+ int ret;
+
+ dr = devres_alloc(devm_atomic_notifier_chain_unregister,
+ sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ ret = atomic_notifier_chain_register(nh, n);
+ if (ret) {
+ devres_free(dr);
+ return ret;
+ }
+
+ dr->nh = nh;
+ dr->nb = n;
+ devres_add(dev, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_atomic_notifier_chain_register);
+
/**
* atomic_notifier_call_chain - Call functions in an atomic notifier chain
* @nh: Pointer to head of the atomic notifier chain
@@ -349,6 +399,57 @@ int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
}
EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_robust);
+struct blocking_notifier_chain_devres {
+ struct blocking_notifier_head *nh;
+ struct notifier_block *nb;
+};
+
+static void devm_blocking_notifier_chain_unregister(struct device *dev,
+ void *res)
+{
+ struct blocking_notifier_chain_devres *dr = res;
+
+ blocking_notifier_chain_unregister(dr->nh, dr->nb);
+}
+
+/**
+ * devm_blocking_notifier_chain_register - Device-managed blocking notifier registration
+ * @dev: Device to tie the notifier lifetime to
+ * @nh: Pointer to head of the blocking notifier chain
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to a blocking notifier chain and registers a cleanup
+ * action to automatically unregister it when @dev is unbound.
+ * Must be called in process context.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int devm_blocking_notifier_chain_register(struct device *dev,
+ struct blocking_notifier_head *nh,
+ struct notifier_block *n)
+{
+ struct blocking_notifier_chain_devres *dr;
+ int ret;
+
+ dr = devres_alloc(devm_blocking_notifier_chain_unregister,
+ sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ ret = blocking_notifier_chain_register(nh, n);
+ if (ret) {
+ devres_free(dr);
+ return ret;
+ }
+
+ dr->nh = nh;
+ dr->nb = n;
+ devres_add(dev, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_blocking_notifier_chain_register);
+
/**
* blocking_notifier_call_chain - Call functions in a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain
@@ -430,6 +531,56 @@ int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
}
EXPORT_SYMBOL_GPL(raw_notifier_call_chain_robust);
+struct raw_notifier_chain_devres {
+ struct raw_notifier_head *nh;
+ struct notifier_block *nb;
+};
+
+static void devm_raw_notifier_chain_unregister(struct device *dev, void *res)
+{
+ struct raw_notifier_chain_devres *dr = res;
+
+ raw_notifier_chain_unregister(dr->nh, dr->nb);
+}
+
+/**
+ * devm_raw_notifier_chain_register - Device-managed raw notifier registration
+ * @dev: Device to tie the notifier lifetime to
+ * @nh: Pointer to head of the raw notifier chain
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to a raw notifier chain and registers a cleanup
+ * action to automatically unregister it when @dev is unbound.
+ * All locking must be provided by the caller.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int devm_raw_notifier_chain_register(struct device *dev,
+ struct raw_notifier_head *nh,
+ struct notifier_block *n)
+{
+ struct raw_notifier_chain_devres *dr;
+ int ret;
+
+ dr = devres_alloc(devm_raw_notifier_chain_unregister,
+ sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ ret = raw_notifier_chain_register(nh, n);
+ if (ret) {
+ devres_free(dr);
+ return ret;
+ }
+
+ dr->nh = nh;
+ dr->nb = n;
+ devres_add(dev, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_raw_notifier_chain_register);
+
/**
* raw_notifier_call_chain - Call functions in a raw notifier chain
* @nh: Pointer to head of the raw notifier chain
--
2.47.3
^ permalink raw reply related
* [PATCH 00/12] notifier: add device-managed registration APIs and convert drivers
From: Eliav Farber @ 2026-07-23 17:53 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
Many drivers repeat the same boilerplate when registering notifiers with
device lifetime:
1. Register the notifier with *_notifier_chain_register()
2. Check for error
3. Register a devm action to unregister on teardown
4. Implement a per-driver static unregister callback
This series adds devm_atomic_notifier_chain_register(),
devm_blocking_notifier_chain_register(), and
devm_raw_notifier_chain_register() that automatically unregister the
notifier when the device is unbound, then converts 11 drivers to use
them.
Each conversion eliminates a per-driver unregister callback and the
associated devm_add_action_or_reset() call, reducing code by ~15 lines
per driver.
The implementation follows the established devres pattern used by other
device-managed kernel APIs.
Checkpatch reports 6 CHECKs (0 errors, 0 warnings) on patch 1:
- "extern prototypes should be avoided in .h files"
- "Alignment should match open parenthesis"
Both are intentional to match the existing coding style in notifier.h,
where all declarations use 'extern' and tab-indented continuation lines.
Eliav Farber (12):
notifier: add device-managed registration APIs
pwm: iqs620a: use devm_blocking_notifier_chain_register()
iio: light: iqs621-als: use devm_blocking_notifier_chain_register()
iio: position: iqs624: use devm_blocking_notifier_chain_register()
gpio: adp5585: use devm_blocking_notifier_chain_register()
platform/x86: bitland-mifs-wmi: use
devm_blocking_notifier_chain_register()
Input: adp5585: use devm_blocking_notifier_chain_register()
ACPI: APEI: GHES: use devm_blocking_notifier_chain_register()
platform/x86: uniwill-wmi: use devm_blocking_notifier_chain_register()
gpio: eic-sprd: use devm_atomic_notifier_chain_register()
gpio: gpiolib-kunit: use devm_blocking_notifier_chain_register()
reboot: use devm_blocking_notifier_chain_register()
drivers/acpi/apei/ghes.c | 15 +-
drivers/gpio/gpio-adp5585.c | 20 +--
drivers/gpio/gpio-eic-sprd.c | 17 +--
drivers/gpio/gpiolib-kunit.c | 14 +-
drivers/iio/light/iqs621-als.c | 24 +---
drivers/iio/position/iqs624-pos.c | 24 +---
drivers/input/keyboard/adp5585-keys.c | 18 +--
drivers/platform/x86/bitland-mifs-wmi.c | 17 +--
drivers/platform/x86/uniwill/uniwill-wmi.c | 17 +--
drivers/pwm/pwm-iqs620a.c | 21 +--
include/linux/notifier.h | 10 ++
kernel/notifier.c | 151 +++++++++++++++++++++
kernel/reboot.c | 24 +---
13 files changed, 191 insertions(+), 181 deletions(-)
--
2.47.3
^ permalink raw reply
* Re: [PATCH] Input: xpad - add support for ZENAIM LEVERLESS
From: Dmitry Torokhov @ 2026-07-23 17:53 UTC (permalink / raw)
To: Kyohei Kadota; +Cc: linux-input, linux-kernel
In-Reply-To: <CAFMepckDUuOHiDDVVhUYc-UqJMeCqrWSfCuxbJ2x2sGgdDD4nw@mail.gmail.com>
Hi Kyohei,
On Thu, Jul 23, 2026 at 07:55:57PM +0900, Kyohei Kadota wrote:
> Add the VID/PID for the ZENAIM LEVERLESS controller to xpad_device and
> the VID to xpad_table.
>
> Signed-off-by: KADOTA, Kyohei <lufia@lufia.org>
Your editor or mailer converted tabs to spaces. I fixed it up and
applied, but just wanted to let you know in case you'd want to submit
more patches in the future.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 1/4] Input: edt-ft5x06 - ignore contacts with an out-of-range slot id
From: Dmitry Torokhov @ 2026-07-23 17:45 UTC (permalink / raw)
To: sashiko-reviews
Cc: Alexandre Hamamdjian, conor+dt, devicetree, linux-input, robh
In-Reply-To: <20260723114100.D6D641F000E9@smtp.kernel.org>
On Thu, Jul 23, 2026 at 11:40:59AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Unbalanced `disable_irq()` calls when suspending and resuming in factory mode lead to a permanently disabled touchscreen.
This is obviously not caused by your series but might be real, need to
check...
> - [High] Stack-allocated buffers are passed to `regmap_bulk_read()` and `i2c_transfer()`, which can cause memory corruption or panics if the underlying I2C host controller driver uses DMA.
Sashiko hallucinates here. I added I2C prompt to teach it that I2C is
generally safe wrt on-stack buffers, but I am not sure if it will trace
it to regmap.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v2] Input: edt-ft5x06 - ignore contacts with an out-of-range slot id
From: Dmitry Torokhov @ 2026-07-23 17:43 UTC (permalink / raw)
To: azkali.limited
Cc: Henrik Rydberg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-input, linux-kernel, devicetree
In-Reply-To: <20260723-b4-ft5426-v2-1-cd2bed168051@gmail.com>
On Thu, Jul 23, 2026 at 08:24:09PM +0700, Alexandre Hamamdjian via B4 Relay wrote:
> From: Alexandre Hamamdjian <azkali.limited@gmail.com>
>
> The per-contact slot id is taken from the top nibble of the third
> report byte, so it can be any value from 0 to 15. The driver only
> allocates max_support_points MT slots (2 to 10 depending on the
> variant), so a report that carries an id at or above that count - be it
> a genuinely higher-numbered contact or a corrupted byte - is outside the
> range the input core was told about.
>
> input_mt_slot() silently ignores an ABS_MT_SLOT beyond num_slots and
> leaves the current slot unchanged, so the following
> input_mt_report_slot_state()/touchscreen_report_pos() pair is applied to
> whichever slot happened to be selected last, reporting the contact at the
> wrong position. Skip such entries instead.
>
> Signed-off-by: Alexandre Hamamdjian <azkali.limited@gmail.com>
Applied, thank you.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 2/4] dt-bindings: input: edt-ft5x06 - add no-regmap-bulk-read property
From: Conor Dooley @ 2026-07-23 15:56 UTC (permalink / raw)
To: azkali.limited
Cc: Dmitry Torokhov, Henrik Rydberg, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-input, linux-kernel, devicetree
In-Reply-To: <20260723-b4-ft5426-v1-2-d4b4e32be042@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2192 bytes --]
On Thu, Jul 23, 2026 at 06:27:09PM +0700, Alexandre Hamamdjian via B4 Relay wrote:
> From: Alexandre Hamamdjian <azkali.limited@gmail.com>
>
> Document an optional boolean property for boards whose i2c controller
> cannot reliably sustain the multi-byte block read of a full touch frame.
> When set, the driver reads the frame one register at a time instead of in
> a single bulk transfer.
>
> Signed-off-by: Alexandre Hamamdjian <azkali.limited@gmail.com>
> ---
> .../devicetree/bindings/input/touchscreen/edt-ft5x06.yaml | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
> index 68b2f1601654..0d8310a290ea 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
> +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
> @@ -111,6 +111,14 @@ properties:
>
> interrupt-controller: true
>
> + no-regmap-bulk-read:
"regmap" is a linux software construct, nothing to do with this
touchscreen or hardware at all for that matter - it's i2c bulk reads you
cannot do.
> + type: boolean
> + description:
> + Set this when the i2c controller the touch controller is attached to
Problems with your controller should be dealt with at the controller
level, not in the device node because the device doesn't have a problem,
the controller does. I think "i2c_adapter_quirks" is the knob used for
this.
This kind of property seems to have come up the other day in a similar context:
https://lore.kernel.org/all/20260722-regmap-single-read-v1-0-aaaf31591669@linux.dev/
The regmap maintainer there rejected a device level property in favour
of discovering this from the controller.
pwbot: rejected
Cheers,
Conor.
> + cannot reliably sustain the multi-byte block read of a full touch
> + frame and aborts long transfers. The driver then reads the touch
> + frame one register at a time instead of in a single bulk transfer.
> +
> unevaluatedProperties: false
>
> required:
>
> --
> 2.55.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH] Input: ims-pcu - fix heap-buffer-overflow in ims_pcu_process_data()
From: Seungjin Bae @ 2026-07-23 15:55 UTC (permalink / raw)
To: stable; +Cc: Dmitry Torokhov, linux-input
Hi,
Could you please pick up the following mainline commit for all
applicable stable trees?
commit 875115b82c295277b81b6dfee7debc725f44e854
Input: ims-pcu - fix heap-buffer-overflow in ims_pcu_process_data()
This fixes a heap-buffer-overflow in the ims-pcu driver that can be
triggered by a malicious USB device. The missing bounds check on
read_pos lets an attacker overwrite the index and corrupt heap memory,
which can lead to a control-flow hijack.
The commit was merged to mainline without a Cc: stable tag, so it was
not picked up automatically. The bug has been present since the driver
was first introduced, so all stable trees containing the ims-pcu driver
are affected.
Fixes: 628329d52474 ("Input: add IMS Passenger Control Unit driver")
Thanks,
Seungjin Bae
^ permalink raw reply
* Re: [PATCH v3 3/3] Input: ilitek_ts: ratelimit unexpected report logging
From: sashiko-bot @ 2026-07-23 15:49 UTC (permalink / raw)
To: Kristian Mide; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260723152244.11252-4-kristian@mide.dk>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing `enable_irq()` on error paths in PM suspend and resume callbacks, leaving the touchscreen interrupt permanently disabled.
- [High] The driver unconditionally disables the device IRQ during suspend, breaking system wakeup.
--
--- Patch [3]: [PATCH v3 3/3] Input: ilitek_ts: ratelimit unexpected report logging ---
commit d857848ba27cfb246552c60fc75946ecead183d4
Author: Kristian Mide <kristian@mide.dk>
Input: ilitek_ts: ratelimit unexpected report logging
This commit replaces dev_err() with dev_err_ratelimited() when logging
unexpected report IDs in the ilitek touchscreen driver. It adds the first
16 bytes of the raw packet to the log for better debugging context. It also
returns success after logging to prevent duplicate errors from being emitted
by the IRQ handler.
> diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
> index a184d024d6c4f..2f1741d77e6a9 100644
> --- a/drivers/input/touchscreen/ilitek_ts_i2c.c
> +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
> @@ -238,8 +238,10 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
> return ilitek_process_pen_report(ts, buf);
>
> if (buf[0] != ILITEK_TP_I2C_REPORT_ID) {
> - dev_err(dev, "get touch info failed. Wrong id: 0x%02X\n", buf[0]);
> - return -EINVAL;
> + dev_err_ratelimited(dev,
> + "get touch info failed. Wrong id: 0x%02X raw[0:16]=%*ph\n",
> + buf[0], 16, buf);
> + return 0;
> }
>
> report_max_point = buf[REPORT_COUNT_ADDRESS];
[ ... ]
While looking at this driver, I noticed a few pre-existing issues in the
power management callbacks:
> static int ilitek_suspend(struct device *dev)
> {
> struct i2c_client *client = to_i2c_client(dev);
> struct ilitek_ts_data *ts = i2c_get_clientdata(client);
> int error;
>
> disable_irq(client->irq);
>
> if (!device_may_wakeup(dev)) {
[Severity: High]
This is a pre-existing issue, but does unconditionally masking the IRQ here
break system wakeup?
By calling disable_irq(), the interrupt controller is prevented from seeing
the event and waking the CPU. Even though the sleep command is skipped when
device_may_wakeup(dev) is true, the unconditionally disabled IRQ line ensures
that any touch events generated by the hardware while suspended are dropped.
> error = api_protocol_set_cmd(ts, SET_IC_SLEEP, NULL, NULL);
> if (error)
> return error;
[Severity: High]
This isn't a bug introduced by this patch, but if api_protocol_set_cmd()
fails, does this error path leave the touchscreen interrupt permanently
disabled?
If this returns early without calling enable_irq(), the PM core aborts the
suspend process. Since the suspend failed, the resume callback is never
invoked for this device, leaving the IRQ depth unbalanced and the touchscreen
unresponsive until a reboot or module reload.
> }
>
> return 0;
> }
>
> static int ilitek_resume(struct device *dev)
> {
> struct i2c_client *client = to_i2c_client(dev);
> struct ilitek_ts_data *ts = i2c_get_clientdata(client);
> int error;
>
> if (!device_may_wakeup(dev)) {
> error = api_protocol_set_cmd(ts, SET_IC_WAKE, NULL, NULL);
> if (error)
> return error;
[Severity: High]
This is a pre-existing issue, but could this error path also leave the IRQ
disabled?
Similar to the suspend callback, if SET_IC_WAKE fails here, the function
returns an error before reaching enable_irq(client->irq). This would also
leave the interrupt permanently disabled.
>
> ilitek_reset(ts, ts->reset_time);
> }
>
> enable_irq(client->irq);
>
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723152244.11252-1-kristian@mide.dk?part=3
^ permalink raw reply
* Re: [PATCH v3 2/3] Input: ilitek_ts: handle short I2C transfers
From: sashiko-bot @ 2026-07-23 15:39 UTC (permalink / raw)
To: Kristian Mide; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260723152244.11252-3-kristian@mide.dk>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing IRQ re-enable on error paths in suspend/resume handlers.
- [High] Unsafe DMA Buffer Allocation for I2C transfers (stack variables passed to i2c_transfer).
- [High] Data parsing error for multi-touch reporting when more than 10 contacts are present.
--
--- Patch [2]: [PATCH v3 2/3] Input: ilitek_ts: handle short I2C transfers ---
commit 642c55e3cb3ec68f3ba0fdc9a106d372a6e3c257
Author: Kristian Mide <kristian@mide.dk>
Input: ilitek_ts: handle short I2C transfers
Check that i2c_transfer() returns the expected number of messages in
ilitek_i2c_write_and_read(). Short transfers were previously treated as
success, allowing callers to continue with partially filled buffers.
> diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
> index 86975fa9a0940..a184d024d6c4f 100644
> --- a/drivers/input/touchscreen/ilitek_ts_i2c.c
> +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
> @@ -131,11 +131,15 @@ static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts,
> error = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
[Severity: High]
This isn't a bug introduced by this patch, but will passing stack buffers to
i2c_transfer() cause memory corruption or kernel panics if the I2C adapter
driver uses DMA?
For example, ilitek_process_and_report_v6() allocates a 512-byte buffer on the
stack and passes it down the call chain:
ilitek_process_and_report_v6()
u8 buf[512];
...
error = ilitek_i2c_write_and_read(ts, NULL, 0, 0, buf, 64);
And api_protocol_get_mcu_ver() does something similar:
api_protocol_get_mcu_ver()
u8 buf[64];
...
error = ilitek_i2c_write_and_read(ts, buf, 1, 5, outbuf, 32);
On systems with CONFIG_VMAP_STACK=y, stack pages are not physically
contiguous. Is there a risk of dma_map_single() silently failing or
corrupting memory when mapping these buffers?
> if (error < 0)
> return error;
> + if (error != ARRAY_SIZE(msgs))
> + return -EIO;
[Severity: High]
This is a pre-existing issue, but returning explicitly on short transfers
makes error paths more likely to be triggered. Are we leaking IRQ states in
the suspend and resume routines?
If api_protocol_set_cmd() fails due to this new -EIO return during
ilitek_suspend(), we return early:
ilitek_suspend()
...
if (error)
return error;
The function returns without re-enabling the interrupt that was disabled at
the start of the function. The PM core aborts the suspend transition and
won't call the resume callback, leaving the device interrupt permanently
disabled.
A similar situation happens in ilitek_resume():
ilitek_resume()
...
if (error)
return error;
This skips the enable_irq(client->irq) call at the end of the function.
Could this leave the touchscreen permanently unresponsive?
> } else {
> if (write_len > 0) {
> error = i2c_transfer(client->adapter, msgs, 1);
> if (error < 0)
> return error;
> + if (error != 1)
> + return -EIO;
> }
[ ... ]
> @@ -144,6 +148,8 @@ static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts,
> error = i2c_transfer(client->adapter, msgs + 1, 1);
> if (error < 0)
> return error;
> + if (error != 1)
> + return -EIO;
[Severity: High]
This is also a pre-existing issue, but does the data parsing loop in
ilitek_process_and_report_v6() calculate offsets correctly when there are
more than 10 contacts?
When report_max_point > 10, the driver fetches subsequent data in 64-byte
chunks. However, the parsing loop calculates offsets linearly assuming a
continuous array:
ilitek_process_and_report_v6()
for (i = 0; i < report_max_point; i++) {
status = buf[i * packet_len + 1] & 0x40;
...
For the 11th point (where i = 10 and packet_len = 5), the offset is 51, which
falls inside the 14-byte padding at the end of the first 64-byte chunk. The
actual data for this point was written to the second chunk starting at
index 64.
Will this cause garbage touch events to be sent to userspace for the 11th
and subsequent fingers?
> }
> }
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723152244.11252-1-kristian@mide.dk?part=2
^ permalink raw reply
* [PATCH v3 3/3] Input: ilitek_ts: ratelimit unexpected report logging
From: Kristian Mide @ 2026-07-23 15:22 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, linux-kernel, Kristian Mide
In-Reply-To: <20260723152244.11252-1-kristian@mide.dk>
Unexpected report IDs can repeat quickly when the controller
emits unknown packets.
Use dev_err_ratelimited() and include the first 16 bytes of the
raw packet to keep dmesg usable while preserving enough context
for debugging.
Return success after logging the unexpected report ID so the IRQ
handler does not emit a second unratelimited error for the same
condition.
Signed-off-by: Kristian Mide <kristian@mide.dk>
---
drivers/input/touchscreen/ilitek_ts_i2c.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index a184d024d..2f1741d77 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -238,8 +238,10 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
return ilitek_process_pen_report(ts, buf);
if (buf[0] != ILITEK_TP_I2C_REPORT_ID) {
- dev_err(dev, "get touch info failed. Wrong id: 0x%02X\n", buf[0]);
- return -EINVAL;
+ dev_err_ratelimited(dev,
+ "get touch info failed. Wrong id: 0x%02X raw[0:16]=%*ph\n",
+ buf[0], 16, buf);
+ return 0;
}
report_max_point = buf[REPORT_COUNT_ADDRESS];
--
2.54.0
^ permalink raw reply related
* [PATCH v3 2/3] Input: ilitek_ts: handle short I2C transfers
From: Kristian Mide @ 2026-07-23 15:22 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, linux-kernel, Kristian Mide
In-Reply-To: <20260723152244.11252-1-kristian@mide.dk>
Check that i2c_transfer() returns the expected number of
messages in ilitek_i2c_write_and_read().
Short transfers were previously treated as success, allowing
callers to continue with partially filled buffers. In the report
path that can expose uninitialized stack data through debugging
output and can also confuse packet parsing.
Signed-off-by: Kristian Mide <kristian@mide.dk>
---
drivers/input/touchscreen/ilitek_ts_i2c.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index 86975fa9a..a184d024d 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -131,11 +131,15 @@ static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts,
error = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (error < 0)
return error;
+ if (error != ARRAY_SIZE(msgs))
+ return -EIO;
} else {
if (write_len > 0) {
error = i2c_transfer(client->adapter, msgs, 1);
if (error < 0)
return error;
+ if (error != 1)
+ return -EIO;
}
if (delay > 0)
fsleep(delay * 1000);
@@ -144,6 +148,8 @@ static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts,
error = i2c_transfer(client->adapter, msgs + 1, 1);
if (error < 0)
return error;
+ if (error != 1)
+ return -EIO;
}
}
--
2.54.0
^ permalink raw reply related
* [PATCH v3 1/3] Input: ilitek_ts: add stylus input support
From: Kristian Mide @ 2026-07-23 15:22 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, linux-kernel, Kristian Mide
In-Reply-To: <20260723152244.11252-1-kristian@mide.dk>
Add a separate stylus input device for report ID 0x0c packets,
with pressure, hover, and side-button support.
The pen device is created lazily on first pen report so
touchscreen-only hardware does not expose stylus capabilities up
front.
The packet format is reverse engineered from a tested CHUWI
Hi10 Max. Pressure is reported from buf[6..7] shifted right by
one, matching the observed 1024 pressure levels on the tested
device.
Pen coordinates are reported through touchscreen_report_pos()
so the same axis inversion and swapping properties used by the
touch path apply to the stylus as well.
The pen device lifetime is managed explicitly so the IRQ is
removed before the lazy pen input device is unregistered during
driver teardown.
Use input_set_capability() for the pen key capabilities.
Signed-off-by: Kristian Mide <kristian@mide.dk>
---
drivers/input/touchscreen/ilitek_ts_i2c.c | 137 +++++++++++++++++++++-
1 file changed, 134 insertions(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index 3de0fbf8d..86975fa9a 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -37,6 +37,18 @@
#define ILITEK_TP_CMD_GET_IC_MODE 0xC0
#define ILITEK_TP_I2C_REPORT_ID 0x48
+/* Reverse engineered stylus report on a tested CHUWI Hi10 Max device. */
+#define ILITEK_PEN_I2C_REPORT_ID 0x0C
+#define ILITEK_PEN_PRESSURE_MAX 1023
+#define ILITEK_PEN_DISTANCE_MAX 2
+/* Userspace expects tablet axis resolution; with INPUT_PROP_DIRECT this is */
+/* mostly descriptive and does not materially affect event coordinates. */
+#define ILITEK_PEN_RESOLUTION 68
+
+#define ILITEK_PEN_FLAG_TOUCH 0x01
+#define ILITEK_PEN_FLAG_STYLUS2 0x02
+#define ILITEK_PEN_FLAG_STYLUS 0x08
+#define ILITEK_PEN_FLAG_PROX 0x10
#define REPORT_COUNT_ADDRESS 61
#define ILITEK_SUPPORT_MAX_POINT 40
@@ -50,6 +62,7 @@ struct ilitek_ts_data {
struct i2c_client *client;
struct gpio_desc *reset_gpio;
struct input_dev *input_dev;
+ struct input_dev *pen_input_dev;
struct touchscreen_properties prop;
const struct ilitek_protocol_map *ptl_cb_func;
@@ -89,6 +102,9 @@ enum ilitek_cmds {
MAX_CMD_CNT
};
+static int ilitek_pen_input_dev_init(struct device *dev,
+ struct ilitek_ts_data *ts);
+
/* ILITEK I2C R/W APIs */
static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts,
u8 *cmd, int write_len, int delay,
@@ -146,6 +162,54 @@ static void ilitek_touch_down(struct ilitek_ts_data *ts, unsigned int id,
touchscreen_report_pos(input, &ts->prop, x, y, true);
}
+/*
+ * buf[1] carries prox/touch/side-button state and buf[6..7] carries
+ * pressure. A right shift by one matches the observed 1024 pressure levels.
+ */
+static int ilitek_process_pen_report(struct ilitek_ts_data *ts, u8 *buf)
+{
+ struct device *dev = &ts->client->dev;
+ struct input_dev *input = ts->pen_input_dev;
+ unsigned int x, y, z, distance;
+ bool prox, touch, stylus, stylus2;
+ int error;
+
+ if (!input) {
+ error = ilitek_pen_input_dev_init(dev, ts);
+ if (error) {
+ dev_err_ratelimited(dev,
+ "failed to register pen input device: %d\n",
+ error);
+ return 0;
+ }
+ input = ts->pen_input_dev;
+ }
+
+ x = get_unaligned_le16(buf + 2);
+ y = get_unaligned_le16(buf + 4);
+ z = get_unaligned_le16(buf + 6) >> 1;
+ prox = !!(buf[1] & ILITEK_PEN_FLAG_PROX);
+ touch = !!(buf[1] & ILITEK_PEN_FLAG_TOUCH);
+ stylus = !!(buf[1] & ILITEK_PEN_FLAG_STYLUS);
+ stylus2 = !!(buf[1] & ILITEK_PEN_FLAG_STYLUS2);
+ distance = prox ? (touch ? 0 : 1) : ILITEK_PEN_DISTANCE_MAX;
+ if (!touch)
+ z = 0;
+ else if (z > ILITEK_PEN_PRESSURE_MAX)
+ z = ILITEK_PEN_PRESSURE_MAX;
+
+ input_report_key(input, BTN_TOOL_PEN, prox || touch);
+ input_report_key(input, BTN_TOUCH, touch);
+ input_report_key(input, BTN_STYLUS, stylus);
+ input_report_key(input, BTN_STYLUS2, stylus2);
+ touchscreen_report_pos(input, &ts->prop, x, y, false);
+ input_report_abs(input, ABS_PRESSURE, z);
+ input_report_abs(input, ABS_DISTANCE, distance);
+ input_sync(input);
+
+ return 0;
+}
+
static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
{
int error = 0;
@@ -164,6 +228,9 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
return error;
}
+ if (buf[0] == ILITEK_PEN_I2C_REPORT_ID)
+ return ilitek_process_pen_report(ts, buf);
+
if (buf[0] != ILITEK_TP_I2C_REPORT_ID) {
dev_err(dev, "get touch info failed. Wrong id: 0x%02X\n", buf[0]);
return -EINVAL;
@@ -459,6 +526,58 @@ static int ilitek_read_tp_info(struct ilitek_ts_data *ts, bool boot)
return 0;
}
+static int ilitek_pen_input_dev_init(struct device *dev, struct ilitek_ts_data *ts)
+{
+ struct input_dev *pen_input;
+ int error;
+
+ if (ts->pen_input_dev)
+ return 0;
+
+ /* No explicit pen capability probe is known; create on first pen report. */
+
+ pen_input = input_allocate_device();
+ if (!pen_input)
+ return -ENOMEM;
+
+ ts->pen_input_dev = pen_input;
+ pen_input->dev.parent = dev;
+ pen_input->name = "ilitek_ts_pen";
+ pen_input->id.bustype = BUS_I2C;
+
+ __set_bit(INPUT_PROP_DIRECT, pen_input->propbit);
+ input_set_capability(pen_input, EV_KEY, BTN_TOUCH);
+ input_set_capability(pen_input, EV_KEY, BTN_TOOL_PEN);
+ input_set_capability(pen_input, EV_KEY, BTN_STYLUS);
+ input_set_capability(pen_input, EV_KEY, BTN_STYLUS2);
+
+ input_set_abs_params(pen_input, ABS_X,
+ input_abs_get_min(ts->input_dev, ABS_MT_POSITION_X),
+ input_abs_get_max(ts->input_dev, ABS_MT_POSITION_X),
+ 0, 0);
+ input_set_abs_params(pen_input, ABS_Y,
+ input_abs_get_min(ts->input_dev, ABS_MT_POSITION_Y),
+ input_abs_get_max(ts->input_dev, ABS_MT_POSITION_Y),
+ 0, 0);
+ input_set_abs_params(pen_input, ABS_PRESSURE, 0,
+ ILITEK_PEN_PRESSURE_MAX, 0, 0);
+ input_set_abs_params(pen_input, ABS_DISTANCE, 0,
+ ILITEK_PEN_DISTANCE_MAX, 0, 0);
+ input_abs_set_res(pen_input, ABS_X, ILITEK_PEN_RESOLUTION);
+ input_abs_set_res(pen_input, ABS_Y, ILITEK_PEN_RESOLUTION);
+
+ error = input_register_device(pen_input);
+ if (error)
+ goto err_free_pen_input;
+
+ return 0;
+
+err_free_pen_input:
+ ts->pen_input_dev = NULL;
+ input_free_device(pen_input);
+ return error;
+}
+
static int ilitek_input_dev_init(struct device *dev, struct ilitek_ts_data *ts)
{
int error;
@@ -589,9 +708,8 @@ static int ilitek_ts_i2c_probe(struct i2c_client *client)
return error;
}
- error = devm_request_threaded_irq(dev, ts->client->irq,
- NULL, ilitek_i2c_isr, IRQF_ONESHOT,
- "ilitek_touch_irq", ts);
+ error = request_threaded_irq(ts->client->irq, NULL, ilitek_i2c_isr,
+ IRQF_ONESHOT, "ilitek_touch_irq", ts);
if (error) {
dev_err(dev, "request threaded irq failed: %d\n", error);
return error;
@@ -600,6 +718,18 @@ static int ilitek_ts_i2c_probe(struct i2c_client *client)
return 0;
}
+static void ilitek_ts_i2c_remove(struct i2c_client *client)
+{
+ struct ilitek_ts_data *ts = i2c_get_clientdata(client);
+
+ free_irq(client->irq, ts);
+
+ if (ts->pen_input_dev) {
+ input_unregister_device(ts->pen_input_dev);
+ ts->pen_input_dev = NULL;
+ }
+}
+
static int ilitek_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -677,6 +807,7 @@ static struct i2c_driver ilitek_ts_i2c_driver = {
.acpi_match_table = ACPI_PTR(ilitekts_acpi_id),
},
.probe = ilitek_ts_i2c_probe,
+ .remove = ilitek_ts_i2c_remove,
.id_table = ilitek_ts_i2c_id,
};
module_i2c_driver(ilitek_ts_i2c_driver);
--
2.54.0
^ permalink raw reply related
* [PATCH v3 0/3] Input: ilitek_ts: add stylus support for 0x0c reports
From: Kristian Mide @ 2026-07-23 15:22 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, linux-kernel, Kristian Mide
In-Reply-To: <20260709182602.7308-1-kristian@mide.dk>
Hi,
I bought a CHUWI Hi10 Max and was annoyed to find that the built-in
stylus was not usable with the upstream ilitek_ts driver.
This series adds support for the pen report format emitted by the
device, exposing the stylus as a separate input device with hover,
pressure, and side-button support. The pen device is created lazily on
first pen report so touchscreen-only hardware does not advertise stylus
capabilities up front.
The packet format was reverse engineered on this device. In particular,
report ID 0x0c appears to carry pen events, pressure comes from
buf[6..7] shifted right by one, and the side buttons map to two bits in
buf[1].
Changes in v3:
- return success after ratelimited unexpected-report logging so the IRQ
handler does not emit a second unratelimited error
- use input_set_capability() for pen key capabilities
Changes in v2:
- manage the lazy pen device lifetime explicitly and tear down the IRQ
before unregistering the pen device
- sync pen axis limits with the DT-adjusted touch axis limits
- reject short I2C transfers in ilitek_i2c_write_and_read()
- split the short-transfer fix from the ratelimited logging change
On the tested CHUWI Hi10 Max this makes the pen usable in GNOME/Krita,
including pressure and side buttons.
Thanks,
Kristian
Kristian Mide (3):
Input: ilitek_ts: add stylus input support
Input: ilitek_ts: handle short I2C transfers
Input: ilitek_ts: ratelimit unexpected report logging
drivers/input/touchscreen/ilitek_ts_i2c.c | 149 +++++++++++++++++++++-
1 file changed, 144 insertions(+), 5 deletions(-)
--
2.54.0
^ permalink raw reply
* [PATCH v2] Input: edt-ft5x06 - ignore contacts with an out-of-range slot id
From: Alexandre Hamamdjian via B4 Relay @ 2026-07-23 13:24 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-input, linux-kernel, devicetree, Alexandre Hamamdjian
From: Alexandre Hamamdjian <azkali.limited@gmail.com>
The per-contact slot id is taken from the top nibble of the third
report byte, so it can be any value from 0 to 15. The driver only
allocates max_support_points MT slots (2 to 10 depending on the
variant), so a report that carries an id at or above that count - be it
a genuinely higher-numbered contact or a corrupted byte - is outside the
range the input core was told about.
input_mt_slot() silently ignores an ABS_MT_SLOT beyond num_slots and
leaves the current slot unchanged, so the following
input_mt_report_slot_state()/touchscreen_report_pos() pair is applied to
whichever slot happened to be selected last, reporting the contact at the
wrong position. Skip such entries instead.
Signed-off-by: Alexandre Hamamdjian <azkali.limited@gmail.com>
---
A single generic correctness fix: a report whose contact id is at or
above max_support_points selects an MT slot the input core was never
told about, so input_mt_slot() ignores it and the contact is reported
against the previously-selected slot.
The marginal-i2c-bus mitigations that accompanied this in v1 (the
no-regmap-bulk-read property + driver fallback, and the poll-while-down
recovery) are dropped: reviewers correctly noted the bulk-read quirk is
a property of the i2c controller rather than the touch controller and
does not belong in the touch node's binding, so that work is better
placed in the i2c controller (or kept out of tree) and is not part of
this series.
---
drivers/input/touchscreen/edt-ft5x06.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index d3b1177185a3..d6c3d033b83d 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -331,6 +331,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
swap(x, y);
id = (buf[2] >> 4) & 0x0f;
+ if (id >= tsdata->max_support_points)
+ continue;
input_mt_slot(tsdata->input, id);
if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
---
base-commit: e98d21c170b01ddef366f023bbfcf6b31509fa83
change-id: 20260723-b4-ft5426-393d8514e4bf
Best regards,
--
Alexandre Hamamdjian <azkali.limited@gmail.com>
^ permalink raw reply related
* Re: (subset) [PATCH 3/6] [v6] leds: gpio: make legacy gpiolib interface optional
From: Lee Jones @ 2026-07-23 13:08 UTC (permalink / raw)
To: linux-gpio, Linus Walleij, Bartosz Golaszewski, Arnd Bergmann
Cc: Arnd Bergmann, John Paul Adrian Glaubitz, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Dmitry Torokhov, Lee Jones, Pavel Machek, linux-sh, linux-kernel,
linux-input, linux-leds, Bartosz Golaszewski, Andy Shevchenko
In-Reply-To: <20260710211854.1371746-4-arnd@kernel.org>
On Fri, 10 Jul 2026 23:18:51 +0200, Arnd Bergmann wrote:
> There are still a handful of ancient mips/armv5/sh boards that use the
> gpio_led:gpio member to pass an old-style gpio number, but all modern
> users have been converted to gpio descriptors.
>
> While the CONFIG_GPIOLIB_LEGACY option that guards devm_gpio_request_one()
> and related helpers is currently turned on in all kernel builds,
> the plan is to only enable it on the few platforms that actually
> pass gpio numbers in any platform_data.
>
> [...]
Applied, thanks!
[3/6] leds: gpio: make legacy gpiolib interface optional
commit: 98c5c7b0d4269ecabfc86b8b49ffcfa47979e99d
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH v10 2/7] mfd: Add driver for ASUS Transformer embedded controller
From: Uwe Kleine-König @ 2026-07-23 6:25 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
Lee Jones, Pavel Machek, Sebastian Reichel, Ion Agorria,
Michał Mirosław, devicetree, linux-kernel, linux-input,
linux-leds, linux-pm
In-Reply-To: <20260721095233.420823-3-clamor95@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1606 bytes --]
Hello,
On Tue, Jul 21, 2026 at 12:52:28PM +0300, Svyatoslav Ryhel wrote:
> From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
>
> Support Nuvoton NPCE795-based ECs as used in Asus Transformer TF201,
> TF300T, TF300TG, TF300TL and TF700T pad and dock, as well as TF101 dock
> and TF600T, P1801-T and TF701T pad. This is a glue driver handling
> detection and common operations for EC's functions.
>
> Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Documentation/process/submitting-patches.rst has:
[...] the ordering of Signed-off-by: tags should reflect the
chronological history of the patch insofar as possible [...]
So your S-o-b should be last when you submit a patch.
> +#include <linux/i2c.h>
> [...]
> +#include <linux/mod_devicetable.h>
<linux/mod_devicetable.h> will go away soon. Please rely on
<linux/i2c.h> to provide a definition of struct of_device_id and drop
the #include of mod_devicetable.h.
> +static const struct of_device_id asus_ec_match[] = {
> + {
> + .compatible = "asus,sl101-ec-dock",
> + .data = &asus_ec_sl101_dock_data
> + }, {
> + .compatible = "asus,tf101-ec-dock",
> + .data = &asus_ec_tf101_dock_data
> + }, {
> + .compatible = "asus,tf201-ec-pad",
> + .data = &asus_ec_tf201_pad_data
> + }, {
> + .compatible = "asus,tf600t-ec-pad",
> + .data = &asus_ec_tf600t_pad_data
> + },
> + { /* sentinel */ }
> +};
Trailing comma after the assignments to .data please.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH] Input: uinput/uhid - disallow control characters in phys paths
From: Peter Hutterer @ 2026-07-23 5:54 UTC (permalink / raw)
To: sashiko-bot; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260717050748.5DC071F000E9@smtp.kernel.org>
On Fri, Jul 17, 2026 at 05:07:47AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] The patch provides an incomplete mitigation for CVE-2026-50292. It sanitizes the `phys` property to prevent udev property injection via control characters (newlines), but completely fails to sanitize the `name` and `uniq` properties, which are also exported to uevents and controlled by userspace.
> --
>
> --- Patch [1]: [PATCH] Input: uinput/uhid - disallow control characters in phys paths ---
> commit 1a76e90e7acc09a84a52efddc46e598419020a19
> Author: Peter Hutterer <peter.hutterer@who-t.net>
>
> Input: uinput/uhid - disallow control characters in phys paths
>
> This commit sanitizes the phys property in uinput and uhid devices to replace
> control characters with '?'. This prevents userspace from injecting malicious
> udev properties via newlines, which previously triggered CVE-2026-50292.
>
> > diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
> > index 37b60c3aaf66a..baf1fe8290f75 100644
> > --- a/drivers/hid/uhid.c
> > +++ b/drivers/hid/uhid.c
> > @@ -518,6 +518,7 @@ static int uhid_dev_create2(struct uhid_device *uhid,
> > strscpy(hid->name, ev->u.create2.name, sizeof(hid->name));
> > BUILD_BUG_ON(sizeof(hid->phys) != sizeof(ev->u.create2.phys));
> > strscpy(hid->phys, ev->u.create2.phys, sizeof(hid->phys));
> > + input_sanitize_phys(hid->phys);
> > BUILD_BUG_ON(sizeof(hid->uniq) != sizeof(ev->u.create2.uniq));
> > strscpy(hid->uniq, ev->u.create2.uniq, sizeof(hid->uniq));
>
> [Severity: High]
> This isn't a bug introduced by this patch, but while this successfully mitigates
> CVE-2026-50292 for the phys property, does it still leave the name and uniq
> properties vulnerable?
>
> In uhid_dev_create2(), the user-controlled ev->u.create2.name and
> ev->u.create2.uniq strings are copied directly without passing through a
> similar sanitization function.
>
> Additionally, in drivers/input/misc/uinput.c:uinput_dev_setup(), the name
> property is also set without sanitization:
>
> dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);
>
> If a user with write access to /dev/uinput or /dev/uhid sets the name or uniq
> properties to strings containing newlines, wouldn't this still allow the
> injection of arbitrary udev environment variables when INPUT_ADD_HOTPLUG_VAR
> formats them for uevents?
name and uniq are controlled by the firmware and thus by the vendor and
control characters (or at least non-ascii) may be legitimately present.
There is no such thing as a sanitized name.
Cheers,
Peter
^ permalink raw reply
* [PATCH] Input: tca8418_keypad - fix potential infinite loop and OOB, access on I2C error
From: Liang Zhan @ 2026-07-23 3:41 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, linux-kernel
From 187224ee38e19fd3f74bfc08d1908c97398fef82 Mon Sep 17 00:00:00 2001
From: Zhian Liang <liangzhan5dev@gmail.com>
Date: Thu, 23 Jul 2026 00:08:15 +0800
Subject: [PATCH] Input: tca8418_keypad - fix potential infinite loop and OOB
access on I2C error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If the I2C bus returns 0xFF (e.g., due to a stuck bus or device fault),
the original code would treat it as a valid key event, leading to two
critical issues:
1. The loop in tca8418_read_keypad() would never terminate because the
condition "reg <= 0" is false for 0xFF (255). This stalls the threaded
IRQ handler indefinitely.
2. The extracted hardware keycode (127) is used to compute row/col
indices that exceed the valid range (rows*cols ≤ 80), causing an
out-of-bounds read on "keymap[code]" when reporting the key.
Fix both by:
- Recognizing 0xFF as an empty FIFO condition (along with 0x00).
- Validating the keycode before calculating row/col, skipping invalid
codes and preventing array overrun.
Cc: stable@vger.kernel.org
Signed-off-by: Zhian Liang <liangzhan5dev@gmail.com>
---
drivers/input/keyboard/tca8418_keypad.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/input/keyboard/tca8418_keypad.c
b/drivers/input/keyboard/tca8418_keypad.c
index b124e576feca..cec6a589192d 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -171,13 +171,20 @@ static void tca8418_read_keypad(struct
tca8418_keypad *keypad_data)
break;
}
- /* Assume that key code 0 signifies empty FIFO */
- if (reg <= 0)
+ /* 0x00 = empty FIFO, 0xFF = likely bus fault */
+ if (reg == 0 || reg == 0xFF)
break;
state = reg & KEY_EVENT_VALUE;
code = reg & KEY_EVENT_CODE;
+ /* validate keycode: must be non-zero and within hardware limits */
+ if (code == 0 || code > TCA8418_MAX_ROWS * TCA8418_MAX_COLS){
+ dev_err(&keypad_data->client->dev,
+ "invalid key code: %d\n", code);
+ continue;
+ }
+
row = code / TCA8418_MAX_COLS;
col = code % TCA8418_MAX_COLS;
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] Input: charlieplex_keypad - check gpiod_direction_output() return value
From: sashiko-bot @ 2026-07-23 2:38 UTC (permalink / raw)
To: kr494167; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260723022943.9337-1-kr494167@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The return value of `gpiod_direction_input()` is ignored, which can leave the line configured as an output driving HIGH upon hardware failure, breaking the matrix scanning logic.
--
--- Patch [1]: [PATCH] Input: charlieplex_keypad - check gpiod_direction_output() return value ---
commit dcc381a1c321f8eedf04b92519f6edd1db4050eb
Author: Surendra Singh Chouhan <kr494167@gmail.com>
Input: charlieplex_keypad - check gpiod_direction_output() return value
This commit updates charlieplex_keypad_scan_line() to capture and return
the error code if setting the active output line fails. This prevents
the keypad from continuing to sleep and read inputs from an improperly
configured GPIO.
> diff --git a/drivers/input/keyboard/charlieplex_keypad.c b/drivers/input/keyboard/charlieplex_keypad.c
> --- a/drivers/input/keyboard/charlieplex_keypad.c
> +++ b/drivers/input/keyboard/charlieplex_keypad.c
> @@ -77,7 +77,9 @@ static int charlieplex_keypad_scan_line(struct charlieplex_keypad *keypad,
> int err;
>
> /* Activate only one line as output at a time. */
> - gpiod_direction_output(line_gpios->desc[oline], 1);
> + err = gpiod_direction_output(line_gpios->desc[oline], 1);
> + if (err)
> + return err;
[Severity: High]
This is a pre-existing issue, but since this patch explicitly adds error
checking for gpiod_direction_output(), should we also check the return value
when restoring the line to an input state?
A few lines below in charlieplex_keypad_scan_line(), the same pattern exists
when restoring the line direction:
err = gpiod_get_array_value_cansleep(line_gpios->ndescs, ...);
gpiod_direction_input(line_gpios->desc[oline]);
if (err)
return err;
If gpiod_direction_input() fails here due to a temporary hardware or bus error
(like on an i2c or spi GPIO expander), does this leave the line configured
as an output driving high?
On subsequent scans, this could cause multiple lines to act as outputs
simultaneously and break the matrix scanning logic entirely.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723022943.9337-1-kr494167@gmail.com?part=1
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox