Commit 9d17ad23 authored by Rajat Jain's avatar Rajat Jain Committed by Dmitry Torokhov
Browse files

Input: atkbd - receive and use physcode->keycode mapping from FW



Allow the firmware to specify the mapping between the scan 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: default avatarRajat Jain <rajatja@google.com>
Link: https://lore.kernel.org/r/20200427210259.91330-3-rajatja@google.com


Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 8f7b057a
Loading
Loading
Loading
Loading
+40 −1
Original line number Diff line number Diff line
@@ -66,6 +66,9 @@ MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard conne

#define MAX_FUNCTION_ROW_KEYS	24

#define SCANCODE(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,39 @@ 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 scancode, 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++) {
		scancode = SCANCODE(ptr[i]);
		keycode = KEYCODE(ptr[i]);
		atkbd->keycode[scancode] = keycode;
	}

	kfree(ptr);
	return 0;
}

/*
 * atkbd_set_keycode_table() initializes keyboard's keycode table
 * according to the selected scancode set
@@ -1039,13 +1075,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];