diff options
| -rw-r--r-- | drivers/input/Makefile | 2 | ||||
| -rw-r--r-- | drivers/input/key_matrix.c | 208 | ||||
| -rw-r--r-- | include/key_matrix.h | 99 | 
3 files changed, 309 insertions, 0 deletions
| diff --git a/drivers/input/Makefile b/drivers/input/Makefile index d06acb9c9..5c831b261 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -26,11 +26,13 @@ include $(TOPDIR)/config.mk  LIB	:= $(obj)libinput.o  COBJS-$(CONFIG_I8042_KBD) += i8042.o +COBJS-$(CONFIG_TEGRA2_KEYBOARD) += tegra-kbc.o  ifdef CONFIG_PS2KBD  COBJS-y += keyboard.o pc_keyb.o  COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o  endif  COBJS-y += input.o +COBJS-$(CONFIG_OF_CONTROL) += key_matrix.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/input/key_matrix.c b/drivers/input/key_matrix.c new file mode 100644 index 000000000..84b898ff3 --- /dev/null +++ b/drivers/input/key_matrix.c @@ -0,0 +1,208 @@ +/* + * Manage Keyboard Matrices + * + * Copyright (c) 2012 The Chromium OS Authors. + * (C) Copyright 2004 DENX Software Engineering, Wolfgang Denk, wd@denx.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <fdtdec.h> +#include <key_matrix.h> +#include <malloc.h> +#include <linux/input.h> + +/** + * Determine if the current keypress configuration can cause key ghosting + * + * We figure this out by seeing if we have two or more keys in the same + * column, as well as two or more keys in the same row. + * + * @param config	Keyboard matrix config + * @param keys		List of keys to check + * @param valid		Number of valid keypresses to check + * @return 0 if no ghosting is possible, 1 if it is + */ +static int has_ghosting(struct key_matrix *config, struct key_matrix_key *keys, +			int valid) +{ +	int key_in_same_col = 0, key_in_same_row = 0; +	int i, j; + +	for (i = 0; i < valid; i++) { +		/* +		 * Find 2 keys such that one key is in the same row +		 * and the other is in the same column as the i-th key. +		 */ +		for (j = i + 1; j < valid; j++) { +			if (keys[j].col == keys[i].col) +				key_in_same_col = 1; +			if (keys[j].row == keys[i].row) +				key_in_same_row = 1; +		} +	} + +	if (key_in_same_col && key_in_same_row) +		return 1; +	else +		return 0; +} + +int key_matrix_decode(struct key_matrix *config, struct key_matrix_key keys[], +		      int num_keys, int keycode[], int max_keycodes) +{ +	const u8 *keymap; +	int valid, upto; +	int pos; + +	debug("%s: num_keys = %d\n", __func__, num_keys); +	keymap = config->plain_keycode; +	for (valid = upto = 0; upto < num_keys; upto++) { +		struct key_matrix_key *key = &keys[upto]; + +		debug("  valid=%d, row=%d, col=%d\n", key->valid, key->row, +		      key->col); +		if (!key->valid) +			continue; +		pos = key->row * config->num_cols + key->col; +		if (config->fn_keycode && pos == config->fn_pos) +			keymap = config->fn_keycode; + +		/* Convert the (row, col) values into a keycode */ +		if (valid < max_keycodes) +			keycode[valid++] = keymap[pos]; +		debug("    keycode=%d\n", keymap[pos]); +	} + +	/* For a ghost key config, ignore the keypresses for this iteration. */ +	if (valid >= 3 && has_ghosting(config, keys, valid)) { +		valid = 0; +		debug("    ghosting detected!\n"); +	} +	debug("  %d valid keycodes found\n", valid); + +	return valid; +} + +/** + * Create a new keycode map from some provided data + * + * This decodes a keycode map in the format used by the fdt, which is one + * word per entry, with the row, col and keycode encoded in that word. + * + * We create a (row x col) size byte array with each entry containing the + * keycode for that (row, col). We also search for map_keycode and return + * its position if found (this is used for finding the Fn key). + * + * @param config        Key matrix dimensions structure + * @param data          Keycode data + * @param len           Number of entries in keycode table + * @param map_keycode   Key code to find in the map + * @param pos           Returns position of map_keycode, if found, else -1 + * @return map  Pointer to allocated map + */ +static uchar *create_keymap(struct key_matrix *config, u32 *data, int len, +			    int map_keycode, int *pos) +{ +	uchar *map; + +	if (pos) +		*pos = -1; +	map = (uchar *)calloc(1, config->key_count); +	if (!map) { +		debug("%s: failed to malloc %d bytes\n", __func__, +			config->key_count); +		return NULL; +	} + +	for (; len >= sizeof(u32); data++, len -= 4) { +		u32 tmp = fdt32_to_cpu(*data); +		int key_code, row, col; +		int entry; + +		row = (tmp >> 24) & 0xff; +		col = (tmp >> 16) & 0xff; +		key_code = tmp & 0xffff; +		entry = row * config->num_cols + col; +		map[entry] = key_code; +		if (pos && map_keycode == key_code) +			*pos = entry; +	} + +	return map; +} + +int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, +			  int node) +{ +	const struct fdt_property *prop; +	int offset; + +	/* Check each property name for ones that we understand */ +	for (offset = fdt_first_property_offset(blob, node); +		      offset > 0; +		      offset = fdt_next_property_offset(blob, offset)) { +		const char *name; +		int len; + +		prop = fdt_get_property_by_offset(blob, offset, NULL); +		name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); +		len = strlen(name); + +		/* Name needs to match "1,<type>keymap" */ +		debug("%s: property '%s'\n", __func__, name); +		if (strncmp(name, "1,", 2) || len < 8 || +		    strcmp(name + len - 6, "keymap")) +			continue; + +		len -= 8; +		if (len == 0) { +			config->plain_keycode = create_keymap(config, +				(u32 *)prop->data, fdt32_to_cpu(prop->len), +				KEY_FN, &config->fn_pos); +		} else if (0 == strncmp(name + 2, "fn-", len)) { +			config->fn_keycode = create_keymap(config, +				(u32 *)prop->data, fdt32_to_cpu(prop->len), +				-1, NULL); +		} else { +			debug("%s: unrecognised property '%s'\n", __func__, +			      name); +		} +	} +	debug("%s: Decoded key maps %p, %p from fdt\n", __func__, +	      config->plain_keycode, config->fn_keycode); + +	if (!config->plain_keycode) { +		debug("%s: cannot find keycode-plain map\n", __func__); +		return -1; +	} + +	return 0; +} + +int key_matrix_init(struct key_matrix *config, int rows, int cols) +{ +	memset(config, '\0', sizeof(*config)); +	config->num_rows = rows; +	config->num_cols = cols; +	config->key_count = rows * cols; +	assert(config->key_count > 0); + +	return 0; +} diff --git a/include/key_matrix.h b/include/key_matrix.h new file mode 100644 index 000000000..f41331407 --- /dev/null +++ b/include/key_matrix.h @@ -0,0 +1,99 @@ +/* + * Keyboard matrix helper functions + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _KEY_MATRIX_H +#define _KEY_MATRIX_H + +#include <common.h> + +/* Information about a matrix keyboard */ +struct key_matrix { +	/* Dimensions of the keyboard matrix, in rows and columns */ +	int num_rows; +	int num_cols; +	int key_count;	/* number of keys in the matrix (= rows * cols) */ + +	/* +	 * Information about keycode mappings. The plain_keycode array must +	 * exist but fn may be NULL in which case it is not decoded. +	 */ +	const u8 *plain_keycode;        /* key code for each row / column */ +	const u8 *fn_keycode;           /* ...when Fn held down */ +	int fn_pos;                     /* position of Fn key in key (or -1) */ +}; + +/* Information about a particular key (row, column pair) in the matrix */ +struct key_matrix_key { +	uint8_t row;	/* row number (0 = first) */ +	uint8_t col;	/* column number (0 = first) */ +	uint8_t valid;	/* 1 if valid, 0 to ignore this */ +}; + +/** + * Decode a set of pressed keys into key codes + * + * Given a list of keys that are pressed, this converts this list into + * a list of key codes. Each of the keys has a valid flag, which can be + * used to mark a particular key as invalid (so that it is ignored). + * + * The plain keymap is used, unless the Fn key is detected along the way, + * at which point we switch to the Fn key map. + * + * If key ghosting is detected, we simply ignore the keys and return 0. + * + * @param config        Keyboard matrix config + * @param keys		List of keys to process (each is row, col) + * @param num_keys	Number of keys to process + * @param keycode	Returns a list of key codes, decoded from input + * @param max_keycodes	Size of key codes array (suggest 8) + * + */ +int key_matrix_decode(struct key_matrix *config, struct key_matrix_key *keys, +		      int num_keys, int keycode[], int max_keycodes); + +/** + * Read the keyboard configuration out of the fdt. + * + * Decode properties of named "linux,<type>keymap" where <type> is either + * empty, or "fn-". Then set up the plain key map (and the FN keymap if + * present). + * + * @param config        Keyboard matrix config + * @param blob          FDT blob + * @param node          Node containing compatible data + * @return 0 if ok, -1 on error + */ +int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, +			  int node); + +/** + * Set up a new key matrix. + * + * @param config	Keyboard matrix config + * @param rows		Number of rows in key matrix + * @param cols		Number of columns in key matrix + * @return 0 if ok, -1 on error + */ +int key_matrix_init(struct key_matrix *config, int rows, int cols); + +#endif |