Commit 5e24e1ec authored by Hans de Goede's avatar Hans de Goede

platform/x86: panasonic-laptop: filter out duplicate volume up/down/mute keypresses

On some Panasonic models the volume up/down/mute keypresses get
reported both through the Panasonic ACPI HKEY interface as well as
through the atkbd device.

Filter out the atkbd scan-codes for these to avoid reporting presses
twice.

Note normally we would leave the filtering of these to userspace by mapping
the scan-codes to KEY_UNKNOWN through /lib/udev/hwdb.d/60-keyboard.hwdb.
However in this case that would cause regressions since we were filtering
the Panasonic ACPI HKEY events before, so filter these in the kernel.

Fixes: ed83c917 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug")
Reported-and-tested-by: default avatarStefan Seyfried <seife+kernel@b1-systems.com>
Reported-and-tested-by: default avatarKenneth Chan <kenneth.t.chan@gmail.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20220624112340.10130-7-hdegoede@redhat.com
parent 027f8845
...@@ -919,6 +919,7 @@ config PANASONIC_LAPTOP ...@@ -919,6 +919,7 @@ config PANASONIC_LAPTOP
depends on INPUT && ACPI depends on INPUT && ACPI
depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_CLASS_DEVICE
depends on ACPI_VIDEO=n || ACPI_VIDEO depends on ACPI_VIDEO=n || ACPI_VIDEO
depends on SERIO_I8042 || SERIO_I8042 = n
select INPUT_SPARSEKMAP select INPUT_SPARSEKMAP
help help
This driver adds support for access to backlight control and hotkeys This driver adds support for access to backlight control and hotkeys
......
...@@ -122,6 +122,7 @@ ...@@ -122,6 +122,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/backlight.h> #include <linux/backlight.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/i8042.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sparse-keymap.h> #include <linux/input/sparse-keymap.h>
...@@ -129,6 +130,7 @@ ...@@ -129,6 +130,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/serio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -241,6 +243,42 @@ struct pcc_acpi { ...@@ -241,6 +243,42 @@ struct pcc_acpi {
struct platform_device *platform; struct platform_device *platform;
}; };
/*
* On some Panasonic models the volume up / down / mute keys send duplicate
* keypress events over the PS/2 kbd interface, filter these out.
*/
static bool panasonic_i8042_filter(unsigned char data, unsigned char str,
struct serio *port)
{
static bool extended;
if (str & I8042_STR_AUXDATA)
return false;
if (data == 0xe0) {
extended = true;
return true;
} else if (extended) {
extended = false;
switch (data & 0x7f) {
case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */
case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */
case 0x30: /* e0 30 / e0 b0, Volume Up press / release */
return true;
default:
/*
* Report the previously filtered e0 before continuing
* with the next non-filtered byte.
*/
serio_interrupt(port, 0xe0, 0);
return false;
}
}
return false;
}
/* method access functions */ /* method access functions */
static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val) static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
{ {
...@@ -1006,6 +1044,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) ...@@ -1006,6 +1044,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
pcc->platform = NULL; pcc->platform = NULL;
} }
i8042_install_filter(panasonic_i8042_filter);
return 0; return 0;
out_platform: out_platform:
...@@ -1029,6 +1068,8 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device) ...@@ -1029,6 +1068,8 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device)
if (!device || !pcc) if (!device || !pcc)
return -EINVAL; return -EINVAL;
i8042_remove_filter(panasonic_i8042_filter);
if (pcc->platform) { if (pcc->platform) {
device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
platform_device_unregister(pcc->platform); platform_device_unregister(pcc->platform);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment