* [PATCH v3 2/3] Documentation/ABI: Add sysfs documentation for TrackPoint doubletap
2025-09-01 13:53 [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support Vishnu Sankar
@ 2025-09-01 13:53 ` Vishnu Sankar
2025-09-01 13:53 ` [PATCH v3 3/3] platform/x86: thinkpad_acpi: Use trackpoint doubletap interface via sysfs Vishnu Sankar
` (2 subsequent siblings)
3 siblings, 0 replies; 9+ messages in thread
From: Vishnu Sankar @ 2025-09-01 13:53 UTC (permalink / raw)
To: dmitry.torokhov, hmh, hansg, ilpo.jarvinen, derekjohn.clark
Cc: mpearson-lenovo, linux-input, linux-kernel, ibm-acpi-devel,
platform-driver-x86, vsankar, Vishnu Sankar
Adding sysfs documentation for trackpoint doubletap.
Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
---
Changes in v3:
- Add sysfs documentation.
---
.../testing/sysfs-driver-trackpoint-doubletap | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-trackpoint-doubletap
diff --git a/Documentation/ABI/testing/sysfs-driver-trackpoint-doubletap b/Documentation/ABI/testing/sysfs-driver-trackpoint-doubletap
new file mode 100644
index 000000000000..d7cd63005523
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-trackpoint-doubletap
@@ -0,0 +1,17 @@
+What: /sys/bus/serio/devices/serioX/doubletap_enabled
+Date: Aug 2025
+KernelVersion: 6.17
+Contact: linux-input@vger.kernel.org, platform-driver-x86@vger.kernel.org
+Description:
+ A read/write attribute controlling TrackPoint doubletap.
+
+ Reading returns the current state:
+ 0 - disabled
+ 1 - enabled
+
+ Writing:
+ 0 - disable doubletap
+ 1 - enable doubletap
+
+ The attribute is only present if the TrackPoint firmware
+ supports doubletap functionality.
--
2.48.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/3] platform/x86: thinkpad_acpi: Use trackpoint doubletap interface via sysfs
2025-09-01 13:53 [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support Vishnu Sankar
2025-09-01 13:53 ` [PATCH v3 2/3] Documentation/ABI: Add sysfs documentation for TrackPoint doubletap Vishnu Sankar
@ 2025-09-01 13:53 ` Vishnu Sankar
2025-09-18 2:37 ` [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support Vishnu Sankar
2025-09-18 4:57 ` Dmitry Torokhov
3 siblings, 0 replies; 9+ messages in thread
From: Vishnu Sankar @ 2025-09-01 13:53 UTC (permalink / raw)
To: dmitry.torokhov, hmh, hansg, ilpo.jarvinen, derekjohn.clark
Cc: mpearson-lenovo, linux-input, linux-kernel, ibm-acpi-devel,
platform-driver-x86, vsankar, Vishnu Sankar
TrackPoint devices supporting doubletap expose a sysfs attribute under
/sys/devices/.../trackpoint/doubletap_enabled. This patch enables
thinkpad_acpi to detect if the system has a TrackPoint device with
doubletap capability, and allows toggling the feature via sysfs.
This avoids direct linking between subsystems and relies on sysfs
as the interface for coordination between input and platform drivers.
Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
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
---
drivers/platform/x86/lenovo/thinkpad_acpi.c | 155 +++++++++++++++++++-
1 file changed, 147 insertions(+), 8 deletions(-)
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
index cc19fe520ea9..f5070442a7ba 100644
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
@@ -72,6 +72,13 @@
#include <linux/units.h>
#include <linux/workqueue.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/err.h>
+#include <linux/fcntl.h>
+#include <linux/namei.h>
+#include <linux/kernel_read_file.h>
+
#include <acpi/battery.h>
#include <acpi/video.h>
@@ -373,7 +380,8 @@ static struct {
u32 hotkey_poll_active:1;
u32 has_adaptive_kbd:1;
u32 kbd_lang:1;
- u32 trackpoint_doubletap:1;
+ u32 trackpoint_doubletap_state:1;
+ u32 trackpoint_doubletap_capable:1;
struct quirk_entry *quirks;
} tp_features;
@@ -2879,6 +2887,107 @@ static DEVICE_ATTR_RW(hotkey_poll_freq);
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+/*
+ * Trackpoint doubletap handlers
+ * These set of functions will communicate with the sysfs attributes of TrackPoint driver
+ * Attribute : /sys/bus/serio/devices/seriox/doubletap_enabled
+ */
+
+/* Global buffer to reuse path */
+static char trackpoint_doubletap_path[128];
+
+/* Function to find the correct serio path with TrackPoint attribute "doubletap_enabled" */
+static int thinkpad_find_trackpoint_path(void)
+{
+ struct path serio_path;
+ char path_buf[128];
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ snprintf(path_buf, sizeof(path_buf),
+ "/sys/bus/serio/devices/serio%d/doubletap_enabled", i);
+
+ if (!kern_path(path_buf, LOOKUP_FOLLOW, &serio_path)) {
+ path_put(&serio_path);
+ snprintf(trackpoint_doubletap_path, sizeof(trackpoint_doubletap_path),
+ "%s", path_buf);
+ pr_info("ThinkPad ACPI: TrackPoint doubletap found at %s\n",
+ trackpoint_doubletap_path);
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+/* Writing to the sysfs attribute of Trackpoint "doubletap_enabled" */
+static int write_doubletap_sysfs_value(const void *buf, size_t count, loff_t *pos)
+{
+ struct file *filp;
+ ssize_t written;
+
+ if (!buf)
+ return -EINVAL;
+
+ filp = filp_open(trackpoint_doubletap_path, O_WRONLY | O_CREAT, 0644);
+ if (IS_ERR(filp))
+ return PTR_ERR(filp);
+
+ /* Required to avoid EINVAL from vfs checks in some cases */
+ if (!(filp->f_mode & FMODE_CAN_WRITE)) {
+ filp_close(filp, NULL);
+ return -EINVAL;
+ }
+
+ /* Write using kernel_write */
+ written = kernel_write(filp, buf, count, pos);
+ filp_close(filp, NULL);
+
+ return written < 0 ? written : 0;
+}
+
+/* Function to read the TrackPoint doubletap status */
+static int trackpoint_read_doubletap_status(bool *enabled)
+{
+ struct file *filp;
+ loff_t pos = 0;
+ char buf[8];
+ ssize_t ret;
+
+ if (!enabled)
+ return -EINVAL;
+
+ if (!trackpoint_doubletap_path[0])
+ return -ENODEV;
+
+ filp = filp_open(trackpoint_doubletap_path, O_RDONLY, 0);
+ if (IS_ERR(filp))
+ return PTR_ERR(filp);
+
+ ret = kernel_read(filp, buf, sizeof(buf) - 1, &pos);
+ filp_close(filp, NULL);
+
+ if (ret < 0)
+ return ret;
+
+ buf[ret] = '\0'; // Safe: ret < sizeof(buf)
+
+ *enabled = (buf[0] == '1');
+
+ return 0;
+}
+
+/* Function to check the TrackPoint doubletap status */
+static int thinkpad_set_doubletap_status(bool enable)
+{
+ const char *val = enable ? "1" : "0";
+ loff_t pos = 0;
+
+ if (!trackpoint_doubletap_path[0])
+ return -ENODEV;
+
+ return write_doubletap_sysfs_value(val, strlen(val), &pos);
+}
+
/* sysfs hotkey radio_sw (pollable) ------------------------------------ */
static ssize_t hotkey_radio_sw_show(struct device *dev,
struct device_attribute *attr,
@@ -3326,6 +3435,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
bool radiosw_state = false;
bool tabletsw_state = false;
int hkeyv, res, status, camera_shutter_state;
+ bool dt_state;
+ int rc;
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
"initializing hotkey subdriver\n");
@@ -3557,9 +3668,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;
+ /* Checking doubletap status by default */
+ rc = thinkpad_find_trackpoint_path();
+ if (rc) {
+ dev_dbg(&tpacpi_pdev->dev, "Could not find TrackPoint doubletap sysfs path\n");
+ tp_features.trackpoint_doubletap_capable = false;
+ return 0;
+ }
+ tp_features.trackpoint_doubletap_capable = true;
+ rc = trackpoint_read_doubletap_status(&dt_state);
+ if (rc) {
+ /* Disable if access to register fails */
+ dt_state = false;
+ dev_dbg(&tpacpi_pdev->dev, "Doubletap failed to check status\n");
+ }
+ tp_features.trackpoint_doubletap_state = dt_state;
return 0;
}
@@ -3863,9 +3987,7 @@ 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)
- tpacpi_input_send_key(hkey, send_acpi_ev);
-
+ *send_acpi_ev = true;
return true;
default:
return false;
@@ -11194,6 +11316,7 @@ static struct platform_driver tpacpi_hwmon_pdriver = {
static bool tpacpi_driver_event(const unsigned int hkey_event)
{
int camera_shutter_state;
+ int rc;
switch (hkey_event) {
case TP_HKEY_EV_BRGHT_UP:
@@ -11285,8 +11408,24 @@ 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;
- return true;
+ if (tp_features.trackpoint_doubletap_capable) {
+ rc = thinkpad_set_doubletap_status(!tp_features.trackpoint_doubletap_state);
+
+ if (rc) {
+ dev_dbg(&tpacpi_pdev->dev, "Trackpoint doubletap toggle failed\n");
+ } else {
+ tp_features.trackpoint_doubletap_state =
+ !tp_features.trackpoint_doubletap_state;
+ dev_dbg(&tpacpi_pdev->dev, "Trackpoint doubletap is %s\n",
+ tp_features.trackpoint_doubletap_state ? "enabled" : "disabled");
+ return true;
+ }
+ }
+ /*
+ * Suppress the event if Doubletap is not supported
+ * or if the trackpoint_set_doubletap_status() is failing
+ */
+ return false;
case TP_HKEY_EV_PROFILE_TOGGLE:
case TP_HKEY_EV_PROFILE_TOGGLE2:
platform_profile_cycle();
--
2.48.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support
2025-09-01 13:53 [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support Vishnu Sankar
2025-09-01 13:53 ` [PATCH v3 2/3] Documentation/ABI: Add sysfs documentation for TrackPoint doubletap Vishnu Sankar
2025-09-01 13:53 ` [PATCH v3 3/3] platform/x86: thinkpad_acpi: Use trackpoint doubletap interface via sysfs Vishnu Sankar
@ 2025-09-18 2:37 ` Vishnu Sankar
2025-09-18 7:31 ` Hans de Goede
2025-09-18 4:57 ` Dmitry Torokhov
3 siblings, 1 reply; 9+ messages in thread
From: Vishnu Sankar @ 2025-09-18 2:37 UTC (permalink / raw)
To: dmitry.torokhov, hmh, hansg, ilpo.jarvinen, derekjohn.clark
Cc: mpearson-lenovo, linux-input, linux-kernel, ibm-acpi-devel,
platform-driver-x86, vsankar
Hello all,
Do we have any questions or concerns?
Thanks in advance!
On Mon, Sep 1, 2025 at 10:53 PM Vishnu Sankar <vishnuocv@gmail.com> wrote:
>
> Add support for enabling and disabling doubletap on TrackPoint devices
> that support this functionality. The feature is detected using firmware
> ID and exposed via sysfs as `doubletap_enabled`.
>
> The feature is only available on newer ThinkPads (2023 and later).The driver
> exposes this capability via a new sysfs attribute:
> "/sys/bus/serio/devices/seriox/doubletap_enabled".
>
> The attribute is only created if the device is detected to be capable of
> doubletap via firmware and variant ID checks. This functionality will be
> used by platform drivers such as thinkpad_acpi to expose and control doubletap
> via user interfaces.
>
> Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
> 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.
> Changes in v3:
> - No changes.
> ---
> drivers/input/mouse/trackpoint.c | 149 +++++++++++++++++++++++++++++++
> drivers/input/mouse/trackpoint.h | 15 ++++
> 2 files changed, 164 insertions(+)
>
> diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> index 5f6643b69a2c..c6f17b0dec3a 100644
> --- a/drivers/input/mouse/trackpoint.c
> +++ b/drivers/input/mouse/trackpoint.c
> @@ -16,6 +16,8 @@
> #include "psmouse.h"
> #include "trackpoint.h"
>
> +static struct trackpoint_data *trackpoint_dev;
> +
> static const char * const trackpoint_variants[] = {
> [TP_VARIANT_IBM] = "IBM",
> [TP_VARIANT_ALPS] = "ALPS",
> @@ -63,6 +65,21 @@ static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
> return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
> }
>
> +/* Read function for TrackPoint extended registers */
> +static int trackpoint_extended_read(struct ps2dev *ps2dev, u8 loc, u8 *val)
> +{
> + u8 ext_param[2] = {TP_READ_MEM, loc};
> + int error;
> +
> + error = ps2_command(ps2dev,
> + ext_param, MAKE_PS2_CMD(2, 1, TP_COMMAND));
> +
> + if (!error)
> + *val = ext_param[0];
> +
> + return error;
> +}
> +
> static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
> {
> u8 param[3] = { TP_TOGGLE, loc, mask };
> @@ -393,6 +410,131 @@ 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 eg: is "PNP: LEN030d PNP0f13".
> + */
> +static bool is_trackpoint_dt_capable(const char *pnp_id)
> +{
> + const char *id_start;
> + char id[8];
> +
> + 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 blacklisted */
> + for (size_t i = 0; i < ARRAY_SIZE(dt_incompatible_devices); ++i) {
> + if (strcmp(id, dt_incompatible_devices[i]) == 0)
> + return false;
> + }
> + return true;
> +}
> +
> +/* Trackpoint doubletap status function */
> +static int trackpoint_doubletap_status(bool *status)
> +{
> + struct trackpoint_data *tp = trackpoint_dev;
> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> + u8 reg_val;
> + int rc;
> +
> + /* Reading the Doubletap register using extended read */
> + rc = trackpoint_extended_read(ps2dev, TP_DOUBLETAP, ®_val);
> + if (rc)
> + return rc;
> +
> + *status = reg_val & TP_DOUBLETAP_STATUS ? true : false;
> +
> + return 0;
> +}
> +
> +/* Trackpoint doubletap enable/disable function */
> +static int trackpoint_set_doubletap(bool enable)
> +{
> + struct trackpoint_data *tp = trackpoint_dev;
> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> + static u8 doubletap_state;
> + u8 new_val;
> +
> + if (!tp)
> + return -ENODEV;
> +
> + new_val = enable ? TP_DOUBLETAP_ENABLE : TP_DOUBLETAP_DISABLE;
> +
> + if (doubletap_state == new_val)
> + return 0;
> +
> + doubletap_state = new_val;
> +
> + return trackpoint_write(ps2dev, TP_DOUBLETAP, new_val);
> +}
> +
> +/*
> + * Trackpoint Doubletap Interface
> + * Control/Monitoring of Trackpoint Doubletap from:
> + * /sys/bus/serio/devices/seriox/doubletap_enabled
> + */
> +static ssize_t doubletap_enabled_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct serio *serio = to_serio_port(dev);
> + struct psmouse *psmouse = psmouse_from_serio(serio);
> + struct trackpoint_data *tp = psmouse->private;
> + bool status;
> + int rc;
> +
> + if (!tp || !tp->doubletap_capable)
> + return -ENODEV;
> +
> + rc = trackpoint_doubletap_status(&status);
> + if (rc)
> + return rc;
> +
> + return sysfs_emit(buf, "%d\n", status ? 1 : 0);
> +}
> +
> +static ssize_t doubletap_enabled_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct serio *serio = to_serio_port(dev);
> + struct psmouse *psmouse = psmouse_from_serio(serio);
> + struct trackpoint_data *tp = psmouse->private;
> + bool enable;
> + int err;
> +
> + if (!tp || !tp->doubletap_capable)
> + return -ENODEV;
> +
> + err = kstrtobool(buf, &enable);
> + if (err)
> + return err;
> +
> + err = trackpoint_set_doubletap(enable);
> + if (err)
> + return err;
> +
> + return count;
> +}
> +
> +static DEVICE_ATTR_RW(doubletap_enabled);
> +
> int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> {
> struct ps2dev *ps2dev = &psmouse->ps2dev;
> @@ -425,6 +567,9 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> psmouse->reconnect = trackpoint_reconnect;
> psmouse->disconnect = trackpoint_disconnect;
>
> + trackpoint_dev = psmouse->private;
> + trackpoint_dev->parent_psmouse = psmouse;
> +
> if (variant_id != TP_VARIANT_IBM) {
> /* Newer variants do not support extended button query. */
> button_info = 0x33;
> @@ -470,6 +615,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> psmouse->vendor, firmware_id,
> (button_info & 0xf0) >> 4, button_info & 0x0f);
>
> + tp->doubletap_capable = is_trackpoint_dt_capable(ps2dev->serio->firmware_id);
> + if (tp->doubletap_capable)
> + device_create_file(&psmouse->ps2dev.serio->dev, &dev_attr_doubletap_enabled);
> +
> return 0;
> }
>
> diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
> index eb5412904fe0..256e8cb35581 100644
> --- a/drivers/input/mouse/trackpoint.h
> +++ b/drivers/input/mouse/trackpoint.h
> @@ -8,6 +8,8 @@
> #ifndef _TRACKPOINT_H
> #define _TRACKPOINT_H
>
> +#include <linux/bitops.h>
> +
> /*
> * These constants are from the TrackPoint System
> * Engineering documentation Version 4 from IBM Watson
> @@ -69,6 +71,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 */
>
> @@ -139,6 +143,14 @@
> #define TP_DEF_TWOHAND 0x00
> #define TP_DEF_SOURCE_TAG 0x00
>
> +/* Doubletap register values */
> +#define TP_DOUBLETAP_ENABLE 0xFF /* Enable value */
> +#define TP_DOUBLETAP_DISABLE 0xFE /* Disable value */
> +
> +#define TP_DOUBLETAP_STATUS_BIT 0 /* 0th bit defines enable/disable */
> +
> +#define TP_DOUBLETAP_STATUS BIT(TP_DOUBLETAP_STATUS_BIT)
> +
> #define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
>
> struct trackpoint_data {
> @@ -150,11 +162,14 @@ struct trackpoint_data {
> u8 thresh, upthresh;
> u8 ztime, jenks;
> u8 drift_time;
> + bool doubletap_capable;
>
> /* toggles */
> bool press_to_select;
> bool skipback;
> bool ext_dev;
> +
> + struct psmouse *parent_psmouse;
> };
>
> int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
> --
> 2.48.1
>
--
Regards,
Vishnu Sankar
+817015150407 (Japan)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support
2025-09-18 2:37 ` [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support Vishnu Sankar
@ 2025-09-18 7:31 ` Hans de Goede
2025-09-19 1:12 ` Dmitry Torokhov
2025-09-24 4:55 ` Vishnu Sankar
0 siblings, 2 replies; 9+ messages in thread
From: Hans de Goede @ 2025-09-18 7:31 UTC (permalink / raw)
To: Vishnu Sankar, dmitry.torokhov, hmh, ilpo.jarvinen,
derekjohn.clark
Cc: mpearson-lenovo, linux-input, linux-kernel, ibm-acpi-devel,
platform-driver-x86, vsankar
Hi Vishnu,
On 18-Sep-25 4:37 AM, Vishnu Sankar wrote:
> Hello all,
>
> Do we have any questions or concerns?
> Thanks in advance!
>
> On Mon, Sep 1, 2025 at 10:53 PM Vishnu Sankar <vishnuocv@gmail.com> wrote:
>>
>> Add support for enabling and disabling doubletap on TrackPoint devices
>> that support this functionality. The feature is detected using firmware
>> ID and exposed via sysfs as `doubletap_enabled`.
Hmm, you seem to be using a firmware ID prefix match, combined with
a deny list of some firmware IDs with that prefix which do not support
this. How do we know this deny list is complete?
Also as Dmitry says you really should use the is_visible() callback
to not show the attribute at all on unsupported systems.
>> The feature is only available on newer ThinkPads (2023 and later).The driver
>> exposes this capability via a new sysfs attribute:
>> "/sys/bus/serio/devices/seriox/doubletap_enabled".
>>
>> The attribute is only created if the device is detected to be capable of
>> doubletap via firmware and variant ID checks. This functionality will be
>> used by platform drivers such as thinkpad_acpi to expose and control doubletap
>> via user interfaces.
Hmm, you refer to thinkpad_acpi as a possible consumer of this
functionality. But you only add a sysfs interface.
thinkpad_acpi will need some in kernel interface to use this.
Which brings me to my main question: thinkpad_acpi is the driver
receiving the doubletap events since these are send out-of-bound
and not through the ps/2 trackpoint protocol.
thinkpad_acpi already has the capability to filter out these doubletap
events and report nothing. Why is it necessary / better to disable
the doubletap at the trackpoint fw-level, rather then just filtering
it at the thinkpad_acpi level ?
I don't really see a big advantage in filtering these events at
the fw-level rather then in the kernel and we already have the
in kernel filtering.
Since this is highly ThinkPad specific it seems that the current
handling in thinkpad_acpi also logically is the best place to
handle this.
What new use-cases if any does this enable?
If you e.g. want some Lenovo specific control-panel GUI to
enable/disable this, why not expose the existing filtering
in thinkpad_acpi (which is hotkey controller only atm)
in sysfs through thinkpad_acpi ?
If we go the route of using the trackpoint fw-level filtering
as is done in this patch, then IMHO we really also should
make the existing code in thinkpad_acpi:
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)
tpacpi_input_send_key(hkey, send_acpi_ev);
return true;
default:
return false;
}
}
static bool tpacpi_driver_event(const unsigned int hkey_event)
{
...
case TP_HKEY_EV_DOUBLETAP_TOGGLE:
tp_features.trackpoint_doubletap = !tp_features.trackpoint_doubletap;
return true;
...
}
Also use the fw-level filtering rather then having 2 different
filters/enable-flags active with events only coming through if
both let them through.
But making the thinkpad_acpi code use the fw-level filtering
will require some sort of in kernel API for this which is
going to be tricky since these are 2 completely different
subsystems ...
So to me it seems KISS to just stick with the existing thinkpad_acpi
level filtering.
TL;DR:
- What use-cases does this new code enable ?
- Why can't those use-cases be implemented with
the thinkpad_acpi level filtering?
Regards,
Hans
>>
>> Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
>> Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
>> Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>> ---
>> 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.
>> Changes in v3:
>> - No changes.
>> ---
>> drivers/input/mouse/trackpoint.c | 149 +++++++++++++++++++++++++++++++
>> drivers/input/mouse/trackpoint.h | 15 ++++
>> 2 files changed, 164 insertions(+)
>>
>> diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
>> index 5f6643b69a2c..c6f17b0dec3a 100644
>> --- a/drivers/input/mouse/trackpoint.c
>> +++ b/drivers/input/mouse/trackpoint.c
>> @@ -16,6 +16,8 @@
>> #include "psmouse.h"
>> #include "trackpoint.h"
>>
>> +static struct trackpoint_data *trackpoint_dev;
>> +
>> static const char * const trackpoint_variants[] = {
>> [TP_VARIANT_IBM] = "IBM",
>> [TP_VARIANT_ALPS] = "ALPS",
>> @@ -63,6 +65,21 @@ static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
>> return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
>> }
>>
>> +/* Read function for TrackPoint extended registers */
>> +static int trackpoint_extended_read(struct ps2dev *ps2dev, u8 loc, u8 *val)
>> +{
>> + u8 ext_param[2] = {TP_READ_MEM, loc};
>> + int error;
>> +
>> + error = ps2_command(ps2dev,
>> + ext_param, MAKE_PS2_CMD(2, 1, TP_COMMAND));
>> +
>> + if (!error)
>> + *val = ext_param[0];
>> +
>> + return error;
>> +}
>> +
>> static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
>> {
>> u8 param[3] = { TP_TOGGLE, loc, mask };
>> @@ -393,6 +410,131 @@ 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 eg: is "PNP: LEN030d PNP0f13".
>> + */
>> +static bool is_trackpoint_dt_capable(const char *pnp_id)
>> +{
>> + const char *id_start;
>> + char id[8];
>> +
>> + 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 blacklisted */
>> + for (size_t i = 0; i < ARRAY_SIZE(dt_incompatible_devices); ++i) {
>> + if (strcmp(id, dt_incompatible_devices[i]) == 0)
>> + return false;
>> + }
>> + return true;
>> +}
>> +
>> +/* Trackpoint doubletap status function */
>> +static int trackpoint_doubletap_status(bool *status)
>> +{
>> + struct trackpoint_data *tp = trackpoint_dev;
>> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
>> + u8 reg_val;
>> + int rc;
>> +
>> + /* Reading the Doubletap register using extended read */
>> + rc = trackpoint_extended_read(ps2dev, TP_DOUBLETAP, ®_val);
>> + if (rc)
>> + return rc;
>> +
>> + *status = reg_val & TP_DOUBLETAP_STATUS ? true : false;
>> +
>> + return 0;
>> +}
>> +
>> +/* Trackpoint doubletap enable/disable function */
>> +static int trackpoint_set_doubletap(bool enable)
>> +{
>> + struct trackpoint_data *tp = trackpoint_dev;
>> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
>> + static u8 doubletap_state;
>> + u8 new_val;
>> +
>> + if (!tp)
>> + return -ENODEV;
>> +
>> + new_val = enable ? TP_DOUBLETAP_ENABLE : TP_DOUBLETAP_DISABLE;
>> +
>> + if (doubletap_state == new_val)
>> + return 0;
>> +
>> + doubletap_state = new_val;
>> +
>> + return trackpoint_write(ps2dev, TP_DOUBLETAP, new_val);
>> +}
>> +
>> +/*
>> + * Trackpoint Doubletap Interface
>> + * Control/Monitoring of Trackpoint Doubletap from:
>> + * /sys/bus/serio/devices/seriox/doubletap_enabled
>> + */
>> +static ssize_t doubletap_enabled_show(struct device *dev,
>> + struct device_attribute *attr, char *buf)
>> +{
>> + struct serio *serio = to_serio_port(dev);
>> + struct psmouse *psmouse = psmouse_from_serio(serio);
>> + struct trackpoint_data *tp = psmouse->private;
>> + bool status;
>> + int rc;
>> +
>> + if (!tp || !tp->doubletap_capable)
>> + return -ENODEV;
>> +
>> + rc = trackpoint_doubletap_status(&status);
>> + if (rc)
>> + return rc;
>> +
>> + return sysfs_emit(buf, "%d\n", status ? 1 : 0);
>> +}
>> +
>> +static ssize_t doubletap_enabled_store(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> + struct serio *serio = to_serio_port(dev);
>> + struct psmouse *psmouse = psmouse_from_serio(serio);
>> + struct trackpoint_data *tp = psmouse->private;
>> + bool enable;
>> + int err;
>> +
>> + if (!tp || !tp->doubletap_capable)
>> + return -ENODEV;
>> +
>> + err = kstrtobool(buf, &enable);
>> + if (err)
>> + return err;
>> +
>> + err = trackpoint_set_doubletap(enable);
>> + if (err)
>> + return err;
>> +
>> + return count;
>> +}
>> +
>> +static DEVICE_ATTR_RW(doubletap_enabled);
>> +
>> int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
>> {
>> struct ps2dev *ps2dev = &psmouse->ps2dev;
>> @@ -425,6 +567,9 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
>> psmouse->reconnect = trackpoint_reconnect;
>> psmouse->disconnect = trackpoint_disconnect;
>>
>> + trackpoint_dev = psmouse->private;
>> + trackpoint_dev->parent_psmouse = psmouse;
>> +
>> if (variant_id != TP_VARIANT_IBM) {
>> /* Newer variants do not support extended button query. */
>> button_info = 0x33;
>> @@ -470,6 +615,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
>> psmouse->vendor, firmware_id,
>> (button_info & 0xf0) >> 4, button_info & 0x0f);
>>
>> + tp->doubletap_capable = is_trackpoint_dt_capable(ps2dev->serio->firmware_id);
>> + if (tp->doubletap_capable)
>> + device_create_file(&psmouse->ps2dev.serio->dev, &dev_attr_doubletap_enabled);
>> +
>> return 0;
>> }
>>
>> diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
>> index eb5412904fe0..256e8cb35581 100644
>> --- a/drivers/input/mouse/trackpoint.h
>> +++ b/drivers/input/mouse/trackpoint.h
>> @@ -8,6 +8,8 @@
>> #ifndef _TRACKPOINT_H
>> #define _TRACKPOINT_H
>>
>> +#include <linux/bitops.h>
>> +
>> /*
>> * These constants are from the TrackPoint System
>> * Engineering documentation Version 4 from IBM Watson
>> @@ -69,6 +71,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 */
>>
>> @@ -139,6 +143,14 @@
>> #define TP_DEF_TWOHAND 0x00
>> #define TP_DEF_SOURCE_TAG 0x00
>>
>> +/* Doubletap register values */
>> +#define TP_DOUBLETAP_ENABLE 0xFF /* Enable value */
>> +#define TP_DOUBLETAP_DISABLE 0xFE /* Disable value */
>> +
>> +#define TP_DOUBLETAP_STATUS_BIT 0 /* 0th bit defines enable/disable */
>> +
>> +#define TP_DOUBLETAP_STATUS BIT(TP_DOUBLETAP_STATUS_BIT)
>> +
>> #define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
>>
>> struct trackpoint_data {
>> @@ -150,11 +162,14 @@ struct trackpoint_data {
>> u8 thresh, upthresh;
>> u8 ztime, jenks;
>> u8 drift_time;
>> + bool doubletap_capable;
>>
>> /* toggles */
>> bool press_to_select;
>> bool skipback;
>> bool ext_dev;
>> +
>> + struct psmouse *parent_psmouse;
>> };
>>
>> int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
>> --
>> 2.48.1
>>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support
2025-09-18 7:31 ` Hans de Goede
@ 2025-09-19 1:12 ` Dmitry Torokhov
2025-09-24 4:55 ` Vishnu Sankar
1 sibling, 0 replies; 9+ messages in thread
From: Dmitry Torokhov @ 2025-09-19 1:12 UTC (permalink / raw)
To: Hans de Goede
Cc: Vishnu Sankar, hmh, ilpo.jarvinen, derekjohn.clark,
mpearson-lenovo, linux-input, linux-kernel, ibm-acpi-devel,
platform-driver-x86, vsankar
On Thu, Sep 18, 2025 at 09:31:47AM +0200, Hans de Goede wrote:
> Hi Vishnu,
>
> On 18-Sep-25 4:37 AM, Vishnu Sankar wrote:
> > Hello all,
> >
> > Do we have any questions or concerns?
> > Thanks in advance!
> >
> > On Mon, Sep 1, 2025 at 10:53 PM Vishnu Sankar <vishnuocv@gmail.com> wrote:
> >>
> >> Add support for enabling and disabling doubletap on TrackPoint devices
> >> that support this functionality. The feature is detected using firmware
> >> ID and exposed via sysfs as `doubletap_enabled`.
>
> Hmm, you seem to be using a firmware ID prefix match, combined with
> a deny list of some firmware IDs with that prefix which do not support
> this. How do we know this deny list is complete?
>
> Also as Dmitry says you really should use the is_visible() callback
> to not show the attribute at all on unsupported systems.
>
> >> The feature is only available on newer ThinkPads (2023 and later).The driver
> >> exposes this capability via a new sysfs attribute:
> >> "/sys/bus/serio/devices/seriox/doubletap_enabled".
> >>
> >> The attribute is only created if the device is detected to be capable of
> >> doubletap via firmware and variant ID checks. This functionality will be
> >> used by platform drivers such as thinkpad_acpi to expose and control doubletap
> >> via user interfaces.
>
> Hmm, you refer to thinkpad_acpi as a possible consumer of this
> functionality. But you only add a sysfs interface.
>
> thinkpad_acpi will need some in kernel interface to use this.
>
> Which brings me to my main question: thinkpad_acpi is the driver
> receiving the doubletap events since these are send out-of-bound
> and not through the ps/2 trackpoint protocol.
>
> thinkpad_acpi already has the capability to filter out these doubletap
> events and report nothing. Why is it necessary / better to disable
> the doubletap at the trackpoint fw-level, rather then just filtering
> it at the thinkpad_acpi level ?
>
> I don't really see a big advantage in filtering these events at
> the fw-level rather then in the kernel and we already have the
> in kernel filtering.
That is an excellent observation, thank you Hans. The frequency of these
events should be extremely low, so cost of simply ignoring events should
be miniscule...
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support
2025-09-18 7:31 ` Hans de Goede
2025-09-19 1:12 ` Dmitry Torokhov
@ 2025-09-24 4:55 ` Vishnu Sankar
1 sibling, 0 replies; 9+ messages in thread
From: Vishnu Sankar @ 2025-09-24 4:55 UTC (permalink / raw)
To: Hans de Goede
Cc: dmitry.torokhov, hmh, ilpo.jarvinen, derekjohn.clark,
mpearson-lenovo, linux-input, linux-kernel, ibm-acpi-devel,
platform-driver-x86, vsankar
Hi Hans,
Thank you so much for your review.
Sorry for the delay in response.
On Thu, Sep 18, 2025 at 4:31 PM Hans de Goede <hansg@kernel.org> wrote:
>
> Hi Vishnu,
>
> On 18-Sep-25 4:37 AM, Vishnu Sankar wrote:
> > Hello all,
> >
> > Do we have any questions or concerns?
> > Thanks in advance!
> >
> > On Mon, Sep 1, 2025 at 10:53 PM Vishnu Sankar <vishnuocv@gmail.com> wrote:
> >>
> >> Add support for enabling and disabling doubletap on TrackPoint devices
> >> that support this functionality. The feature is detected using firmware
> >> ID and exposed via sysfs as `doubletap_enabled`.
>
> Hmm, you seem to be using a firmware ID prefix match, combined with
> a deny list of some firmware IDs with that prefix which do not support
> this. How do we know this deny list is complete?
We confirmed with the Lenovo product team, and this is what they
recommended using. Internal Documentation has listed these as the only
ID's that don't have double-tap support. And the trackpoint CO
confirmed that all future trackpoints will support the double-tap
feature.
>
> Also as Dmitry says you really should use the is_visible() callback
> to not show the attribute at all on unsupported systems.
Understood.
>
> >> The feature is only available on newer ThinkPads (2023 and later).The driver
> >> exposes this capability via a new sysfs attribute:
> >> "/sys/bus/serio/devices/seriox/doubletap_enabled".
> >>
> >> The attribute is only created if the device is detected to be capable of
> >> doubletap via firmware and variant ID checks. This functionality will be
> >> used by platform drivers such as thinkpad_acpi to expose and control doubletap
> >> via user interfaces.
>
> Hmm, you refer to thinkpad_acpi as a possible consumer of this
> functionality. But you only add a sysfs interface.
>
> thinkpad_acpi will need some in kernel interface to use this.
>
This was what I understood from the review of v1 of the patch, to just
use sysfs in thinkpad_acpi.
I'm sorry if my understanding was incorrect.
> Which brings me to my main question: thinkpad_acpi is the driver
> receiving the doubletap events since these are send out-of-bound
> and not through the ps/2 trackpoint protocol.
>
> thinkpad_acpi already has the capability to filter out these doubletap
> events and report nothing. Why is it necessary / better to disable
> the doubletap at the trackpoint fw-level, rather then just filtering
> it at the thinkpad_acpi level ?
On Windows, Lenovo’s driver toggles the firmware register (fn + G)
rather than just filtering in software. We thought that exposing the
same mechanism in Linux ensures consistent behavior across operating
systems.
>
> I don't really see a big advantage in filtering these events at
> the fw-level rather then in the kernel and we already have the
> in kernel filtering.
understood
>
> Since this is highly ThinkPad specific it seems that the current
> handling in thinkpad_acpi also logically is the best place to
> handle this.
Originally, when this feature was provided, it was enabled by default,
so nothing extra was needed to use it.
With new ThinkPads, it is disabled by default, and we need to change
the setting in the trackpoint registers.
In doing this, we thought it was better to make this enable/disable
use the register (Similar to Windows), but we understood that we can
just enable it and handle the masking/unmasking in thinkpad_acpi. This
will make it easier and not require communication between the drivers.
>
> What new use-cases if any does this enable?
Allows users to use the trackpoint doubletap as an input for whatever
they want. It's an HW feature, and we're trying to make sure Linux
users can access the same features that Windows (Quick launch) has.
>
> If you e.g. want some Lenovo specific control-panel GUI to
> enable/disable this, why not expose the existing filtering
> in thinkpad_acpi (which is hotkey controller only atm)
> in sysfs through thinkpad_acpi ?
>
No, we just want it to be enabled and usable by default for now.
The register needs to be set for the hotkey enable/disable to work.
> If we go the route of using the trackpoint fw-level filtering
> as is done in this patch, then IMHO we really also should
> make the existing code in thinkpad_acpi:
>
> 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)
> tpacpi_input_send_key(hkey, send_acpi_ev);
>
> return true;
> default:
> return false;
> }
> }
>
> static bool tpacpi_driver_event(const unsigned int hkey_event)
> {
> ...
> case TP_HKEY_EV_DOUBLETAP_TOGGLE:
> tp_features.trackpoint_doubletap = !tp_features.trackpoint_doubletap;
> return true;
> ...
> }
>
> Also use the fw-level filtering rather then having 2 different
> filters/enable-flags active with events only coming through if
> both let them through.
>
> But making the thinkpad_acpi code use the fw-level filtering
> will require some sort of in kernel API for this which is
> going to be tricky since these are 2 completely different
> subsystems ...
>
> So to me it seems KISS to just stick with the existing thinkpad_acpi
> level filtering.
Understood.
>
> TL;DR:
> - What use-cases does this new code enable ?
Enables the trackpoint doubletap so it works by default.
> - Why can't those use-cases be implemented with
> the thinkpad_acpi level filtering?
As mentioned earlier, this feature is off by default.
It needs to be enabled before we get the enable/disable hotkeys.
>
>
> Regards,
>
> Hans
>
>
>
>
>
>
> >>
> >> Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> >> Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> >> Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> >> ---
> >> 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.
> >> Changes in v3:
> >> - No changes.
> >> ---
> >> drivers/input/mouse/trackpoint.c | 149 +++++++++++++++++++++++++++++++
> >> drivers/input/mouse/trackpoint.h | 15 ++++
> >> 2 files changed, 164 insertions(+)
> >>
> >> diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> >> index 5f6643b69a2c..c6f17b0dec3a 100644
> >> --- a/drivers/input/mouse/trackpoint.c
> >> +++ b/drivers/input/mouse/trackpoint.c
> >> @@ -16,6 +16,8 @@
> >> #include "psmouse.h"
> >> #include "trackpoint.h"
> >>
> >> +static struct trackpoint_data *trackpoint_dev;
> >> +
> >> static const char * const trackpoint_variants[] = {
> >> [TP_VARIANT_IBM] = "IBM",
> >> [TP_VARIANT_ALPS] = "ALPS",
> >> @@ -63,6 +65,21 @@ static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
> >> return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
> >> }
> >>
> >> +/* Read function for TrackPoint extended registers */
> >> +static int trackpoint_extended_read(struct ps2dev *ps2dev, u8 loc, u8 *val)
> >> +{
> >> + u8 ext_param[2] = {TP_READ_MEM, loc};
> >> + int error;
> >> +
> >> + error = ps2_command(ps2dev,
> >> + ext_param, MAKE_PS2_CMD(2, 1, TP_COMMAND));
> >> +
> >> + if (!error)
> >> + *val = ext_param[0];
> >> +
> >> + return error;
> >> +}
> >> +
> >> static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
> >> {
> >> u8 param[3] = { TP_TOGGLE, loc, mask };
> >> @@ -393,6 +410,131 @@ 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 eg: is "PNP: LEN030d PNP0f13".
> >> + */
> >> +static bool is_trackpoint_dt_capable(const char *pnp_id)
> >> +{
> >> + const char *id_start;
> >> + char id[8];
> >> +
> >> + 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 blacklisted */
> >> + for (size_t i = 0; i < ARRAY_SIZE(dt_incompatible_devices); ++i) {
> >> + if (strcmp(id, dt_incompatible_devices[i]) == 0)
> >> + return false;
> >> + }
> >> + return true;
> >> +}
> >> +
> >> +/* Trackpoint doubletap status function */
> >> +static int trackpoint_doubletap_status(bool *status)
> >> +{
> >> + struct trackpoint_data *tp = trackpoint_dev;
> >> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> >> + u8 reg_val;
> >> + int rc;
> >> +
> >> + /* Reading the Doubletap register using extended read */
> >> + rc = trackpoint_extended_read(ps2dev, TP_DOUBLETAP, ®_val);
> >> + if (rc)
> >> + return rc;
> >> +
> >> + *status = reg_val & TP_DOUBLETAP_STATUS ? true : false;
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +/* Trackpoint doubletap enable/disable function */
> >> +static int trackpoint_set_doubletap(bool enable)
> >> +{
> >> + struct trackpoint_data *tp = trackpoint_dev;
> >> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> >> + static u8 doubletap_state;
> >> + u8 new_val;
> >> +
> >> + if (!tp)
> >> + return -ENODEV;
> >> +
> >> + new_val = enable ? TP_DOUBLETAP_ENABLE : TP_DOUBLETAP_DISABLE;
> >> +
> >> + if (doubletap_state == new_val)
> >> + return 0;
> >> +
> >> + doubletap_state = new_val;
> >> +
> >> + return trackpoint_write(ps2dev, TP_DOUBLETAP, new_val);
> >> +}
> >> +
> >> +/*
> >> + * Trackpoint Doubletap Interface
> >> + * Control/Monitoring of Trackpoint Doubletap from:
> >> + * /sys/bus/serio/devices/seriox/doubletap_enabled
> >> + */
> >> +static ssize_t doubletap_enabled_show(struct device *dev,
> >> + struct device_attribute *attr, char *buf)
> >> +{
> >> + struct serio *serio = to_serio_port(dev);
> >> + struct psmouse *psmouse = psmouse_from_serio(serio);
> >> + struct trackpoint_data *tp = psmouse->private;
> >> + bool status;
> >> + int rc;
> >> +
> >> + if (!tp || !tp->doubletap_capable)
> >> + return -ENODEV;
> >> +
> >> + rc = trackpoint_doubletap_status(&status);
> >> + if (rc)
> >> + return rc;
> >> +
> >> + return sysfs_emit(buf, "%d\n", status ? 1 : 0);
> >> +}
> >> +
> >> +static ssize_t doubletap_enabled_store(struct device *dev,
> >> + struct device_attribute *attr,
> >> + const char *buf, size_t count)
> >> +{
> >> + struct serio *serio = to_serio_port(dev);
> >> + struct psmouse *psmouse = psmouse_from_serio(serio);
> >> + struct trackpoint_data *tp = psmouse->private;
> >> + bool enable;
> >> + int err;
> >> +
> >> + if (!tp || !tp->doubletap_capable)
> >> + return -ENODEV;
> >> +
> >> + err = kstrtobool(buf, &enable);
> >> + if (err)
> >> + return err;
> >> +
> >> + err = trackpoint_set_doubletap(enable);
> >> + if (err)
> >> + return err;
> >> +
> >> + return count;
> >> +}
> >> +
> >> +static DEVICE_ATTR_RW(doubletap_enabled);
> >> +
> >> int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> >> {
> >> struct ps2dev *ps2dev = &psmouse->ps2dev;
> >> @@ -425,6 +567,9 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> >> psmouse->reconnect = trackpoint_reconnect;
> >> psmouse->disconnect = trackpoint_disconnect;
> >>
> >> + trackpoint_dev = psmouse->private;
> >> + trackpoint_dev->parent_psmouse = psmouse;
> >> +
> >> if (variant_id != TP_VARIANT_IBM) {
> >> /* Newer variants do not support extended button query. */
> >> button_info = 0x33;
> >> @@ -470,6 +615,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> >> psmouse->vendor, firmware_id,
> >> (button_info & 0xf0) >> 4, button_info & 0x0f);
> >>
> >> + tp->doubletap_capable = is_trackpoint_dt_capable(ps2dev->serio->firmware_id);
> >> + if (tp->doubletap_capable)
> >> + device_create_file(&psmouse->ps2dev.serio->dev, &dev_attr_doubletap_enabled);
> >> +
> >> return 0;
> >> }
> >>
> >> diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
> >> index eb5412904fe0..256e8cb35581 100644
> >> --- a/drivers/input/mouse/trackpoint.h
> >> +++ b/drivers/input/mouse/trackpoint.h
> >> @@ -8,6 +8,8 @@
> >> #ifndef _TRACKPOINT_H
> >> #define _TRACKPOINT_H
> >>
> >> +#include <linux/bitops.h>
> >> +
> >> /*
> >> * These constants are from the TrackPoint System
> >> * Engineering documentation Version 4 from IBM Watson
> >> @@ -69,6 +71,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 */
> >>
> >> @@ -139,6 +143,14 @@
> >> #define TP_DEF_TWOHAND 0x00
> >> #define TP_DEF_SOURCE_TAG 0x00
> >>
> >> +/* Doubletap register values */
> >> +#define TP_DOUBLETAP_ENABLE 0xFF /* Enable value */
> >> +#define TP_DOUBLETAP_DISABLE 0xFE /* Disable value */
> >> +
> >> +#define TP_DOUBLETAP_STATUS_BIT 0 /* 0th bit defines enable/disable */
> >> +
> >> +#define TP_DOUBLETAP_STATUS BIT(TP_DOUBLETAP_STATUS_BIT)
> >> +
> >> #define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
> >>
> >> struct trackpoint_data {
> >> @@ -150,11 +162,14 @@ struct trackpoint_data {
> >> u8 thresh, upthresh;
> >> u8 ztime, jenks;
> >> u8 drift_time;
> >> + bool doubletap_capable;
> >>
> >> /* toggles */
> >> bool press_to_select;
> >> bool skipback;
> >> bool ext_dev;
> >> +
> >> + struct psmouse *parent_psmouse;
> >> };
> >>
> >> int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
> >> --
> >> 2.48.1
> >>
> >
> >
>
--
Regards,
Vishnu Sankar
+817015150407 (Japan)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support
2025-09-01 13:53 [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support Vishnu Sankar
` (2 preceding siblings ...)
2025-09-18 2:37 ` [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support Vishnu Sankar
@ 2025-09-18 4:57 ` Dmitry Torokhov
2025-09-22 4:14 ` Vishnu Sankar
3 siblings, 1 reply; 9+ messages in thread
From: Dmitry Torokhov @ 2025-09-18 4:57 UTC (permalink / raw)
To: Vishnu Sankar
Cc: hmh, hansg, ilpo.jarvinen, derekjohn.clark, mpearson-lenovo,
linux-input, linux-kernel, ibm-acpi-devel, platform-driver-x86,
vsankar
Hi Vishnu,
On Mon, Sep 01, 2025 at 10:53:05PM +0900, Vishnu Sankar wrote:
> Add support for enabling and disabling doubletap on TrackPoint devices
> that support this functionality. The feature is detected using firmware
> ID and exposed via sysfs as `doubletap_enabled`.
>
> The feature is only available on newer ThinkPads (2023 and later).The driver
> exposes this capability via a new sysfs attribute:
> "/sys/bus/serio/devices/seriox/doubletap_enabled".
>
> The attribute is only created if the device is detected to be capable of
> doubletap via firmware and variant ID checks. This functionality will be
> used by platform drivers such as thinkpad_acpi to expose and control doubletap
> via user interfaces.
>
> Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
> 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.
> Changes in v3:
> - No changes.
> ---
> drivers/input/mouse/trackpoint.c | 149 +++++++++++++++++++++++++++++++
> drivers/input/mouse/trackpoint.h | 15 ++++
> 2 files changed, 164 insertions(+)
>
> diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> index 5f6643b69a2c..c6f17b0dec3a 100644
> --- a/drivers/input/mouse/trackpoint.c
> +++ b/drivers/input/mouse/trackpoint.c
> @@ -16,6 +16,8 @@
> #include "psmouse.h"
> #include "trackpoint.h"
>
> +static struct trackpoint_data *trackpoint_dev;
Please do not use globals.
> +
> static const char * const trackpoint_variants[] = {
> [TP_VARIANT_IBM] = "IBM",
> [TP_VARIANT_ALPS] = "ALPS",
> @@ -63,6 +65,21 @@ static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
> return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
> }
>
> +/* Read function for TrackPoint extended registers */
> +static int trackpoint_extended_read(struct ps2dev *ps2dev, u8 loc, u8 *val)
> +{
> + u8 ext_param[2] = {TP_READ_MEM, loc};
> + int error;
> +
> + error = ps2_command(ps2dev,
> + ext_param, MAKE_PS2_CMD(2, 1, TP_COMMAND));
> +
> + if (!error)
> + *val = ext_param[0];
> +
> + return error;
> +}
> +
> static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
> {
> u8 param[3] = { TP_TOGGLE, loc, mask };
> @@ -393,6 +410,131 @@ 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 eg: is "PNP: LEN030d PNP0f13".
> + */
> +static bool is_trackpoint_dt_capable(const char *pnp_id)
> +{
> + const char *id_start;
> + char id[8];
> +
> + 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 blacklisted */
> + for (size_t i = 0; i < ARRAY_SIZE(dt_incompatible_devices); ++i) {
> + if (strcmp(id, dt_incompatible_devices[i]) == 0)
> + return false;
> + }
> + return true;
> +}
> +
> +/* Trackpoint doubletap status function */
> +static int trackpoint_doubletap_status(bool *status)
> +{
> + struct trackpoint_data *tp = trackpoint_dev;
> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> + u8 reg_val;
> + int rc;
> +
> + /* Reading the Doubletap register using extended read */
> + rc = trackpoint_extended_read(ps2dev, TP_DOUBLETAP, ®_val);
> + if (rc)
> + return rc;
> +
> + *status = reg_val & TP_DOUBLETAP_STATUS ? true : false;
> +
> + return 0;
> +}
> +
> +/* Trackpoint doubletap enable/disable function */
> +static int trackpoint_set_doubletap(bool enable)
> +{
> + struct trackpoint_data *tp = trackpoint_dev;
> + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> + static u8 doubletap_state;
> + u8 new_val;
> +
> + if (!tp)
> + return -ENODEV;
> +
> + new_val = enable ? TP_DOUBLETAP_ENABLE : TP_DOUBLETAP_DISABLE;
> +
> + if (doubletap_state == new_val)
> + return 0;
> +
> + doubletap_state = new_val;
> +
> + return trackpoint_write(ps2dev, TP_DOUBLETAP, new_val);
> +}
> +
> +/*
> + * Trackpoint Doubletap Interface
> + * Control/Monitoring of Trackpoint Doubletap from:
> + * /sys/bus/serio/devices/seriox/doubletap_enabled
> + */
> +static ssize_t doubletap_enabled_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct serio *serio = to_serio_port(dev);
> + struct psmouse *psmouse = psmouse_from_serio(serio);
> + struct trackpoint_data *tp = psmouse->private;
> + bool status;
> + int rc;
> +
> + if (!tp || !tp->doubletap_capable)
> + return -ENODEV;
> +
> + rc = trackpoint_doubletap_status(&status);
> + if (rc)
> + return rc;
> +
> + return sysfs_emit(buf, "%d\n", status ? 1 : 0);
> +}
> +
> +static ssize_t doubletap_enabled_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct serio *serio = to_serio_port(dev);
> + struct psmouse *psmouse = psmouse_from_serio(serio);
> + struct trackpoint_data *tp = psmouse->private;
> + bool enable;
> + int err;
> +
> + if (!tp || !tp->doubletap_capable)
> + return -ENODEV;
> +
> + err = kstrtobool(buf, &enable);
> + if (err)
> + return err;
> +
> + err = trackpoint_set_doubletap(enable);
> + if (err)
> + return err;
> +
> + return count;
> +}
> +
> +static DEVICE_ATTR_RW(doubletap_enabled);
> +
> int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> {
> struct ps2dev *ps2dev = &psmouse->ps2dev;
> @@ -425,6 +567,9 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> psmouse->reconnect = trackpoint_reconnect;
> psmouse->disconnect = trackpoint_disconnect;
>
> + trackpoint_dev = psmouse->private;
> + trackpoint_dev->parent_psmouse = psmouse;
> +
> if (variant_id != TP_VARIANT_IBM) {
> /* Newer variants do not support extended button query. */
> button_info = 0x33;
> @@ -470,6 +615,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> psmouse->vendor, firmware_id,
> (button_info & 0xf0) >> 4, button_info & 0x0f);
>
> + tp->doubletap_capable = is_trackpoint_dt_capable(ps2dev->serio->firmware_id);
> + if (tp->doubletap_capable)
> + device_create_file(&psmouse->ps2dev.serio->dev, &dev_attr_doubletap_enabled);
Please use existing facilities in psmouse driver to define and register
protocol-specific attributes. Use is_visible() to control whether the
attribute is accessible or not.
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] input: mouse: trackpoint: Add doubletap enable/disable support
2025-09-18 4:57 ` Dmitry Torokhov
@ 2025-09-22 4:14 ` Vishnu Sankar
0 siblings, 0 replies; 9+ messages in thread
From: Vishnu Sankar @ 2025-09-22 4:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: hmh, hansg, ilpo.jarvinen, derekjohn.clark, mpearson-lenovo,
linux-input, linux-kernel, ibm-acpi-devel, platform-driver-x86,
vsankar
Hi Dimitry,
Thanks a lot for the comments.
On Thu, Sep 18, 2025 at 1:57 PM Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
> Hi Vishnu,
>
> On Mon, Sep 01, 2025 at 10:53:05PM +0900, Vishnu Sankar wrote:
> > Add support for enabling and disabling doubletap on TrackPoint devices
> > that support this functionality. The feature is detected using firmware
> > ID and exposed via sysfs as `doubletap_enabled`.
> >
> > The feature is only available on newer ThinkPads (2023 and later).The driver
> > exposes this capability via a new sysfs attribute:
> > "/sys/bus/serio/devices/seriox/doubletap_enabled".
> >
> > The attribute is only created if the device is detected to be capable of
> > doubletap via firmware and variant ID checks. This functionality will be
> > used by platform drivers such as thinkpad_acpi to expose and control doubletap
> > via user interfaces.
> >
> > Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> > Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> > Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > ---
> > 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.
> > Changes in v3:
> > - No changes.
> > ---
> > drivers/input/mouse/trackpoint.c | 149 +++++++++++++++++++++++++++++++
> > drivers/input/mouse/trackpoint.h | 15 ++++
> > 2 files changed, 164 insertions(+)
> >
> > diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> > index 5f6643b69a2c..c6f17b0dec3a 100644
> > --- a/drivers/input/mouse/trackpoint.c
> > +++ b/drivers/input/mouse/trackpoint.c
> > @@ -16,6 +16,8 @@
> > #include "psmouse.h"
> > #include "trackpoint.h"
> >
> > +static struct trackpoint_data *trackpoint_dev;
>
> Please do not use globals.
Understood.
>
> > +
> > static const char * const trackpoint_variants[] = {
> > [TP_VARIANT_IBM] = "IBM",
> > [TP_VARIANT_ALPS] = "ALPS",
> > @@ -63,6 +65,21 @@ static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
> > return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
> > }
> >
> > +/* Read function for TrackPoint extended registers */
> > +static int trackpoint_extended_read(struct ps2dev *ps2dev, u8 loc, u8 *val)
> > +{
> > + u8 ext_param[2] = {TP_READ_MEM, loc};
> > + int error;
> > +
> > + error = ps2_command(ps2dev,
> > + ext_param, MAKE_PS2_CMD(2, 1, TP_COMMAND));
> > +
> > + if (!error)
> > + *val = ext_param[0];
> > +
> > + return error;
> > +}
> > +
> > static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
> > {
> > u8 param[3] = { TP_TOGGLE, loc, mask };
> > @@ -393,6 +410,131 @@ 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 eg: is "PNP: LEN030d PNP0f13".
> > + */
> > +static bool is_trackpoint_dt_capable(const char *pnp_id)
> > +{
> > + const char *id_start;
> > + char id[8];
> > +
> > + 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 blacklisted */
> > + for (size_t i = 0; i < ARRAY_SIZE(dt_incompatible_devices); ++i) {
> > + if (strcmp(id, dt_incompatible_devices[i]) == 0)
> > + return false;
> > + }
> > + return true;
> > +}
> > +
> > +/* Trackpoint doubletap status function */
> > +static int trackpoint_doubletap_status(bool *status)
> > +{
> > + struct trackpoint_data *tp = trackpoint_dev;
> > + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> > + u8 reg_val;
> > + int rc;
> > +
> > + /* Reading the Doubletap register using extended read */
> > + rc = trackpoint_extended_read(ps2dev, TP_DOUBLETAP, ®_val);
> > + if (rc)
> > + return rc;
> > +
> > + *status = reg_val & TP_DOUBLETAP_STATUS ? true : false;
> > +
> > + return 0;
> > +}
> > +
> > +/* Trackpoint doubletap enable/disable function */
> > +static int trackpoint_set_doubletap(bool enable)
> > +{
> > + struct trackpoint_data *tp = trackpoint_dev;
> > + struct ps2dev *ps2dev = &tp->parent_psmouse->ps2dev;
> > + static u8 doubletap_state;
> > + u8 new_val;
> > +
> > + if (!tp)
> > + return -ENODEV;
> > +
> > + new_val = enable ? TP_DOUBLETAP_ENABLE : TP_DOUBLETAP_DISABLE;
> > +
> > + if (doubletap_state == new_val)
> > + return 0;
> > +
> > + doubletap_state = new_val;
> > +
> > + return trackpoint_write(ps2dev, TP_DOUBLETAP, new_val);
> > +}
> > +
> > +/*
> > + * Trackpoint Doubletap Interface
> > + * Control/Monitoring of Trackpoint Doubletap from:
> > + * /sys/bus/serio/devices/seriox/doubletap_enabled
> > + */
> > +static ssize_t doubletap_enabled_show(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + struct serio *serio = to_serio_port(dev);
> > + struct psmouse *psmouse = psmouse_from_serio(serio);
> > + struct trackpoint_data *tp = psmouse->private;
> > + bool status;
> > + int rc;
> > +
> > + if (!tp || !tp->doubletap_capable)
> > + return -ENODEV;
> > +
> > + rc = trackpoint_doubletap_status(&status);
> > + if (rc)
> > + return rc;
> > +
> > + return sysfs_emit(buf, "%d\n", status ? 1 : 0);
> > +}
> > +
> > +static ssize_t doubletap_enabled_store(struct device *dev,
> > + struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + struct serio *serio = to_serio_port(dev);
> > + struct psmouse *psmouse = psmouse_from_serio(serio);
> > + struct trackpoint_data *tp = psmouse->private;
> > + bool enable;
> > + int err;
> > +
> > + if (!tp || !tp->doubletap_capable)
> > + return -ENODEV;
> > +
> > + err = kstrtobool(buf, &enable);
> > + if (err)
> > + return err;
> > +
> > + err = trackpoint_set_doubletap(enable);
> > + if (err)
> > + return err;
> > +
> > + return count;
> > +}
> > +
> > +static DEVICE_ATTR_RW(doubletap_enabled);
> > +
> > int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> > {
> > struct ps2dev *ps2dev = &psmouse->ps2dev;
> > @@ -425,6 +567,9 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> > psmouse->reconnect = trackpoint_reconnect;
> > psmouse->disconnect = trackpoint_disconnect;
> >
> > + trackpoint_dev = psmouse->private;
> > + trackpoint_dev->parent_psmouse = psmouse;
> > +
> > if (variant_id != TP_VARIANT_IBM) {
> > /* Newer variants do not support extended button query. */
> > button_info = 0x33;
> > @@ -470,6 +615,10 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
> > psmouse->vendor, firmware_id,
> > (button_info & 0xf0) >> 4, button_info & 0x0f);
> >
> > + tp->doubletap_capable = is_trackpoint_dt_capable(ps2dev->serio->firmware_id);
> > + if (tp->doubletap_capable)
> > + device_create_file(&psmouse->ps2dev.serio->dev, &dev_attr_doubletap_enabled);
>
> Please use existing facilities in psmouse driver to define and register
> protocol-specific attributes. Use is_visible() to control whether the
> attribute is accessible or not.
Got it.
Will change this.
>
> Thanks.
>
> --
> Dmitry
--
Regards,
Vishnu Sankar
+817015150407 (Japan)
^ permalink raw reply [flat|nested] 9+ messages in thread