diff mbox series

[1/3] Input: atkbd - add skip_commands module parameter

Message ID 20231005201544.26983-2-hdegoede@redhat.com
State New
Headers show
Series [1/3] Input: atkbd - add skip_commands module parameter | expand

Commit Message

Hans de Goede Oct. 5, 2023, 8:15 p.m. UTC
While debugging a keyboard issue on some HP laptops (see link)
adding i8042.dumbkbd helped to avoid the issue. So one of the commands
send by atkbd.c seemed to be the culprit.

Add a skip_commands option to help debug cases like this by adding
a bit-field which allows disabling a subset of the ps2_command()
calls the atkbd driver makes.

This also avoids the need to add special flags for each command
which atkbd needs to skip on certain models, like e.g. the existing
atkbd_skip_deactivate flag.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2086156
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
The next patch in this series replaces the atkbd_skip_deactivate flag
with using atbkd_skip_commands to avoid having 2 deactivate skip checks.
---
 drivers/input/keyboard/atkbd.c | 52 ++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index c92e544c792d..7c16f9cc1e40 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -65,6 +65,10 @@  static bool atkbd_terminal;
 module_param_named(terminal, atkbd_terminal, bool, 0);
 MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
 
+static int atkbd_skip_commands;
+module_param_named(skip_commands, atkbd_skip_commands, int, 0444);
+MODULE_PARM_DESC(skip_commands, "Bitfield where each bits skips a specific keyboard cmd (0 - 0x3f)");
+
 #define SCANCODE(keymap)	((keymap >> 16) & 0xFFFF)
 #define KEYCODE(keymap)		(keymap & 0xFFFF)
 
@@ -182,6 +186,13 @@  static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_XL_HANGEUL	0x10
 #define ATKBD_XL_HANJA		0x20
 
+#define ATKBD_SKIP_GETID	0x01l
+#define ATKBD_SKIP_ACTIVATE	0x02l
+#define ATKBD_SKIP_DEACTIVATE	0x04l
+#define ATKBD_SKIP_SETREP	0x08l
+#define ATKBD_SKIP_SETLEDS	0x10l
+#define ATKBD_SKIP_RESET_DEF	0x20l
+
 static const struct {
 	unsigned short keycode;
 	unsigned char set2;
@@ -592,6 +603,9 @@  static int atkbd_set_repeat_rate(struct atkbd *atkbd)
 	unsigned char param;
 	int i = 0, j = 0;
 
+	if (atkbd_skip_commands & ATKBD_SKIP_SETREP)
+		return 0;
+
 	while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
 		i++;
 	dev->rep[REP_PERIOD] = period[i];
@@ -609,6 +623,9 @@  static int atkbd_set_leds(struct atkbd *atkbd)
 	struct input_dev *dev = atkbd->dev;
 	unsigned char param[2];
 
+	if (atkbd_skip_commands & ATKBD_SKIP_SETLEDS)
+		return 0;
+
 	param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
 		 | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
 		 | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
@@ -736,6 +753,9 @@  static int atkbd_activate(struct atkbd *atkbd)
 {
 	struct ps2dev *ps2dev = &atkbd->ps2dev;
 
+	if (atkbd_skip_commands & ATKBD_SKIP_ACTIVATE)
+		return 0;
+
 /*
  * Enable the keyboard to receive keystrokes.
  */
@@ -759,6 +779,9 @@  static void atkbd_deactivate(struct atkbd *atkbd)
 {
 	struct ps2dev *ps2dev = &atkbd->ps2dev;
 
+	if (atkbd_skip_commands & ATKBD_SKIP_DEACTIVATE)
+		return;
+
 	if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
 		dev_err(&ps2dev->serio->dev,
 			"Failed to deactivate keyboard on %s\n",
@@ -786,6 +809,13 @@  static int atkbd_probe(struct atkbd *atkbd)
 				 "keyboard reset failed on %s\n",
 				 ps2dev->serio->phys);
 
+/* Only skip probe for translated keyboards to avoid mis-identifying mice */
+	if (atkbd->translated && (atkbd_skip_commands & ATKBD_SKIP_GETID)) {
+		atkbd->id = 0xab00;
+		atkbd_deactivate(atkbd);
+		return 0;
+	}
+
 /*
  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
  * Some keyboards report different values, but the first byte is always 0xab or
@@ -802,7 +832,8 @@  static int atkbd_probe(struct atkbd *atkbd)
  * the LEDs off, which we want anyway.
  */
 		param[0] = 0;
-		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
+		if (!(atkbd_skip_commands & ATKBD_SKIP_SETLEDS) &&
+		    ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
 			return -1;
 		atkbd->id = 0xabba;
 		return 0;
@@ -906,17 +937,21 @@  static int atkbd_reset_state(struct atkbd *atkbd)
  * Set the LEDs to a predefined state (all off).
  */
 
-	param[0] = 0;
-	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
-		return -1;
+	if (!(atkbd_skip_commands & ATKBD_SKIP_SETLEDS)) {
+		param[0] = 0;
+		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
+			return -1;
+	}
 
 /*
  * Set autorepeat to fastest possible.
  */
 
-	param[0] = 0;
-	if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
-		return -1;
+	if (!(atkbd_skip_commands & ATKBD_SKIP_SETREP)) {
+		param[0] = 0;
+		if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
+			return -1;
+	}
 
 	return 0;
 }
@@ -931,7 +966,8 @@  static void atkbd_cleanup(struct serio *serio)
 	struct atkbd *atkbd = atkbd_from_serio(serio);
 
 	atkbd_disable(atkbd);
-	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
+	if (!(atkbd_skip_commands & ATKBD_SKIP_RESET_DEF))
+		ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
 }