[PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event

Jonathan Denose posted 2 patches 2 months, 4 weeks ago
[PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
Posted by Jonathan Denose 2 months, 4 weeks ago
Many touchpad modules have a pin which is expected to be connected to the
lid angle sensor in laptops. The pin sends a signal to the touchpad module
about the lid state and each touchpad vendor handles this notification in
their firmware.

The Elan touchpad with VID 323b does not always have this aforementioned
pin, which then causes interference between the lid and the touchpad when
the lid is closed. This interference causes a few seconds delay before the
touchpad works again, or it causes it to be come completely unresponsive.
To circumvent this hardware issue in software, implement a device quirk
which will allow the hid-multitouch driver to register a notifier_block
to listen for lid switch events. When the lid switch closes, the
touchpad surface will be turned off and when the lid switch opens, the
touchpad surgace will be turned on. This triggers recalibration which
resolves interference issues when the lid is closed.

Signed-off-by: Jonathan Denose <jdenose@google.com>
---
 drivers/hid/hid-multitouch.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 2879e65cf303b1456311ac06115adda5a78a2600..9a89913c193bc110a0a821a901aebd97892c66bd 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -35,6 +35,7 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/notifier.h>
 #include <linux/slab.h>
 #include <linux/input/mt.h>
 #include <linux/jiffies.h>
@@ -76,6 +77,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_DISABLE_WAKEUP		BIT(21)
 #define MT_QUIRK_ORIENTATION_INVERT	BIT(22)
 #define MT_QUIRK_APPLE_TOUCHBAR		BIT(23)
+#define MT_QUIRK_REGISTER_LID_NOTIFIER BIT(24)
 
 #define MT_INPUTMODE_TOUCHSCREEN	0x02
 #define MT_INPUTMODE_TOUCHPAD		0x03
@@ -183,6 +185,8 @@ struct mt_device {
 	struct list_head reports;
 };
 
+static struct hid_device *lid_notify_hdev;
+
 static void mt_post_parse_default_settings(struct mt_device *td,
 					   struct mt_application *app);
 static void mt_post_parse(struct mt_device *td, struct mt_application *app);
@@ -227,6 +231,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
 #define MT_CLS_SMART_TECH			0x0113
 #define MT_CLS_APPLE_TOUCHBAR			0x0114
 #define MT_CLS_SIS				0x0457
+#define MT_CLS_REGISTER_LID_NOTIFIER 0x0115
 
 #define MT_DEFAULT_MAXCONTACT	10
 #define MT_MAX_MAXCONTACT	250
@@ -327,7 +332,9 @@ static const struct mt_class mt_classes[] = {
 			MT_QUIRK_CONTACT_CNT_ACCURATE |
 			MT_QUIRK_WIN8_PTP_BUTTONS,
 		.export_all_inputs = true },
-
+	{ .name = MT_CLS_REGISTER_LID_NOTIFIER,
+		.quirks = MT_QUIRK_REGISTER_LID_NOTIFIER,
+		.export_all_inputs = true },
 	/*
 	 * vendor specific classes
 	 */
@@ -1840,6 +1847,20 @@ static void mt_expired_timeout(struct timer_list *t)
 	clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
 }
 
+static int mt_input_notifier(struct notifier_block *nb, unsigned long action, void *dev)
+{
+	if (action)
+		mt_set_modes(lid_notify_hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE);
+	else if (!action)
+		mt_set_modes(lid_notify_hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL);
+
+	return 0;
+}
+
+static struct notifier_block mt_lid_notifier_block = {
+	.notifier_call = mt_input_notifier
+};
+
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	int ret, i;
@@ -1920,6 +1941,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
 		hdev->quirks |= HID_QUIRK_NOGET;
 
+	if (mtclass->quirks & MT_CLS_REGISTER_LID_NOTIFIER) {
+		lid_notify_hdev = hdev;
+		register_lid_notifier(&mt_lid_notifier_block);
+	}
+
 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 	if (ret)
 		return ret;
@@ -2150,6 +2176,10 @@ static const struct hid_device_id mt_devices[] = {
 		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
 			USB_VENDOR_ID_ELAN, 0x32ae) },
 
+	{ .driver_data = MT_CLS_REGISTER_LID_NOTIFIER,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_ELAN, 0x323b) },
+
 	/* Elitegroup panel */
 	{ .driver_data = MT_CLS_SERIAL,
 		MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP,

-- 
2.51.2.1041.gc1ab5b90ca-goog
Re: [PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
Posted by kernel test robot 2 months, 3 weeks ago
Hi Jonathan,

kernel test robot noticed the following build errors:

[auto build test ERROR on 3a8660878839faadb4f1a6dd72c3179c1df56787]

url:    https://github.com/intel-lab-lkp/linux/commits/Jonathan-Denose/Input-Add-lid-switch-notifier/20251112-053559
base:   3a8660878839faadb4f1a6dd72c3179c1df56787
patch link:    https://lore.kernel.org/r/20251111-lid-switch-notifier-v2-2-789723d78d89%40google.com
patch subject: [PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
config: parisc-randconfig-002-20251112 (https://download.01.org/0day-ci/archive/20251112/202511122158.oyGRoKNz-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251112/202511122158.oyGRoKNz-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511122158.oyGRoKNz-lkp@intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "register_lid_notifier" [drivers/hid/hid-multitouch.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
Posted by kernel test robot 2 months, 3 weeks ago
Hi Jonathan,

kernel test robot noticed the following build errors:

[auto build test ERROR on 3a8660878839faadb4f1a6dd72c3179c1df56787]

url:    https://github.com/intel-lab-lkp/linux/commits/Jonathan-Denose/Input-Add-lid-switch-notifier/20251112-053559
base:   3a8660878839faadb4f1a6dd72c3179c1df56787
patch link:    https://lore.kernel.org/r/20251111-lid-switch-notifier-v2-2-789723d78d89%40google.com
patch subject: [PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
config: xtensa-randconfig-002-20251112 (https://download.01.org/0day-ci/archive/20251112/202511122329.Sg4foDAx-lkp@intel.com/config)
compiler: xtensa-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251112/202511122329.Sg4foDAx-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511122329.Sg4foDAx-lkp@intel.com/

All errors (new ones prefixed by >>):

   arch/xtensa/kernel/entry.o: in function `fast_syscall_spill_registers':
   arch/xtensa/kernel/entry.S:1423:(.exception.text+0x21b): dangerous relocation: windowed longcall crosses 1GB boundary; return may fail: make_task_dead
   xtensa-linux-ld: drivers/hid/hid-multitouch.o: in function `mt_touch_report.isra.24':
>> drivers/hid/hid-multitouch.c:1319: undefined reference to `register_lid_notifier'
   xtensa-linux-ld: drivers/hid/hid-multitouch.o: in function `mt_touch_report.isra.24':
>> include/linux/input.h:512: undefined reference to `register_lid_notifier'


vim +1319 drivers/hid/hid-multitouch.c

2d93666e70662c Benjamin Tissoires 2011-01-11  1256  
8dfe14b3b47ff8 Benjamin Tissoires 2018-07-13  1257  static void mt_touch_report(struct hid_device *hid,
8dfe14b3b47ff8 Benjamin Tissoires 2018-07-13  1258  			    struct mt_report_data *rdata)
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1259  {
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1260  	struct mt_device *td = hid_get_drvdata(hid);
8dfe14b3b47ff8 Benjamin Tissoires 2018-07-13  1261  	struct hid_report *report = rdata->report;
8dfe14b3b47ff8 Benjamin Tissoires 2018-07-13  1262  	struct mt_application *app = rdata->application;
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1263  	struct hid_field *field;
01eaac7e57134c Benjamin Tissoires 2018-07-13  1264  	struct input_dev *input;
01eaac7e57134c Benjamin Tissoires 2018-07-13  1265  	struct mt_usages *slot;
55746d28d66860 Hans de Goede      2017-11-22  1266  	bool first_packet;
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1267  	unsigned count;
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1268  	int r, n;
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1269  	int scantime = 0;
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1270  	int contact_count = -1;
5519cab477b613 Benjamin Tissoires 2011-01-07  1271  
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1272  	/* sticky fingers release in progress, abort */
be6e2b5734a425 Andri Yngvason     2022-09-07  1273  	if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1274  		return;
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1275  
01eaac7e57134c Benjamin Tissoires 2018-07-13  1276  	scantime = *app->scantime;
01eaac7e57134c Benjamin Tissoires 2018-07-13  1277  	app->timestamp = mt_compute_timestamp(app, scantime);
01eaac7e57134c Benjamin Tissoires 2018-07-13  1278  	if (app->raw_cc != DEFAULT_ZERO)
01eaac7e57134c Benjamin Tissoires 2018-07-13  1279  		contact_count = *app->raw_cc;
01eaac7e57134c Benjamin Tissoires 2018-07-13  1280  
c2517f62dac608 Benjamin Tissoires 2013-01-31  1281  	/*
c2517f62dac608 Benjamin Tissoires 2013-01-31  1282  	 * Includes multi-packet support where subsequent
c2517f62dac608 Benjamin Tissoires 2013-01-31  1283  	 * packets are sent with zero contactcount.
c2517f62dac608 Benjamin Tissoires 2013-01-31  1284  	 */
01eaac7e57134c Benjamin Tissoires 2018-07-13  1285  	if (contact_count >= 0) {
af8dc4d0949092 Hans de Goede      2017-11-22  1286  		/*
af8dc4d0949092 Hans de Goede      2017-11-22  1287  		 * For Win8 PTPs the first packet (td->num_received == 0) may
af8dc4d0949092 Hans de Goede      2017-11-22  1288  		 * have a contactcount of 0 if there only is a button event.
af8dc4d0949092 Hans de Goede      2017-11-22  1289  		 * We double check that this is not a continuation packet
af8dc4d0949092 Hans de Goede      2017-11-22  1290  		 * of a possible multi-packet frame be checking that the
af8dc4d0949092 Hans de Goede      2017-11-22  1291  		 * timestamp has changed.
af8dc4d0949092 Hans de Goede      2017-11-22  1292  		 */
3ceb3826448d1e Benjamin Tissoires 2018-07-13  1293  		if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1294  		    app->num_received == 0 &&
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1295  		    app->prev_scantime != scantime)
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1296  			app->num_expected = contact_count;
af8dc4d0949092 Hans de Goede      2017-11-22  1297  		/* A non 0 contact count always indicates a first packet */
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1298  		else if (contact_count)
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1299  			app->num_expected = contact_count;
7e3cc447ff8906 Benjamin Tissoires 2013-02-06  1300  	}
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1301  	app->prev_scantime = scantime;
c2517f62dac608 Benjamin Tissoires 2013-01-31  1302  
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1303  	first_packet = app->num_received == 0;
01eaac7e57134c Benjamin Tissoires 2018-07-13  1304  
01eaac7e57134c Benjamin Tissoires 2018-07-13  1305  	input = report->field[0]->hidinput->input;
01eaac7e57134c Benjamin Tissoires 2018-07-13  1306  
01eaac7e57134c Benjamin Tissoires 2018-07-13  1307  	list_for_each_entry(slot, &app->mt_usages, list) {
01eaac7e57134c Benjamin Tissoires 2018-07-13  1308  		if (!mt_process_slot(td, input, app, slot))
01eaac7e57134c Benjamin Tissoires 2018-07-13  1309  			app->num_received++;
01eaac7e57134c Benjamin Tissoires 2018-07-13  1310  	}
01eaac7e57134c Benjamin Tissoires 2018-07-13  1311  
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1312  	for (r = 0; r < report->maxfield; r++) {
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1313  		field = report->field[r];
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1314  		count = field->report_count;
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1315  
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1316  		if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1317  			continue;
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1318  
55978fa9dc4c57 Benjamin Tissoires 2013-01-31 @1319  		for (n = 0; n < count; n++)
01eaac7e57134c Benjamin Tissoires 2018-07-13  1320  			mt_process_mt_event(hid, app, field,
01eaac7e57134c Benjamin Tissoires 2018-07-13  1321  					    &field->usage[n], field->value[n],
01eaac7e57134c Benjamin Tissoires 2018-07-13  1322  					    first_packet);
55978fa9dc4c57 Benjamin Tissoires 2013-01-31  1323  	}
5b62efd8250d6a Benjamin Tissoires 2013-02-27  1324  
f146d1c4d7eafd Benjamin Tissoires 2018-07-13  1325  	if (app->num_received >= app->num_expected)
01eaac7e57134c Benjamin Tissoires 2018-07-13  1326  		mt_sync_frame(td, app, input);
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1327  
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1328  	/*
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1329  	 * Windows 8 specs says 2 things:
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1330  	 * - once a contact has been reported, it has to be reported in each
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1331  	 *   subsequent report
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1332  	 * - the report rate when fingers are present has to be at least
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1333  	 *   the refresh rate of the screen, 60 or 120 Hz
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1334  	 *
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1335  	 * I interprete this that the specification forces a report rate of
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1336  	 * at least 60 Hz for a touchscreen to be certified.
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1337  	 * Which means that if we do not get a report whithin 16 ms, either
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1338  	 * something wrong happens, either the touchscreen forgets to send
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1339  	 * a release. Taking a reasonable margin allows to remove issues
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1340  	 * with USB communication or the load of the machine.
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1341  	 *
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1342  	 * Given that Win 8 devices are forced to send a release, this will
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1343  	 * only affect laggish machines and the ones that have a firmware
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1344  	 * defect.
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1345  	 */
3ceb3826448d1e Benjamin Tissoires 2018-07-13  1346  	if (app->quirks & MT_QUIRK_STICKY_FINGERS) {
9609827458c37d Benjamin Tissoires 2017-06-15  1347  		if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
9609827458c37d Benjamin Tissoires 2017-06-15  1348  			mod_timer(&td->release_timer,
9609827458c37d Benjamin Tissoires 2017-06-15  1349  				  jiffies + msecs_to_jiffies(100));
9609827458c37d Benjamin Tissoires 2017-06-15  1350  		else
8fa7292fee5c52 Thomas Gleixner    2025-04-05  1351  			timer_delete(&td->release_timer);
9609827458c37d Benjamin Tissoires 2017-06-15  1352  	}
4f4001bc76fd1a Benjamin Tissoires 2017-06-15  1353  
be6e2b5734a425 Andri Yngvason     2022-09-07  1354  	clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
5519cab477b613 Benjamin Tissoires 2011-01-07  1355  }
5519cab477b613 Benjamin Tissoires 2011-01-07  1356  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
Posted by Dmitry Torokhov 2 months, 4 weeks ago
Hi Jonathan,

On Tue, Nov 11, 2025 at 09:34:07PM +0000, Jonathan Denose wrote:
> Many touchpad modules have a pin which is expected to be connected to the
> lid angle sensor in laptops. The pin sends a signal to the touchpad module
> about the lid state and each touchpad vendor handles this notification in
> their firmware.
> 
> The Elan touchpad with VID 323b does not always have this aforementioned
> pin, which then causes interference between the lid and the touchpad when
> the lid is closed. This interference causes a few seconds delay before the
> touchpad works again, or it causes it to be come completely unresponsive.
> To circumvent this hardware issue in software, implement a device quirk
> which will allow the hid-multitouch driver to register a notifier_block
> to listen for lid switch events. When the lid switch closes, the
> touchpad surface will be turned off and when the lid switch opens, the
> touchpad surgace will be turned on. This triggers recalibration which
> resolves interference issues when the lid is closed.
> 
> Signed-off-by: Jonathan Denose <jdenose@google.com>
> ---
>  drivers/hid/hid-multitouch.c | 32 +++++++++++++++++++++++++++++++-
>  1 file changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index 2879e65cf303b1456311ac06115adda5a78a2600..9a89913c193bc110a0a821a901aebd97892c66bd 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -35,6 +35,7 @@
>  #include <linux/device.h>
>  #include <linux/hid.h>
>  #include <linux/module.h>
> +#include <linux/notifier.h>
>  #include <linux/slab.h>
>  #include <linux/input/mt.h>
>  #include <linux/jiffies.h>
> @@ -76,6 +77,7 @@ MODULE_LICENSE("GPL");
>  #define MT_QUIRK_DISABLE_WAKEUP		BIT(21)
>  #define MT_QUIRK_ORIENTATION_INVERT	BIT(22)
>  #define MT_QUIRK_APPLE_TOUCHBAR		BIT(23)
> +#define MT_QUIRK_REGISTER_LID_NOTIFIER BIT(24)
>  
>  #define MT_INPUTMODE_TOUCHSCREEN	0x02
>  #define MT_INPUTMODE_TOUCHPAD		0x03
> @@ -183,6 +185,8 @@ struct mt_device {
>  	struct list_head reports;
>  };
>  
> +static struct hid_device *lid_notify_hdev;

This should really be per-device.

> +
>  static void mt_post_parse_default_settings(struct mt_device *td,
>  					   struct mt_application *app);
>  static void mt_post_parse(struct mt_device *td, struct mt_application *app);
> @@ -227,6 +231,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
>  #define MT_CLS_SMART_TECH			0x0113
>  #define MT_CLS_APPLE_TOUCHBAR			0x0114
>  #define MT_CLS_SIS				0x0457
> +#define MT_CLS_REGISTER_LID_NOTIFIER 0x0115
>  
>  #define MT_DEFAULT_MAXCONTACT	10
>  #define MT_MAX_MAXCONTACT	250
> @@ -327,7 +332,9 @@ static const struct mt_class mt_classes[] = {
>  			MT_QUIRK_CONTACT_CNT_ACCURATE |
>  			MT_QUIRK_WIN8_PTP_BUTTONS,
>  		.export_all_inputs = true },
> -
> +	{ .name = MT_CLS_REGISTER_LID_NOTIFIER,
> +		.quirks = MT_QUIRK_REGISTER_LID_NOTIFIER,
> +		.export_all_inputs = true },
>  	/*
>  	 * vendor specific classes
>  	 */
> @@ -1840,6 +1847,20 @@ static void mt_expired_timeout(struct timer_list *t)
>  	clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
>  }
>  
> +static int mt_input_notifier(struct notifier_block *nb, unsigned long action, void *dev)
> +{
> +	if (action)
> +		mt_set_modes(lid_notify_hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE);
> +	else if (!action)
> +		mt_set_modes(lid_notify_hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL);
> +
> +	return 0;
> +}
> +
> +static struct notifier_block mt_lid_notifier_block = {
> +	.notifier_call = mt_input_notifier
> +};
> +
>  static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
>  {
>  	int ret, i;
> @@ -1920,6 +1941,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
>  	if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
>  		hdev->quirks |= HID_QUIRK_NOGET;
>  
> +	if (mtclass->quirks & MT_CLS_REGISTER_LID_NOTIFIER) {
> +		lid_notify_hdev = hdev;
> +		register_lid_notifier(&mt_lid_notifier_block);
> +	}
> +
>  	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
>  	if (ret)
>  		return ret;
> @@ -2150,6 +2176,10 @@ static const struct hid_device_id mt_devices[] = {
>  		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
>  			USB_VENDOR_ID_ELAN, 0x32ae) },
>  
> +	{ .driver_data = MT_CLS_REGISTER_LID_NOTIFIER,
> +		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
> +			USB_VENDOR_ID_ELAN, 0x323b) },

The need to have special handling of LID events is a quirk of board
design, not quire of a controller. So I think it needs to be triggered
by DMI quirk.

> +
>  	/* Elitegroup panel */
>  	{ .driver_data = MT_CLS_SERIAL,
>  		MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP,
> 

Thanks.

-- 
Dmitry
Re: [PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
Posted by Jonathan Denose 2 months, 3 weeks ago
Hi Dmitry,

Thanks for your review.

On Tue, Nov 11, 2025 at 4:37 PM Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
> Hi Jonathan,
>
> On Tue, Nov 11, 2025 at 09:34:07PM +0000, Jonathan Denose wrote:
> > Many touchpad modules have a pin which is expected to be connected to the
> > lid angle sensor in laptops. The pin sends a signal to the touchpad module
> > about the lid state and each touchpad vendor handles this notification in
> > their firmware.
> >
> > The Elan touchpad with VID 323b does not always have this aforementioned
> > pin, which then causes interference between the lid and the touchpad when
> > the lid is closed. This interference causes a few seconds delay before the
> > touchpad works again, or it causes it to be come completely unresponsive.
> > To circumvent this hardware issue in software, implement a device quirk
> > which will allow the hid-multitouch driver to register a notifier_block
> > to listen for lid switch events. When the lid switch closes, the
> > touchpad surface will be turned off and when the lid switch opens, the
> > touchpad surgace will be turned on. This triggers recalibration which
> > resolves interference issues when the lid is closed.
> >
> > Signed-off-by: Jonathan Denose <jdenose@google.com>
> > ---
> >  drivers/hid/hid-multitouch.c | 32 +++++++++++++++++++++++++++++++-
> >  1 file changed, 31 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> > index 2879e65cf303b1456311ac06115adda5a78a2600..9a89913c193bc110a0a821a901aebd97892c66bd 100644
> > --- a/drivers/hid/hid-multitouch.c
> > +++ b/drivers/hid/hid-multitouch.c
> > @@ -35,6 +35,7 @@
> >  #include <linux/device.h>
> >  #include <linux/hid.h>
> >  #include <linux/module.h>
> > +#include <linux/notifier.h>
> >  #include <linux/slab.h>
> >  #include <linux/input/mt.h>
> >  #include <linux/jiffies.h>
> > @@ -76,6 +77,7 @@ MODULE_LICENSE("GPL");
> >  #define MT_QUIRK_DISABLE_WAKEUP              BIT(21)
> >  #define MT_QUIRK_ORIENTATION_INVERT  BIT(22)
> >  #define MT_QUIRK_APPLE_TOUCHBAR              BIT(23)
> > +#define MT_QUIRK_REGISTER_LID_NOTIFIER BIT(24)
> >
> >  #define MT_INPUTMODE_TOUCHSCREEN     0x02
> >  #define MT_INPUTMODE_TOUCHPAD                0x03
> > @@ -183,6 +185,8 @@ struct mt_device {
> >       struct list_head reports;
> >  };
> >
> > +static struct hid_device *lid_notify_hdev;
>
> This should really be per-device.

Just to be sure I'm following correctly, the initialization of
lid_notify_hdev should be per-device?

> > +
> >  static void mt_post_parse_default_settings(struct mt_device *td,
> >                                          struct mt_application *app);
> >  static void mt_post_parse(struct mt_device *td, struct mt_application *app);
> > @@ -227,6 +231,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
> >  #define MT_CLS_SMART_TECH                    0x0113
> >  #define MT_CLS_APPLE_TOUCHBAR                        0x0114
> >  #define MT_CLS_SIS                           0x0457
> > +#define MT_CLS_REGISTER_LID_NOTIFIER 0x0115
> >
> >  #define MT_DEFAULT_MAXCONTACT        10
> >  #define MT_MAX_MAXCONTACT    250
> > @@ -327,7 +332,9 @@ static const struct mt_class mt_classes[] = {
> >                       MT_QUIRK_CONTACT_CNT_ACCURATE |
> >                       MT_QUIRK_WIN8_PTP_BUTTONS,
> >               .export_all_inputs = true },
> > -
> > +     { .name = MT_CLS_REGISTER_LID_NOTIFIER,
> > +             .quirks = MT_QUIRK_REGISTER_LID_NOTIFIER,
> > +             .export_all_inputs = true },
> >       /*
> >        * vendor specific classes
> >        */
> > @@ -1840,6 +1847,20 @@ static void mt_expired_timeout(struct timer_list *t)
> >       clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
> >  }
> >
> > +static int mt_input_notifier(struct notifier_block *nb, unsigned long action, void *dev)
> > +{
> > +     if (action)
> > +             mt_set_modes(lid_notify_hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE);
> > +     else if (!action)
> > +             mt_set_modes(lid_notify_hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL);
> > +
> > +     return 0;
> > +}
> > +
> > +static struct notifier_block mt_lid_notifier_block = {
> > +     .notifier_call = mt_input_notifier
> > +};
> > +
> >  static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
> >  {
> >       int ret, i;
> > @@ -1920,6 +1941,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
> >       if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
> >               hdev->quirks |= HID_QUIRK_NOGET;
> >
> > +     if (mtclass->quirks & MT_CLS_REGISTER_LID_NOTIFIER) {
> > +             lid_notify_hdev = hdev;
> > +             register_lid_notifier(&mt_lid_notifier_block);
> > +     }
> > +
> >       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> >       if (ret)
> >               return ret;
> > @@ -2150,6 +2176,10 @@ static const struct hid_device_id mt_devices[] = {
> >               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
> >                       USB_VENDOR_ID_ELAN, 0x32ae) },
> >
> > +     { .driver_data = MT_CLS_REGISTER_LID_NOTIFIER,
> > +             HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
> > +                     USB_VENDOR_ID_ELAN, 0x323b) },
>
> The need to have special handling of LID events is a quirk of board
> design, not quire of a controller. So I think it needs to be triggered
> by DMI quirk.
> > +
> >       /* Elitegroup panel */
> >       { .driver_data = MT_CLS_SERIAL,
> >               MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP,
> >
>
> Thanks.
>
> --
> Dmitry
-- 
Jonathan
Re: [PATCH v2 2/2] HID: multitouch: Toggle touch surface on Elan touchpad on lid event
Posted by Dmitry Torokhov 2 months, 3 weeks ago
On Wed, Nov 12, 2025 at 05:49:53PM -0600, Jonathan Denose wrote:
> Hi Dmitry,
> 
> Thanks for your review.
> 
> On Tue, Nov 11, 2025 at 4:37 PM Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> >
> > Hi Jonathan,
> >
> > On Tue, Nov 11, 2025 at 09:34:07PM +0000, Jonathan Denose wrote:
> > > Many touchpad modules have a pin which is expected to be connected to the
> > > lid angle sensor in laptops. The pin sends a signal to the touchpad module
> > > about the lid state and each touchpad vendor handles this notification in
> > > their firmware.
> > >
> > > The Elan touchpad with VID 323b does not always have this aforementioned
> > > pin, which then causes interference between the lid and the touchpad when
> > > the lid is closed. This interference causes a few seconds delay before the
> > > touchpad works again, or it causes it to be come completely unresponsive.
> > > To circumvent this hardware issue in software, implement a device quirk
> > > which will allow the hid-multitouch driver to register a notifier_block
> > > to listen for lid switch events. When the lid switch closes, the
> > > touchpad surface will be turned off and when the lid switch opens, the
> > > touchpad surgace will be turned on. This triggers recalibration which
> > > resolves interference issues when the lid is closed.
> > >
> > > Signed-off-by: Jonathan Denose <jdenose@google.com>
> > > ---
> > >  drivers/hid/hid-multitouch.c | 32 +++++++++++++++++++++++++++++++-
> > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> > > index 2879e65cf303b1456311ac06115adda5a78a2600..9a89913c193bc110a0a821a901aebd97892c66bd 100644
> > > --- a/drivers/hid/hid-multitouch.c
> > > +++ b/drivers/hid/hid-multitouch.c
> > > @@ -35,6 +35,7 @@
> > >  #include <linux/device.h>
> > >  #include <linux/hid.h>
> > >  #include <linux/module.h>
> > > +#include <linux/notifier.h>
> > >  #include <linux/slab.h>
> > >  #include <linux/input/mt.h>
> > >  #include <linux/jiffies.h>
> > > @@ -76,6 +77,7 @@ MODULE_LICENSE("GPL");
> > >  #define MT_QUIRK_DISABLE_WAKEUP              BIT(21)
> > >  #define MT_QUIRK_ORIENTATION_INVERT  BIT(22)
> > >  #define MT_QUIRK_APPLE_TOUCHBAR              BIT(23)
> > > +#define MT_QUIRK_REGISTER_LID_NOTIFIER BIT(24)
> > >
> > >  #define MT_INPUTMODE_TOUCHSCREEN     0x02
> > >  #define MT_INPUTMODE_TOUCHPAD                0x03
> > > @@ -183,6 +185,8 @@ struct mt_device {
> > >       struct list_head reports;
> > >  };
> > >
> > > +static struct hid_device *lid_notify_hdev;
> >
> > This should really be per-device.
> 
> Just to be sure I'm following correctly, the initialization of
> lid_notify_hdev should be per-device?

Yes. I believe this is the best practice.

Thanks.

-- 
Dmitry