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>
This commit is contained in:
parent
1e4e3dff9e
commit
cec8c359f8
|
|
@ -121,7 +121,7 @@ static void slidebar_mode_set(u8 mode)
|
|||
}
|
||||
|
||||
static bool slidebar_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
struct serio *port, void *context)
|
||||
{
|
||||
static bool extended = false;
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ static int __init ideapad_probe(struct platform_device* pdev)
|
|||
input_set_capability(slidebar_input_dev, EV_ABS, ABS_X);
|
||||
input_set_abs_params(slidebar_input_dev, ABS_X, 0, 0xff, 0, 0);
|
||||
|
||||
err = i8042_install_filter(slidebar_i8042_filter);
|
||||
err = i8042_install_filter(slidebar_i8042_filter, NULL);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to install i8042 filter: %d\n", err);
|
||||
|
|
|
|||
|
|
@ -179,8 +179,8 @@ static struct platform_device *i8042_platform_device;
|
|||
static struct notifier_block i8042_kbd_bind_notifier_block;
|
||||
|
||||
static bool i8042_handle_data(int irq);
|
||||
static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio);
|
||||
static i8042_filter_t i8042_platform_filter;
|
||||
static void *i8042_platform_filter_context;
|
||||
|
||||
void i8042_lock_chip(void)
|
||||
{
|
||||
|
|
@ -194,8 +194,7 @@ void i8042_unlock_chip(void)
|
|||
}
|
||||
EXPORT_SYMBOL(i8042_unlock_chip);
|
||||
|
||||
int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio))
|
||||
int i8042_install_filter(i8042_filter_t filter, void *context)
|
||||
{
|
||||
guard(spinlock_irqsave)(&i8042_lock);
|
||||
|
||||
|
|
@ -203,12 +202,12 @@ int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
|||
return -EBUSY;
|
||||
|
||||
i8042_platform_filter = filter;
|
||||
i8042_platform_filter_context = context;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(i8042_install_filter);
|
||||
|
||||
int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *port))
|
||||
int i8042_remove_filter(i8042_filter_t filter)
|
||||
{
|
||||
guard(spinlock_irqsave)(&i8042_lock);
|
||||
|
||||
|
|
@ -216,6 +215,7 @@ int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
|||
return -EINVAL;
|
||||
|
||||
i8042_platform_filter = NULL;
|
||||
i8042_platform_filter_context = NULL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(i8042_remove_filter);
|
||||
|
|
@ -480,7 +480,10 @@ static bool i8042_filter(unsigned char data, unsigned char str,
|
|||
}
|
||||
}
|
||||
|
||||
if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
|
||||
if (!i8042_platform_filter)
|
||||
return false;
|
||||
|
||||
if (i8042_platform_filter(data, str, serio, i8042_platform_filter_context)) {
|
||||
dbg("Filtered out by platform filter\n");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-do
|
|||
static struct quirk_entry *quirks;
|
||||
static bool atkbd_reports_vol_keys;
|
||||
|
||||
static bool asus_i8042_filter(unsigned char data, unsigned char str, struct serio *port)
|
||||
static bool asus_i8042_filter(unsigned char data, unsigned char str, struct serio *port,
|
||||
void *context)
|
||||
{
|
||||
static bool extended_e0;
|
||||
static bool extended_e1;
|
||||
|
|
|
|||
|
|
@ -4824,7 +4824,7 @@ static int asus_wmi_add(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (asus->driver->i8042_filter) {
|
||||
err = i8042_install_filter(asus->driver->i8042_filter);
|
||||
err = i8042_install_filter(asus->driver->i8042_filter, NULL);
|
||||
if (err)
|
||||
pr_warn("Unable to install key filter - %d\n", err);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,7 @@ struct asus_wmi_driver {
|
|||
void (*key_filter) (struct asus_wmi_driver *driver, int *code,
|
||||
unsigned int *value, bool *autorelease);
|
||||
/* Optional standard i8042 filter */
|
||||
bool (*i8042_filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio);
|
||||
i8042_filter_t i8042_filter;
|
||||
|
||||
int (*probe) (struct platform_device *device);
|
||||
void (*detect_quirks) (struct asus_wmi_driver *driver);
|
||||
|
|
|
|||
|
|
@ -725,8 +725,8 @@ static void dell_update_rfkill(struct work_struct *ignored)
|
|||
}
|
||||
static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
|
||||
|
||||
static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, struct serio *port,
|
||||
void *context)
|
||||
{
|
||||
static bool extended;
|
||||
|
||||
|
|
@ -884,7 +884,7 @@ static int __init dell_setup_rfkill(void)
|
|||
pr_warn("Unable to register dell rbtn notifier\n");
|
||||
goto err_filter;
|
||||
} else {
|
||||
ret = i8042_install_filter(dell_laptop_i8042_filter);
|
||||
ret = i8042_install_filter(dell_laptop_i8042_filter, NULL);
|
||||
if (ret) {
|
||||
pr_warn("Unable to install key filter\n");
|
||||
goto err_filter;
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ static struct delayed_led_classdev hpled_led = {
|
|||
};
|
||||
|
||||
static bool hp_accel_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
struct serio *port, void *context)
|
||||
{
|
||||
static bool extended;
|
||||
|
||||
|
|
@ -326,7 +326,7 @@ static int lis3lv02d_probe(struct platform_device *device)
|
|||
/* filter to remove HPQ6000 accelerometer data
|
||||
* from keyboard bus stream */
|
||||
if (strstr(dev_name(&device->dev), "HPQ6000"))
|
||||
i8042_install_filter(hp_accel_i8042_filter);
|
||||
i8042_install_filter(hp_accel_i8042_filter, NULL);
|
||||
|
||||
INIT_WORK(&hpled_led.work, delayed_set_status_worker);
|
||||
ret = led_classdev_register(NULL, &hpled_led.led_classdev);
|
||||
|
|
|
|||
|
|
@ -806,8 +806,8 @@ static void msi_send_touchpad_key(struct work_struct *ignored)
|
|||
}
|
||||
static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
|
||||
|
||||
static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, struct serio *port,
|
||||
void *context)
|
||||
{
|
||||
static bool extended;
|
||||
|
||||
|
|
@ -996,7 +996,7 @@ static int __init load_scm_model_init(struct platform_device *sdev)
|
|||
if (result)
|
||||
goto fail_input;
|
||||
|
||||
result = i8042_install_filter(msi_laptop_i8042_filter);
|
||||
result = i8042_install_filter(msi_laptop_i8042_filter, NULL);
|
||||
if (result) {
|
||||
pr_err("Unable to install key filter\n");
|
||||
goto fail_filter;
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ struct pcc_acpi {
|
|||
* 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)
|
||||
struct serio *port, void *context)
|
||||
{
|
||||
static bool extended;
|
||||
|
||||
|
|
@ -1100,7 +1100,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
|||
pcc->platform = NULL;
|
||||
}
|
||||
|
||||
i8042_install_filter(panasonic_i8042_filter);
|
||||
i8042_install_filter(panasonic_i8042_filter, NULL);
|
||||
return 0;
|
||||
|
||||
out_platform:
|
||||
|
|
|
|||
|
|
@ -2755,7 +2755,7 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
|
|||
}
|
||||
|
||||
static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
struct serio *port, void *context)
|
||||
{
|
||||
if (str & I8042_STR_AUXDATA)
|
||||
return false;
|
||||
|
|
@ -2915,7 +2915,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
|||
if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
|
||||
INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
|
||||
|
||||
error = i8042_install_filter(toshiba_acpi_i8042_filter);
|
||||
error = i8042_install_filter(toshiba_acpi_i8042_filter, NULL);
|
||||
if (error) {
|
||||
pr_err("Error installing key filter\n");
|
||||
goto err_free_dev;
|
||||
|
|
|
|||
|
|
@ -54,15 +54,29 @@
|
|||
|
||||
struct serio;
|
||||
|
||||
/**
|
||||
* typedef i8042_filter_t - i8042 filter callback
|
||||
* @data: Data received by the i8042 controller
|
||||
* @str: Status register of the i8042 controller
|
||||
* @serio: Serio of the i8042 controller
|
||||
* @context: Context pointer associated with this callback
|
||||
*
|
||||
* This represents a i8042 filter callback which can be used with i8042_install_filter()
|
||||
* and i8042_remove_filter() to filter the i8042 input for platform-specific key codes.
|
||||
*
|
||||
* Context: Interrupt context.
|
||||
* Returns: true if the data should be filtered out, false if otherwise.
|
||||
*/
|
||||
typedef bool (*i8042_filter_t)(unsigned char data, unsigned char str, struct serio *serio,
|
||||
void *context);
|
||||
|
||||
#if defined(CONFIG_SERIO_I8042) || defined(CONFIG_SERIO_I8042_MODULE)
|
||||
|
||||
void i8042_lock_chip(void);
|
||||
void i8042_unlock_chip(void);
|
||||
int i8042_command(unsigned char *param, int command);
|
||||
int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio));
|
||||
int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio));
|
||||
int i8042_install_filter(i8042_filter_t filter, void *context);
|
||||
int i8042_remove_filter(i8042_filter_t filter);
|
||||
|
||||
#else
|
||||
|
||||
|
|
@ -79,14 +93,12 @@ static inline int i8042_command(unsigned char *param, int command)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio))
|
||||
static inline int i8042_install_filter(i8042_filter_t filter, void *context)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
||||
struct serio *serio))
|
||||
static inline int i8042_remove_filter(i8042_filter_t filter)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue