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
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
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
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
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
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
© 2016 - 2026 Red Hat, Inc.