* Re: [PATCH] HID: usbhid: skip interrupt IN polling for devices with no input reports
From: Denis Benato @ 2026-06-06 12:42 UTC (permalink / raw)
To: Antheas Kapenekakis, Ahmed Yaseen
Cc: Jiri Kosina, Benjamin Tissoires, Ilpo Järvinen,
Kerim Kabirov, GameBurrow, linux-usb, linux-input, linux-kernel
In-Reply-To: <CAGwozwFWbW=v2B7ruS4OUGuPhjSayw4Qxj3K+bCzwmgQu158Ng@mail.gmail.com>
On 6/5/26 14:02, Antheas Kapenekakis wrote:
> On Fri, 5 Jun 2026 at 13:40, Ahmed Yaseen <yaseen@ghoul.dev> wrote:
>> usbhid starts polling a device's interrupt IN endpoint on open
>> (usbhid_open() -> hid_start_in()). If the report descriptor declares no
>> input reports there is nothing to read there, so the poll is useless,
>> and on some composite devices it is also harmful.
> If it did have input reports, would starting the polling still cause
> issues? Because if it would, the issue is in the polling itself.
So far we haven't found an asus device that has more than one interface
that supports reading data out of if.
> Given the creativity of manufacturers when implementing hid protocols,
> I find it certain that they do use the in endpoint even without input
> reports. E.g., for feature reports. This could cause regressions.
While I mostly agree with this it is also true that the general direction
for the kernel (especially lately) has been to not do out-of-spec things
at least by default.
If things really regress it's expected to do so only an very few specific
devices with a buggy firmware, and we can think of something different
for those (hopefully very few ones).
Perhaps someone concerned with security might be interested in what
we have because it doesn't look very normal.
Note that below I have written a few ideas that maybe are worth
looking into.
>> The ASUS ROG N-Key keyboards expose a second, input-less interface used
>> only for RGB control via feature reports. Opening its hidraw node (any
>> hidraw reader does, including SDL/Steam Input or a plain cat) starts the
> cating a hidraw causing issues would be expected, so let's focus on the former.
Simply opening an hidraw should not trigger a delayed disconnect of that device,
I don't know why you would expect this to happen nor why you would
consider it acceptable. It's a bug.
Focusing on userspace software exposing the bug is not a realistic option
because over the time we found a good chunk of software doing that:
- logitech control software (forgot the name)
- open razer software
- sdl
- asusctl (obviously it opens the device albeit in the future I will change this)
and likely more given the fact not all software was identified.
> Asusctl has a bug where if you add the quirk that separates the event
> nodes per hid, this bug is reproduced as well. I chucked it to
> complicated threading getting out of control. It is the reason we
> skipped that patch that was in my series.
I found and solved the bug already. Regardless the issue remains:
Even with no asusctl at all, if a user has one logitech mouse
(and its control software) and a razer keyboard (and its control software)
the asus N-Key device will start an endless disconnect-reconnect loop.
Any combination of two or more of those tools will trigger the issue
on some devices (weirdly enough not every model is affected):
this is not good.
> Now, you say SDL/Steam do a spurious read as well, can you identify
> the codepath so we can look into it? What devices are affected? The
> early return fixes a warning on the Z13, but it also feeds through the
> universal lamp interface on the new Xbox Allies. Is this a bug on
> those devices or keyboards? If yes, it could be caused by userspace
> hanging on that node
Sure, and I agree with you that fixing all userspace tools is desirable
but it's also unfeasible to fix them all, if we managed to do that
there will be years before everyone receives a fixed version of every
affected software and even then a core issue would remain:
linux tries to poll something it can't have anything out from.
I am much more oriented on the fact that kernel shouldn't
be doing weird things (at least not by default) so this has to
somehow be stopped regardless of how well userspace behaves.
If you have better ideas on how to fix the kernel we would
like to hear those as well.
Best regards,
Denis
> Antheas
>
>> pointless IN poll and keypress reports on the keyboard interface get
>> dropped for as long as the node stays open: a lost key-down drops a
>> letter, a lost key-up leaves the key stuck. usbmon shows the dropped
>> reports never reach the URB layer.
>>
>> The useless poll itself is long-standing; commit 4ac74ea68f64 ("HID:
>> asus: early return for ROG devices") is what exposes it on these
>> devices by keeping the input-less interface alive instead of ejecting
>> it, so its hidraw node can be opened and the poll started.
>>
>> Skip the poll in usbhid_open() when the device has no input reports.
>> Feature reports and hidraw output keep working over the control and OUT
>> endpoints, so the interface is otherwise unaffected.
I will write my review here to avoid forking the discussion:
I agree with the general idea but perhaps we can avoid
some hid devices to ever get HID_QUIRK_ALWAYS_POLL
and that might be enough to skip the problematic code?
Maybe there is value in doing this with a quirk flag in hid-asus.c
affecting the least amount of devices?
Or maybe just prevent devices with no data possibly coming out
to ever get HID_QUIRK_ALWAYS_POLL?
For how to best do this we will need to hear what Jiri and
Benjamin have to say but if they think the proposed solution
is the correct solution:
Reviewed-by: Denis Benato <denis.benato@linux.dev>
>> Fixes: 4ac74ea68f64 ("HID: asus: early return for ROG devices")
>> Tested-by: Kerim Kabirov <the.privat33r+linux@pm.me>
>> Tested-by: GameBurrow <gameburrow@pm.me>
>> Signed-off-by: Ahmed Yaseen <yaseen@ghoul.dev>
>> ---
>> drivers/hid/usbhid/hid-core.c | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
>> index 96b0181cf819..90a8b34d9305 100644
>> --- a/drivers/hid/usbhid/hid-core.c
>> +++ b/drivers/hid/usbhid/hid-core.c
>> @@ -688,7 +688,8 @@ static int usbhid_open(struct hid_device *hid)
>>
>> set_bit(HID_OPENED, &usbhid->iofl);
>>
>> - if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
>> + if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) ||
>> + list_empty(&hid->report_enum[HID_INPUT_REPORT].report_list)) {
>> res = 0;
>> goto Done;
>> }
>> --
>> 2.54.0
>>
>>
>>
^ permalink raw reply
* Re: [PATCH] HID: usbhid: skip interrupt IN polling for devices with no input reports
From: Antheas Kapenekakis @ 2026-06-06 13:13 UTC (permalink / raw)
To: Denis Benato
Cc: Ahmed Yaseen, Jiri Kosina, Benjamin Tissoires, Ilpo Järvinen,
Kerim Kabirov, GameBurrow, linux-usb, linux-input, linux-kernel
In-Reply-To: <ceb5ed4b-1654-463d-9cff-4a1b91d52e92@gmail.com>
On Sat, 6 Jun 2026 at 14:42, Denis Benato <benato.denis96@gmail.com> wrote:
>
>
> On 6/5/26 14:02, Antheas Kapenekakis wrote:
> > On Fri, 5 Jun 2026 at 13:40, Ahmed Yaseen <yaseen@ghoul.dev> wrote:
> >> usbhid starts polling a device's interrupt IN endpoint on open
> >> (usbhid_open() -> hid_start_in()). If the report descriptor declares no
> >> input reports there is nothing to read there, so the poll is useless,
> >> and on some composite devices it is also harmful.
> > If it did have input reports, would starting the polling still cause
> > issues? Because if it would, the issue is in the polling itself.
> So far we haven't found an asus device that has more than one interface
> that supports reading data out of if.
> > Given the creativity of manufacturers when implementing hid protocols,
> > I find it certain that they do use the in endpoint even without input
> > reports. E.g., for feature reports. This could cause regressions.
> While I mostly agree with this it is also true that the general direction
> for the kernel (especially lately) has been to not do out-of-spec things
> at least by default.
>
> If things really regress it's expected to do so only an very few specific
> devices with a buggy firmware, and we can think of something different
> for those (hopefully very few ones).
>
> Perhaps someone concerned with security might be interested in what
> we have because it doesn't look very normal.
>
> Note that below I have written a few ideas that maybe are worth
The degradation would be silent.
> looking into.
> >> The ASUS ROG N-Key keyboards expose a second, input-less interface used
> >> only for RGB control via feature reports. Opening its hidraw node (any
> >> hidraw reader does, including SDL/Steam Input or a plain cat) starts the
> > cating a hidraw causing issues would be expected, so let's focus on the former.
Try to add spaces before and after your responses
> Simply opening an hidraw should not trigger a delayed disconnect of that device,
> I don't know why you would expect this to happen nor why you would
> consider it acceptable. It's a bug.
>
> Focusing on userspace software exposing the bug is not a realistic option
> because over the time we found a good chunk of software doing that:
> - logitech control software (forgot the name)
> - open razer software
> - sdl
> - asusctl (obviously it opens the device albeit in the future I will change this)
>
> and likely more given the fact not all software was identified.
> > Asusctl has a bug where if you add the quirk that separates the event
> > nodes per hid, this bug is reproduced as well. I chucked it to
> > complicated threading getting out of control. It is the reason we
> > skipped that patch that was in my series.
> I found and solved the bug already. Regardless the issue remains:
> Even with no asusctl at all, if a user has one logitech mouse
> (and its control software) and a razer keyboard (and its control software)
> the asus N-Key device will start an endless disconnect-reconnect loop.
>
> Any combination of two or more of those tools will trigger the issue
> on some devices (weirdly enough not every model is affected):
>
> this is not good.
> > Now, you say SDL/Steam do a spurious read as well, can you identify
> > the codepath so we can look into it? What devices are affected? The
> > early return fixes a warning on the Z13, but it also feeds through the
> > universal lamp interface on the new Xbox Allies. Is this a bug on
> > those devices or keyboards? If yes, it could be caused by userspace
> > hanging on that node
> Sure, and I agree with you that fixing all userspace tools is desirable
> but it's also unfeasible to fix them all, if we managed to do that
> there will be years before everyone receives a fixed version of every
> affected software and even then a core issue would remain:
> linux tries to poll something it can't have anything out from.
>
> I am much more oriented on the fact that kernel shouldn't
> be doing weird things (at least not by default) so this has to
> somehow be stopped regardless of how well userspace behaves.
The kernel is not doing weird things and I also did not ask you to fix
all userspace software. I asked for a reproduction scenario, as it is
not covered in the patch description. Relooking at the patch today, I
also do not understand what it does fully.
It skips enabling input interrupts (but not only that) for devices
that have no input reports. So the kernel behavior will depend on the
feature descriptor moving forward.
And that fixes a hang on the affected devices because enabling
interrupts on an endpoint without periodic input reports blocks a
parallel endpoint that does have input reports?
I would like this fix to target the actual cause that causes the block
but it is not clear to me what that is or what is affected.
Antheas
> If you have better ideas on how to fix the kernel we would
> like to hear those as well.
>
> Best regards,
> Denis
> > Antheas
> >
> >> pointless IN poll and keypress reports on the keyboard interface get
> >> dropped for as long as the node stays open: a lost key-down drops a
> >> letter, a lost key-up leaves the key stuck. usbmon shows the dropped
> >> reports never reach the URB layer.
> >>
> >> The useless poll itself is long-standing; commit 4ac74ea68f64 ("HID:
> >> asus: early return for ROG devices") is what exposes it on these
> >> devices by keeping the input-less interface alive instead of ejecting
> >> it, so its hidraw node can be opened and the poll started.
> >>
> >> Skip the poll in usbhid_open() when the device has no input reports.
> >> Feature reports and hidraw output keep working over the control and OUT
> >> endpoints, so the interface is otherwise unaffected.
> I will write my review here to avoid forking the discussion:
>
> I agree with the general idea but perhaps we can avoid
> some hid devices to ever get HID_QUIRK_ALWAYS_POLL
> and that might be enough to skip the problematic code?
>
> Maybe there is value in doing this with a quirk flag in hid-asus.c
> affecting the least amount of devices?
>
> Or maybe just prevent devices with no data possibly coming out
> to ever get HID_QUIRK_ALWAYS_POLL?
>
> For how to best do this we will need to hear what Jiri and
> Benjamin have to say but if they think the proposed solution
> is the correct solution:
>
> Reviewed-by: Denis Benato <denis.benato@linux.dev>
> >> Fixes: 4ac74ea68f64 ("HID: asus: early return for ROG devices")
> >> Tested-by: Kerim Kabirov <the.privat33r+linux@pm.me>
> >> Tested-by: GameBurrow <gameburrow@pm.me>
> >> Signed-off-by: Ahmed Yaseen <yaseen@ghoul.dev>
> >> ---
> >> drivers/hid/usbhid/hid-core.c | 3 ++-
> >> 1 file changed, 2 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
> >> index 96b0181cf819..90a8b34d9305 100644
> >> --- a/drivers/hid/usbhid/hid-core.c
> >> +++ b/drivers/hid/usbhid/hid-core.c
> >> @@ -688,7 +688,8 @@ static int usbhid_open(struct hid_device *hid)
> >>
> >> set_bit(HID_OPENED, &usbhid->iofl);
> >>
> >> - if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
> >> + if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) ||
> >> + list_empty(&hid->report_enum[HID_INPUT_REPORT].report_list)) {
> >> res = 0;
> >> goto Done;
> >> }
> >> --
> >> 2.54.0
> >>
> >>
> >>
>
^ permalink raw reply
* [PATCH 0/8] Input: cap11xx - Add support for CAP1114
From: Jun Yan @ 2026-06-06 15:03 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
PATCH 1~3 mainly focus on cleaning up the driver and dt-bindings.
PATCH 4~5 add reset-gpios support for CAP11xx.
PATCH 6~8 add support for CAP1114.
Jun Yan (8):
Input: cap11xx - clean up duplicate log and add probe error logs
Input: cap11xx - remove unused register macros
dt-bindings: input: microchip,cap11xx: Cleanup and refine LED
constraints
dt-bindings: input: microchip,cap11xx: Add reset-gpios property
Input: cap11xx - add reset gpio support
Input: cap11xx - refactor code for better CAP1114 support.
dt-bindings: input: microchip,cap11xx: Add CAP1114 support
Input: cap11xx - add support for CAP1114
.../bindings/input/microchip,cap11xx.yaml | 93 ++++++--
drivers/input/keyboard/cap11xx.c | 223 +++++++++++-------
2 files changed, 215 insertions(+), 101 deletions(-)
--
2.54.0
^ permalink raw reply
* [PATCH 1/8] Input: cap11xx - clean up duplicate log and add probe error logs
From: Jun Yan @ 2026-06-06 15:03 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
Duplicated device detection log exists at line 537 and line 542,
which brings redundant repeated kernel print messages. Drop one
redundant log entry to clean up dmesg output.
Meanwhile add missing error logs when I2C communication fails
during driver probe(), helping capture abnormal hardware access
for debug.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 2447c1ae2166..485d8ba97723 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -512,7 +512,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val);
if (error)
- return error;
+ return dev_err_probe(dev, error, "Failed to read product ID\n");
if (val != cap->product_id) {
dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
@@ -522,7 +522,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
error = regmap_read(priv->regmap, CAP11XX_REG_MANUFACTURER_ID, &val);
if (error)
- return error;
+ return dev_err_probe(dev, error, "Failed to read manufacturer ID\n");
if (val != CAP11XX_MANUFACTURER_ID) {
dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
@@ -531,11 +531,8 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
}
error = regmap_read(priv->regmap, CAP11XX_REG_REVISION, &rev);
- if (error < 0)
- return error;
-
- dev_info(dev, "CAP11XX detected, model %s, revision 0x%02x\n",
- id->name, rev);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to read revision\n");
priv->model = cap;
--
2.54.0
^ permalink raw reply related
* [PATCH 2/8] Input: cap11xx - remove unused register macros
From: Jun Yan @ 2026-06-06 15:03 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
Remove unused register address macros and unused definitions in
the cap11xx_reg_defaults array and cap11xx_volatile_reg.
This cleanup reduces code clutter and makes the driver easier to
maintain without affecting functionality.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 58 --------------------------------
1 file changed, 58 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 485d8ba97723..686174722204 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -20,53 +20,23 @@
#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6)
#define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
#define CAP11XX_REG_MAIN_CONTROL_DLSEEP BIT(4)
-#define CAP11XX_REG_GENERAL_STATUS 0x02
#define CAP11XX_REG_SENSOR_INPUT 0x03
-#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a
-#define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X))
#define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f
#define CAP11XX_REG_SENSITIVITY_CONTROL_DELTA_SENSE_MASK 0x70
-#define CAP11XX_REG_CONFIG 0x20
-#define CAP11XX_REG_SENSOR_ENABLE 0x21
-#define CAP11XX_REG_SENSOR_CONFIG 0x22
-#define CAP11XX_REG_SENSOR_CONFIG2 0x23
-#define CAP11XX_REG_SAMPLING_CONFIG 0x24
-#define CAP11XX_REG_CALIBRATION 0x26
-#define CAP11XX_REG_INT_ENABLE 0x27
#define CAP11XX_REG_REPEAT_RATE 0x28
#define CAP11XX_REG_SIGNAL_GUARD_ENABLE 0x29
-#define CAP11XX_REG_MT_CONFIG 0x2a
-#define CAP11XX_REG_MT_PATTERN_CONFIG 0x2b
-#define CAP11XX_REG_MT_PATTERN 0x2d
-#define CAP11XX_REG_RECALIB_CONFIG 0x2f
#define CAP11XX_REG_SENSOR_THRESH(X) (0x30 + (X))
-#define CAP11XX_REG_SENSOR_NOISE_THRESH 0x38
-#define CAP11XX_REG_STANDBY_CHANNEL 0x40
-#define CAP11XX_REG_STANDBY_CONFIG 0x41
-#define CAP11XX_REG_STANDBY_SENSITIVITY 0x42
-#define CAP11XX_REG_STANDBY_THRESH 0x43
#define CAP11XX_REG_CONFIG2 0x44
#define CAP11XX_REG_CONFIG2_ALT_POL BIT(6)
-#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
-#define CAP11XX_REG_LED_POLARITY 0x73
#define CAP11XX_REG_LED_OUTPUT_CONTROL 0x74
#define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG 0x80
#define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG2 0x81
-
-#define CAP11XX_REG_LED_DUTY_CYCLE_1 0x90
-#define CAP11XX_REG_LED_DUTY_CYCLE_2 0x91
-#define CAP11XX_REG_LED_DUTY_CYCLE_3 0x92
#define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93
-#define CAP11XX_REG_LED_DUTY_MIN_MASK (0x0f)
-#define CAP11XX_REG_LED_DUTY_MIN_MASK_SHIFT (0)
#define CAP11XX_REG_LED_DUTY_MAX_MASK (0xf0)
#define CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT (4)
#define CAP11XX_REG_LED_DUTY_MAX_VALUE (15)
-#define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X))
-#define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9
-#define CAP11XX_REG_SENSOR_CALIB_LSB2 0xba
#define CAP11XX_REG_PRODUCT_ID 0xfd
#define CAP11XX_REG_MANUFACTURER_ID 0xfe
#define CAP11XX_REG_REVISION 0xff
@@ -111,37 +81,15 @@ struct cap11xx_hw_model {
static const struct reg_default cap11xx_reg_defaults[] = {
{ CAP11XX_REG_MAIN_CONTROL, 0x00 },
- { CAP11XX_REG_GENERAL_STATUS, 0x00 },
- { CAP11XX_REG_SENSOR_INPUT, 0x00 },
- { CAP11XX_REG_NOISE_FLAG_STATUS, 0x00 },
{ CAP11XX_REG_SENSITIVITY_CONTROL, 0x2f },
- { CAP11XX_REG_CONFIG, 0x20 },
- { CAP11XX_REG_SENSOR_ENABLE, 0x3f },
- { CAP11XX_REG_SENSOR_CONFIG, 0xa4 },
- { CAP11XX_REG_SENSOR_CONFIG2, 0x07 },
- { CAP11XX_REG_SAMPLING_CONFIG, 0x39 },
- { CAP11XX_REG_CALIBRATION, 0x00 },
- { CAP11XX_REG_INT_ENABLE, 0x3f },
{ CAP11XX_REG_REPEAT_RATE, 0x3f },
- { CAP11XX_REG_MT_CONFIG, 0x80 },
- { CAP11XX_REG_MT_PATTERN_CONFIG, 0x00 },
- { CAP11XX_REG_MT_PATTERN, 0x3f },
- { CAP11XX_REG_RECALIB_CONFIG, 0x8a },
{ CAP11XX_REG_SENSOR_THRESH(0), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(1), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(2), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(3), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(4), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(5), 0x40 },
- { CAP11XX_REG_SENSOR_NOISE_THRESH, 0x01 },
- { CAP11XX_REG_STANDBY_CHANNEL, 0x00 },
- { CAP11XX_REG_STANDBY_CONFIG, 0x39 },
- { CAP11XX_REG_STANDBY_SENSITIVITY, 0x02 },
- { CAP11XX_REG_STANDBY_THRESH, 0x40 },
{ CAP11XX_REG_CONFIG2, 0x40 },
- { CAP11XX_REG_LED_POLARITY, 0x00 },
- { CAP11XX_REG_SENSOR_CALIB_LSB1, 0x00 },
- { CAP11XX_REG_SENSOR_CALIB_LSB2, 0x00 },
};
static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
@@ -149,12 +97,6 @@ static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case CAP11XX_REG_MAIN_CONTROL:
case CAP11XX_REG_SENSOR_INPUT:
- case CAP11XX_REG_SENOR_DELTA(0):
- case CAP11XX_REG_SENOR_DELTA(1):
- case CAP11XX_REG_SENOR_DELTA(2):
- case CAP11XX_REG_SENOR_DELTA(3):
- case CAP11XX_REG_SENOR_DELTA(4):
- case CAP11XX_REG_SENOR_DELTA(5):
return true;
}
--
2.54.0
^ permalink raw reply related
* [PATCH 3/8] dt-bindings: input: microchip,cap11xx: Cleanup and refine LED constraints
From: Jun Yan @ 2026-06-06 15:03 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
Add detailed datasheet links for all supported CAP11xx devices.
Unify LED node pattern to support all chip variants in preparation
for CAP1114 support.
Remove redundant LED properties inherited from common.yaml
Apply per-chip LED channel limits:
- CAP1126: max 2 channels (0-1)
- CAP1188: max 8 channels (0-7)
- CAP1106, CAP12xx: no LED support
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
.../bindings/input/microchip,cap11xx.yaml | 51 ++++++++++++++-----
1 file changed, 37 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index 7ade03f1b32b..99d00f572a2d 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -10,6 +10,15 @@ description: |
The Microchip CAP1xxx Family of RightTouchTM multiple-channel capacitive
touch controllers and LED drivers. The device communication via I2C only.
+ For more product information please see the links below:
+ CAP1106: https://ww1.microchip.com/downloads/en/DeviceDoc/00001624B.pdf
+ CAP1126: https://ww1.microchip.com/downloads/en/DeviceDoc/00001623B.pdf
+ CAP1188: https://ww1.microchip.com/downloads/en/DeviceDoc/00001620C.pdf
+ CAP1203: https://ww1.microchip.com/downloads/en/DeviceDoc/00001572B.pdf
+ CAP1206: https://ww1.microchip.com/downloads/en/DeviceDoc/00001567B.pdf
+ CAP1293: https://ww1.microchip.com/downloads/en/DeviceDoc/00001566B.pdf
+ CAP1298: https://ww1.microchip.com/downloads/en/DeviceDoc/00001571B.pdf
+
maintainers:
- Rob Herring <robh@kernel.org>
@@ -124,25 +133,21 @@ properties:
The number of entries must correspond to the number of channels.
patternProperties:
- "^led@[0-7]$":
+ "^led@[0-9a-f]$":
type: object
description: CAP11xx LEDs
$ref: /schemas/leds/common.yaml#
properties:
reg:
- enum: [0, 1, 2, 3, 4, 5, 6, 7]
-
- label: true
-
- linux,default-trigger: true
-
- default-state: true
+ description: LED channel number
+ minimum: 0
+ maximum: 7
required:
- reg
- additionalProperties: false
+ unevaluatedProperties: false
allOf:
- $ref: input.yaml
@@ -158,7 +163,20 @@ allOf:
- microchip,cap1298
then:
patternProperties:
- "^led@[0-7]$": false
+ "^led@": false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1126
+ then:
+ patternProperties:
+ "^led@":
+ properties:
+ reg:
+ maximum: 1
- if:
properties:
@@ -183,6 +201,9 @@ additionalProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/leds/common.h>
+
i2c {
#address-cells = <1>;
#size-cells = <0>;
@@ -208,19 +229,21 @@ examples:
#size-cells = <0>;
led@0 {
- label = "cap11xx:green:usr0";
reg = <0>;
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_GREEN>;
};
led@1 {
- label = "cap11xx:green:usr1";
reg = <1>;
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_GREEN>;
};
led@2 {
- label = "cap11xx:green:alive";
reg = <2>;
- linux,default-trigger = "heartbeat";
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_GREEN>;
};
};
};
--
2.54.0
^ permalink raw reply related
* [PATCH 4/8] dt-bindings: input: microchip,cap11xx: Add reset-gpios property
From: Jun Yan @ 2026-06-06 15:03 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
Add support for the optional reset-gpios property to describe
the active-high reset pin for CAP1126/CAP1188 devices.
Driving the GPIO high asserts reset and deep sleep, while driving
it low releases reset for normal operation.
Restrict this property to be available only on CAP1126 and CAP1188
chips, as other CAP11xx variants do not have a hardware reset pin.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
.../bindings/input/microchip,cap11xx.yaml | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index 99d00f572a2d..e307628350c2 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -49,6 +49,13 @@ properties:
device's ALERT#/CM_IRQ# pin is connected to.
The device only has one interrupt source.
+ reset-gpios:
+ description: |
+ GPIO connected to the active-high RESET pin of the chip;
+ driving it high asserts reset and deep sleep, while driving
+ it low releases reset for normal operation.
+ maxItems: 1
+
autorepeat:
description: |
Enables the Linux input system's autorepeat feature on the input device.
@@ -151,6 +158,20 @@ patternProperties:
allOf:
- $ref: input.yaml
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1106
+ - microchip,cap1203
+ - microchip,cap1206
+ - microchip,cap1293
+ - microchip,cap1298
+ then:
+ properties:
+ reset-gpios: false
+
- if:
properties:
compatible:
@@ -225,6 +246,8 @@ examples:
<109>, /* KEY_PAGEDOWN */
<104>; /* KEY_PAGEUP */
+ reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+
#address-cells = <1>;
#size-cells = <0>;
--
2.54.0
^ permalink raw reply related
* [PATCH 5/8] Input: cap11xx - add reset gpio support
From: Jun Yan @ 2026-06-06 15:03 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
Some CAP11xx devices (CAP1126/CAP1188) have a dedicated RESET pin.
Add hardware reset operation to improve device reliability and
ensure proper initialization on probe.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 686174722204..7015aa7654ce 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -43,6 +43,10 @@
#define CAP11XX_MANUFACTURER_ID 0x5d
+#define CAP11XX_T_RST_FILT_MIN 10000
+#define CAP11XX_T_RST_ON_MIN 400000
+#define CAP11XX_T_RST_ON_MAX 500000
+
#ifdef CONFIG_LEDS_CLASS
struct cap11xx_led {
struct cap11xx_priv *priv;
@@ -55,6 +59,7 @@ struct cap11xx_priv {
struct regmap *regmap;
struct device *dev;
struct input_dev *idev;
+ struct gpio_desc *reset_gpio;
const struct cap11xx_hw_model *model;
struct cap11xx_led *leds;
@@ -452,6 +457,17 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "Failed to get 'reset' GPIO\n");
+ if (priv->reset_gpio) {
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ usleep_range(CAP11XX_T_RST_FILT_MIN, CAP11XX_T_RST_FILT_MIN * 2);
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+ usleep_range(CAP11XX_T_RST_ON_MIN, CAP11XX_T_RST_ON_MAX);
+ }
+
error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val);
if (error)
return dev_err_probe(dev, error, "Failed to read product ID\n");
--
2.54.0
^ permalink raw reply related
* [PATCH 6/8] Input: cap11xx - refactor code for better CAP1114 support.
From: Jun Yan @ 2026-06-06 15:03 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
Extend cap11xx_hw_model structure to support CAP1114 with
different register offsets and hardware characteristics:
- led_output_control_reg_base: different address on CAP1114
- sensor_input_reg_base: different address on CAP1114
- num_sensor_thresholds: separate value from num_channels for CAP1114
- has_repeat_en: repeat enable support, disabled by default on CAP1114
Include linux/bits.h, update the register operations related to LEDs.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 73 +++++++++++++++++++++++---------
1 file changed, 53 insertions(+), 20 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 7015aa7654ce..408880cf6516 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -5,6 +5,7 @@
* (c) 2014 Daniel Mack <linux@zonque.org>
*/
+#include <linux/bits.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -34,7 +35,6 @@
#define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93
#define CAP11XX_REG_LED_DUTY_MAX_MASK (0xf0)
-#define CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT (4)
#define CAP11XX_REG_LED_DUTY_MAX_VALUE (15)
#define CAP11XX_REG_PRODUCT_ID 0xfd
@@ -76,10 +76,14 @@ struct cap11xx_priv {
struct cap11xx_hw_model {
u8 product_id;
+ u8 led_output_control_reg_base;
+ u8 sensor_input_reg_base;
unsigned int num_channels;
unsigned int num_leds;
+ unsigned int num_sensor_thresholds;
bool has_gain;
bool has_irq_config;
+ bool has_repeat_en;
bool has_sensitivity_control;
bool has_signal_guard;
};
@@ -204,8 +208,8 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
}
if (!of_property_read_u32_array(node, "microchip,input-threshold",
- priv->thresholds, priv->model->num_channels)) {
- for (i = 0; i < priv->model->num_channels; i++) {
+ priv->thresholds, priv->model->num_sensor_thresholds)) {
+ for (i = 0; i < priv->model->num_sensor_thresholds; i++) {
if (priv->thresholds[i] > 127) {
dev_err(dev, "Invalid input-threshold value %u\n",
priv->thresholds[i]);
@@ -279,10 +283,12 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
of_property_read_u32_array(node, "linux,keycodes",
priv->keycodes, priv->model->num_channels);
- /* Disable autorepeat. The Linux input system has its own handling. */
- error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
- if (error)
- return error;
+ if (priv->model->has_repeat_en) {
+ /* Disable autorepeat. The Linux input system has its own handling. */
+ error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
+ if (error)
+ return error;
+ }
return 0;
}
@@ -301,7 +307,7 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
if (ret < 0)
goto out;
- ret = regmap_read(priv->regmap, CAP11XX_REG_SENSOR_INPUT, &status);
+ ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base, &status);
if (ret < 0)
goto out;
@@ -355,7 +361,7 @@ static int cap11xx_led_set(struct led_classdev *cdev,
* 0 (OFF) and 1 (ON).
*/
return regmap_update_bits(priv->regmap,
- CAP11XX_REG_LED_OUTPUT_CONTROL,
+ priv->model->led_output_control_reg_base,
BIT(led->reg),
value ? BIT(led->reg) : 0);
}
@@ -367,6 +373,7 @@ static int cap11xx_init_leds(struct device *dev,
struct cap11xx_led *led;
int cnt = of_get_child_count(node);
int error;
+ u32 duty_val;
if (!num_leds || !cnt)
return 0;
@@ -380,15 +387,18 @@ static int cap11xx_init_leds(struct device *dev,
priv->leds = led;
+ /* Set all LEDs to off */
error = regmap_update_bits(priv->regmap,
- CAP11XX_REG_LED_OUTPUT_CONTROL, 0xff, 0);
+ priv->model->led_output_control_reg_base,
+ GENMASK(num_leds - 1, 0), 0);
if (error)
return error;
+ duty_val = FIELD_PREP(CAP11XX_REG_LED_DUTY_MAX_MASK,
+ CAP11XX_REG_LED_DUTY_MAX_VALUE);
+
error = regmap_update_bits(priv->regmap, CAP11XX_REG_LED_DUTY_CYCLE_4,
- CAP11XX_REG_LED_DUTY_MAX_MASK,
- CAP11XX_REG_LED_DUTY_MAX_VALUE <<
- CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT);
+ CAP11XX_REG_LED_DUTY_MAX_MASK, duty_val);
if (error)
return error;
@@ -554,41 +564,64 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
}
static const struct cap11xx_hw_model cap1106_model = {
- .product_id = 0x55, .num_channels = 6, .num_leds = 0,
+ .product_id = 0x55,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6,
.has_gain = true,
.has_irq_config = true,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1126_model = {
- .product_id = 0x53, .num_channels = 6, .num_leds = 2,
+ .product_id = 0x53,
+ .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .num_channels = 6, .num_leds = 2, .num_sensor_thresholds = 6,
.has_gain = true,
.has_irq_config = true,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1188_model = {
- .product_id = 0x50, .num_channels = 8, .num_leds = 8,
+ .product_id = 0x50,
+ .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .num_channels = 8, .num_leds = 8, .num_sensor_thresholds = 8,
.has_gain = true,
.has_irq_config = true,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1203_model = {
- .product_id = 0x6d, .num_channels = 3, .num_leds = 0,
+ .product_id = 0x6d,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1206_model = {
- .product_id = 0x67, .num_channels = 6, .num_leds = 0,
+ .product_id = 0x67,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1293_model = {
- .product_id = 0x6f, .num_channels = 3, .num_leds = 0,
+ .product_id = 0x6f,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3,
.has_gain = true,
+ .has_repeat_en = true,
.has_sensitivity_control = true,
.has_signal_guard = true,
};
static const struct cap11xx_hw_model cap1298_model = {
- .product_id = 0x71, .num_channels = 8, .num_leds = 0,
+ .product_id = 0x71,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .num_channels = 8, .num_leds = 0, .num_sensor_thresholds = 8,
.has_gain = true,
+ .has_repeat_en = true,
.has_sensitivity_control = true,
.has_signal_guard = true,
};
--
2.54.0
^ permalink raw reply related
* [PATCH 7/8] dt-bindings: input: microchip,cap11xx: Add CAP1114 support
From: Jun Yan @ 2026-06-06 15:04 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
Add the compatible string for CAP1114, include its datasheet URL,
and update the maximum count of LED channels and linux,keycodes entries.
Add description for microchip,input-threshold: CAP1114 only provides eight
threshold entries, which does not match its total channel count.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
.../bindings/input/microchip,cap11xx.yaml | 21 +++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index e307628350c2..08233386a433 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -12,6 +12,7 @@ description: |
For more product information please see the links below:
CAP1106: https://ww1.microchip.com/downloads/en/DeviceDoc/00001624B.pdf
+ CAP1114: https://ww1.microchip.com/downloads/en/DeviceDoc/00002444A.pdf
CAP1126: https://ww1.microchip.com/downloads/en/DeviceDoc/00001623B.pdf
CAP1188: https://ww1.microchip.com/downloads/en/DeviceDoc/00001620C.pdf
CAP1203: https://ww1.microchip.com/downloads/en/DeviceDoc/00001572B.pdf
@@ -26,6 +27,7 @@ properties:
compatible:
enum:
- microchip,cap1106
+ - microchip,cap1114
- microchip,cap1126
- microchip,cap1188
- microchip,cap1203
@@ -62,7 +64,7 @@ properties:
linux,keycodes:
minItems: 3
- maxItems: 8
+ maxItems: 14
description: |
Specifies an array of numeric keycode values to
be used for the channels. If this property is
@@ -122,6 +124,8 @@ properties:
is required for a touch to be registered, making the touch sensor less
sensitive.
The number of entries must correspond to the number of channels.
+ CAP1114 is an exception where channels 8~14 reuse the eighth entry's
+ threshold, so counts differ.
microchip,calib-sensitivity:
$ref: /schemas/types.yaml#/definitions/uint32-array
@@ -149,7 +153,7 @@ patternProperties:
reg:
description: LED channel number
minimum: 0
- maximum: 7
+ maximum: 10
required:
- reg
@@ -199,6 +203,19 @@ allOf:
reg:
maximum: 1
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1188
+ then:
+ patternProperties:
+ "^led@":
+ properties:
+ reg:
+ maximum: 7
+
- if:
properties:
compatible:
--
2.54.0
^ permalink raw reply related
* [PATCH 8/8] Input: cap11xx - add support for CAP1114
From: Jun Yan @ 2026-06-06 15:04 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260606150458.250606-1-jerrysteve1101@gmail.com>
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
The CAP1114 uses two separate control registers for LED output
management and requires two button status registers for touch input
state reporting.
By default, channels CS8~CS14 operate as a single grouped block.
Set the corresponding register enable bit to enable these channels as
independent touch inputs. Note these channels share the input threshold
of the eighth entry, causing num_sensor_thresholds to differ from
num_channels.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 65 +++++++++++++++++++++++++++++++-
1 file changed, 64 insertions(+), 1 deletion(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 408880cf6516..2aba3b508947 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -17,6 +17,12 @@
#include <linux/gpio/consumer.h>
#include <linux/bitfield.h>
+#define CAP1114_REG_BUTTON_STATUS1 0x03
+#define CAP1114_REG_BUTTON_STATUS2 0x04
+#define CAP1114_REG_CONFIG2 0x40
+#define CAP1114_REG_CONFIG2_VOL_UP_DOWN BIT(1)
+#define CAP1114_REG_LED_OUTPUT_CONTROL1 0x73
+
#define CAP11XX_REG_MAIN_CONTROL 0x00
#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6)
#define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
@@ -82,6 +88,7 @@ struct cap11xx_hw_model {
unsigned int num_leds;
unsigned int num_sensor_thresholds;
bool has_gain;
+ bool has_grouped_sensors;
bool has_irq_config;
bool has_repeat_en;
bool has_sensitivity_control;
@@ -98,6 +105,9 @@ static const struct reg_default cap11xx_reg_defaults[] = {
{ CAP11XX_REG_SENSOR_THRESH(3), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(4), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(5), 0x40 },
+ { CAP11XX_REG_SENSOR_THRESH(6), 0x40 },
+ { CAP11XX_REG_SENSOR_THRESH(7), 0x40 },
+ { CAP11XX_REG_SENSOR_THRESH(8), 0x40 },
{ CAP11XX_REG_CONFIG2, 0x40 },
};
@@ -106,6 +116,12 @@ static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case CAP11XX_REG_MAIN_CONTROL:
case CAP11XX_REG_SENSOR_INPUT:
+ /*
+ * CAP1114_REG_BUTTON_STATUS1 (CAP11XX_REG_SENSOR_INPUT) and
+ * CAP1114_REG_BUTTON_STATUS2 is volatile for the CAP1114,
+ * which supports more than 8 touch channels.
+ */
+ case CAP1114_REG_BUTTON_STATUS2:
return true;
}
@@ -283,6 +299,16 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
of_property_read_u32_array(node, "linux,keycodes",
priv->keycodes, priv->model->num_channels);
+ /*
+ * CAP1114 needs dedicated configuration to split grouped sensors into independent inputs.
+ */
+ if (priv->model->has_grouped_sensors) {
+ error = regmap_set_bits(priv->regmap, CAP1114_REG_CONFIG2,
+ CAP1114_REG_CONFIG2_VOL_UP_DOWN);
+ if (error)
+ return error;
+ }
+
if (priv->model->has_repeat_en) {
/* Disable autorepeat. The Linux input system has its own handling. */
error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
@@ -311,6 +337,20 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
if (ret < 0)
goto out;
+ if (priv->model->num_channels > 8) {
+ unsigned int status2;
+
+ ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base + 1, &status2);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * CAP1114 STATUS1 register only contains data for the first 6 channels.
+ * the remaining channels is stored in STATUS2.
+ */
+ status |= FIELD_PREP(GENMASK(13, 6), status2);
+ }
+
for (i = 0; i < priv->idev->keycodemax; i++)
input_report_key(priv->idev, priv->keycodes[i],
status & (1 << i));
@@ -360,7 +400,13 @@ static int cap11xx_led_set(struct led_classdev *cdev,
* limitation. Brightness levels per LED are either
* 0 (OFF) and 1 (ON).
*/
- return regmap_update_bits(priv->regmap,
+ if (led->reg >= 8)
+ return regmap_update_bits(priv->regmap,
+ priv->model->led_output_control_reg_base + 1,
+ BIT(led->reg - 8),
+ value ? BIT(led->reg - 8) : 0);
+ else
+ return regmap_update_bits(priv->regmap,
priv->model->led_output_control_reg_base,
BIT(led->reg),
value ? BIT(led->reg) : 0);
@@ -393,6 +439,13 @@ static int cap11xx_init_leds(struct device *dev,
GENMASK(num_leds - 1, 0), 0);
if (error)
return error;
+ if (num_leds > 8) {
+ error = regmap_update_bits(priv->regmap,
+ priv->model->led_output_control_reg_base + 1,
+ GENMASK(num_leds - 8 - 1, 0), 0);
+ if (error)
+ return error;
+ }
duty_val = FIELD_PREP(CAP11XX_REG_LED_DUTY_MAX_MASK,
CAP11XX_REG_LED_DUTY_MAX_VALUE);
@@ -572,6 +625,14 @@ static const struct cap11xx_hw_model cap1106_model = {
.has_repeat_en = true,
};
+static const struct cap11xx_hw_model cap1114_model = {
+ .product_id = 0x3a,
+ .led_output_control_reg_base = CAP1114_REG_LED_OUTPUT_CONTROL1,
+ .sensor_input_reg_base = CAP1114_REG_BUTTON_STATUS1,
+ .num_channels = 14, .num_leds = 11, .num_sensor_thresholds = 8,
+ .has_grouped_sensors = true,
+};
+
static const struct cap11xx_hw_model cap1126_model = {
.product_id = 0x53,
.led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL,
@@ -628,6 +689,7 @@ static const struct cap11xx_hw_model cap1298_model = {
static const struct of_device_id cap11xx_dt_ids[] = {
{ .compatible = "microchip,cap1106", .data = &cap1106_model },
+ { .compatible = "microchip,cap1114", .data = &cap1114_model },
{ .compatible = "microchip,cap1126", .data = &cap1126_model },
{ .compatible = "microchip,cap1188", .data = &cap1188_model },
{ .compatible = "microchip,cap1203", .data = &cap1203_model },
@@ -640,6 +702,7 @@ MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
static const struct i2c_device_id cap11xx_i2c_ids[] = {
{ .name = "cap1106", .driver_data = (kernel_ulong_t)&cap1106_model },
+ { .name = "cap1114", .driver_data = (kernel_ulong_t)&cap1114_model },
{ .name = "cap1126", .driver_data = (kernel_ulong_t)&cap1126_model },
{ .name = "cap1188", .driver_data = (kernel_ulong_t)&cap1188_model },
{ .name = "cap1203", .driver_data = (kernel_ulong_t)&cap1203_model },
--
2.54.0
^ permalink raw reply related
* Re: [PATCH 5/8] Input: cap11xx - add reset gpio support
From: sashiko-bot @ 2026-06-06 15:13 UTC (permalink / raw)
To: Jun Yan; +Cc: robh, dmitry.torokhov, conor+dt, devicetree, linux-input
In-Reply-To: <20260606150458.250606-6-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] Inefficient delay using usleep_range() for a large duration (400-500ms).
- [Low] Missing explicit inclusion of <linux/delay.h>.
--
commit 83de47341df3454fdb8216dc0a95948c3f158a40
Author: Jun Yan <jerrysteve1101@gmail.com>
Input: cap11xx - add reset gpio support
This commit adds hardware reset support for CAP11xx devices by toggling a
dedicated reset GPIO during the i2c probe phase. It incorporates specific
timing requirements for the reset filter and active reset duration.
> diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
> index 686174722204c..7015aa7654ce7 100644
> --- a/drivers/input/keyboard/cap11xx.c
> +++ b/drivers/input/keyboard/cap11xx.c
[ ... ]
> @@ -452,6 +457,17 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
> if (IS_ERR(priv->regmap))
> return PTR_ERR(priv->regmap);
>
> + priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> + if (IS_ERR(priv->reset_gpio))
> + return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
> + "Failed to get 'reset' GPIO\n");
> + if (priv->reset_gpio) {
> + gpiod_set_value_cansleep(priv->reset_gpio, 1);
> + usleep_range(CAP11XX_T_RST_FILT_MIN, CAP11XX_T_RST_FILT_MIN * 2);
> + gpiod_set_value_cansleep(priv->reset_gpio, 0);
> + usleep_range(CAP11XX_T_RST_ON_MIN, CAP11XX_T_RST_ON_MAX);
[Severity: Low]
Does this regression introduce unnecessary overhead by using usleep_range()
for a 400-500ms delay in cap11xx_i2c_probe()?
According to kernel timer guidelines, usleep_range() is designed for short
delays (10us to 20ms) and sets up high-resolution timers. For delays longer
than 20ms, using msleep() or fsleep() avoids unnecessary overhead and
expensive CPU wakeups.
[Severity: Low]
Could this regression in header dependencies be avoided by explicitly
including <linux/delay.h> since we are now calling usleep_range() here?
While the code might compile due to implicit inclusion via other headers,
relying on implicit includes can sometimes lead to build failures on other
architectures or if intermediate headers are refactored in the future.
> + }
> +
> error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val);
> if (error)
> return dev_err_probe(dev, error, "Failed to read product ID\n");
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260606150458.250606-1-jerrysteve1101@gmail.com?part=5
^ permalink raw reply
* Re: [PATCH 7/8] dt-bindings: input: microchip,cap11xx: Add CAP1114 support
From: sashiko-bot @ 2026-06-06 15:16 UTC (permalink / raw)
To: Jun Yan; +Cc: robh, dmitry.torokhov, devicetree, linux-input, conor+dt
In-Reply-To: <20260606150458.250606-8-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The new `microchip,cap1114` compatible string was omitted from the `if-then` conditional block that restricts `microchip,signal-guard` and `microchip,calib-sensitivity` for prior CAP11xx generations.
--
commit 5c58a6baee363da7434a9782efa913c250015130
Author: Jun Yan <jerrysteve1101@gmail.com>
dt-bindings: input: microchip,cap11xx: Add CAP1114 support
This commit adds device tree binding support for the CAP1114 capacitive
touch sensor. It updates the compatible string list, maximum LED channel
counts, and keycode entries.
> diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> index e307628350c24..08233386a4336 100644
> --- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> +++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
[ ... ]
> @@ -26,6 +27,7 @@ properties:
> compatible:
> enum:
> - microchip,cap1106
> + - microchip,cap1114
> - microchip,cap1126
> - microchip,cap1188
> - microchip,cap1203
[Severity: Medium]
Since microchip,cap1114 is being added here, could this validation
regression be avoided by also appending it to the if-then conditional
block further down the schema that restricts microchip,signal-guard and
microchip,calib-sensitivity?
Documentation/devicetree/bindings/input/microchip,cap11xx.yaml:
- if:
properties:
compatible:
contains:
enum:
- microchip,cap1106
- microchip,cap1126
- microchip,cap1188
- microchip,cap1203
- microchip,cap1206
then:
properties:
microchip,signal-guard: false
microchip,calib-sensitivity: false
Since the maxItems for these properties remains at 8 (and CAP1114 has 14
channels), it appears CAP1114 does not support them either. Omitting the
new compatible string from this block allows device trees with these
unsupported properties to pass schema validation.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260606150458.250606-1-jerrysteve1101@gmail.com?part=7
^ permalink raw reply
* Re: [PATCH 4/8] dt-bindings: input: microchip,cap11xx: Add reset-gpios property
From: sashiko-bot @ 2026-06-06 15:18 UTC (permalink / raw)
To: Jun Yan; +Cc: conor+dt, linux-input, robh, devicetree, dmitry.torokhov
In-Reply-To: <20260606150458.250606-5-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The driver fails to probe when a Device Tree fallback compatible string is used because it rigidly requires an exact I2C device ID match.
--
commit 804bdcc3e4e43cb8aa1a476f171c69be30e83854
Author: Jun Yan <jerrysteve1101@gmail.com>
dt-bindings: input: microchip,cap11xx: Add reset-gpios property
Add support for the optional reset-gpios property to describe
the active-high reset pin for CAP1126/CAP1188 devices.
Driving the GPIO high asserts reset and deep sleep, while driving
it low releases reset for normal operation.
Restrict this property to be available only on CAP1126 and CAP1188
chips, as other CAP11xx variants do not have a hardware reset pin.
> diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> index 99d00f572a2d9..e307628350c24 100644
> --- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> +++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
[ ... ]
[Severity: High]
This isn't a bug introduced by this patch, but since we are updating
bindings for this hardware, is the I2C ID matching in the driver too
strict for standard Device Tree fallback compatibles?
Looking at cap11xx_i2c_probe() in drivers/input/keyboard/cap11xx.c:
id = i2c_client_get_device_id(i2c_client);
cap = i2c_get_match_data(i2c_client);
if (!id || !cap || !cap->num_channels) {
dev_err(dev, "Invalid device configuration\n");
return -EINVAL;
}
When a device is instantiated from a Device Tree using a fallback compatible
string (e.g., compatible = "vendor,custom-board", "microchip,cap1188"), the
I2C core sets client->name to the local string without the vendor prefix.
Because this local name is not present in the cap11xx_i2c_ids table,
i2c_client_get_device_id() evaluates to NULL and completely aborts the probe.
Could this early exit be updated so that valid I2C clients instantiated via
fallback compatibles are not erroneously rejected?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260606150458.250606-1-jerrysteve1101@gmail.com?part=4
^ permalink raw reply
* Re: [PATCH 8/8] Input: cap11xx - add support for CAP1114
From: sashiko-bot @ 2026-06-06 15:20 UTC (permalink / raw)
To: Jun Yan; +Cc: robh, dmitry.torokhov, conor+dt, linux-input, devicetree
In-Reply-To: <20260606150458.250606-9-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Buffer overflow when reading the 'microchip,calib-sensitivity' device tree property for devices with >8 channels.
- [High] Failure to mask `STATUS1` before ORing `STATUS2` can cause phantom key presses for channels 7 and 8.
- [Low] Bitmask calculation for 'microchip,signal-guard' truncates settings for channels 8 and above.
--
commit 8885b1d0f98cb8d5ca53ba5fd9a458743481d5be
Author: Jun Yan <jerrysteve1101@gmail.com>
Input: cap11xx - add support for CAP1114
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support. The CAP1114 uses two separate control registers
for LED output management and requires two button status registers for touch
input state reporting.
> diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
> index 408880cf65167..2aba3b508947d 100644
> --- a/drivers/input/keyboard/cap11xx.c
> +++ b/drivers/input/keyboard/cap11xx.c
[ ... ]
> @@ -311,6 +337,20 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
> if (ret < 0)
> goto out;
>
> + if (priv->model->num_channels > 8) {
> + unsigned int status2;
> +
> + ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base + 1, &status2);
> + if (ret < 0)
> + goto out;
> +
> + /*
> + * CAP1114 STATUS1 register only contains data for the first 6 channels.
> + * the remaining channels is stored in STATUS2.
> + */
> + status |= FIELD_PREP(GENMASK(13, 6), status2);
[Severity: High]
If the hardware sets reserved bits 6 or 7 in the first status register to 1,
will they be preserved and incorrectly reported as touch events for channels
7 and 8?
Since the status variable (which holds STATUS1) is not masked before this OR
operation, any reserved bits set in STATUS1 could overlap with the shifted
status2 values.
Should the status variable be masked to clear bits 6 and 7 before ORing in
status2?
> + }
> +
> for (i = 0; i < priv->idev->keycodemax; i++)
[ ... ]
> @@ -572,6 +625,14 @@ static const struct cap11xx_hw_model cap1106_model = {
> .has_repeat_en = true,
> };
>
> +static const struct cap11xx_hw_model cap1114_model = {
> + .product_id = 0x3a,
> + .led_output_control_reg_base = CAP1114_REG_LED_OUTPUT_CONTROL1,
> + .sensor_input_reg_base = CAP1114_REG_BUTTON_STATUS1,
> + .num_channels = 14, .num_leds = 11, .num_sensor_thresholds = 8,
[Severity: High]
Does configuring num_channels to 14 cause a buffer overflow when parsing the
device tree?
In struct cap11xx_priv, calib_sensitivities is defined as a fixed 8-element
array:
struct cap11xx_priv {
...
u32 calib_sensitivities[8];
u32 keycodes[];
};
When cap11xx_init_keys() parses the microchip,calib-sensitivity property, it
requests num_channels elements:
of_property_read_u32_array(node, "microchip,calib-sensitivity",
priv->calib_sensitivities,
priv->model->num_channels)
If the device tree provides 14 elements, won't this write 56 bytes into the
32-byte array, overflowing into the adjacent keycodes flexible array?
[Severity: Low]
Additionally, does setting num_channels to 14 cause truncation in the
microchip,signal-guard bitmask logic?
In cap11xx_init_keys(), priv->signal_guard_inputs_mask is typed as a u8, but
the initialization loop runs up to num_channels:
if (u32_val)
priv->signal_guard_inputs_mask |= 0x01 << i;
For i >= 8, does the shifted bit exceed the 8-bit width and get silently
truncated to 0 during the assignment?
> + .has_grouped_sensors = true,
> +};
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260606150458.250606-1-jerrysteve1101@gmail.com?part=8
^ permalink raw reply
* [PATCH v3] HID: i2c-hid: Refactor _DSM helper and add i2c-hid-acpi-prp0001 driver
From: 谢致邦 (XIE Zhibang) @ 2026-06-06 16:06 UTC (permalink / raw)
To: linux-input, hansg, dmitry.torokhov, bentiss, yeking
Cc: dianders, jikos, linux-kernel, sashiko-bot, sashiko-reviews,
superm1, 谢致邦 (XIE Zhibang)
In-Reply-To: <tencent_3310584FFECD3CBBB563FC8C079ED072F40A@qq.com>
Move the _DSM call that gets the HID descriptor address from
i2c-hid-acpi.c into i2c-hid-acpi.h as a static inline so both the ACPI
and the new PRP0001 driver can use it. While refactoring, move the
blacklist check and the _DSM call to the top of probe() to avoid a
pointless alloc when the device is blacklisted or does not implement the
_DSM.
Some devices, for example the Lenovo KaiTian N60d and Inspur CP300L3,
are declared with _HID "PRP0001" and _DSD compatible "hid-over-i2c" but
lack "hid-descr-addr" from the _DSD and provide the HID descriptor
address only through an ACPI _DSM. The OF driver fails to probe them
because it requires hid-descr-addr. Add a new driver that handles these
devices by calling the shared _DSM helper.
Fixes: b33752c30023 ("HID: i2c-hid: Reorganize so ACPI and OF are separate modules")
Signed-off-by: 谢致邦 (XIE Zhibang) <Yeking@Red54.com>
---
v2: Name the unused parameter and document why
acpi_device_fix_up_power() is skipped.
v3: Add a dev_warn() asking users to contact vendors for firmware
updates, and use existing locals in devm_kzalloc() and
acpi_device_fix_up_power().
drivers/hid/i2c-hid/Kconfig | 18 ++++
drivers/hid/i2c-hid/Makefile | 1 +
drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c | 98 ++++++++++++++++++++++
drivers/hid/i2c-hid/i2c-hid-acpi.c | 52 ++++--------
drivers/hid/i2c-hid/i2c-hid-acpi.h | 32 +++++++
5 files changed, 163 insertions(+), 38 deletions(-)
create mode 100644 drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c
create mode 100644 drivers/hid/i2c-hid/i2c-hid-acpi.h
diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig
index e8d51f410cc1..7db8b2abff78 100644
--- a/drivers/hid/i2c-hid/Kconfig
+++ b/drivers/hid/i2c-hid/Kconfig
@@ -22,6 +22,24 @@ config I2C_HID_ACPI
will be called i2c-hid-acpi. It will also build/depend on the
module i2c-hid.
+config I2C_HID_ACPI_PRP0001
+ tristate "Driver for PRP0001 devices missing hid-descr-addr"
+ depends on ACPI
+ depends on DRM || !DRM
+ select I2C_HID_CORE
+ help
+ Say Y here if you want support for I2C HID touchpads that
+ are declared with _HID "PRP0001" and _DSD compatible
+ "hid-over-i2c" but lack the "hid-descr-addr" property from
+ the _DSD. The HID descriptor address is instead provided
+ through an ACPI _DSM. Known affected devices include the
+ Lenovo KaiTian N60d and Inspur CP300L3.
+
+ If unsure, say N.
+
+ This support is also available as a module. If so, the
+ module will be called i2c-hid-acpi-prp0001.
+
config I2C_HID_OF
tristate "HID over I2C transport layer Open Firmware driver"
# No "depends on OF" because this can also be used for manually
diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
index 55bd5e0f35af..da420c1a8ec6 100644
--- a/drivers/hid/i2c-hid/Makefile
+++ b/drivers/hid/i2c-hid/Makefile
@@ -9,6 +9,7 @@ i2c-hid-objs = i2c-hid-core.o
i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o
obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o
+obj-$(CONFIG_I2C_HID_ACPI_PRP0001) += i2c-hid-acpi-prp0001.o
obj-$(CONFIG_I2C_HID_OF) += i2c-hid-of.o
obj-$(CONFIG_I2C_HID_OF_ELAN) += i2c-hid-of-elan.o
obj-$(CONFIG_I2C_HID_OF_GOODIX) += i2c-hid-of-goodix.o
diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c b/drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c
new file mode 100644
index 000000000000..b54370a938ab
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HID over I2C driver for PRP0001 devices missing hid-descr-addr
+ *
+ * Some devices, for example the Lenovo KaiTian N60d and Inspur CP300L3, use
+ * _HID "PRP0001" with _DSD compatible "hid-over-i2c" but lack "hid-descr-addr"
+ * from the _DSD. The HID descriptor address is provided only through an ACPI
+ * _DSM. The TPD0 node in the DSDT shows _DSM Function 1 returning 0x20.
+ *
+ * Copyright (C) 2026 谢致邦 (XIE Zhibang) <Yeking@Red54.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include "i2c-hid.h"
+#include "i2c-hid-acpi.h"
+
+static int i2c_hid_acpi_prp0001_power_up(struct i2chid_ops *ops)
+{
+ /* give the device time to power up */
+ msleep(250);
+ return 0;
+}
+
+static struct i2chid_ops i2c_hid_acpi_prp0001_ops = {
+ .power_up = i2c_hid_acpi_prp0001_power_up,
+ /*
+ * No .restore_sequence needed: the _DSM on these devices returns a
+ * constant (0x20) with no side effects, unlike some PNP0C50 _DSM
+ * implementations that switch the hardware between PS/2 and I2C modes.
+ */
+};
+
+static int i2c_hid_acpi_prp0001_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct acpi_device *adev;
+ u16 hid_descriptor_address;
+ int ret;
+
+ /* If hid-descr-addr is present, let i2c-hid-of handle it */
+ if (device_property_present(dev, "hid-descr-addr"))
+ return -ENODEV;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return -ENODEV;
+
+ ret = i2c_hid_acpi_get_descriptor(adev);
+ if (ret < 0)
+ return ret;
+ dev_warn(dev,
+ "hid-descr-addr device property NOT found, using ACPI _DSM fallback. Contact vendor for firmware update!\n");
+ hid_descriptor_address = ret;
+
+ /*
+ * No acpi_device_fix_up_power() needed: TPD0 has no _PS0, _PS3, _PSC
+ * or _PRx methods and follows I2C bus power.
+ */
+ return i2c_hid_core_probe(client, &i2c_hid_acpi_prp0001_ops,
+ hid_descriptor_address, 0);
+}
+
+static const struct of_device_id i2c_hid_acpi_prp0001_of_match[] = {
+ { .compatible = "hid-over-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, i2c_hid_acpi_prp0001_of_match);
+
+static const struct i2c_device_id i2c_hid_acpi_prp0001_id[] = {
+ { .name = "hid-over-i2c" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, i2c_hid_acpi_prp0001_id);
+
+static struct i2c_driver i2c_hid_acpi_prp0001_driver = {
+ .driver = {
+ .name = "i2c_hid_acpi_prp0001",
+ .pm = &i2c_hid_core_pm,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = of_match_ptr(i2c_hid_acpi_prp0001_of_match),
+ },
+
+ .probe = i2c_hid_acpi_prp0001_probe,
+ .remove = i2c_hid_core_remove,
+ .shutdown = i2c_hid_core_shutdown,
+ .id_table = i2c_hid_acpi_prp0001_id,
+};
+
+module_i2c_driver(i2c_hid_acpi_prp0001_driver);
+
+MODULE_DESCRIPTION("HID over I2C driver for PRP0001 devices missing hid-descr-addr");
+MODULE_AUTHOR("谢致邦 (XIE Zhibang) <Yeking@Red54.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c
index abd700a101f4..13f977d6aab6 100644
--- a/drivers/hid/i2c-hid/i2c-hid-acpi.c
+++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c
@@ -25,9 +25,9 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pm.h>
-#include <linux/uuid.h>
#include "i2c-hid.h"
+#include "i2c-hid-acpi.h"
struct i2c_hid_acpi {
struct i2chid_ops ops;
@@ -48,39 +48,11 @@ static const struct acpi_device_id i2c_hid_acpi_blacklist[] = {
{ }
};
-/* HID I²C Device: 3cdff6f7-4267-4555-ad05-b30a3d8938de */
-static guid_t i2c_hid_guid =
- GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555,
- 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE);
-
-static int i2c_hid_acpi_get_descriptor(struct i2c_hid_acpi *ihid_acpi)
-{
- struct acpi_device *adev = ihid_acpi->adev;
- acpi_handle handle = acpi_device_handle(adev);
- union acpi_object *obj;
- u16 hid_descriptor_address;
-
- if (acpi_match_device_ids(adev, i2c_hid_acpi_blacklist) == 0)
- return -ENODEV;
-
- obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL,
- ACPI_TYPE_INTEGER);
- if (!obj) {
- acpi_handle_err(handle, "Error _DSM call to get HID descriptor address failed\n");
- return -ENODEV;
- }
-
- hid_descriptor_address = obj->integer.value;
- ACPI_FREE(obj);
-
- return hid_descriptor_address;
-}
-
static void i2c_hid_acpi_restore_sequence(struct i2chid_ops *ops)
{
struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops);
- i2c_hid_acpi_get_descriptor(ihid_acpi);
+ i2c_hid_acpi_get_descriptor(ihid_acpi->adev);
}
static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops)
@@ -93,24 +65,28 @@ static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops)
static int i2c_hid_acpi_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct i2c_hid_acpi *ihid_acpi;
u16 hid_descriptor_address;
int ret;
- ihid_acpi = devm_kzalloc(&client->dev, sizeof(*ihid_acpi), GFP_KERNEL);
+ if (acpi_match_device_ids(adev, i2c_hid_acpi_blacklist) == 0)
+ return -ENODEV;
+
+ ret = i2c_hid_acpi_get_descriptor(adev);
+ if (ret < 0)
+ return ret;
+ hid_descriptor_address = ret;
+
+ ihid_acpi = devm_kzalloc(dev, sizeof(*ihid_acpi), GFP_KERNEL);
if (!ihid_acpi)
return -ENOMEM;
- ihid_acpi->adev = ACPI_COMPANION(dev);
+ ihid_acpi->adev = adev;
ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail;
ihid_acpi->ops.restore_sequence = i2c_hid_acpi_restore_sequence;
- ret = i2c_hid_acpi_get_descriptor(ihid_acpi);
- if (ret < 0)
- return ret;
- hid_descriptor_address = ret;
-
- acpi_device_fix_up_power(ihid_acpi->adev);
+ acpi_device_fix_up_power(adev);
return i2c_hid_core_probe(client, &ihid_acpi->ops,
hid_descriptor_address, 0);
diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.h b/drivers/hid/i2c-hid/i2c-hid-acpi.h
new file mode 100644
index 000000000000..8cebbeebcc23
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid-acpi.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _I2C_HID_ACPI_H
+#define _I2C_HID_ACPI_H
+
+#include <linux/acpi.h>
+#include <linux/uuid.h>
+
+static inline int i2c_hid_acpi_get_descriptor(struct acpi_device *adev)
+{
+ /* HID I²C Device: 3cdff6f7-4267-4555-ad05-b30a3d8938de */
+ static const guid_t i2c_hid_guid =
+ GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555,
+ 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE);
+
+ acpi_handle handle = acpi_device_handle(adev);
+ union acpi_object *obj;
+ u16 addr;
+
+ obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid,
+ 1, 1, NULL, ACPI_TYPE_INTEGER);
+ if (!obj) {
+ acpi_handle_err(handle, "Error _DSM call to get HID descriptor address failed\n");
+ return -ENODEV;
+ }
+
+ addr = obj->integer.value;
+ ACPI_FREE(obj);
+ return addr;
+}
+
+#endif
--
2.54.0
^ permalink raw reply related
* [PATCH] HID: uhid: convert to hid_safe_input_report()
From: Carlos Llamas @ 2026-06-06 18:15 UTC (permalink / raw)
To: David Rheinsberg, Jiri Kosina, Benjamin Tissoires, Lee Jones
Cc: kernel-team, linux-kernel, Carlos Llamas, stable,
open list:UHID USERSPACE HID IO DRIVER
Commit 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing
bogus memset()"), added a check in hid_report_raw_event() to reject
reports if the received data size is smaller than expected. This was
intended to prevent OOB errors by no longer allowing zeroing-out of
shorter reports due to the lack of buffer size information.
However, this leads to regressions in hid_report_raw_event(), where
shorter than expected reports are rejected, even though their buffers
are sufficiently large to be zero-padded.
To solve this issue, Benjamin introduced a safer alternative in commit
206342541fc8 ("HID: core: introduce hid_safe_input_report()"), which
forwards the buffer size and allows hid_report_raw_event() to safely
zero-pad the data.
Convert uhid to use hid_safe_input_report() and pass UHID_DATA_MAX as
the buffer size. This prevents the reported regressions [1], allowing
hid core to zero-pad the shorter reports safely as expected.
Cc: stable@vger.kernel.org
Fixes: 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()")
Closes: https://lore.kernel.org/all/ahsh0UtTX6e0ZeHa@google.com/ [1]
Signed-off-by: Carlos Llamas <cmllamas@google.com>
---
drivers/hid/uhid.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 524b53a3c87b..37b60c3aaf66 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -595,8 +595,8 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
if (!READ_ONCE(uhid->running))
return -EINVAL;
- hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
- min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
+ hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, UHID_DATA_MAX,
+ min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
return 0;
}
@@ -606,8 +606,8 @@ static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
if (!READ_ONCE(uhid->running))
return -EINVAL;
- hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
- min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
+ hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, UHID_DATA_MAX,
+ min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
return 0;
}
--
2.54.0.1032.g2f8565e1d1-goog
^ permalink raw reply related
* Re: [PATCH] HID: uhid: convert to hid_safe_input_report()
From: sashiko-bot @ 2026-06-06 18:26 UTC (permalink / raw)
To: Carlos Llamas; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260606181552.3095967-1-cmllamas@google.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] In `dispatch_hid_bpf_device_event()`, there is no bounds check before copying `*size` bytes into `hdev->bpf.device_data`, leading to an out-of-bounds write if the injected report size exceeds the BPF allocated memory.
--
commit c570c0c551ca1ea46eb86fb2144c1ad379f64069
Author: Carlos Llamas <cmllamas@google.com>
HID: uhid: convert to hid_safe_input_report()
This commit converts uhid to use hid_safe_input_report() and passes
UHID_DATA_MAX as the buffer size. This allows hid core to safely zero-pad
shorter reports instead of rejecting them, preventing regressions caused by
the earlier bogus memset() removal.
Closes: https://lore.kernel.org/all/ahsh0UtTX6e0ZeHa@google.com/
> diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
> index 524b53a3c87b3..37b60c3aaf66a 100644
> --- a/drivers/hid/uhid.c
> +++ b/drivers/hid/uhid.c
> @@ -595,8 +595,8 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
> if (!READ_ONCE(uhid->running))
> return -EINVAL;
>
> - hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
> - min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
> + hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, UHID_DATA_MAX,
> + min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
[Severity: Critical]
This is a pre-existing issue, but does forwarding this report size without
constraining it to the device's max_report_len cause a buffer overflow in HID
BPF?
In uhid_dev_input(), we allow userspace to inject input reports up to
UHID_DATA_MAX (4096 bytes) regardless of the device's parsed max_report_len.
When a HID-BPF program is attached to the device, hdev->bpf.device_data is
allocated based on the device's max_report_len, which could be much smaller.
Later, in drivers/hid/bpf/hid_bpf_dispatch.c:dispatch_hid_bpf_device_event(),
it executes:
memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
memcpy(ctx_kern.data, data, *size);
Since there is no bounds check on *size before the memcpy(), could a malicious
uhid client injecting a large report size cause a heap buffer overflow when
copying into the smaller BPF allocated memory?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260606181552.3095967-1-cmllamas@google.com?part=1
^ permalink raw reply
* Re: [PATCH] Input: xilinx_ps2 - remove driver
From: Dmitry Torokhov @ 2026-06-06 20:47 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-input, Michal Simek, open list,
moderated list:ARM/ZYNQ ARCHITECTURE
In-Reply-To: <20260603054217.442016-1-rosenp@gmail.com>
On Tue, Jun 02, 2026 at 10:42:17PM -0700, Rosen Penev wrote:
> Remove the Xilinx XPS PS/2 controller driver. This driver supports an
> old Xilinx EDK IP core that is no longer in active use. The hardware
> is not available on modern platforms, and the driver has no users here.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
Applied, thank you.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] Input: apbps2: Simplify resource mapping and IRQ retrieval
From: Dmitry Torokhov @ 2026-06-06 21:01 UTC (permalink / raw)
To: Rosen Penev; +Cc: linux-input, open list
In-Reply-To: <20260603192415.6679-1-rosenp@gmail.com>
On Wed, Jun 03, 2026 at 12:24:15PM -0700, Rosen Penev wrote:
> Simplify resource mapping by using devm_platform_ioremap_resource()
> instead of the longer devm_platform_get_and_ioremap_resource() helper
> as the last argument is NULL.
>
> Additionally, use platform_get_irq() to retrieve the interrupt
> instead of irq_of_parse_and_map() and propagate its error code on
> failure. irq_of_parse_and_map() requires irq_dispose_mapping, which is
> missing.
>
> Assisted-by: Antigravity:Gemini-3.5-Flash
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
Applied, thank you.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] Input: atkbd - skip deactivate for HONOR BCC-N's internal keyboard
From: Dmitry Torokhov @ 2026-06-06 21:01 UTC (permalink / raw)
To: Cryolitia PukNgae
Cc: Hans de Goede, linux-input, linux-kernel, zhanjun, niecheng1,
Mingcong Bai, Kexy Biscuit, kernel, Hongfei Ren, stable
In-Reply-To: <20260605-honor-v1-1-78e05e491193@linux.dev>
On Fri, Jun 05, 2026 at 03:27:21PM +0800, Cryolitia PukNgae wrote:
> After commit 9cf6e24c9fbf17e52de9fff07f12be7565ea6d61 ("Input: atkbd -
> do not skip atkbd_deactivate() when skipping ATKBD_CMD_GETID"), HONOR
> BCC-N, aka HONOR MagicBook 14 2026's internal keyboard stops
> working. Adding the atkbd_deactivate_fixup quirk fixes it.
>
> DMI: HONOR BCC-N/BCC-N-PCB, BIOS 1.04 04/07/2026
>
> Fixes: 9cf6e24c9fbf17e52de9fff07f12be7565ea6d61 ("Input: atkbd - do not skip atkbd_deactivate() when skipping ATKBD_CMD_GETID")
> Reported-by: Hongfei Ren <lcrhf@outlook.com>
> Link: https://github.com/colorcube/Linux-on-Honor-Magicbook-14-Pro/issues/1#issuecomment-4562679891
> Tested-by: Hongfei Ren <lcrhf@outlook.com>
> Cc: stable@kernel.org
> Signed-off-by: Cryolitia PukNgae <cryolitia.pukngae@linux.dev>
Applied, thank you.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v2 4/4] dt-bindings: input: remove obsolete matrix-keymap.txt
From: Dmitry Torokhov @ 2026-06-06 21:03 UTC (permalink / raw)
To: Rob Herring (Arm), Lee Jones
Cc: Akash Sukhavasi, Conor Dooley, David S. Miller, Andrew Lunn,
linux-tegra, linux-input, Mauro Carvalho Chehab, Heiner Kallweit,
Thierry Reding, linux-media, Krzysztof Kozlowski, Jakub Kicinski,
Vladimir Oltean, linux-doc, linux-kernel, Eric Dumazet,
Jonathan Hunter, Simon Horman, devicetree, Paolo Abeni, netdev,
Shuah Khan, Russell King, Jonathan Corbet
In-Reply-To: <178052559618.2296868.8781332297681333925.robh@kernel.org>
On Wed, Jun 03, 2026 at 05:26:38PM -0500, Rob Herring (Arm) wrote:
>
> On Wed, 03 Jun 2026 15:42:21 -0500, Akash Sukhavasi wrote:
> > matrix-keymap.txt has been a single-line redirect to
> > matrix-keymap.yaml since commit 639d6eda3b80 ("dt-bindings: input:
> > Convert matrix-keymap to json-schema"), which introduced the .yaml
> > schema and reduced the .txt to a stub in the same change. The .yaml
> > has the same filename in the same directory, making this redirect
> > unnecessary for discoverability.
> >
> > Eight instances across six files still reference matrix-keymap.txt,
> > forcing readers through an extra hop to reach the .yaml. The stub has
> > not been touched since June 2020. Update all references across input
> > and mfd binding documentation to point directly to matrix-keymap.yaml
> > and remove the stub.
> >
> > Signed-off-by: Akash Sukhavasi <akash.sukhavasi@gmail.com>
> > ---
> > v2:
> > - Patch 4/4: corrected commit message (eight references in six files,
> > not eight files), Sashiko review.
> > https://sashiko.dev/#/patchset/20260529052246.4934-1-akash.sukhavasi@gmail.com?part=4
> >
> > v1: https://lore.kernel.org/all/20260529052246.4934-5-akash.sukhavasi@gmail.com/
> > ---
> > Documentation/devicetree/bindings/input/brcm,bcm-keypad.txt | 2 +-
> > Documentation/devicetree/bindings/input/clps711x-keypad.txt | 2 +-
> > Documentation/devicetree/bindings/input/matrix-keymap.txt | 1 -
> > Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt | 2 +-
> > Documentation/devicetree/bindings/input/pxa27x-keypad.txt | 2 +-
> > Documentation/devicetree/bindings/input/st-keyscan.txt | 2 +-
> > Documentation/devicetree/bindings/mfd/tc3589x.txt | 6 +++---
> > 7 files changed, 8 insertions(+), 9 deletions(-)
> >
>
> Acked-by: Rob Herring (Arm) <robh@kernel.org>
>
Lee, could you please ack for MFD piece and I can take it through input?
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH] Input: stop force-feedback timer when unregistering input devices
From: Dmitry Torokhov @ 2026-06-07 3:42 UTC (permalink / raw)
To: linux-input; +Cc: linux-kernel, Benjamin Tissoires, Jiri Kosina
Memoryless force-feedback devices use a timer to manage playback of
effects. When a driver for such a device is unbound (or the device is
unregistered for other reasons), the driver typically frees its private
data synchronously. However, the input_dev structure (and its associated
force-feedback structures, including the timer) is only freed when the
last user closes the corresponding device node.
If userspace keeps the device node open while the device is unregistered
(e.g., during driver unbind), the force-feedback timer can still fire
after the driver's private data has been freed.
Introduce a new 'stop' callback to struct ff_device, and call it from
input_unregister_device() before the device is deleted. Implement this
callback for memoryless devices and synchronously shut down the timer to
ensure it is stopped and cannot be rearmed once unregistration happens.
Assisted-by: Gemini:gemini-3.1-pro
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/ff-memless.c | 27 +++++++++++++++++++++------
drivers/input/input.c | 3 +++
include/linux/input.h | 3 +++
3 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 937370d04928..d1fefd1dfc0d 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -484,17 +484,31 @@ static void ml_ff_destroy(struct ff_device *ff)
struct ml_device *ml = ff->private;
/*
- * Even though we stop all playing effects when tearing down
- * an input device (via input_device_flush() that calls into
- * input_ff_flush() that stops and erases all effects), we
- * do not actually stop the timer, and therefore we should
- * do it here.
+ * The timer is normally shut down in ml_ff_stop() when the device
+ * is unregistered. However, we still shut it down here as a safety
+ * net and for cases where the device was never registered (e.g.
+ * error paths during probe).
*/
- timer_delete_sync(&ml->timer);
+ timer_shutdown_sync(&ml->timer);
kfree(ml->private);
}
+static void ml_ff_stop(struct ff_device *ff)
+{
+ struct ml_device *ml = ff->private;
+
+ /*
+ * Even though we stop all playing effects when tearing down an
+ * input device (by the way of evdev calling input_flush_device()
+ * that calls into input_ff_flush() that stops and erases all
+ * effects), we do not actually shutdown the timer, and therefore
+ * we should do it here to prevent it firing after the input
+ * device is unregistered and its associated resources are freed.
+ */
+ timer_shutdown_sync(&ml->timer);
+}
+
/**
* input_ff_create_memless() - create memoryless force-feedback device
* @dev: input device supporting force-feedback
@@ -529,6 +543,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
ff->playback = ml_ff_playback;
ff->set_gain = ml_ff_set_gain;
ff->destroy = ml_ff_destroy;
+ ff->stop = ml_ff_stop;
/* we can emulate periodic effects with RUMBLE */
if (test_bit(FF_RUMBLE, ff->ffbit)) {
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 39d9d2b1e3ca..cf6fecea79b8 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -2212,6 +2212,9 @@ static void __input_unregister_device(struct input_dev *dev)
input_wakeup_procfs_readers();
}
+ if (dev->ff && dev->ff->stop)
+ dev->ff->stop(dev->ff);
+
device_del(&dev->dev);
}
diff --git a/include/linux/input.h b/include/linux/input.h
index 06ca62328db1..3022bb730898 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -543,6 +543,8 @@ extern const struct class input_class;
* @set_autocenter: Called to auto-center device
* @destroy: called by input core when parent input device is being
* destroyed
+ * @stop: called by input core when parent input device is being
+ * unregistered
* @private: driver-specific data, will be freed automatically
* @ffbit: bitmap of force feedback capabilities truly supported by
* device (not emulated like ones in input_dev->ffbit)
@@ -571,6 +573,7 @@ struct ff_device {
void (*set_autocenter)(struct input_dev *dev, u16 magnitude);
void (*destroy)(struct ff_device *);
+ void (*stop)(struct ff_device *);
void *private;
--
2.54.0.1032.g2f8565e1d1-goog
--
Dmitry
^ permalink raw reply related
* [git pull] Input updates for v7.1-rc6
From: Dmitry Torokhov @ 2026-06-07 5:05 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, linux-input
Hi Linus,
Please pull from:
git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git tags/input-for-v7.1-rc6
to receive updates for the input subsystem. You will get:
- two quirks for atkbd to deal with laptops that can not handle
"deactivate" command on the keyboard PS/2 port.
Changelog:
---------
Cryolitia PukNgae (1):
Input: atkbd - skip deactivate for HONOR BCC-N's internal keyboard
Zeyu WANG (1):
Input: atkbd - add DMI quirk for Lenovo Yoga Air 14 (83QK)
Diffstat:
--------
drivers/input/keyboard/atkbd.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [git pull] Input updates for v7.1-rc6
From: pr-tracker-bot @ 2026-06-07 15:48 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Linus Torvalds, linux-kernel, linux-input
In-Reply-To: <aiT7-939zBREw3FG@google.com>
The pull request you sent on Sat, 6 Jun 2026 22:05:16 -0700:
> git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git tags/input-for-v7.1-rc6
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/33d8d8ec31b591952ded59d596c2f3db45004937
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ 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