All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Friedrich Vock <friedrich.vock@gmx.de>
Cc: linux-input@vger.kernel.org,
	Mario Limonciello <mario.limonciello@amd.com>
Subject: Re: [PATCH] Input: i8042 - Add quirk for polling the KBD port
Date: Fri, 21 Jul 2023 16:44:18 -0700	[thread overview]
Message-ID: <ZLsYUlSMIK0Gtr21@google.com> (raw)
In-Reply-To: <20230530153644.17262-1-friedrich.vock@gmx.de>

Hi Friedrich,

On Tue, May 30, 2023 at 05:36:44PM +0200, Friedrich Vock wrote:
> It seems like there are some devices in the ASUS TUF A16 laptops that
> just don't send any keyboard interrupts until you read from the KBD port.

I am sorry, but continuously polling keyboard port will absolutely wreck
battery life on these devices, so this can not be a real solution.

I wonder if this is yet another example of incorrect IRQ 1 polarity
override on devices with AMD chipsets (CC-ing Mario).

> 
> Signed-off-by: Friedrich Vock <friedrich.vock@gmx.de>
> ---
>  drivers/input/serio/i8042-acpipnpio.h | 30 +++++++++++++++--
>  drivers/input/serio/i8042.c           | 47 ++++++++++++++++++++++-----
>  drivers/input/serio/i8042.h           |  2 +-
>  3 files changed, 67 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
> index 028e45bd050b..be2e72aaa658 100644
> --- a/drivers/input/serio/i8042-acpipnpio.h
> +++ b/drivers/input/serio/i8042-acpipnpio.h
> @@ -83,6 +83,7 @@ static inline void i8042_write_command(int val)
>  #define SERIO_QUIRK_KBDRESET		BIT(12)
>  #define SERIO_QUIRK_DRITEK		BIT(13)
>  #define SERIO_QUIRK_NOPNP		BIT(14)
> +#define SERIO_QUIRK_POLL_KBD            BIT(15)
> 
>  /* Quirk table for different mainboards. Options similar or identical to i8042
>   * module parameters.
> @@ -99,6 +100,26 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
>  		},
>  		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
>  	},
> +	/* Some laptops seem to not trigger any keyboard interrupts at all,
> +	 * even when there is data available. On these devices, manually
> +	 * polling the keyboard port is required.
> +	 */
> +	{
> +		/* ASUS TUF Gaming A16 with Ryzen 7 7735HS */
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "FA617NS"),
> +		},
> +		.driver_data = (void *)(SERIO_QUIRK_POLL_KBD)
> +	},
> +	{
> +		/* ASUS TUF Gaming A16 with Ryzen 9 7940HS */
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "FA617XS"),
> +		},
> +		.driver_data = (void *)(SERIO_QUIRK_POLL_KBD)
> +	},
>  	{
>  		.matches = {
>  			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
> @@ -1634,6 +1655,8 @@ static void __init i8042_check_quirks(void)
>  	if (quirks & SERIO_QUIRK_NOPNP)
>  		i8042_nopnp = true;
>  #endif
> +	if (quirks & SERIO_QUIRK_POLL_KBD)
> +		i8042_poll_kbd = true;
>  }
>  #else
>  static inline void i8042_check_quirks(void) {}
> @@ -1667,7 +1690,7 @@ static int __init i8042_platform_init(void)
> 
>  	i8042_check_quirks();
> 
> -	pr_debug("Active quirks (empty means none):%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
> +	pr_debug("Active quirks (empty means none):%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
>  		i8042_nokbd ? " nokbd" : "",
>  		i8042_noaux ? " noaux" : "",
>  		i8042_nomux ? " nomux" : "",
> @@ -1687,10 +1710,11 @@ static int __init i8042_platform_init(void)
>  		"",
>  #endif
>  #ifdef CONFIG_PNP
> -		i8042_nopnp ? " nopnp" : "");
> +		i8042_nopnp ? " nopnp" : "",
>  #else
> -		"");
> +		"",
>  #endif
> +		i8042_poll_kbd ? "poll_kbd" : "");
> 
>  	retval = i8042_pnp_init();
>  	if (retval)
> diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
> index 6dac7c1853a5..7212263d3a41 100644
> --- a/drivers/input/serio/i8042.c
> +++ b/drivers/input/serio/i8042.c
> @@ -115,6 +115,10 @@ module_param_named(nopnp, i8042_nopnp, bool, 0);
>  MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
>  #endif
> 
> +static bool i8042_poll_kbd;
> +module_param_named(poll_kbd, i8042_poll_kbd, bool, 0);
> +MODULE_PARM_DESC(poll_kbd, "Continuously poll the KBD port instead of relying on interrupts");
> +
>  #define DEBUG
>  #ifdef DEBUG
>  static bool i8042_debug;
> @@ -178,6 +182,24 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id);
>  static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
>  				     struct serio *serio);
> 
> +#define POLL_TIME 1
> +static void i8042_poll_func(struct timer_list *timer)
> +{
> +	unsigned char status;
> +	unsigned long flags;
> +
> +	do {
> +		spin_lock_irqsave(&i8042_lock, flags);
> +		status = i8042_read_status();
> +		spin_unlock_irqrestore(&i8042_lock, flags);
> +		if (status & I8042_STR_OBF)
> +			i8042_interrupt(0, NULL);
> +	} while (status & I8042_STR_OBF);
> +	mod_timer(timer, jiffies + msecs_to_jiffies(POLL_TIME));
> +}
> +
> +DEFINE_TIMER(poll_timer, i8042_poll_func);
> +
>  void i8042_lock_chip(void)
>  {
>  	mutex_lock(&i8042_mutex);
> @@ -1437,13 +1459,15 @@ static void i8042_unregister_ports(void)
>  	}
>  }
> 
> +
>  static void i8042_free_irqs(void)
>  {
>  	if (i8042_aux_irq_registered)
>  		free_irq(I8042_AUX_IRQ, i8042_platform_device);
> -	if (i8042_kbd_irq_registered)
> +	if (i8042_poll_kbd)
> +		del_timer(&poll_timer);
> +	else if (i8042_kbd_irq_registered)
>  		free_irq(I8042_KBD_IRQ, i8042_platform_device);
> -
>  	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
>  }
> 
> @@ -1497,10 +1521,14 @@ static int i8042_setup_kbd(void)
>  	if (error)
>  		return error;
> 
> -	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
> -			    "i8042", i8042_platform_device);
> -	if (error)
> -		goto err_free_port;
> +	if (i8042_poll_kbd)
> +		mod_timer(&poll_timer, msecs_to_jiffies(POLL_TIME));
> +	else {
> +		error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
> +				    "i8042", i8042_platform_device);
> +		if (error)
> +			goto err_free_port;
> +	}
> 
>  	error = i8042_enable_kbd_port();
>  	if (error)
> @@ -1510,8 +1538,11 @@ static int i8042_setup_kbd(void)
>  	return 0;
> 
>   err_free_irq:
> -	free_irq(I8042_KBD_IRQ, i8042_platform_device);
> - err_free_port:
> +	if (i8042_poll_kbd)
> +		del_timer(&poll_timer);
> +	else
> +		free_irq(I8042_KBD_IRQ, i8042_platform_device);
> +err_free_port:
>  	i8042_free_kbd_port();
>  	return error;
>  }
> --
> 2.40.1
> 

Thanks.

-- 
Dmitry

  reply	other threads:[~2023-07-21 23:44 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-30 15:36 [PATCH] Input: i8042 - Add quirk for polling the KBD port Friedrich Vock
2023-07-21 23:44 ` Dmitry Torokhov [this message]
2023-07-22 15:35   ` Friedrich Vock
2023-07-23 15:45     ` Mario Limonciello

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ZLsYUlSMIK0Gtr21@google.com \
    --to=dmitry.torokhov@gmail.com \
    --cc=friedrich.vock@gmx.de \
    --cc=linux-input@vger.kernel.org \
    --cc=mario.limonciello@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.