* Re: [PATCH v4 2/3] platform/x86: thinkpad_acpi - Add doubletap_filter sysfs interface
From: Hans de Goede @ 2025-11-29 14:48 UTC (permalink / raw)
To: Vishnu Sankar, corbet, dmitry.torokhov, hmh, derekjohn.clark,
ilpo.jarvinen
Cc: mpearson-lenovo, linux-doc, linux-input, linux-kernel,
ibm-acpi-devel, platform-driver-x86, vsankar
In-Reply-To: <20251129002533.9070-3-vishnuocv@gmail.com>
Hi Vishnu,
On 29-Nov-25 1:25 AM, Vishnu Sankar wrote:
> Add sysfs interface for controlling TrackPoint doubletap event filtering.
> This allows userspace to enable/disable doubletap functionality and
> query the current state.
>
> The attribute is available at:
> /sys/devices/platform/thinkpad_acpi/doubletap_filter
>
> When set to 1, doubletap events are filtered out (ignored).
> When set to 0, doubletap events are processed (default).
>
> This complements the automatic hardware enablement in the trackpoint
> driver by providing user control over event processing at the kernel level.
>
> Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> ---
> Changes in v2:
> - Updated commit message to clarify dependency on trackpoint driver
> - Now handling sysfs read/write of trackpoint driver using file read/write
> - Removed sysfs attribute creation of trackpoint double tap here
> - Reversed the logic and return false right away
> - Dropped unnecessary debug messages
> - Using dev_dbg() instead of pr_xxxx()
>
> Changes in v3:
> - No changes
>
> Changes in v4:
> - Simplified approach: single sysfs attribute for user control
> - Clear naming: doubletap_filter instead of doubletap_enabled
> - Intuitive behavior: 0=process events, 1=filter events
> - No cross-driver dependencies or complex interactions
> - Minimal code changes using existing thinkpad_acpi infrastructure
> ---
> ---
> drivers/platform/x86/lenovo/thinkpad_acpi.c | 54 +++++++++++++++++++--
> 1 file changed, 49 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
> index cc19fe520ea9..9b646ecff452 100644
> --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
> +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
> @@ -373,7 +373,7 @@ static struct {
> u32 hotkey_poll_active:1;
> u32 has_adaptive_kbd:1;
> u32 kbd_lang:1;
> - u32 trackpoint_doubletap:1;
> + u32 trackpoint_doubletap_filter:1;
Why the rename? The new name suggests that events will be filtered
when trackpoint_doubletap_filter = 1, so inverted of the old name
but when processing events events are let through when
trackpoint_doubletap_filter == 1 so 1 means _not_ filtering which
makes the name weird:
> + /* Only send the event if kernel-level filtering allows it */
> + if (tp_features.trackpoint_doubletap_filter)
> tpacpi_input_send_key(hkey, send_acpi_ev);
Maybe you forgot to add an '!' here, iow this should become:
/* Only send the event if kernel-level filtering allows it */
if (!tp_features.trackpoint_doubletap_filter)
tpacpi_input_send_key(hkey, send_acpi_ev);
?
> struct quirk_entry *quirks;
> } tp_features;
>
> @@ -3104,8 +3104,35 @@ static void tpacpi_send_radiosw_update(void)
> hotkey_radio_sw_notify_change();
> }
>
> +static ssize_t doubletap_filter_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return sysfs_emit(buf, "%d\n", tp_features.trackpoint_doubletap_filter);
> +}
> +
> +static ssize_t doubletap_filter_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + bool filter;
> + int err;
> +
> + err = kstrtobool(buf, &filter);
> + if (err)
> + return err;
> +
> + tp_features.trackpoint_doubletap_filter = filter;
> + return count;
> +}
> +
> +static DEVICE_ATTR_RW(doubletap_filter);
> +
> static void hotkey_exit(void)
> {
> + if (tpacpi_pdev)
> + device_remove_file(&tpacpi_pdev->dev, &dev_attr_doubletap_filter);
> +
New code should not use device_create_file() / device_remove_file() instead
the attribute should be added to hotkey_attributes[] and then the driver
core will automatically add/remove it.
> mutex_lock(&hotkey_mutex);
> hotkey_poll_stop_sync();
> dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY,
> @@ -3557,8 +3584,22 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
>
> hotkey_poll_setup_safe(true);
>
> - /* Enable doubletap by default */
> - tp_features.trackpoint_doubletap = 1;
> + /*
> + * Enable kernel-level doubletap event filtering by default.
> + * This allows doubletap events to reach userspace.
> + */
> + tp_features.trackpoint_doubletap_filter = 1;
Again this seems to be inverted, or if you really want
trackpoint_doubletap_filter to work as an enable flag
then please rename it to trackpoint_doubletap_enable.
> +
> + /* Create doubletap_filter sysfs attribute */
> + if (tpacpi_pdev) {
> + int err = device_create_file(&tpacpi_pdev->dev, &dev_attr_doubletap_filter);
> + if (err) {
> + pr_warn("Unable to create doubletap_filter sysfs attribute\n");
> + /* Continue even if sysfs creation fails */
> + } else {
> + pr_info("ThinkPad ACPI doubletap_filter sysfs attribute created\n");
> + }
> + }
This can be dropped (replaced by adding the attr to hotkey_attributes[].
Regards,
Hans
^ permalink raw reply
* [PATCH] Input: xpad - Add support for CRKD Guitars
From: Sanjay Govind @ 2025-11-29 7:37 UTC (permalink / raw)
To: Dmitry Torokhov, Vicki Pfau, Pavel Rojtberg, Nilton Perim Neto,
Antheas Kapenekakis, Pierre-Loup A. Griffais, Mario Limonciello
Cc: winston.tan, Sanjay Govind, linux-input, linux-kernel
This commit adds support for various CRKD Guitar Controllers
Signed-off-by: Sanjay Govind <sanjay.govind9@gmail.com>
---
drivers/input/joystick/xpad.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index d72e89c25e50..363d50949386 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -133,6 +133,8 @@ static const struct xpad_device {
} xpad_device[] = {
/* Please keep this list sorted by vendor and product ID. */
{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
+ { 0x0351, 0x1000, "CRKD LP Blueberry Burst Pro Edition (Xbox)", 0, XTYPE_XBOX360 },
+ { 0x0351, 0x2000, "CRKD LP Black Tribal Edition (Xbox) ", 0, XTYPE_XBOX360 },
{ 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 },
{ 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 },
{ 0x03f0, 0x038D, "HyperX Clutch", 0, XTYPE_XBOX360 }, /* wired */
@@ -420,6 +422,7 @@ static const struct xpad_device {
{ 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE },
{ 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 },
{ 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE },
+ { 0x3651, 0x1000, "CRKD SG", 0, XTYPE_XBOX360 },
{ 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT },
{ 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX },
{ 0x37d7, 0x2501, "Flydigi Apex 5", 0, XTYPE_XBOX360 },
@@ -518,6 +521,7 @@ static const struct usb_device_id xpad_table[] = {
*/
{ USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */
XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */
+ XPAD_XBOX360_VENDOR(0x0351), /* CRKD Controllers */
XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */
XPAD_XBOX360_VENDOR(0x03f0), /* HP HyperX Xbox 360 controllers */
XPAD_XBOXONE_VENDOR(0x03f0), /* HP HyperX Xbox One controllers */
@@ -578,6 +582,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOXONE_VENDOR(0x3285), /* Nacon Evol-X */
XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */
XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */
+ XPAD_XBOX360_VENDOR(0x3651), /* CRKD Controllers */
XPAD_XBOXONE_VENDOR(0x366c), /* ByoWave controllers */
XPAD_XBOX360_VENDOR(0x37d7), /* Flydigi Controllers */
XPAD_XBOX360_VENDOR(0x413d), /* Black Shark Green Ghost Controller */
--
2.52.0
^ permalink raw reply related
* [PATCH v4 3/3] Documentation: thinkpad-acpi - Document doubletap_filter attribute
From: Vishnu Sankar @ 2025-11-29 0:25 UTC (permalink / raw)
To: corbet, dmitry.torokhov, hmh, derekjohn.clark, hansg,
ilpo.jarvinen
Cc: mpearson-lenovo, linux-doc, linux-input, linux-kernel,
ibm-acpi-devel, platform-driver-x86, vsankar, Vishnu Sankar
In-Reply-To: <20251129002533.9070-1-vishnuocv@gmail.com>
Document the doubletap_filter sysfs attribute for ThinkPad ACPI driver.
Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
---
.../admin-guide/laptops/thinkpad-acpi.rst | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
index 4ab0fef7d440..a1e84d25e151 100644
--- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst
+++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
@@ -1521,6 +1521,26 @@ Currently 2 antenna types are supported as mentioned below:
The property is read-only. If the platform doesn't have support the sysfs
class is not created.
+doubletap_filter
+----------------
+
+sysfs: doubletap_filter
+
+Controls whether TrackPoint doubletap events are filtered out. Doubletap is a
+feature where quickly tapping the TrackPoint twice triggers a special function key event.
+
+The available commands are::
+
+ cat /sys/devices/platform/thinkpad_acpi/doubletap_filter
+ echo 1 | sudo tee /sys/devices/platform/thinkpad_acpi/doubletap_filter
+ echo 0 | sudo tee /sys/devices/platform/thinkpad_acpi/doubletap_filter
+
+Values:
+ * 0 - doubletap events are processed (default)
+ * 1 - doubletap events are filtered out (ignored)
+
+ This setting can also be toggled via the Fn+doubletap hotkey.
+
Auxmac
------
--
2.51.0
^ permalink raw reply related
* [PATCH v4 2/3] platform/x86: thinkpad_acpi - Add doubletap_filter sysfs interface
From: Vishnu Sankar @ 2025-11-29 0:25 UTC (permalink / raw)
To: corbet, dmitry.torokhov, hmh, derekjohn.clark, hansg,
ilpo.jarvinen
Cc: mpearson-lenovo, linux-doc, linux-input, linux-kernel,
ibm-acpi-devel, platform-driver-x86, vsankar, Vishnu Sankar
In-Reply-To: <20251129002533.9070-1-vishnuocv@gmail.com>
Add sysfs interface for controlling TrackPoint doubletap event filtering.
This allows userspace to enable/disable doubletap functionality and
query the current state.
The attribute is available at:
/sys/devices/platform/thinkpad_acpi/doubletap_filter
When set to 1, doubletap events are filtered out (ignored).
When set to 0, doubletap events are processed (default).
This complements the automatic hardware enablement in the trackpoint
driver by providing user control over event processing at the kernel level.
Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
---
Changes in v2:
- Updated commit message to clarify dependency on trackpoint driver
- Now handling sysfs read/write of trackpoint driver using file read/write
- Removed sysfs attribute creation of trackpoint double tap here
- Reversed the logic and return false right away
- Dropped unnecessary debug messages
- Using dev_dbg() instead of pr_xxxx()
Changes in v3:
- No changes
Changes in v4:
- Simplified approach: single sysfs attribute for user control
- Clear naming: doubletap_filter instead of doubletap_enabled
- Intuitive behavior: 0=process events, 1=filter events
- No cross-driver dependencies or complex interactions
- Minimal code changes using existing thinkpad_acpi infrastructure
---
---
drivers/platform/x86/lenovo/thinkpad_acpi.c | 54 +++++++++++++++++++--
1 file changed, 49 insertions(+), 5 deletions(-)
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
index cc19fe520ea9..9b646ecff452 100644
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
@@ -373,7 +373,7 @@ static struct {
u32 hotkey_poll_active:1;
u32 has_adaptive_kbd:1;
u32 kbd_lang:1;
- u32 trackpoint_doubletap:1;
+ u32 trackpoint_doubletap_filter:1;
struct quirk_entry *quirks;
} tp_features;
@@ -3104,8 +3104,35 @@ static void tpacpi_send_radiosw_update(void)
hotkey_radio_sw_notify_change();
}
+static ssize_t doubletap_filter_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%d\n", tp_features.trackpoint_doubletap_filter);
+}
+
+static ssize_t doubletap_filter_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ bool filter;
+ int err;
+
+ err = kstrtobool(buf, &filter);
+ if (err)
+ return err;
+
+ tp_features.trackpoint_doubletap_filter = filter;
+ return count;
+}
+
+static DEVICE_ATTR_RW(doubletap_filter);
+
static void hotkey_exit(void)
{
+ if (tpacpi_pdev)
+ device_remove_file(&tpacpi_pdev->dev, &dev_attr_doubletap_filter);
+
mutex_lock(&hotkey_mutex);
hotkey_poll_stop_sync();
dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY,
@@ -3557,8 +3584,22 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
hotkey_poll_setup_safe(true);
- /* Enable doubletap by default */
- tp_features.trackpoint_doubletap = 1;
+ /*
+ * Enable kernel-level doubletap event filtering by default.
+ * This allows doubletap events to reach userspace.
+ */
+ tp_features.trackpoint_doubletap_filter = 1;
+
+ /* Create doubletap_filter sysfs attribute */
+ if (tpacpi_pdev) {
+ int err = device_create_file(&tpacpi_pdev->dev, &dev_attr_doubletap_filter);
+ if (err) {
+ pr_warn("Unable to create doubletap_filter sysfs attribute\n");
+ /* Continue even if sysfs creation fails */
+ } else {
+ pr_info("ThinkPad ACPI doubletap_filter sysfs attribute created\n");
+ }
+ }
return 0;
}
@@ -3863,7 +3904,8 @@ static bool hotkey_notify_8xxx(const u32 hkey, bool *send_acpi_ev)
{
switch (hkey) {
case TP_HKEY_EV_TRACK_DOUBLETAP:
- if (tp_features.trackpoint_doubletap)
+ /* Only send the event if kernel-level filtering allows it */
+ if (tp_features.trackpoint_doubletap_filter)
tpacpi_input_send_key(hkey, send_acpi_ev);
return true;
@@ -11285,7 +11327,9 @@ static bool tpacpi_driver_event(const unsigned int hkey_event)
mutex_unlock(&tpacpi_inputdev_send_mutex);
return true;
case TP_HKEY_EV_DOUBLETAP_TOGGLE:
- tp_features.trackpoint_doubletap = !tp_features.trackpoint_doubletap;
+ /* Toggle kernel-level doubletap event filtering */
+ tp_features.trackpoint_doubletap_filter =
+ !tp_features.trackpoint_doubletap_filter;
return true;
case TP_HKEY_EV_PROFILE_TOGGLE:
case TP_HKEY_EV_PROFILE_TOGGLE2:
--
2.51.0
^ permalink raw reply related
* [PATCH v4 1/3] input: trackpoint - Enable doubletap by default on capable devices
From: Vishnu Sankar @ 2025-11-29 0:25 UTC (permalink / raw)
To: corbet, dmitry.torokhov, hmh, derekjohn.clark, hansg,
ilpo.jarvinen
Cc: mpearson-lenovo, linux-doc, linux-input, linux-kernel,
ibm-acpi-devel, platform-driver-x86, vsankar, Vishnu Sankar
In-Reply-To: <20251129002533.9070-1-vishnuocv@gmail.com>
Enable doubletap functionality by default on TrackPoint devices that
support it. The feature is detected using firmware ID pattern matching
(PNP: LEN03xxx) with a deny list of incompatible devices.
This provides immediate doubletap functionality without requiring
userspace configuration. The hardware is enabled during device
detection, while event filtering continues to be handled by the
thinkpad_acpi driver as before.
Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
---
Changes in v4:
- Simplified approach: removed all sysfs attributes and user interface
- Enable doubletap by default during device detection
- Removed global variables and complex attribute infrastructure
- Uses minimal firmware ID detection with deny list
- Follows KISS principle as suggested by reviewers
Changes in v3:
- No changes
Changes in v2:
- Improve commit messages
- Sysfs attributes moved to trackpoint.c
- Removed unnecessary comments
- Removed unnecessary debug messages
- Using strstarts() instead of strcmp()
- is_trackpoint_dt_capable() modified
- Removed _BIT suffix and used BIT() define
- Reverse the trackpoint_doubletap_status() logic to return error first
- Removed export functions as a result of the design change
- Changed trackpoint_dev->psmouse to parent_psmouse
- The path of trackpoint.h is not changed
---
drivers/input/mouse/trackpoint.c | 51 ++++++++++++++++++++++++++++++++
drivers/input/mouse/trackpoint.h | 5 ++++
2 files changed, 56 insertions(+)
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 5f6643b69a2c..67144c27bccd 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -393,6 +393,48 @@ static int trackpoint_reconnect(struct psmouse *psmouse)
return 0;
}
+/* List of known incapable device PNP IDs */
+static const char * const dt_incompatible_devices[] = {
+ "LEN0304",
+ "LEN0306",
+ "LEN0317",
+ "LEN031A",
+ "LEN031B",
+ "LEN031C",
+ "LEN031D",
+};
+
+/*
+ * Checks if it's a doubletap capable device
+ * The PNP ID format is "PNP: LEN030d PNP0f13".
+ */
+static bool is_trackpoint_dt_capable(const char *pnp_id)
+{
+ const char *id_start;
+ char id[8];
+ size_t i;
+
+ if (!strstarts(pnp_id, "PNP: LEN03"))
+ return false;
+
+ /* Points to "LEN03xxxx" */
+ id_start = pnp_id + 5;
+ if (sscanf(id_start, "%7s", id) != 1)
+ return false;
+
+ /* Check if it's in the deny list */
+ for (i = 0; i < ARRAY_SIZE(dt_incompatible_devices); i++) {
+ if (strcmp(id, dt_incompatible_devices[i]) == 0)
+ return false;
+ }
+ return true;
+}
+
+static int trackpoint_set_doubletap(struct ps2dev *ps2dev, bool enable)
+{
+ return trackpoint_write(ps2dev, TP_DOUBLETAP, enable ? TP_DOUBLETAP_ENABLE : TP_DOUBLETAP_DISABLE);
+}
+
int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
@@ -470,6 +512,15 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
psmouse->vendor, firmware_id,
(button_info & 0xf0) >> 4, button_info & 0x0f);
+ /* Enable doubletap by default on capable devices */
+ if (is_trackpoint_dt_capable(ps2dev->serio->firmware_id)) {
+ int error = trackpoint_set_doubletap(ps2dev, true);
+ if (!error)
+ psmouse_info(psmouse, "Doubletap enabled by default!\n");
+ else
+ psmouse_warn(psmouse, "Failed to enable doubletap: %d\n", error);
+ }
+
return 0;
}
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index eb5412904fe0..3e03cdb39449 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -69,6 +69,8 @@
/* (how hard it is to drag */
/* with Z-axis pressed) */
+#define TP_DOUBLETAP 0x58 /* TrackPoint doubletap register */
+
#define TP_MINDRAG 0x59 /* Minimum amount of force needed */
/* to trigger dragging */
@@ -110,6 +112,9 @@
external device will be forced to 1 */
#define TP_MASK_EXT_TAG 0x04
+/* Doubletap register values */
+#define TP_DOUBLETAP_ENABLE 0xFF /* Enable value */
+#define TP_DOUBLETAP_DISABLE 0xFE /* Disable value */
/* Power on Self Test Results */
#define TP_POR_SUCCESS 0x3B
--
2.51.0
^ permalink raw reply related
* [PATCH v4 0/3] TrackPoint doubletap enablement and user control
From: Vishnu Sankar @ 2025-11-29 0:25 UTC (permalink / raw)
To: corbet, dmitry.torokhov, hmh, derekjohn.clark, hansg,
ilpo.jarvinen
Cc: mpearson-lenovo, linux-doc, linux-input, linux-kernel,
ibm-acpi-devel, platform-driver-x86, vsankar, Vishnu Sankar
This patch series adds doubletap support for TrackPoint devices with
a clean separation of concerns:
1. Firmware enablement (trackpoint.c): Automatically enables doubletap
on capable hardware during device detection
2. User control (thinkpad_acpi.c): Provides sysfs interface for
controlling event filtering
The simplified approach follows KISS principle:
- Trackpoint driver enables hardware functionality by default
- Thinkpad_acpi driver provides user control via existing filtering
- No cross-driver dependencies or complex interactions
Changes in v4:
- Complete redesign based on reviewer feedback
- trackpoint.c: Simplified to only enable doubletap by default
- trackpoint.c: Removed all sysfs attributes and global variables
- trackpoint.c: Uses firmware ID detection with deny list
- thinkpad_acpi.c: Added simple sysfs interface for event filtering
- thinkpad_acpi.c: Uses clear naming (doubletap_filter)
- thinkpad_acpi.c: No cross-driver dependencies
- Documentation: Updated to reflect simplified sysfs approach
Changes in v3:
- No changes
Changes in v2:
- Improved commit messages
- Removed unnecessary comments and debug messages
- Using strstarts() instead of strcmp()
- Modified is_trackpoint_dt_capable()
- Removed _BIT suffix and used BIT() define
This version addresses the core reviewer feedback by:
- Removing dual filtering complexity
- Following KISS principle with clear separation
- Providing immediate functionality without configuration
Vishnu Sankar (3):
input: trackpoint - Enable doubletap by default on capable devices
platform/x86: thinkpad_acpi - Add doubletap_filter sysfs interface
Documentation: thinkpad-acpi - Document doubletap_filter attribute
.../admin-guide/laptops/thinkpad-acpi.rst | 20 +++++++
drivers/input/mouse/trackpoint.c | 51 ++++++++++++++++++
drivers/input/mouse/trackpoint.h | 5 ++
drivers/platform/x86/lenovo/thinkpad_acpi.c | 54 +++++++++++++++++--
4 files changed, 125 insertions(+), 5 deletions(-)
--
2.51.0
^ permalink raw reply
* Re: [PATCH v3] HID: Apply quirk HID_QUIRK_ALWAYS_POLL to Edifier QR30 (2d99:a101)
From: Terry Junge @ 2025-11-29 0:08 UTC (permalink / raw)
To: Rodrigo Lugathe da Conceição Alves, bentiss, jikos
Cc: linux-input, linux-kernel, linux-usb, stern, dmitry.torokhov,
linuxsound, michal.pecio
In-Reply-To: <20251127220357.1218420-1-lugathe2@gmail.com>
Hi Rodrigo,
Thanks for reporting, debugging, finding the solution, and submitting a patch!
Reviewed-by: Terry Junge <linuxhid@cosmicgizmosystems.com>
Original thread - https://lore.kernel.org/all/CALvgqEAq8ZWgG4Dyg_oL7_+nUDy+LUoTXi+-6aceO-AKtBS3Mg@mail.gmail.com/
Regards,
Terry
On 11/27/25 2:03 PM, Rodrigo Lugathe da Conceição Alves wrote:
> The USB speaker has a bug that causes it to reboot when changing the
> brightness using the physical knob.
>
> Add a new vendor and product ID entry in hid-ids.h, and register
> the corresponding device in hid-quirks.c with the required quirk.
>
> Signed-off-by: Rodrigo Lugathe da Conceição Alves <lugathe2@gmail.com>
^ permalink raw reply
* Re: [PATCH 3/4] Input: Ignore the KEY_POWER events if hibernation is in progress
From: Muhammad Usama Anjum @ 2025-11-28 17:00 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: usama.anjum, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Dmitry Torokhov, Thomas Gleixner,
Peter Zijlstra, linux-acpi, linux-kernel, linux-pm, linux-input,
kernel, superm1
In-Reply-To: <CAJZ5v0iDUPB9s2fPJxqVqPGj5wbw54tR4thmDD2V-r4+Q2prwg@mail.gmail.com>
On 11/25/25 5:25 PM, Rafael J. Wysocki wrote:
> On Tue, Nov 25, 2025 at 11:23 AM Muhammad Usama Anjum
> <usama.anjum@collabora.com> wrote:
>>
>> On 11/24/25 11:50 PM, Rafael J. Wysocki wrote:
>>> On Fri, Nov 7, 2025 at 7:45 PM Muhammad Usama Anjum
>>> <usama.anjum@collabora.com> wrote:
>>>>
>>>> Input (Serio) drivers call input_handle_event(). Although the serio
>>>> drivers have duplicate events, they have separate code path and call
>>>> input_handle_event(). Ignore the KEY_POWER such that this event isn't
>>>> sent to the userspace if hibernation is in progress.
>>>
>>> Your change affects suspend too.
>>>
>>> Also, what's the goal you want to achieve?
>> Two goals:
>> * Don't send event to userspace
>> * Set pm_wakeup for hibernation cancellation for non-acpi devices (This api
>> call should be tested on non-acpi devices such as arm board to see if it
>> helps. I don't have an arm board in hand)
>>
>>>
>>>> Abort the hibernation by calling pm_wakeup_dev_event(). In case of serio,
>>>> doesn't have wakeup source registered, this call doesn't do anything.
>>>> But there may be other input drivers which will require this.
>>>>
>>>> Without this, the event is sent to the userspace and it suspends the
>>>> device after hibernation cancellation.
>>>
>>> I think that's because user space handles it this way, isn't it?
>>
>> Yes, it depends on how userspace handles such events. There are different settings
>> configured for systemd-logind when power event is received. The purpose is to consume
>> this event to cancel the hibernation without letting userspace know about it.
>>
>> Thinking more about it, I wasn't sure if all of such events are compulsory to be
>> delivered to userspace. But then I found an example: In acpi_button_notify(), all
>> such events are not sent to userspace if button is suspended. So it seems okay to
>> not send this as well and just consume in the kernel.
>
> You want the given key (and it doesn't matter whether or not this is
> KEY_POWER or something else) to play two roles. One of them is to
> send a specific key code to user space and let it handle the keypress
> as it wants. This is how it works most of the time. The second one
> is to wake up the system from sleep (and I'm not sure why you want to
> limit this to hibernation) in which case the key code will not be sent
> to user space.
>
> For this to work, you need to switch between the two modes quite
> precisely and checking things like pm_sleep_transition_in_progress()
> (which is only used for debug and its raciness is not relevant there)
> is not sufficient for this purpose. That's what the "suspended" flag
> in the ACPI button driver is for.
I've been testing and trying out `suspended` flag. But this flag gets set very late.
If we depend on it, we'll not be able to wakeup in time after cancelling hibernation.
Initially we were using hibernation_in_progress() in RFC and we switched to
pm_sleep_transition_in_progress() in order to cancel the sleep as well (which wasn't
the original intention).
The sleep detection isn't working through pm_suspend_target_state or pm_suspend_in_progress()
as it is set very late in suspend process. While hibernation_in_progress() gets set in
start of hibernation.
Then as you said, they are unreliable. I'm thinking what other options. But I've not
found any. Please share ideas what other way can work instead of suspended flag better?
--
---
Thanks,
Usama
^ permalink raw reply
* Re: [PATCH 2/4] ACPI: button: Cancel hibernation if button is pressed during hibernation
From: Muhammad Usama Anjum @ 2025-11-28 14:17 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: usama.anjum, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Dmitry Torokhov, Thomas Gleixner,
Peter Zijlstra, linux-acpi, linux-kernel, linux-pm, linux-input,
kernel, superm1
In-Reply-To: <CAJZ5v0iWCxXSw3fBbesoMEWqGrRL9xrD85pMoW8rPuBBwTayhw@mail.gmail.com>
On 11/24/25 11:42 PM, Rafael J. Wysocki wrote:
> On Fri, Nov 7, 2025 at 7:45 PM Muhammad Usama Anjum
> <usama.anjum@collabora.com> wrote:
>>
>> acpi_pm_wakeup_event() is called from acpi_button_notify() which is
>> called when power button is pressed. The system is worken up from s2idle
>> in this case by setting hard parameter to pm_wakeup_dev_event().
>
> Right, so presumably you want to set it for hibernation too.
>
>> Call acpi_pm_wakeup_event() if power button is pressed and hibernation
>> is in progress.
>
> Well, this is not what the code does after the change.
>
>> Set the hard parameter such that pm_system_wakeup()
>> gets called which increments pm_abort_suspend counter. The explicit call
>> to acpi_pm_wakeup_event() is necessary as ACPI button device has the
>> wakeup source. Hence call to input_report_key() with input device
>> doesn't call pm_system_wakeup() as it doesn't have wakeup source
>> registered.
>>
>> Hence hibernation would be cancelled as in hibernation path, this counter
>> is checked if it should be aborted.
>>
>> Signed-off-by: Muhammad Usama Anjum <usama.anjum@collabora.com>
>> ---
>> Changes since RFC:
>> - Use pm_sleep_transition_in_progress()
>> - Update descriptin why explicit call to acpi_pm_wakeup_event() is
>> necessary
>> ---
>> drivers/acpi/button.c | 12 +++++++++---
>> 1 file changed, 9 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
>> index 3c6dd9b4ba0ad..e4be5c763edaf 100644
>> --- a/drivers/acpi/button.c
>> +++ b/drivers/acpi/button.c
>> @@ -20,6 +20,7 @@
>> #include <linux/acpi.h>
>> #include <linux/dmi.h>
>> #include <acpi/button.h>
>> +#include <linux/suspend.h>
>>
>> #define ACPI_BUTTON_CLASS "button"
>> #define ACPI_BUTTON_FILE_STATE "state"
>> @@ -458,11 +459,16 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
>> acpi_pm_wakeup_event(&device->dev);
>
> The above is what you want to change, as this already reports the
> event. Reporting it twice is unnecessary and potentially confusing.
Thanks for mentioning. This will be fixed easily by adding newer
version of acpi_pm_wakeup_event() which takes hard parameter.
>
>> button = acpi_driver_data(device);
>> - if (button->suspended || event == ACPI_BUTTON_NOTIFY_WAKE)
>> - return;
>> -
>> input = button->input;
>> keycode = test_bit(KEY_SLEEP, input->keybit) ? KEY_SLEEP : KEY_POWER;
>> + if (event == ACPI_BUTTON_NOTIFY_STATUS && keycode == KEY_POWER &&
>> + pm_sleep_transition_in_progress()) {
>> + pm_wakeup_dev_event(&device->dev, 0, true);
>> + return;
>> + }
>
> First, this will affect suspend too.
I'll fix terminologies in entire series.
>
> Second, this reports an already reported wakeup event.
As mentioned above, I'll update to only 1 call to pm_wakeup_dev_event().>
> Next, why KEY_POWER only? Is KEY_SLEEP not expected to wake up?
Yes, this is true. This will be fixed in next version.
>
> And why event == ACPI_BUTTON_NOTIFY_STATUS? Isn't this what
> ACPI_BUTTON_NOTIFY_WAKE is for?
While device is hibernating, at that if power button is pressed,
ACPI_BUTTON_NOTIFY_STATUS event is received.
ACPI_BUTTON_NOTIFY_WAKE is received when we turn on the device from sleeping state
(suspend) or turned off state (hibernated).
>
>> +
>> + if (button->suspended || event == ACPI_BUTTON_NOTIFY_WAKE)
>> + return;
>>
>> input_report_key(input, keycode, 1);
>> input_sync(input);
>> --
--
---
Thanks,
Usama
^ permalink raw reply
* [PATCH] HID: quirks: work around VID/PID conflict for appledisplay
From: René Rebe @ 2025-11-28 12:46 UTC (permalink / raw)
To: linux-input; +Cc: Jiri Kosina, Benjamin Tissoires
For years I wondered why the Apple Cinema Display driver would not
just work for me. Turns out the hidraw driver instantly takes it
over. Fix by adding appledisplay VID/PIDs to hid_have_special_driver.
Fixes: 069e8a65cd79 ("Driver for Apple Cinema Display")
Signed-off-by: René Rebe <rene@exactco.de>
---
Tested since 2024-05-15 in T2/Linux.
---
drivers/hid/hid-quirks.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index c89a015686c0..6a8a7ca3d804 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -232,6 +232,15 @@ static const struct hid_device_id hid_quirks[] = {
* used as a driver. See hid_scan_report().
*/
static const struct hid_device_id hid_have_special_driver[] = {
+#if IS_ENABLED(CONFIG_APPLEDISPLAY)
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921d) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9222) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9226) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9236) },
+#endif
#if IS_ENABLED(CONFIG_HID_A4TECH)
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
--
2.46.0
--
René Rebe, ExactCODE GmbH, Berlin, Germany
https://exactco.de • https://t2linux.com • https://patreon.com/renerebe
^ permalink raw reply related
* Re: [PATCH v5 05/11] mfd: macsmc: Add new __SMC_KEY macro
From: James Calligeros @ 2025-11-28 10:36 UTC (permalink / raw)
To: Lee Jones
Cc: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alexandre Belloni,
Jean Delvare, Guenter Roeck, Dmitry Torokhov, Jonathan Corbet,
asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251120134445.GC661940@google.com>
On Thursday, 20 November 2025 11:44:45 pm Australian Eastern Standard Time Lee
Jones wrote:
> On Wed, 12 Nov 2025, James Calligeros wrote:
> > When using the _SMC_KEY macro in switch/case statements, GCC 15.2.1 errors
> > out with 'case label does not reduce to an integer constant'. Introduce
> > a new __SMC_KEY macro that can be used instead.
> >
> > Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
> > ---
> >
> > include/linux/mfd/macsmc.h | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/include/linux/mfd/macsmc.h b/include/linux/mfd/macsmc.h
> > index 6b13f01a8592..f6f80c33b5cf 100644
> > --- a/include/linux/mfd/macsmc.h
> > +++ b/include/linux/mfd/macsmc.h
> > @@ -41,6 +41,7 @@ typedef u32 smc_key;
> >
> > */
> >
> > #define SMC_KEY(s) (smc_key)(_SMC_KEY(#s))
> > #define _SMC_KEY(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) |
> > (s)[3])>
> > +#define __SMC_KEY(a, b, c, d) (((u32)(a) << 24) | ((u32)(b) << 16) |
> > ((u32)(c) << 8) | ((u32)(d)))
> Are we expecting users/consumers to be able to tell the difference
> between SMC_KEY and __SMC_KEY (assuming that _SMC_KEY is just an
> internal)?
_SMC_KEY is used in the gpio driver, and I would have used it here too if not
for GCC complaining about it. I wouldn't expect anyone to want to use
__SMC_KEY outside of the specific use case this commit addresses given the
suboptimal ergonomics.
> I have not tested this and it is just off the top of my head, but does
> this work:
>
> #define _SMC_KEY(s) __SMC_KEY((s)[0], (s)[1], (s)[2], (s)[3])
This works fine on a smattering of M1 and M2 series machines. I can submit a
v6 with this and the hwmon driver dropped if need be.
Regards,
James
^ permalink raw reply
* Re: [PATCH v5 06/11] hwmon: Add Apple Silicon SMC hwmon driver
From: Dan Carpenter @ 2025-11-28 8:10 UTC (permalink / raw)
To: James Calligeros
Cc: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Jean Delvare, Guenter Roeck, Dmitry Torokhov,
Jonathan Corbet, asahi, linux-arm-kernel, devicetree,
linux-kernel, linux-rtc, linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251112-macsmc-subdevs-v5-6-728e4b91fe81@gmail.com>
On Wed, Nov 12, 2025 at 09:16:52PM +1000, James Calligeros wrote:
> +static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon,
> + struct device_node *hwmon_node)
> +{
> + struct device_node *key_node __maybe_unused;
The for_each_child_of_node_with_prefix() macros declare key_node so this
declaration is never used so far as I can see. I thought Sparse had a
warning where we declared shadow variables where two variables have the
same name but it doesn't complain here. #strange
> + struct macsmc_hwmon_sensor *sensor;
> + u32 n_current = 0, n_fan = 0, n_power = 0, n_temperature = 0, n_voltage = 0;
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
^^^^^^^^
regards,
dan carpenter
> + n_current++;
> + }
> +
> + if (n_current) {
> + hwmon->curr.sensors = devm_kcalloc(hwmon->dev, n_current,
> + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
> + if (!hwmon->curr.sensors)
> + return -ENOMEM;
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
> + sensor = &hwmon->curr.sensors[hwmon->curr.count];
> + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
> + sensor->attrs = HWMON_C_INPUT;
> +
> + if (*sensor->label)
> + sensor->attrs |= HWMON_C_LABEL;
> +
> + hwmon->curr.count++;
> + }
> + }
> + }
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
> + n_fan++;
> + }
> +
> + if (n_fan) {
> + hwmon->fan.fans = devm_kcalloc(hwmon->dev, n_fan,
> + sizeof(struct macsmc_hwmon_fan), GFP_KERNEL);
> + if (!hwmon->fan.fans)
> + return -ENOMEM;
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
> + if (!macsmc_hwmon_create_fan(hwmon->dev, hwmon->smc, key_node,
> + &hwmon->fan.fans[hwmon->fan.count]))
> + hwmon->fan.count++;
> + }
> + }
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
> + n_power++;
> + }
> +
> + if (n_power) {
> + hwmon->power.sensors = devm_kcalloc(hwmon->dev, n_power,
> + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
> + if (!hwmon->power.sensors)
> + return -ENOMEM;
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
> + sensor = &hwmon->power.sensors[hwmon->power.count];
> + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
> + sensor->attrs = HWMON_P_INPUT;
> +
> + if (*sensor->label)
> + sensor->attrs |= HWMON_P_LABEL;
> +
> + hwmon->power.count++;
> + }
> + }
> + }
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
> + n_temperature++;
> + }
> +
> + if (n_temperature) {
> + hwmon->temp.sensors = devm_kcalloc(hwmon->dev, n_temperature,
> + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
> + if (!hwmon->temp.sensors)
> + return -ENOMEM;
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
> + sensor = &hwmon->temp.sensors[hwmon->temp.count];
> + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
> + sensor->attrs = HWMON_T_INPUT;
> +
> + if (*sensor->label)
> + sensor->attrs |= HWMON_T_LABEL;
> +
> + hwmon->temp.count++;
> + }
> + }
> + }
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
> + n_voltage++;
> + }
> +
> + if (n_voltage) {
> + hwmon->volt.sensors = devm_kcalloc(hwmon->dev, n_voltage,
> + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
> + if (!hwmon->volt.sensors)
> + return -ENOMEM;
> +
> + for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-") {
> + sensor = &hwmon->temp.sensors[hwmon->temp.count];
> + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
> + sensor->attrs = HWMON_I_INPUT;
> +
> + if (*sensor->label)
> + sensor->attrs |= HWMON_I_LABEL;
> +
> + hwmon->volt.count++;
> + }
> + }
> + }
> +
> + return 0;
> +}
^ permalink raw reply
* Re: Regression: SYNA3602 I2C touchpad broken in Linux 6.17.7 (works in 6.17.6 and previous versions)
From: Benjamin Tissoires @ 2025-11-28 8:05 UTC (permalink / raw)
To: Vijay; +Cc: regressions, linux-kernel, linux-input, linux-pm, linux-acpi,
jikos
In-Reply-To: <CAMBhvbYA=onQkkcgkODaTj=+tkybwo28Cdi6P3vodGpVZi8OVA@mail.gmail.com>
Hi,
On Fri, Nov 28, 2025 at 7:40 AM Vijay <vijayg0127@gmail.com> wrote:
>
> Hello,
>
> I would like to report a regression in the Linux kernel affecting I2C-HID
> touchpads that run through the Intel ISH + DesignWare I2C controller.
>
> Hardware:
> - Laptop: Infinix Y4 Max
> - CPU: Intel (13th gen core i5)
> - Touchpad: SYNA3602:00 093A:35ED (I2C HID)
> - Bus path: SYNA3602 → i2c_designware → Intel ISH → HID
> - OS: Linux (Arch/CachyOS)
> - Kernel config: Default distro config
>
> Regression summary:
> - Touchpad works perfectly in Linux 6.17.6 and below versions
> - Touchpad stops working in Linux 6.17.7 and all newer versions (6.17.8, 6.17.9, etc.)
> - Desktop environment does not matter (Hyprland/GNOME both fail)
> - The failure happens before userspace loads
> - Touchpad also works fine in Linux 6.12 LTS
>
> This is a kernel-level regression introduced between:
> Good: Linux 6.17.6
> Bad: Linux 6.17.7
>
> **Dmesg logs from broken kernel (6.17.7 and newer):**
>
> i2c-SYNA3602:00: can't add hid device: -110
> hid_sensor_hub: reading report descriptor failed
> intel-hid INTC1078:00: failed to enable HID power button
Looks like i2c-hid can't even communicate with any I2C device, so this
is slightly worrying.
>
> And the DesignWare I2C controller logs around the failure:
> i2c_designware 0000:00:15.0: controller timed out
> i2c_designware 0000:00:15.0: lost arbitration
> i2c_designware 0000:00:15.0: transfer aborted (status = -110)
>
> These errors appear only on 6.17.7+ and not on 6.17.6.
>
> On working versions (6.17.6 and 6.12 LTS), the touchpad initializes normally:
>
> input: SYNA3602:00 093A:35ED Touchpad as /devices/.../input/inputX
> hid-multitouch: I2C HID v1.00 device initialized
> i2c_designware 0000:00:15.0: controller operating normally
>
> This narrow regression window should make it possible to identify the offending
> change in either:
> - HID core
> - I2C-HID
> - Intel ISH HID
> - DesignWare I2C controller
> - ACPI timing changes
>
> I can provide:
> - Full dmesg (working and broken)
> - acpidump
Are you running on a full vanilla kernel?
The changelog between 6.17.6 and 6.17.7 is rather small, so it should
be easy enough to bisect and get the offending commit.
I have my suspicions on:
f1971d5ba2ef ("genirq/manage: Add buslock back in to enable_irq()")
b990b4c6ea6b ("genirq/manage: Add buslock back in to __disable_irq_nosync()")
3c97437239df ("genirq/chip: Add buslock back in to irq_set_handler()")
Because anything else is unrelated to any component involved in i2c-hid.
(But that's also assuming you are running vanilla kernels without any
extra patches.)
OTOH, I've booted a 6.17.8 and 6.17.7 shipped by Fedora and I don't
see any issues related to i2c-hid, so those 3 commits might not be the
culprits.
>
> Please let me know what additional data is needed.
Can you do a bisect between v6.17.7 and v6.17.6?
Cheers,
Benjamin
>
> Thank you,
> Vijay.
^ permalink raw reply
* [PATCH] hid: intel-thc-hid: Select SGL_ALLOC
From: Tim Zimmermann @ 2025-11-28 7:54 UTC (permalink / raw)
Cc: tim, Even Xu, Xinpeng Sun, Jiri Kosina, Benjamin Tissoires,
linux-input, linux-kernel
intel-thc-dma.c uses sgl_alloc() resulting in a build failure if CONFIG_SGL_ALLOC is not enabled
Signed-off-by: Tim Zimmermann <tim@linux4.de>
---
drivers/hid/intel-thc-hid/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/intel-thc-hid/Kconfig b/drivers/hid/intel-thc-hid/Kconfig
index 0351d1137607..9d74e53b8c62 100644
--- a/drivers/hid/intel-thc-hid/Kconfig
+++ b/drivers/hid/intel-thc-hid/Kconfig
@@ -7,6 +7,7 @@ menu "Intel THC HID Support"
config INTEL_THC_HID
tristate "Intel Touch Host Controller"
depends on ACPI
+ select SGL_ALLOC
help
THC (Touch Host Controller) is the name of the IP block in PCH that
interfaces with Touch Devices (ex: touchscreen, touchpad etc.). It
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] Input: misc: pwm-vibra: fix resource leaks on start failure
From: Sebastian Reichel @ 2025-11-27 23:20 UTC (permalink / raw)
To: Haotian Zhang; +Cc: dmitry.torokhov, linux-input, linux-kernel, kernel
In-Reply-To: <20251126145635.954-1-vulab@iscas.ac.cn>
[-- Attachment #1: Type: text/plain, Size: 2837 bytes --]
Hi,
On Wed, Nov 26, 2025 at 10:56:35PM +0800, Haotian Zhang wrote:
> The pwm_vibrator_start() function returns immediately if
> pwm_apply_might_sleep() fails, neglecting to disable the
> regulator or reset the enable GPIO. This results in a
> potential resource leak.
>
> Introduce a local flag to track regulator enablement
> and implement an error handling path. Deassert the enable
> GPIO and disable the regulator upon failure.
>
> Fixes: 3e5b08518f6a ("Input: add a driver for PWM controllable vibrators")
> Signed-off-by: Haotian Zhang <vulab@iscas.ac.cn>
> ---
As the remaining driver code right now always ignores the return
code from pwm_vibrator_start(), it is expected running even with the
PWM failure. There is no real resource leak, since things will
properly be disabled in pwm_vibrator_stop() when userspace is done
with the vibrator request.
So I think this patch does not really add any value without changing
the error handling behavior in general.
I guess this has been found by some code analysis tool and not on
real hardware...
Greetings,
-- Sebastian
> drivers/input/misc/pwm-vibra.c | 14 ++++++++++++--
> 1 file changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
> index 3e5ed685ed8f..d323a12596c3 100644
> --- a/drivers/input/misc/pwm-vibra.c
> +++ b/drivers/input/misc/pwm-vibra.c
> @@ -40,6 +40,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
> struct device *pdev = vibrator->input->dev.parent;
> struct pwm_state state;
> int err;
> + bool new_vcc_on = false;
>
> if (!vibrator->vcc_on) {
> err = regulator_enable(vibrator->vcc);
> @@ -48,6 +49,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
> return err;
> }
> vibrator->vcc_on = true;
> + new_vcc_on = true;
> }
>
> gpiod_set_value_cansleep(vibrator->enable_gpio, 1);
> @@ -59,7 +61,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
> err = pwm_apply_might_sleep(vibrator->pwm, &state);
> if (err) {
> dev_err(pdev, "failed to apply pwm state: %d\n", err);
> - return err;
> + goto err_gpio;
> }
>
> if (vibrator->pwm_dir) {
> @@ -71,11 +73,19 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
> if (err) {
> dev_err(pdev, "failed to apply dir-pwm state: %d\n", err);
> pwm_disable(vibrator->pwm);
> - return err;
> + goto err_gpio;
> }
> }
>
> return 0;
> +
> +err_gpio:
> + gpiod_set_value_cansleep(vibrator->enable_gpio, 0);
> + if (new_vcc_on) {
> + regulator_disable(vibrator->vcc);
> + vibrator->vcc_on = false;
> + }
> + return err;
> }
>
> static void pwm_vibrator_stop(struct pwm_vibrator *vibrator)
> --
> 2.50.1.windows.1
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH v3] HID: Apply quirk HID_QUIRK_ALWAYS_POLL to Edifier QR30 (2d99:a101)
From: Rodrigo Lugathe da Conceição Alves @ 2025-11-27 22:03 UTC (permalink / raw)
To: bentiss, jikos
Cc: linux-input, linux-kernel, linux-usb, stern, dmitry.torokhov,
linuxhid, linuxsound, lugathe2, michal.pecio
The USB speaker has a bug that causes it to reboot when changing the
brightness using the physical knob.
Add a new vendor and product ID entry in hid-ids.h, and register
the corresponding device in hid-quirks.c with the required quirk.
Signed-off-by: Rodrigo Lugathe da Conceição Alves <lugathe2@gmail.com>
---
v3:
- Defined correct vendor
- Moved the added lines to the correct location
v2:
- Fixed title
- Simplified commit message
---
drivers/hid/hid-ids.h | 3 +++
drivers/hid/hid-quirks.c | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0723b4b1c9ec..fbccac79e75a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -438,6 +438,9 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002 0xc002
+#define USB_VENDOR_ID_EDIFIER 0x2d99
+#define USB_DEVICE_ID_EDIFIER_QR30 0xa101 /* EDIFIER Hal0 2.0 SE */
+
#define USB_VENDOR_ID_ELAN 0x04f3
#define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401
#define USB_DEVICE_ID_HP_X2 0x074d
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index bcd4bccf1a7c..f6b7ed467723 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -81,6 +81,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_EDIFIER, USB_DEVICE_ID_EDIFIER_QR30), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II), HID_QUIRK_MULTI_INPUT },
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v2 03/12] dt-bindings: net: Convert Marvell 8897/8997 bindings to DT schema
From: Ariel D'Alessandro @ 2025-11-27 18:15 UTC (permalink / raw)
To: Rob Herring
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, conor+dt, davem,
dmitry.torokhov, edumazet, flora.fu, heiko, houlong.wei, jeesw,
kernel, krzk+dt, kuba, lgirdwood, linus.walleij,
louisalexis.eyraud, luiz.dentz, maarten.lankhorst, marcel,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
sean.wang, simona, support.opensource, tiffany.lin, tzimmermann,
yunfei.dong, devicetree, dri-devel, linux-arm-kernel,
linux-bluetooth, linux-gpio, linux-input, linux-kernel,
linux-media, linux-mediatek, linux-rockchip, linux-sound, netdev
In-Reply-To: <CAL_Jsq+eeiw9oaqQPWt2=rZSX98Pak_oB=tfQFvEehwLZ=S52g@mail.gmail.com>
Hi Rob,
On 11/24/25 3:54 PM, Rob Herring wrote:
> On Wed, Oct 1, 2025 at 12:28 PM Ariel D'Alessandro
> <ariel.dalessandro@collabora.com> wrote:
>>
>> Rob,
>>
>> On 9/12/25 11:06 AM, Rob Herring wrote:
>>> On Thu, Sep 11, 2025 at 12:09:52PM -0300, Ariel D'Alessandro wrote:
>>>> Convert the existing text-based DT bindings for Marvell 8897/8997
>>>> (sd8897/sd8997) bluetooth devices controller to a DT schema.
>>>>
>>>> While here:
>>>>
>>>> * bindings for "usb1286,204e" (USB interface) are dropped from the DT
>>>> schema definition as these are currently documented in file [0].
>>>> * DT binding users are updated to use bluetooth generic name
>>>> recommendation.
>>>>
>>>> [0] Documentation/devicetree/bindings/net/btusb.txt
>>>>
>>>> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
>>>> ---
>>>> .../net/bluetooth/marvell,sd8897-bt.yaml | 79 ++++++++++++++++++
>>>> .../devicetree/bindings/net/btusb.txt | 2 +-
>>>> .../bindings/net/marvell-bt-8xxx.txt | 83 -------------------
>>>
>>>> .../dts/rockchip/rk3288-veyron-fievel.dts | 2 +-
>>>> .../boot/dts/rockchip/rk3288-veyron-jaq.dts | 2 +-
>>>> arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi | 2 +-
>>>
>>> .dts files should be separate patches. Please send the bindings patches
>>> separately per subsystem so subsystem maintainers can apply them. All
>>> the Mediatek dts changes can be 1 series.
>>
>> Ack, will fix in v3.
>
> Are you going to send v3 still?
Yes, will be sending out v3 asap, with the remaining changes.
Sorry for the delay.
--
Ariel D'Alessandro
Software Engineer
Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK
Registered in England & Wales, no. 5513718
^ permalink raw reply
* Re: [PATCH v3] HID: memory leak in dualshock4_get_calibration_data
From: Max Staudt @ 2025-11-27 16:55 UTC (permalink / raw)
To: Eslam Khafagy, Jiri Slaby, roderick.colenbrander, jikos, bentiss
Cc: linux-input, linux-kernel, syzbot+4f5f81e1456a1f645bf8, stable
In-Reply-To: <f67a5702-4b44-41bb-9538-19063bc28b41@gmail.com>
On 11/26/25 3:19 AM, Eslam Khafagy wrote:
> Lastly, One question to max,
> at the beginning of the function dualshock4_get_calibration_data
> buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); if (!
> buf) { ret = -ENOMEM; goto transfer_failed; }
> if the allocation fails. can't we just return here
Never.
> or do we need to go the the end of the function and do sanity checks
> at the end?
Correct.
Without the sanitisation code, the driver will divide by zero.
Max
^ permalink raw reply
* Re: [PATCH v4 0/6] Add support for the LTM8054 voltage regulator
From: Romain Gantois @ 2025-11-27 15:06 UTC (permalink / raw)
To: H. Nikolaus Schaller
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Guenter Roeck, Thomas Petazzoni, linux-kernel,
devicetree, linux-iio, Conor Dooley, MyungJoo Ham, Chanwoo Choi,
Peter Rosin, Mariel Tinaco, Lars-Peter Clausen, Michael Hennerich,
Kevin Tsai, Linus Walleij, Dmitry Torokhov, Eugen Hristev,
Vinod Koul, Kishon Vijay Abraham I, Sebastian Reichel,
Chen-Yu Tsai, Support Opensource, Paul Cercueil, Iskren Chernev,
Marek Szyprowski, Matheus Castello, Saravanan Sekar,
Matthias Brugger, AngeloGioacchino Del Regno, Casey Connolly,
Pali Rohár, Orson Zhai, Baolin Wang, Chunyan Zhang,
Amit Kucheria, Thara Gopinath, Rafael J. Wysocki, Daniel Lezcano,
Zhang Rui, Lukasz Luba, Claudiu Beznea, Jaroslav Kysela,
Takashi Iwai, Sylwester Nawrocki, Olivier Moysan,
Arnaud Pouliquen, Maxime Coquelin, Alexandre Torgue, Dixit Parmar,
linux-hwmon, linux-input, linux-phy, linux-pm, linux-mips,
linux-arm-kernel, linux-mediatek, linux-arm-msm, linux-sound,
linux-stm32, Andy Shevchenko
In-Reply-To: <0E900830-E248-4F0F-A048-075EAF1D2440@goldelico.com>
[-- Attachment #1: Type: text/plain, Size: 2608 bytes --]
On Tuesday, 25 November 2025 11:25:24 CET H. Nikolaus Schaller wrote:
> Hi,
>
> > Am 25.11.2025 um 09:41 schrieb Romain Gantois
> > <romain.gantois@bootlin.com>:
> >
> >
> > This is planned support for a voltage regulator chip.
>
> Well, but one which is not by itself programmable. So IMHO, it does not
> support that chip, but the circuit it is used in.
>
The boundary is a bit blurry in this case, sure.
> > > Are you looking for a virtual "glue" driver to logically combine several
> > > low level functions?
> >
> > I'm looking for a clean userspace abstraction for this component, the low-
> > level functions in this case are those of a voltage regulator.
>
> As far as I understood it has
> - constant voltage
> - current can be limited
> - it can be turned on/off
>
> That means it is a fixed-regulator (for constant voltage and turn on/off)
> and a mechanism to program the current limit (iio-dac). Both have clean
> userspace abstraction.
>
> What am I missing?
>
In my case, the regulator has a DAC tapping into the feedback divider with
allows modifying the output voltage level. This isn't specific to the LTM8054
though, you can theoretically do this with any regulator chip that has a
feedback pin.
...
> The question remains if you want to solve something for a single board which
> happens to have an LTM8054 or if you are solving a more general design
> pattern.
>
> In summary my view is that the LTM8054 is just a "fixed-regulator" which
> gets an additional current-limiter feature by adding a DAC chip (which needs
> a driver of course). So software control is required not by the LTM8054 but
> by adding a DAC chip.
>
> Another suggestion: what extending the "regulator-fixed", "regulator-gpio",
> "regulator-fixed-clock" pattern by some
> "regulator-gpio-iio-dac-current-limiter" driver to make it independent of
> your specific chip?
>
> By the way, are you aware of this feature of the regulator-gpio driver?
>
> https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/regulator/gpio-reg
> ulator.c#L97
>
That could be a preferable solution given that similar current limit and
output voltage limit control methods could apply to other regulator chips...
I'll have to think about it some more.
> Just to note: I am neither maintainer nor doing any decisions on this, just
> asking questions for curiosity and from experience and giving hints for
> alternative approaches, where I hope they help to find the really best
> solution.
Sure, I appreciate that.
Thanks,
--
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [RESEND v5] Input: Add driver for PixArt PS/2 touchpad
From: Huacai Chen @ 2025-11-27 9:37 UTC (permalink / raw)
To: Binbin Zhou
Cc: Binbin Zhou, Huacai Chen, Dmitry Torokhov, Xuerui Wang, loongarch,
linux-input, Xiaotian Wu, jeffbai, Benjamin Tissoires, Jon Xie,
Jay Lee, Kexy Biscuit
In-Reply-To: <20251127080203.3218018-1-zhoubinbin@loongson.cn>
On Thu, Nov 27, 2025 at 4:04 PM Binbin Zhou <zhoubinbin@loongson.cn> wrote:
>
> This patch introduces a driver for the PixArt PS/2 touchpad, which
> supports both clickpad and touchpad types.
>
> At the same time, we extended the single data packet length to 16,
> because according to the current PixArt hardware and FW design, we need
> 11 bytes/15 bytes to represent the complete three-finger/four-finger data.
>
> Co-developed-by: Jon Xie <jon_xie@pixart.com>
> Signed-off-by: Jon Xie <jon_xie@pixart.com>
> Co-developed-by: Jay Lee <jay_lee@pixart.com>
> Signed-off-by: Jay Lee <jay_lee@pixart.com>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> Tested-by: Kexy Biscuit <kexybiscuit@aosc.io>
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
> ---
> After rewriting the determination conditions for the PixArt touchpad type,
> we tested multiple types of touchpads and no longer get false positives for
> non-PixArt devices.
>
> So, I am attempting to resend the patch, thanks.
>
> drivers/input/mouse/Kconfig | 12 ++
> drivers/input/mouse/Makefile | 1 +
> drivers/input/mouse/pixart_ps2.c | 310 +++++++++++++++++++++++++++++
> drivers/input/mouse/pixart_ps2.h | 36 ++++
> drivers/input/mouse/psmouse-base.c | 17 ++
> drivers/input/mouse/psmouse.h | 3 +-
> 6 files changed, 378 insertions(+), 1 deletion(-)
> create mode 100644 drivers/input/mouse/pixart_ps2.c
> create mode 100644 drivers/input/mouse/pixart_ps2.h
>
> diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
> index 833b643f0616..8a27a20d04b0 100644
> --- a/drivers/input/mouse/Kconfig
> +++ b/drivers/input/mouse/Kconfig
> @@ -69,6 +69,18 @@ config MOUSE_PS2_LOGIPS2PP
>
> If unsure, say Y.
>
> +config MOUSE_PS2_PIXART
> + bool "PixArt PS/2 touchpad protocol extension" if EXPERT
> + default y
> + depends on MOUSE_PS2
> + help
> + This driver supports the PixArt PS/2 touchpad found in some
> + laptops.
> + Say Y here if you have a PixArt PS/2 TouchPad connected to
> + your system.
> +
> + If unsure, say Y.
> +
> config MOUSE_PS2_SYNAPTICS
> bool "Synaptics PS/2 mouse protocol extension" if EXPERT
> default y
> diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
> index a1336d5bee6f..563029551529 100644
> --- a/drivers/input/mouse/Makefile
> +++ b/drivers/input/mouse/Makefile
> @@ -32,6 +32,7 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
> psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
> psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
> psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
> +psmouse-$(CONFIG_MOUSE_PS2_PIXART) += pixart_ps2.o
> psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
> psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
> psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
> diff --git a/drivers/input/mouse/pixart_ps2.c b/drivers/input/mouse/pixart_ps2.c
> new file mode 100644
> index 000000000000..682aa6499e63
> --- /dev/null
> +++ b/drivers/input/mouse/pixart_ps2.c
> @@ -0,0 +1,310 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Pixart Touchpad Controller 1336U PS2 driver
> + *
> + * Author: Jon Xie <jon_xie@pixart.com>
> + * Jay Lee <jay_lee@pixart.com>
> + * Further cleanup and restructuring by:
> + * Binbin Zhou <zhoubinbin@loongson.cn>
> + *
> + * Copyright (C) 2021-2024 Pixart Imaging.
> + * Copyright (C) 2024-2025 Loongson Technology Corporation Limited.
> + *
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/input.h>
> +#include <linux/input/mt.h>
> +#include <linux/libps2.h>
> +#include <linux/serio.h>
> +#include <linux/slab.h>
> +
> +#include "pixart_ps2.h"
> +
> +static int pixart_read_tp_mode(struct ps2dev *ps2dev, u8 *mode)
> +{
> + int error;
> + u8 param[1] = { 0 };
> +
> + error = ps2_command(ps2dev, param, PIXART_CMD_REPORT_FORMAT);
> + if (error)
> + return error;
> +
> + *mode = param[0] == 1 ? PIXART_MODE_ABS : PIXART_MODE_REL;
> +
> + return 0;
> +}
> +
> +static int pixart_read_tp_type(struct ps2dev *ps2dev, u8 *type)
> +{
> + int error;
> + u8 param[3] = { 0 };
> +
> + param[0] = 0xa;
> + error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
> + if (error)
> + return error;
> +
> + param[0] = 0x0;
> + error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> + if (error)
> + return error;
> +
> + error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> + if (error)
> + return error;
> +
> + error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> + if (error)
> + return error;
> +
> + param[0] = 0x3;
> + error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> + if (error)
> + return error;
> +
> + error = ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
> + if (error)
> + return error;
> +
> + switch (param[0]) {
> + case 0xc:
> + *type = PIXART_TYPE_CLICKPAD;
> + break;
> + case 0xe:
> + *type = PIXART_TYPE_TOUCHPAD;
> + break;
> + default:
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static void pixart_reset(struct psmouse *psmouse)
> +{
> + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
> +
> + /* according to PixArt, 100ms is required for the upcoming reset */
> + msleep(100);
> + psmouse_reset(psmouse);
> +}
> +
> +static void pixart_process_packet(struct psmouse *psmouse)
> +{
> + struct pixart_data *priv = psmouse->private;
> + struct input_dev *dev = psmouse->dev;
> + const u8 *pkt = psmouse->packet;
> + unsigned int contact_cnt = FIELD_GET(CONTACT_CNT_MASK, pkt[0]);
> + unsigned int i, id, abs_x, abs_y;
> + bool tip;
> +
> + for (i = 0; i < contact_cnt; i++) {
> + const u8 *p = &pkt[i * 3];
> +
> + id = FIELD_GET(SLOT_ID_MASK, p[3]);
> + abs_y = FIELD_GET(ABS_Y_MASK, p[3]) << 8 | p[1];
> + abs_x = FIELD_GET(ABS_X_MASK, p[3]) << 8 | p[2];
> +
> + if (i == PIXART_MAX_FINGERS - 1)
> + tip = pkt[14] & BIT(1);
> + else
> + tip = pkt[3 * contact_cnt + 1] & BIT(2 * i + 1);
> +
> + input_mt_slot(dev, id);
> + if (input_mt_report_slot_state(dev, MT_TOOL_FINGER, tip)) {
> + input_report_abs(dev, ABS_MT_POSITION_Y, abs_y);
> + input_report_abs(dev, ABS_MT_POSITION_X, abs_x);
> + }
> + }
> +
> + input_mt_sync_frame(dev);
> +
> + if (priv->type == PIXART_TYPE_CLICKPAD) {
> + input_report_key(dev, BTN_LEFT, pkt[0] & 0x03);
> + } else {
> + input_report_key(dev, BTN_LEFT, pkt[0] & BIT(0));
> + input_report_key(dev, BTN_RIGHT, pkt[0] & BIT(1));
> + }
> +
> + input_sync(dev);
> +}
> +
> +static psmouse_ret_t pixart_protocol_handler(struct psmouse *psmouse)
> +{
> + u8 *pkt = psmouse->packet;
> + u8 contact_cnt;
> +
> + if ((pkt[0] & 0x8c) != 0x80)
> + return PSMOUSE_BAD_DATA;
> +
> + contact_cnt = FIELD_GET(CONTACT_CNT_MASK, pkt[0]);
> + if (contact_cnt > PIXART_MAX_FINGERS)
> + return PSMOUSE_BAD_DATA;
> +
> + if (contact_cnt == PIXART_MAX_FINGERS &&
> + psmouse->pktcnt < psmouse->pktsize) {
> + return PSMOUSE_GOOD_DATA;
> + }
> +
> + if (contact_cnt == 0 && psmouse->pktcnt < 5)
> + return PSMOUSE_GOOD_DATA;
> +
> + if (psmouse->pktcnt < 3 * contact_cnt + 2)
> + return PSMOUSE_GOOD_DATA;
> +
> + pixart_process_packet(psmouse);
> +
> + return PSMOUSE_FULL_PACKET;
> +}
> +
> +static void pixart_disconnect(struct psmouse *psmouse)
> +{
> + pixart_reset(psmouse);
> + kfree(psmouse->private);
> + psmouse->private = NULL;
> +}
> +
> +static int pixart_reconnect(struct psmouse *psmouse)
> +{
> + struct ps2dev *ps2dev = &psmouse->ps2dev;
> + u8 mode;
> + int error;
> +
> + pixart_reset(psmouse);
> +
> + error = pixart_read_tp_mode(ps2dev, &mode);
> + if (error)
> + return error;
> +
> + if (mode != PIXART_MODE_ABS)
> + return -EIO;
> +
> + error = ps2_command(ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
> + if (error)
> + return error;
> +
> + return 0;
> +}
> +
> +static int pixart_set_input_params(struct input_dev *dev,
> + struct pixart_data *priv)
> +{
> + /* No relative support */
> + __clear_bit(EV_REL, dev->evbit);
> + __clear_bit(REL_X, dev->relbit);
> + __clear_bit(REL_Y, dev->relbit);
> + __clear_bit(BTN_MIDDLE, dev->keybit);
> +
> + /* Buttons */
> + __set_bit(EV_KEY, dev->evbit);
> + __set_bit(BTN_LEFT, dev->keybit);
> + if (priv->type == PIXART_TYPE_CLICKPAD)
> + __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
> + else
> + __set_bit(BTN_RIGHT, dev->keybit);
> +
> + /* Absolute position */
> + input_set_abs_params(dev, ABS_X, 0, PIXART_PAD_WIDTH, 0, 0);
> + input_set_abs_params(dev, ABS_Y, 0, PIXART_PAD_HEIGHT, 0, 0);
> +
> + input_set_abs_params(dev, ABS_MT_POSITION_X,
> + 0, PIXART_PAD_WIDTH, 0, 0);
> + input_set_abs_params(dev, ABS_MT_POSITION_Y,
> + 0, PIXART_PAD_HEIGHT, 0, 0);
> +
> + return input_mt_init_slots(dev, PIXART_MAX_FINGERS,
> + INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
> +}
> +
> +static int pixart_query_hardware(struct ps2dev *ps2dev, u8 *mode, u8 *type)
> +{
> + int error;
> +
> + error = pixart_read_tp_type(ps2dev, type);
> + if (error)
> + return error;
> +
> + error = pixart_read_tp_mode(ps2dev, mode);
> + if (error)
> + return error;
> +
> + return 0;
> +}
> +
> +int pixart_detect(struct psmouse *psmouse, bool set_properties)
> +{
> + u8 type;
> + int error;
> +
> + pixart_reset(psmouse);
> +
> + error = pixart_read_tp_type(&psmouse->ps2dev, &type);
> + if (error)
> + return error;
> +
> + if (set_properties) {
> + psmouse->vendor = "PixArt";
> + psmouse->name = (type == PIXART_TYPE_TOUCHPAD) ?
> + "touchpad" : "clickpad";
> + }
> +
> + return 0;
> +}
> +
> +int pixart_init(struct psmouse *psmouse)
> +{
> + int error;
> + struct pixart_data *priv;
> +
> + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + psmouse->private = priv;
> + pixart_reset(psmouse);
> +
> + error = pixart_query_hardware(&psmouse->ps2dev,
> + &priv->mode, &priv->type);
> + if (error) {
> + psmouse_err(psmouse, "init: Unable to query PixArt touchpad hardware.\n");
> + goto err_exit;
> + }
> +
> + /* Relative mode follows standard PS/2 mouse protocol */
> + if (priv->mode != PIXART_MODE_ABS) {
> + error = -EIO;
> + goto err_exit;
> + }
> +
> + /* Set absolute mode */
> + error = ps2_command(&psmouse->ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
> + if (error) {
> + psmouse_err(psmouse, "init: Unable to initialize PixArt absolute mode.\n");
> + goto err_exit;
> + }
> +
> + error = pixart_set_input_params(psmouse->dev, priv);
> + if (error) {
> + psmouse_err(psmouse, "init: Unable to set input params.\n");
> + goto err_exit;
> + }
> +
> + psmouse->pktsize = 15;
> + psmouse->protocol_handler = pixart_protocol_handler;
> + psmouse->disconnect = pixart_disconnect;
> + psmouse->reconnect = pixart_reconnect;
> + psmouse->cleanup = pixart_reset;
> + /* resync is not supported yet */
> + psmouse->resync_time = 0;
> +
> + return 0;
> +
> +err_exit:
> + pixart_reset(psmouse);
> + kfree(priv);
> + psmouse->private = NULL;
> + return error;
> +}
> diff --git a/drivers/input/mouse/pixart_ps2.h b/drivers/input/mouse/pixart_ps2.h
> new file mode 100644
> index 000000000000..47a1d040f2d1
> --- /dev/null
> +++ b/drivers/input/mouse/pixart_ps2.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +#ifndef _PIXART_PS2_H
> +#define _PIXART_PS2_H
> +
> +#include "psmouse.h"
> +
> +#define PIXART_PAD_WIDTH 1023
> +#define PIXART_PAD_HEIGHT 579
> +#define PIXART_MAX_FINGERS 4
> +
> +#define PIXART_CMD_REPORT_FORMAT 0x01d8
> +#define PIXART_CMD_SWITCH_PROTO 0x00de
> +
> +#define PIXART_MODE_REL 0
> +#define PIXART_MODE_ABS 1
> +
> +#define PIXART_TYPE_CLICKPAD 0
> +#define PIXART_TYPE_TOUCHPAD 1
> +
> +#define CONTACT_CNT_MASK GENMASK(6, 4)
> +
> +#define SLOT_ID_MASK GENMASK(2, 0)
> +#define ABS_Y_MASK GENMASK(5, 4)
> +#define ABS_X_MASK GENMASK(7, 6)
> +
> +struct pixart_data {
> + u8 mode;
> + u8 type;
> + int x_max;
> + int y_max;
> +};
> +
> +int pixart_detect(struct psmouse *psmouse, bool set_properties);
> +int pixart_init(struct psmouse *psmouse);
> +
> +#endif /* _PIXART_PS2_H */
> diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
> index 77ea7da3b1c5..f708b75eb91b 100644
> --- a/drivers/input/mouse/psmouse-base.c
> +++ b/drivers/input/mouse/psmouse-base.c
> @@ -36,6 +36,7 @@
> #include "focaltech.h"
> #include "vmmouse.h"
> #include "byd.h"
> +#include "pixart_ps2.h"
>
> #define DRIVER_DESC "PS/2 mouse driver"
>
> @@ -905,6 +906,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
> .detect = byd_detect,
> .init = byd_init,
> },
> +#endif
> +#ifdef CONFIG_MOUSE_PS2_PIXART
> + {
> + .type = PSMOUSE_PIXART,
> + .name = "PixArtPS/2",
> + .alias = "pixart",
> + .detect = pixart_detect,
> + .init = pixart_init,
> + },
> #endif
> {
> .type = PSMOUSE_AUTO,
> @@ -1172,6 +1182,13 @@ static int psmouse_extensions(struct psmouse *psmouse,
> return ret;
> }
>
> + /* Try PixArt touchpad */
> + if (max_proto > PSMOUSE_IMEX &&
> + psmouse_try_protocol(psmouse, PSMOUSE_PIXART, &max_proto,
> + set_properties, true)) {
> + return PSMOUSE_PIXART;
> + }
> +
> if (max_proto > PSMOUSE_IMEX) {
> if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
> &max_proto, set_properties, true))
> diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
> index 4d8acfe0d82a..23f7fa7243cb 100644
> --- a/drivers/input/mouse/psmouse.h
> +++ b/drivers/input/mouse/psmouse.h
> @@ -69,6 +69,7 @@ enum psmouse_type {
> PSMOUSE_BYD,
> PSMOUSE_SYNAPTICS_SMBUS,
> PSMOUSE_ELANTECH_SMBUS,
> + PSMOUSE_PIXART,
> PSMOUSE_AUTO /* This one should always be last */
> };
>
> @@ -94,7 +95,7 @@ struct psmouse {
> const char *vendor;
> const char *name;
> const struct psmouse_protocol *protocol;
> - unsigned char packet[8];
> + unsigned char packet[16];
> unsigned char badbyte;
> unsigned char pktcnt;
> unsigned char pktsize;
>
> base-commit: a311c777f2987e6ddba2d2dd2f82f2135d65f8aa
> --
> 2.47.3
>
>
^ permalink raw reply
* [RESEND v5] Input: Add driver for PixArt PS/2 touchpad
From: Binbin Zhou @ 2025-11-27 8:02 UTC (permalink / raw)
To: Binbin Zhou, Huacai Chen, Dmitry Torokhov
Cc: Huacai Chen, Xuerui Wang, loongarch, linux-input, Xiaotian Wu,
jeffbai, Benjamin Tissoires, Binbin Zhou, Jon Xie, Jay Lee,
Kexy Biscuit
This patch introduces a driver for the PixArt PS/2 touchpad, which
supports both clickpad and touchpad types.
At the same time, we extended the single data packet length to 16,
because according to the current PixArt hardware and FW design, we need
11 bytes/15 bytes to represent the complete three-finger/four-finger data.
Co-developed-by: Jon Xie <jon_xie@pixart.com>
Signed-off-by: Jon Xie <jon_xie@pixart.com>
Co-developed-by: Jay Lee <jay_lee@pixart.com>
Signed-off-by: Jay Lee <jay_lee@pixart.com>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Tested-by: Kexy Biscuit <kexybiscuit@aosc.io>
---
After rewriting the determination conditions for the PixArt touchpad type,
we tested multiple types of touchpads and no longer get false positives for
non-PixArt devices.
So, I am attempting to resend the patch, thanks.
drivers/input/mouse/Kconfig | 12 ++
drivers/input/mouse/Makefile | 1 +
drivers/input/mouse/pixart_ps2.c | 310 +++++++++++++++++++++++++++++
drivers/input/mouse/pixart_ps2.h | 36 ++++
drivers/input/mouse/psmouse-base.c | 17 ++
drivers/input/mouse/psmouse.h | 3 +-
6 files changed, 378 insertions(+), 1 deletion(-)
create mode 100644 drivers/input/mouse/pixart_ps2.c
create mode 100644 drivers/input/mouse/pixart_ps2.h
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 833b643f0616..8a27a20d04b0 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -69,6 +69,18 @@ config MOUSE_PS2_LOGIPS2PP
If unsure, say Y.
+config MOUSE_PS2_PIXART
+ bool "PixArt PS/2 touchpad protocol extension" if EXPERT
+ default y
+ depends on MOUSE_PS2
+ help
+ This driver supports the PixArt PS/2 touchpad found in some
+ laptops.
+ Say Y here if you have a PixArt PS/2 TouchPad connected to
+ your system.
+
+ If unsure, say Y.
+
config MOUSE_PS2_SYNAPTICS
bool "Synaptics PS/2 mouse protocol extension" if EXPERT
default y
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index a1336d5bee6f..563029551529 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -32,6 +32,7 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
+psmouse-$(CONFIG_MOUSE_PS2_PIXART) += pixart_ps2.o
psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
diff --git a/drivers/input/mouse/pixart_ps2.c b/drivers/input/mouse/pixart_ps2.c
new file mode 100644
index 000000000000..682aa6499e63
--- /dev/null
+++ b/drivers/input/mouse/pixart_ps2.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pixart Touchpad Controller 1336U PS2 driver
+ *
+ * Author: Jon Xie <jon_xie@pixart.com>
+ * Jay Lee <jay_lee@pixart.com>
+ * Further cleanup and restructuring by:
+ * Binbin Zhou <zhoubinbin@loongson.cn>
+ *
+ * Copyright (C) 2021-2024 Pixart Imaging.
+ * Copyright (C) 2024-2025 Loongson Technology Corporation Limited.
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/libps2.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+
+#include "pixart_ps2.h"
+
+static int pixart_read_tp_mode(struct ps2dev *ps2dev, u8 *mode)
+{
+ int error;
+ u8 param[1] = { 0 };
+
+ error = ps2_command(ps2dev, param, PIXART_CMD_REPORT_FORMAT);
+ if (error)
+ return error;
+
+ *mode = param[0] == 1 ? PIXART_MODE_ABS : PIXART_MODE_REL;
+
+ return 0;
+}
+
+static int pixart_read_tp_type(struct ps2dev *ps2dev, u8 *type)
+{
+ int error;
+ u8 param[3] = { 0 };
+
+ param[0] = 0xa;
+ error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ if (error)
+ return error;
+
+ param[0] = 0x0;
+ error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ if (error)
+ return error;
+
+ error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ if (error)
+ return error;
+
+ error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ if (error)
+ return error;
+
+ param[0] = 0x3;
+ error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ if (error)
+ return error;
+
+ error = ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
+ if (error)
+ return error;
+
+ switch (param[0]) {
+ case 0xc:
+ *type = PIXART_TYPE_CLICKPAD;
+ break;
+ case 0xe:
+ *type = PIXART_TYPE_TOUCHPAD;
+ break;
+ default:
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void pixart_reset(struct psmouse *psmouse)
+{
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
+
+ /* according to PixArt, 100ms is required for the upcoming reset */
+ msleep(100);
+ psmouse_reset(psmouse);
+}
+
+static void pixart_process_packet(struct psmouse *psmouse)
+{
+ struct pixart_data *priv = psmouse->private;
+ struct input_dev *dev = psmouse->dev;
+ const u8 *pkt = psmouse->packet;
+ unsigned int contact_cnt = FIELD_GET(CONTACT_CNT_MASK, pkt[0]);
+ unsigned int i, id, abs_x, abs_y;
+ bool tip;
+
+ for (i = 0; i < contact_cnt; i++) {
+ const u8 *p = &pkt[i * 3];
+
+ id = FIELD_GET(SLOT_ID_MASK, p[3]);
+ abs_y = FIELD_GET(ABS_Y_MASK, p[3]) << 8 | p[1];
+ abs_x = FIELD_GET(ABS_X_MASK, p[3]) << 8 | p[2];
+
+ if (i == PIXART_MAX_FINGERS - 1)
+ tip = pkt[14] & BIT(1);
+ else
+ tip = pkt[3 * contact_cnt + 1] & BIT(2 * i + 1);
+
+ input_mt_slot(dev, id);
+ if (input_mt_report_slot_state(dev, MT_TOOL_FINGER, tip)) {
+ input_report_abs(dev, ABS_MT_POSITION_Y, abs_y);
+ input_report_abs(dev, ABS_MT_POSITION_X, abs_x);
+ }
+ }
+
+ input_mt_sync_frame(dev);
+
+ if (priv->type == PIXART_TYPE_CLICKPAD) {
+ input_report_key(dev, BTN_LEFT, pkt[0] & 0x03);
+ } else {
+ input_report_key(dev, BTN_LEFT, pkt[0] & BIT(0));
+ input_report_key(dev, BTN_RIGHT, pkt[0] & BIT(1));
+ }
+
+ input_sync(dev);
+}
+
+static psmouse_ret_t pixart_protocol_handler(struct psmouse *psmouse)
+{
+ u8 *pkt = psmouse->packet;
+ u8 contact_cnt;
+
+ if ((pkt[0] & 0x8c) != 0x80)
+ return PSMOUSE_BAD_DATA;
+
+ contact_cnt = FIELD_GET(CONTACT_CNT_MASK, pkt[0]);
+ if (contact_cnt > PIXART_MAX_FINGERS)
+ return PSMOUSE_BAD_DATA;
+
+ if (contact_cnt == PIXART_MAX_FINGERS &&
+ psmouse->pktcnt < psmouse->pktsize) {
+ return PSMOUSE_GOOD_DATA;
+ }
+
+ if (contact_cnt == 0 && psmouse->pktcnt < 5)
+ return PSMOUSE_GOOD_DATA;
+
+ if (psmouse->pktcnt < 3 * contact_cnt + 2)
+ return PSMOUSE_GOOD_DATA;
+
+ pixart_process_packet(psmouse);
+
+ return PSMOUSE_FULL_PACKET;
+}
+
+static void pixart_disconnect(struct psmouse *psmouse)
+{
+ pixart_reset(psmouse);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int pixart_reconnect(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ u8 mode;
+ int error;
+
+ pixart_reset(psmouse);
+
+ error = pixart_read_tp_mode(ps2dev, &mode);
+ if (error)
+ return error;
+
+ if (mode != PIXART_MODE_ABS)
+ return -EIO;
+
+ error = ps2_command(ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int pixart_set_input_params(struct input_dev *dev,
+ struct pixart_data *priv)
+{
+ /* No relative support */
+ __clear_bit(EV_REL, dev->evbit);
+ __clear_bit(REL_X, dev->relbit);
+ __clear_bit(REL_Y, dev->relbit);
+ __clear_bit(BTN_MIDDLE, dev->keybit);
+
+ /* Buttons */
+ __set_bit(EV_KEY, dev->evbit);
+ __set_bit(BTN_LEFT, dev->keybit);
+ if (priv->type == PIXART_TYPE_CLICKPAD)
+ __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
+ else
+ __set_bit(BTN_RIGHT, dev->keybit);
+
+ /* Absolute position */
+ input_set_abs_params(dev, ABS_X, 0, PIXART_PAD_WIDTH, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, PIXART_PAD_HEIGHT, 0, 0);
+
+ input_set_abs_params(dev, ABS_MT_POSITION_X,
+ 0, PIXART_PAD_WIDTH, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y,
+ 0, PIXART_PAD_HEIGHT, 0, 0);
+
+ return input_mt_init_slots(dev, PIXART_MAX_FINGERS,
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
+}
+
+static int pixart_query_hardware(struct ps2dev *ps2dev, u8 *mode, u8 *type)
+{
+ int error;
+
+ error = pixart_read_tp_type(ps2dev, type);
+ if (error)
+ return error;
+
+ error = pixart_read_tp_mode(ps2dev, mode);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+int pixart_detect(struct psmouse *psmouse, bool set_properties)
+{
+ u8 type;
+ int error;
+
+ pixart_reset(psmouse);
+
+ error = pixart_read_tp_type(&psmouse->ps2dev, &type);
+ if (error)
+ return error;
+
+ if (set_properties) {
+ psmouse->vendor = "PixArt";
+ psmouse->name = (type == PIXART_TYPE_TOUCHPAD) ?
+ "touchpad" : "clickpad";
+ }
+
+ return 0;
+}
+
+int pixart_init(struct psmouse *psmouse)
+{
+ int error;
+ struct pixart_data *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ psmouse->private = priv;
+ pixart_reset(psmouse);
+
+ error = pixart_query_hardware(&psmouse->ps2dev,
+ &priv->mode, &priv->type);
+ if (error) {
+ psmouse_err(psmouse, "init: Unable to query PixArt touchpad hardware.\n");
+ goto err_exit;
+ }
+
+ /* Relative mode follows standard PS/2 mouse protocol */
+ if (priv->mode != PIXART_MODE_ABS) {
+ error = -EIO;
+ goto err_exit;
+ }
+
+ /* Set absolute mode */
+ error = ps2_command(&psmouse->ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
+ if (error) {
+ psmouse_err(psmouse, "init: Unable to initialize PixArt absolute mode.\n");
+ goto err_exit;
+ }
+
+ error = pixart_set_input_params(psmouse->dev, priv);
+ if (error) {
+ psmouse_err(psmouse, "init: Unable to set input params.\n");
+ goto err_exit;
+ }
+
+ psmouse->pktsize = 15;
+ psmouse->protocol_handler = pixart_protocol_handler;
+ psmouse->disconnect = pixart_disconnect;
+ psmouse->reconnect = pixart_reconnect;
+ psmouse->cleanup = pixart_reset;
+ /* resync is not supported yet */
+ psmouse->resync_time = 0;
+
+ return 0;
+
+err_exit:
+ pixart_reset(psmouse);
+ kfree(priv);
+ psmouse->private = NULL;
+ return error;
+}
diff --git a/drivers/input/mouse/pixart_ps2.h b/drivers/input/mouse/pixart_ps2.h
new file mode 100644
index 000000000000..47a1d040f2d1
--- /dev/null
+++ b/drivers/input/mouse/pixart_ps2.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _PIXART_PS2_H
+#define _PIXART_PS2_H
+
+#include "psmouse.h"
+
+#define PIXART_PAD_WIDTH 1023
+#define PIXART_PAD_HEIGHT 579
+#define PIXART_MAX_FINGERS 4
+
+#define PIXART_CMD_REPORT_FORMAT 0x01d8
+#define PIXART_CMD_SWITCH_PROTO 0x00de
+
+#define PIXART_MODE_REL 0
+#define PIXART_MODE_ABS 1
+
+#define PIXART_TYPE_CLICKPAD 0
+#define PIXART_TYPE_TOUCHPAD 1
+
+#define CONTACT_CNT_MASK GENMASK(6, 4)
+
+#define SLOT_ID_MASK GENMASK(2, 0)
+#define ABS_Y_MASK GENMASK(5, 4)
+#define ABS_X_MASK GENMASK(7, 6)
+
+struct pixart_data {
+ u8 mode;
+ u8 type;
+ int x_max;
+ int y_max;
+};
+
+int pixart_detect(struct psmouse *psmouse, bool set_properties);
+int pixart_init(struct psmouse *psmouse);
+
+#endif /* _PIXART_PS2_H */
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 77ea7da3b1c5..f708b75eb91b 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -36,6 +36,7 @@
#include "focaltech.h"
#include "vmmouse.h"
#include "byd.h"
+#include "pixart_ps2.h"
#define DRIVER_DESC "PS/2 mouse driver"
@@ -905,6 +906,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = byd_detect,
.init = byd_init,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_PIXART
+ {
+ .type = PSMOUSE_PIXART,
+ .name = "PixArtPS/2",
+ .alias = "pixart",
+ .detect = pixart_detect,
+ .init = pixart_init,
+ },
#endif
{
.type = PSMOUSE_AUTO,
@@ -1172,6 +1182,13 @@ static int psmouse_extensions(struct psmouse *psmouse,
return ret;
}
+ /* Try PixArt touchpad */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_try_protocol(psmouse, PSMOUSE_PIXART, &max_proto,
+ set_properties, true)) {
+ return PSMOUSE_PIXART;
+ }
+
if (max_proto > PSMOUSE_IMEX) {
if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
&max_proto, set_properties, true))
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 4d8acfe0d82a..23f7fa7243cb 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -69,6 +69,7 @@ enum psmouse_type {
PSMOUSE_BYD,
PSMOUSE_SYNAPTICS_SMBUS,
PSMOUSE_ELANTECH_SMBUS,
+ PSMOUSE_PIXART,
PSMOUSE_AUTO /* This one should always be last */
};
@@ -94,7 +95,7 @@ struct psmouse {
const char *vendor;
const char *name;
const struct psmouse_protocol *protocol;
- unsigned char packet[8];
+ unsigned char packet[16];
unsigned char badbyte;
unsigned char pktcnt;
unsigned char pktsize;
base-commit: a311c777f2987e6ddba2d2dd2f82f2135d65f8aa
--
2.47.3
^ permalink raw reply related
* [RESEND PATCH v2] Input: edt-ft5x06 - fix report rate handling by sysfs
From: Dario Binacchi @ 2025-11-27 7:46 UTC (permalink / raw)
To: linux-kernel
Cc: linux-amarula, Dario Binacchi, Dmitry Torokhov, Jens Reidel,
Wolfram Sang, linux-input
In the driver probe, the report-rate-hz value from device tree is written
directly to the M12 controller register, while for the M06 it is divided
by 10 since the controller expects the value in units of 10 Hz. That logic
was missing in the sysfs handling, leading to inconsistent behavior
depending on whether the value came from device tree or sysfs.
This patch makes the report-rate handling consistent by applying the same
logic in both cases. Two dedicated functions, report_rate_hz_{show,store},
were added for the following reasons:
- Avoid modifying the more generic edt_ft5x06_setting_{show,store} and
thus prevent regressions.
- Properly enforce lower and upper limits for the M06 case. The previous
version accepted invalid values for M06, since it relied on the M12
limits.
- Return an error when the property is not supported (e.g. M09), to avoid
misleading users into thinking the property is handled by the
controller.
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---
Changes in v2:
- Drop the patch:
1/2 Input: edt-ft5x06 - rename sysfs attribute report_rate to report_rate_hz
because not accepted.
drivers/input/touchscreen/edt-ft5x06.c | 158 +++++++++++++++++++++----
1 file changed, 135 insertions(+), 23 deletions(-)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index bf498bd4dea9..d7a269a0528f 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -516,9 +516,136 @@ static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255);
-/* m06: range 3 to 14, m12: range 1 to 255 */
-static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
- M12_REGISTER_REPORT_RATE, NO_REGISTER, 0, 255);
+
+static int edt_ft5x06_report_rate_get(struct edt_ft5x06_ts_data *tsdata)
+{
+ unsigned int val;
+ int error;
+
+ if (tsdata->reg_addr.reg_report_rate == NO_REGISTER)
+ return -EOPNOTSUPP;
+
+ error = regmap_read(tsdata->regmap, tsdata->reg_addr.reg_report_rate,
+ &val);
+ if (error)
+ return error;
+
+ if (tsdata->version == EDT_M06)
+ val *= 10;
+
+ if (val != tsdata->report_rate) {
+ dev_warn(&tsdata->client->dev,
+ "report-rate: read (%d) and stored value (%d) differ\n",
+ val, tsdata->report_rate);
+ tsdata->report_rate = val;
+ }
+
+ return 0;
+}
+
+static ssize_t report_rate_show(struct device *dev,
+ struct device_attribute *dattr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+ size_t count;
+ int error;
+
+ mutex_lock(&tsdata->mutex);
+
+ if (tsdata->factory_mode) {
+ error = -EIO;
+ goto out;
+ }
+
+ error = edt_ft5x06_report_rate_get(tsdata);
+ if (error) {
+ dev_err(&tsdata->client->dev,
+ "Failed to fetch attribute %s, error %d\n",
+ dattr->attr.name, error);
+ goto out;
+ }
+
+ count = sysfs_emit(buf, "%d\n", tsdata->report_rate);
+out:
+ mutex_unlock(&tsdata->mutex);
+ return error ?: count;
+}
+
+static int edt_ft5x06_report_rate_set(struct edt_ft5x06_ts_data *tsdata,
+ unsigned int val)
+{
+ if (tsdata->reg_addr.reg_report_rate == NO_REGISTER)
+ return -EOPNOTSUPP;
+
+ if (tsdata->version == EDT_M06)
+ tsdata->report_rate = clamp_val(val, 30, 140);
+ else
+ tsdata->report_rate = clamp_val(val, 1, 255);
+
+ if (val != tsdata->report_rate) {
+ dev_warn(&tsdata->client->dev,
+ "report-rate %dHz is unsupported, use %dHz\n",
+ val, tsdata->report_rate);
+ val = tsdata->report_rate;
+ }
+
+ if (tsdata->version == EDT_M06)
+ val /= 10;
+
+ return regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate,
+ val);
+}
+
+static ssize_t report_rate_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+ unsigned int val;
+ u8 limit_low;
+ u8 limit_high;
+ int error;
+
+ mutex_lock(&tsdata->mutex);
+
+ if (tsdata->factory_mode) {
+ error = -EIO;
+ goto out;
+ }
+
+ error = kstrtouint(buf, 0, &val);
+ if (error)
+ goto out;
+
+ if (tsdata->version == EDT_M06) {
+ limit_low = 30;
+ limit_high = 140;
+ } else {
+ limit_low = 1;
+ limit_high = 255;
+ }
+
+ if (val < limit_low || val > limit_high) {
+ error = -ERANGE;
+ goto out;
+ }
+
+ error = edt_ft5x06_report_rate_set(tsdata, val);
+ if (error) {
+ dev_err(&tsdata->client->dev,
+ "Failed to update attribute %s, error: %d\n",
+ dattr->attr.name, error);
+ goto out;
+ }
+
+out:
+ mutex_unlock(&tsdata->mutex);
+ return error ?: count;
+}
+
+static DEVICE_ATTR_RW(report_rate);
static ssize_t model_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -572,7 +699,7 @@ static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_offset_x.dattr.attr,
&edt_ft5x06_attr_offset_y.dattr.attr,
&edt_ft5x06_attr_threshold.dattr.attr,
- &edt_ft5x06_attr_report_rate.dattr.attr,
+ &dev_attr_report_rate.attr,
&dev_attr_model.attr,
&dev_attr_fw_version.attr,
&dev_attr_header_errors.attr,
@@ -595,8 +722,7 @@ static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata)
if (reg_addr->reg_offset_y != NO_REGISTER)
regmap_write(regmap, reg_addr->reg_offset_y, tsdata->offset_y);
if (reg_addr->reg_report_rate != NO_REGISTER)
- regmap_write(regmap, reg_addr->reg_report_rate,
- tsdata->report_rate);
+ edt_ft5x06_report_rate_set(tsdata, tsdata->report_rate);
}
#ifdef CONFIG_DEBUG_FS
@@ -1029,8 +1155,8 @@ static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
if (reg_addr->reg_offset_y != NO_REGISTER)
regmap_read(regmap, reg_addr->reg_offset_y, &tsdata->offset_y);
if (reg_addr->reg_report_rate != NO_REGISTER)
- regmap_read(regmap, reg_addr->reg_report_rate,
- &tsdata->report_rate);
+ edt_ft5x06_report_rate_get(tsdata);
+
tsdata->num_x = EDT_DEFAULT_NUM_X;
if (reg_addr->reg_num_x != NO_REGISTER) {
if (!regmap_read(regmap, reg_addr->reg_num_x, &val))
@@ -1289,21 +1415,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
if (tsdata->reg_addr.reg_report_rate != NO_REGISTER &&
!device_property_read_u32(&client->dev,
"report-rate-hz", &report_rate)) {
- if (tsdata->version == EDT_M06)
- tsdata->report_rate = clamp_val(report_rate, 30, 140);
- else
- tsdata->report_rate = clamp_val(report_rate, 1, 255);
-
- if (report_rate != tsdata->report_rate)
- dev_warn(&client->dev,
- "report-rate %dHz is unsupported, use %dHz\n",
- report_rate, tsdata->report_rate);
-
- if (tsdata->version == EDT_M06)
- tsdata->report_rate /= 10;
-
- regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate,
- tsdata->report_rate);
+ edt_ft5x06_report_rate_set(tsdata, report_rate);
}
dev_dbg(&client->dev,
--
2.43.0
base-commit: 765e56e41a5af2d456ddda6cbd617b9d3295ab4e
branch: edt-ft5x06-fix-report-rate
^ permalink raw reply related
* Re: [PATCH v12 1/3] dt-bindings: i2c: Add CP2112 HID USB to SMBus Bridge
From: Krzysztof Kozlowski @ 2025-11-27 7:24 UTC (permalink / raw)
To: Danny Kaehn
Cc: Rob Herring, Krzysztof Kozlowski, Benjamin Tissoires,
Andy Shevchenko, Andi Shyti, Conor Dooley, Jiri Kosina,
devicetree, linux-input, Dmitry Torokhov, Bartosz Golaszewski,
Ethan Twardy, linux-i2c, linux-kernel, Leo Huang, Arun D Patil,
Willie Thai, Ting-Kai Chen
In-Reply-To: <20251126-cp2112-dt-v12-1-2cdba6481db3@plexus.com>
On Wed, Nov 26, 2025 at 11:05:24AM -0600, Danny Kaehn wrote:
> + i2c:
> + description: The SMBus/I2C controller node for the CP2112
> + $ref: /schemas/i2c/i2c-controller.yaml#
> + unevaluatedProperties: false
> +
> + properties:
> + sda-gpios:
> + maxItems: 1
> +
> + scl-gpios:
> + maxItems: 1
Neither scl nor sda-gpios are needed, they are allowed by i2c-controller
schema, so drop.
> +
> + clock-frequency:
> + minimum: 10000
> + default: 100000
> + maximum: 400000
> +
> +patternProperties:
> + "-hog(-[0-9]+)?$":
> + type: object
> +
> + required:
> + - gpio-hog
> +
> +required:
> + - compatible
> + - reg
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/irq.h>
> + #include <dt-bindings/gpio/gpio.h>
> +
> + usb {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + cp2112: device@1 {
> + compatible = "usb10c4,ea90";
> + reg = <1>;
> +
> + gpio-controller;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + #gpio-cells = <2>;
> + gpio-line-names = "CP2112_SDA", "CP2112_SCL", "TEST2",
> + "TEST3","TEST4", "TEST5", "TEST6";
Please align the next line with opening ". See also DTS coding style.
> +
> + fan-rst-hog {
> + gpio-hog;
> + gpios = <7 GPIO_ACTIVE_HIGH>;
> + output-high;
> + line-name = "FAN_RST";
> + };
> +
> + i2c {
> + #address-cells = <1>;
Messed indentation, stick to one, preferred is 4 spaces for the example.
> + #size-cells = <0>;
> + sda-gpios = <&cp2112 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> + scl-gpios = <&cp2112 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +
> + temp@48 {
> + compatible = "national,lm75";
> + reg = <0x48>;
> + };
> + };
> +
Drop blank line
> + };
> + };
>
> --
> 2.25.1
>
^ permalink raw reply
* Re: [PATCH v12 0/3] Firmware Support for USB-HID Devices and CP2112
From: Krzysztof Kozlowski @ 2025-11-27 7:20 UTC (permalink / raw)
To: Danny Kaehn
Cc: Rob Herring, Krzysztof Kozlowski, Benjamin Tissoires,
Andy Shevchenko, Andi Shyti, Conor Dooley, Jiri Kosina,
devicetree, linux-input, Dmitry Torokhov, Bartosz Golaszewski,
Ethan Twardy, linux-i2c, linux-kernel, Leo Huang, Arun D Patil,
Willie Thai, Ting-Kai Chen
In-Reply-To: <20251126-cp2112-dt-v12-0-2cdba6481db3@plexus.com>
On Wed, Nov 26, 2025 at 11:05:23AM -0600, Danny Kaehn wrote:
> This patchset allows USB-HID devices to have Firmware bindings through sharing
> the USB fwnode with the HID driver, and adds such a binding and driver
> implementation for the CP2112 USB to SMBus Bridge (which necessitated the
> USB-HID change). This change allows a CP2112 permanently attached in hardware to
> be described in DT and ACPI and interoperate with other drivers.
>
> Changes in v12:
> - dt-binding changes:
> - Drop "on the host controller" from top-level description based on
> comment from Rob H.
> - Correct "Properties must precede subnodes" dt_binding_check error by
> moving gpio_chip-related properties above the i2c subnode in the
> binding and in the example.
> - Include `interrupt-controller` property in the example
> - Modify hid-cp2112.c to support separate schemas for DT vs. ACPI - DT
> combines gpio subnode with the CP2112's node, but will have an I2C
> subnode; while ACPI will maintain separate child nodes for the GPIO
> I2C devices
That's a b4 managed patch, so I wonder what happened with all the lore
links to previous versions.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v12 2/3] HID: cp2112: Fwnode Support
From: Andy Shevchenko @ 2025-11-26 21:23 UTC (permalink / raw)
To: Danny Kaehn
Cc: Rob Herring, Krzysztof Kozlowski, Benjamin Tissoires, Andi Shyti,
Conor Dooley, Jiri Kosina, devicetree, linux-input,
Dmitry Torokhov, Bartosz Golaszewski, Ethan Twardy, linux-i2c,
linux-kernel, Leo Huang, Arun D Patil, Willie Thai, Ting-Kai Chen
In-Reply-To: <20251126193251.GA269764@LNDCL34533.neenah.na.plexus.com>
On Wed, Nov 26, 2025 at 01:32:51PM -0600, Danny Kaehn wrote:
> On Wed, Nov 26, 2025 at 08:27:19PM +0200, Andy Shevchenko wrote:
> > On Wed, Nov 26, 2025 at 11:05:25AM -0600, Danny Kaehn wrote:
...
> > > For ACPI, the i2c_adapter will use the child with _ADR Zero and the
> > > gpio_chip will use the child with _ADR One. For DeviceTree, the
> > > i2c_adapter will use the child with name "i2c", but the gpio_chip
> > > will share a firmware node with the CP2112.
> >
> > Hmm... Is there any explanation why DT decided to go that way?
>
> I don't have an explanation, but Rob H. had directed that I make this
> change in [1].
>
> In v11, I then removed that child node for both ACPI and DT, hoping to
> maintain unity, but you had directed that wouldn't be intuitive for ACPI
> in [2].
>
> Thus, in this v12, I have just entirely split the two, as it seemed
> unlikely that any compromise to unify the schema between the two
> firmware languages would be possible for a change/driver this
> inconsquential to the overall kernel.
Even though, would be nice to try to get a rationale from Rob on this.
Then we can put it in the commit message to explain. Otherwise it will
confuse history diggers in the future.
> [1]:
> https://lore.kernel.org/all/20240213152825.GA1223720-robh@kernel.org/
>
> [2]:
> https://lore.kernel.org/all/ZmISaEIGlxZVK_jf@smile.fi.intel.com/
...
> > > + switch (addr) {
> > > + case CP2112_I2C_ADR:
> > > + device_set_node(&dev->adap.dev, child);
> > > + break;
> > > + case CP2112_GPIO_ADR:
> > > + dev->gc.fwnode = child;
> > > + break;
> >
> > If by any chance we have malformed table and there are more devices with
> > the same address? Maybe we don't need to address this right now, just
> > asking... (I believe ACPI compiler won't allow that, but table can be
> > crafted directly in the binary format.)
> >
>
> You're sugggesting perhaps that we explicitly keep track of which
> addresses have been encountered, and refuse to do any fwnode parsing
> if we detect the same address used twice? I believe the current behavior
> would be that the "last node wins"; not sure if it should be a "first node
> wins" or a full error scenario...
I'm suggesting to think about this, not acting right now. I don't believe in
such a case IRL.
> > > + }
...
> > > + device_set_node(&dev->adap.dev,
> > > + device_get_named_child_node(&hdev->dev, "i2c"));
> >
> > Here we bump the reference count, where is it going to be dropped?
> >
> > Note, in the other branch (ACPI) the reference count is not bumped in
> > the current code.
>
> Great point, forgot that I had dropped that handling in v9. The old
> behavior was that the CP2112 driver maintained a reference to each node
> during the lifetime of the device (and released during probe errors,
> etc..). I'm still a bit confused as to whether that is correct or not,
> or if the references should immediately be dropped once they're done
> being parsed during probe()... My understanding previously was that I
> should keep the reference count for the child fwnodes for the lifetime
> of the CP2112, since the pointers to those are stored in the child
> devices but would usually be managed by the parent bus-level code, does
> that seem correct?
While there is a (theoretical) possibility to have lifetime of fwnode shorter
than a device's, I don't think we have or ever will have such a practical
example. So, assumption is that, the fwnode that struct device holds has
the same or longer lifetime.
Note, I haven't investigated overlays (DT and ACPI) behaviour. IIRC you
experimented with ACPI SSDT on this device, perhaps you can try to see
what happens if there is a confirmed that the above is not only a theoretical
problem.
TL;DR: I would drop reference count just after we got a respective fwnode.
--
With Best Regards,
Andy Shevchenko
^ 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