Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: i8042 - Add support for platform filter contexts

Currently the platform filter cannot access any driver-specific state
which forces drivers installing a i8042 filter to have at least some
kind of global pointer for their filter.

Allow callers of i8042_install_filter() to submit a context pointer
which is then passed to the i8042 filter. This frees drivers from the
responsibility of having to manage this global pointer themself.

Also introduce a separate type for the i8042 filter (i8042_filter_t)
so that the function definitions can stay compact.

Tested on a Dell Inspiron 3505.

Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20250113221314.435812-1-W_Armin@gmx.de
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Armin Wolf and committed by
Ilpo Järvinen
cec8c359 1e4e3dff

+48 -33
+2 -2
drivers/input/misc/ideapad_slidebar.c
··· 121 121 } 122 122 123 123 static bool slidebar_i8042_filter(unsigned char data, unsigned char str, 124 - struct serio *port) 124 + struct serio *port, void *context) 125 125 { 126 126 static bool extended = false; 127 127 ··· 219 219 input_set_capability(slidebar_input_dev, EV_ABS, ABS_X); 220 220 input_set_abs_params(slidebar_input_dev, ABS_X, 0, 0xff, 0, 0); 221 221 222 - err = i8042_install_filter(slidebar_i8042_filter); 222 + err = i8042_install_filter(slidebar_i8042_filter, NULL); 223 223 if (err) { 224 224 dev_err(&pdev->dev, 225 225 "Failed to install i8042 filter: %d\n", err);
+10 -7
drivers/input/serio/i8042.c
··· 179 179 static struct notifier_block i8042_kbd_bind_notifier_block; 180 180 181 181 static bool i8042_handle_data(int irq); 182 - static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, 183 - struct serio *serio); 182 + static i8042_filter_t i8042_platform_filter; 183 + static void *i8042_platform_filter_context; 184 184 185 185 void i8042_lock_chip(void) 186 186 { ··· 194 194 } 195 195 EXPORT_SYMBOL(i8042_unlock_chip); 196 196 197 - int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 198 - struct serio *serio)) 197 + int i8042_install_filter(i8042_filter_t filter, void *context) 199 198 { 200 199 guard(spinlock_irqsave)(&i8042_lock); 201 200 ··· 202 203 return -EBUSY; 203 204 204 205 i8042_platform_filter = filter; 206 + i8042_platform_filter_context = context; 205 207 return 0; 206 208 } 207 209 EXPORT_SYMBOL(i8042_install_filter); 208 210 209 - int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 210 - struct serio *port)) 211 + int i8042_remove_filter(i8042_filter_t filter) 211 212 { 212 213 guard(spinlock_irqsave)(&i8042_lock); 213 214 ··· 215 216 return -EINVAL; 216 217 217 218 i8042_platform_filter = NULL; 219 + i8042_platform_filter_context = NULL; 218 220 return 0; 219 221 } 220 222 EXPORT_SYMBOL(i8042_remove_filter); ··· 480 480 } 481 481 } 482 482 483 - if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) { 483 + if (!i8042_platform_filter) 484 + return false; 485 + 486 + if (i8042_platform_filter(data, str, serio, i8042_platform_filter_context)) { 484 487 dbg("Filtered out by platform filter\n"); 485 488 return true; 486 489 }
+2 -1
drivers/platform/x86/asus-nb-wmi.c
··· 50 50 static struct quirk_entry *quirks; 51 51 static bool atkbd_reports_vol_keys; 52 52 53 - static bool asus_i8042_filter(unsigned char data, unsigned char str, struct serio *port) 53 + static bool asus_i8042_filter(unsigned char data, unsigned char str, struct serio *port, 54 + void *context) 54 55 { 55 56 static bool extended_e0; 56 57 static bool extended_e1;
+1 -1
drivers/platform/x86/asus-wmi.c
··· 4824 4824 } 4825 4825 4826 4826 if (asus->driver->i8042_filter) { 4827 - err = i8042_install_filter(asus->driver->i8042_filter); 4827 + err = i8042_install_filter(asus->driver->i8042_filter, NULL); 4828 4828 if (err) 4829 4829 pr_warn("Unable to install key filter - %d\n", err); 4830 4830 }
+1 -2
drivers/platform/x86/asus-wmi.h
··· 73 73 void (*key_filter) (struct asus_wmi_driver *driver, int *code, 74 74 unsigned int *value, bool *autorelease); 75 75 /* Optional standard i8042 filter */ 76 - bool (*i8042_filter)(unsigned char data, unsigned char str, 77 - struct serio *serio); 76 + i8042_filter_t i8042_filter; 78 77 79 78 int (*probe) (struct platform_device *device); 80 79 void (*detect_quirks) (struct asus_wmi_driver *driver);
+3 -3
drivers/platform/x86/dell/dell-laptop.c
··· 725 725 } 726 726 static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); 727 727 728 - static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, 729 - struct serio *port) 728 + static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, struct serio *port, 729 + void *context) 730 730 { 731 731 static bool extended; 732 732 ··· 884 884 pr_warn("Unable to register dell rbtn notifier\n"); 885 885 goto err_filter; 886 886 } else { 887 - ret = i8042_install_filter(dell_laptop_i8042_filter); 887 + ret = i8042_install_filter(dell_laptop_i8042_filter, NULL); 888 888 if (ret) { 889 889 pr_warn("Unable to install key filter\n"); 890 890 goto err_filter;
+2 -2
drivers/platform/x86/hp/hp_accel.c
··· 267 267 }; 268 268 269 269 static bool hp_accel_i8042_filter(unsigned char data, unsigned char str, 270 - struct serio *port) 270 + struct serio *port, void *context) 271 271 { 272 272 static bool extended; 273 273 ··· 326 326 /* filter to remove HPQ6000 accelerometer data 327 327 * from keyboard bus stream */ 328 328 if (strstr(dev_name(&device->dev), "HPQ6000")) 329 - i8042_install_filter(hp_accel_i8042_filter); 329 + i8042_install_filter(hp_accel_i8042_filter, NULL); 330 330 331 331 INIT_WORK(&hpled_led.work, delayed_set_status_worker); 332 332 ret = led_classdev_register(NULL, &hpled_led.led_classdev);
+3 -3
drivers/platform/x86/msi-laptop.c
··· 806 806 } 807 807 static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key); 808 808 809 - static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 810 - struct serio *port) 809 + static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, struct serio *port, 810 + void *context) 811 811 { 812 812 static bool extended; 813 813 ··· 996 996 if (result) 997 997 goto fail_input; 998 998 999 - result = i8042_install_filter(msi_laptop_i8042_filter); 999 + result = i8042_install_filter(msi_laptop_i8042_filter, NULL); 1000 1000 if (result) { 1001 1001 pr_err("Unable to install key filter\n"); 1002 1002 goto fail_filter;
+2 -2
drivers/platform/x86/panasonic-laptop.c
··· 260 260 * keypress events over the PS/2 kbd interface, filter these out. 261 261 */ 262 262 static bool panasonic_i8042_filter(unsigned char data, unsigned char str, 263 - struct serio *port) 263 + struct serio *port, void *context) 264 264 { 265 265 static bool extended; 266 266 ··· 1100 1100 pcc->platform = NULL; 1101 1101 } 1102 1102 1103 - i8042_install_filter(panasonic_i8042_filter); 1103 + i8042_install_filter(panasonic_i8042_filter, NULL); 1104 1104 return 0; 1105 1105 1106 1106 out_platform:
+2 -2
drivers/platform/x86/toshiba_acpi.c
··· 2755 2755 } 2756 2756 2757 2757 static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 2758 - struct serio *port) 2758 + struct serio *port, void *context) 2759 2759 { 2760 2760 if (str & I8042_STR_AUXDATA) 2761 2761 return false; ··· 2915 2915 if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 2916 2916 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 2917 2917 2918 - error = i8042_install_filter(toshiba_acpi_i8042_filter); 2918 + error = i8042_install_filter(toshiba_acpi_i8042_filter, NULL); 2919 2919 if (error) { 2920 2920 pr_err("Error installing key filter\n"); 2921 2921 goto err_free_dev;
+20 -8
include/linux/i8042.h
··· 54 54 55 55 struct serio; 56 56 57 + /** 58 + * typedef i8042_filter_t - i8042 filter callback 59 + * @data: Data received by the i8042 controller 60 + * @str: Status register of the i8042 controller 61 + * @serio: Serio of the i8042 controller 62 + * @context: Context pointer associated with this callback 63 + * 64 + * This represents a i8042 filter callback which can be used with i8042_install_filter() 65 + * and i8042_remove_filter() to filter the i8042 input for platform-specific key codes. 66 + * 67 + * Context: Interrupt context. 68 + * Returns: true if the data should be filtered out, false if otherwise. 69 + */ 70 + typedef bool (*i8042_filter_t)(unsigned char data, unsigned char str, struct serio *serio, 71 + void *context); 72 + 57 73 #if defined(CONFIG_SERIO_I8042) || defined(CONFIG_SERIO_I8042_MODULE) 58 74 59 75 void i8042_lock_chip(void); 60 76 void i8042_unlock_chip(void); 61 77 int i8042_command(unsigned char *param, int command); 62 - int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 63 - struct serio *serio)); 64 - int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 65 - struct serio *serio)); 78 + int i8042_install_filter(i8042_filter_t filter, void *context); 79 + int i8042_remove_filter(i8042_filter_t filter); 66 80 67 81 #else 68 82 ··· 93 79 return -ENODEV; 94 80 } 95 81 96 - static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 97 - struct serio *serio)) 82 + static inline int i8042_install_filter(i8042_filter_t filter, void *context) 98 83 { 99 84 return -ENODEV; 100 85 } 101 86 102 - static inline int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 103 - struct serio *serio)) 87 + static inline int i8042_remove_filter(i8042_filter_t filter) 104 88 { 105 89 return -ENODEV; 106 90 }