diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-05-10 22:37:15 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-05-10 22:39:43 -0700 |
commit | b45c8f35a7fec17bdd159a7815203b6137c00ab9 (patch) | |
tree | c6fc8efe76ff2b382e8290d6df59129200032a5d /drivers/input/matrix-keymap.c | |
parent | 1932811f426fee71b7ece67e70aeba7e1b0ebb6d (diff) | |
download | linux-b45c8f35a7fec17bdd159a7815203b6137c00ab9.tar.gz linux-b45c8f35a7fec17bdd159a7815203b6137c00ab9.tar.bz2 linux-b45c8f35a7fec17bdd159a7815203b6137c00ab9.zip |
Input: matrix-keymap - wire up device tree support
When platform keymap is not supplied to matrix_keypad_build_keymap()
and device tree support is enabled, try locating specified property
and load keymap from it. If property name is not defined, try using
"linux,keymap".
Based on earlier patch by Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/matrix-keymap.c')
-rw-r--r-- | drivers/input/matrix-keymap.c | 175 |
1 files changed, 98 insertions, 77 deletions
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c index de7992d55da2..db92c1ebfc59 100644 --- a/drivers/input/matrix-keymap.c +++ b/drivers/input/matrix-keymap.c @@ -17,15 +17,91 @@ * */ +#include <linux/device.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/input.h> #include <linux/of.h> #include <linux/export.h> -#include <linux/gfp.h> -#include <linux/slab.h> #include <linux/input/matrix_keypad.h> +static bool matrix_keypad_map_key(struct input_dev *input_dev, + unsigned int rows, unsigned int cols, + unsigned int row_shift, unsigned int key) +{ + unsigned char *keymap = input_dev->keycode; + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short code = KEY_VAL(key); + + if (row >= rows || col >= cols) { + dev_err(input_dev->dev.parent, + "%s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d)\n", + __func__, key, row, col, rows, cols); + return false; + } + + keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code; + __set_bit(code, input_dev->keybit); + + return true; +} + +#ifdef CONFIG_OF +static int matrix_keypad_parse_of_keymap(const char *propname, + unsigned int rows, unsigned int cols, + struct input_dev *input_dev) +{ + struct device *dev = input_dev->dev.parent; + struct device_node *np = dev->of_node; + unsigned int row_shift = get_count_order(cols); + unsigned int max_keys = rows << row_shift; + unsigned int proplen, i, size; + const __be32 *prop; + + if (!np) + return -ENOENT; + + if (!propname) + propname = "linux,keymap"; + + prop = of_get_property(np, propname, &proplen); + if (!prop) { + dev_err(dev, "OF: %s property not defined in %s\n", + propname, np->full_name); + return -ENOENT; + } + + if (proplen % sizeof(u32)) { + dev_err(dev, "OF: Malformed keycode property %s in %s\n", + propname, np->full_name); + return -EINVAL; + } + + size = proplen / sizeof(u32); + if (size > max_keys) { + dev_err(dev, "OF: %s size overflow\n", propname); + return -EINVAL; + } + + for (i = 0; i < size; i++) { + unsigned int key = be32_to_cpup(prop + i); + + if (!matrix_keypad_map_key(input_dev, rows, cols, + row_shift, key)) + return -EINVAL; + } + + return 0; +} +#else +static int matrix_keypad_parse_of_keymap(const char *propname, + unsigned int rows, unsigned int cols, + struct input_dev *input_dev) +{ + return -ENOSYS; +} +#endif /** * matrix_keypad_build_keymap - convert platform keymap into matrix keymap @@ -41,6 +117,13 @@ * This function converts platform keymap (encoded with KEY() macro) into * an array of keycodes that is suitable for using in a standard matrix * keyboard driver that uses row and col as indices. + * + * If @keymap_data is not supplied and device tree support is enabled + * it will attempt load the keymap from property specified by @keymap_name + * argument (or "linux,keymap" if @keymap_name is %NULL). + * + * Callers are expected to set up input_dev->dev.parent before calling this + * function. */ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, const char *keymap_name, @@ -50,6 +133,7 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, { unsigned int row_shift = get_count_order(cols); int i; + int error; input_dev->keycode = keymap; input_dev->keycodesize = sizeof(*keymap); @@ -57,86 +141,23 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, __set_bit(EV_KEY, input_dev->evbit); - for (i = 0; i < keymap_data->keymap_size; i++) { - unsigned int key = keymap_data->keymap[i]; - unsigned int row = KEY_ROW(key); - unsigned int col = KEY_COL(key); - unsigned short code = KEY_VAL(key); + if (keymap_data) { + for (i = 0; i < keymap_data->keymap_size; i++) { + unsigned int key = keymap_data->keymap[i]; - if (row >= rows || col >= cols) { - dev_err(input_dev->dev.parent, - "%s: invalid keymap entry %d (row: %d, col: %d, rows: %d, cols: %d)\n", - __func__, i, row, col, rows, cols); - return -EINVAL; + if (!matrix_keypad_map_key(input_dev, rows, cols, + row_shift, key)) + return -EINVAL; } - - keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code; - __set_bit(code, input_dev->keybit); + } else { + error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols, + input_dev); + if (error) + return error; } + __clear_bit(KEY_RESERVED, input_dev->keybit); return 0; } EXPORT_SYMBOL(matrix_keypad_build_keymap); - -#ifdef CONFIG_OF -struct matrix_keymap_data * -matrix_keyboard_of_fill_keymap(struct device_node *np, - const char *propname) -{ - struct matrix_keymap_data *kd; - u32 *keymap; - int proplen, i; - const __be32 *prop; - - if (!np) - return NULL; - - if (!propname) - propname = "linux,keymap"; - - prop = of_get_property(np, propname, &proplen); - if (!prop) - return NULL; - - if (proplen % sizeof(u32)) { - pr_warn("Malformed keymap property %s in %s\n", - propname, np->full_name); - return NULL; - } - - kd = kzalloc(sizeof(*kd), GFP_KERNEL); - if (!kd) - return NULL; - - kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL); - if (!kd->keymap) { - kfree(kd); - return NULL; - } - - kd->keymap_size = proplen / sizeof(u32); - - for (i = 0; i < kd->keymap_size; i++) { - u32 tmp = be32_to_cpup(prop + i); - int key_code, row, col; - - row = (tmp >> 24) & 0xff; - col = (tmp >> 16) & 0xff; - key_code = tmp & 0xffff; - keymap[i] = KEY(row, col, key_code); - } - - return kd; -} -EXPORT_SYMBOL_GPL(matrix_keyboard_of_fill_keymap); - -void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd) -{ - if (kd) { - kfree(kd->keymap); - kfree(kd); - } -} -EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap); -#endif |