2020-04-27 21:05:02

by Rajat Jain

[permalink] [raw]
Subject: [PATCH v5 1/3] input/serio/i8042: Attach fwnode to serio i8042 kbd device

Attach the firmware node to the serio i8042 kbd device so that device
properties can be passed from the firmware.

Signed-off-by: Rajat Jain <[email protected]>
---
v5: Same as v4
v4: Same as v3
v3: same as v2
v2: Remove the Change-Id from the commit log

drivers/input/serio/i8042-x86ia64io.h | 1 +
drivers/input/serio/i8042.c | 3 +++
2 files changed, 4 insertions(+)

diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 08e919dbeb5d1..d0c39426ca2c8 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -938,6 +938,7 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *
}
i8042_pnp_id_to_string(dev->id, i8042_kbd_firmware_id,
sizeof(i8042_kbd_firmware_id));
+ i8042_kbd_fwnode = dev_fwnode(&dev->dev);

/* Keyboard ports are always supposed to be wakeup-enabled */
device_set_wakeup_enable(&dev->dev, true);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 20ff2bed3917a..0dddf273afd94 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -21,6 +21,7 @@
#include <linux/i8042.h>
#include <linux/slab.h>
#include <linux/suspend.h>
+#include <linux/property.h>

#include <asm/io.h>

@@ -124,6 +125,7 @@ MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive da
static bool i8042_bypass_aux_irq_test;
static char i8042_kbd_firmware_id[128];
static char i8042_aux_firmware_id[128];
+static struct fwnode_handle *i8042_kbd_fwnode;

#include "i8042.h"

@@ -1335,6 +1337,7 @@ static int __init i8042_create_kbd_port(void)
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
strlcpy(serio->firmware_id, i8042_kbd_firmware_id,
sizeof(serio->firmware_id));
+ set_primary_fwnode(&serio->dev, i8042_kbd_fwnode);

port->serio = serio;
port->irq = I8042_KBD_IRQ;
--
2.26.2.303.gf8c07b1a785-goog


2020-04-27 21:05:02

by Rajat Jain

[permalink] [raw]
Subject: [PATCH v5 2/3] Input: atkbd: Expose function row physical map to userspace

Certain keyboards have their top-row keys intended
for actions such as "Browser back", "Browser Refresh", "Fullscreen"
etc as their primary mode, thus they will send physical codes for those
actions. Further, they don't have a dedicated "Fn" key so don't have
the capability to generate function key codes (e.g. F1, F2 etc..).
However in this case, if userspace still wants to "synthesize" those
function keys using the top row action keys, it needs to know the
physical position of the top row keys. (Essentially a mapping between
usage codes and a physical location in the top row).

This patch enhances the atkbd driver to receive such a mapping from the
firmware / device tree, and expose it to userspace in the form of
a function-row-physmap attribute. The attribute would be a space
separated ordered list of physical codes, for the keys in the function
row, in left-to-right order.

The attribute will only be present if the kernel knows about such
mapping, otherwise the attribute shall not be visible.

Signed-off-by: Rajat Jain <[email protected]>
---
v5: Change the size of each array element from u16 to u32
v4: Same as v3
v3: Change to dev_dbg and remove unecessary error check
v2: Remove the Change-Id from the commit log

drivers/input/keyboard/atkbd.c | 56 ++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)

diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 7e3eae54c1926..358e91f8888ff 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -24,6 +24,7 @@
#include <linux/libps2.h>
#include <linux/mutex.h>
#include <linux/dmi.h>
+#include <linux/property.h>

#define DRIVER_DESC "AT and PS/2 keyboard driver"

@@ -63,6 +64,8 @@ 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");

+#define MAX_FUNCTION_ROW_KEYS 24
+
/*
* Scancode to keycode tables. These are just the default setting, and
* are loadable via a userland utility.
@@ -230,6 +233,9 @@ struct atkbd {

/* Serializes reconnect(), attr->set() and event work */
struct mutex mutex;
+
+ u32 function_row_physmap[MAX_FUNCTION_ROW_KEYS];
+ int num_function_row_keys;
};

/*
@@ -283,6 +289,7 @@ static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);

ATKBD_DEFINE_RO_ATTR(err_count);
+ATKBD_DEFINE_RO_ATTR(function_row_physmap);

static struct attribute *atkbd_attributes[] = {
&atkbd_attr_extra.attr,
@@ -292,11 +299,42 @@ static struct attribute *atkbd_attributes[] = {
&atkbd_attr_softrepeat.attr,
&atkbd_attr_softraw.attr,
&atkbd_attr_err_count.attr,
+ &atkbd_attr_function_row_physmap.attr,
NULL
};

+static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf)
+{
+ ssize_t size = 0;
+ int i;
+
+ if (!atkbd->num_function_row_keys)
+ return 0;
+
+ for (i = 0; i < atkbd->num_function_row_keys; i++)
+ size += scnprintf(buf + size, PAGE_SIZE - size, "%02X ",
+ atkbd->function_row_physmap[i]);
+ size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
+ return size;
+}
+
+static umode_t atkbd_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct serio *serio = to_serio_port(dev);
+ struct atkbd *atkbd = serio_get_drvdata(serio);
+
+ if (attr == &atkbd_attr_function_row_physmap.attr &&
+ !atkbd->num_function_row_keys)
+ return 0;
+
+ return attr->mode;
+}
+
static struct attribute_group atkbd_attribute_group = {
.attrs = atkbd_attributes,
+ .is_visible = atkbd_attr_is_visible,
};

static const unsigned int xl_table[] = {
@@ -1121,6 +1159,22 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
}
}

+static void atkbd_parse_fwnode_data(struct serio *serio)
+{
+ struct atkbd *atkbd = serio_get_drvdata(serio);
+ struct device *dev = &serio->dev;
+ int n;
+
+ /* Parse "function-row-physmap" property */
+ n = device_property_count_u32(dev, "function-row-physmap");
+ if (n > 0 && n <= MAX_FUNCTION_ROW_KEYS &&
+ !device_property_read_u32_array(dev, "function-row-physmap",
+ atkbd->function_row_physmap, n)) {
+ atkbd->num_function_row_keys = n;
+ dev_dbg(dev, "FW reported %d function-row key locations\n", n);
+ }
+}
+
/*
* atkbd_connect() is called when the serio module finds an interface
* that isn't handled yet by an appropriate device driver. We check if
@@ -1184,6 +1238,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->id = 0xab00;
}

+ atkbd_parse_fwnode_data(serio);
+
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);

--
2.26.2.303.gf8c07b1a785-goog

2020-04-27 21:05:06

by Rajat Jain

[permalink] [raw]
Subject: [PATCH v5 3/3] Input: atkbd: Receive and use physcode->keycode mapping from FW

Allow the firmware to specify the mapping between the physical
code and the linux keycode. This takes the form of a "linux,keymap"
property which is an array of u32 values, each value specifying
mapping for a key.

Signed-off-by: Rajat Jain <[email protected]>
---
v5: Same as v4
v4: Property name "keymap" -> "linux,keymap"
v3: Don't save the FW mapping in atkbd device.
v2: Remove the Change-Id from the commit log

drivers/input/keyboard/atkbd.c | 41 +++++++++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 358e91f8888ff..9d7594dcc4a47 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -66,6 +66,9 @@ MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard conne

#define MAX_FUNCTION_ROW_KEYS 24

+#define PHYSCODE(keymap) ((keymap >> 16) & 0xFFFF)
+#define KEYCODE(keymap) (keymap & 0xFFFF)
+
/*
* Scancode to keycode tables. These are just the default setting, and
* are loadable via a userland utility.
@@ -1032,6 +1035,38 @@ static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
return code;
}

+static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
+{
+ struct device *dev = &atkbd->ps2dev.serio->dev;
+ int i, n;
+ u32 *ptr;
+ u16 physcode, keycode;
+
+ /* Parse "linux,keymap" property */
+ n = device_property_count_u32(dev, "linux,keymap");
+ if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
+ return -ENXIO;
+
+ ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
+ dev_err(dev, "problem parsing FW keymap property\n");
+ kfree(ptr);
+ return -EINVAL;
+ }
+
+ memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
+ for (i = 0; i < n; i++) {
+ physcode = PHYSCODE(ptr[i]);
+ keycode = KEYCODE(ptr[i]);
+ atkbd->keycode[physcode] = keycode;
+ }
+ kfree(ptr);
+ return 0;
+}
+
/*
* atkbd_set_keycode_table() initializes keyboard's keycode table
* according to the selected scancode set
@@ -1039,13 +1074,16 @@ static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,

static void atkbd_set_keycode_table(struct atkbd *atkbd)
{
+ struct device *dev = &atkbd->ps2dev.serio->dev;
unsigned int scancode;
int i, j;

memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);

- if (atkbd->translated) {
+ if (!atkbd_get_keymap_from_fwnode(atkbd)) {
+ dev_dbg(dev, "Using FW keymap\n");
+ } else if (atkbd->translated) {
for (i = 0; i < 128; i++) {
scancode = atkbd_unxlate_table[i];
atkbd->keycode[i] = atkbd_set2_keycode[scancode];
@@ -1173,6 +1211,7 @@ static void atkbd_parse_fwnode_data(struct serio *serio)
atkbd->num_function_row_keys = n;
dev_dbg(dev, "FW reported %d function-row key locations\n", n);
}
+
}

/*
--
2.26.2.303.gf8c07b1a785-goog