We don't need to allocate memory for keymap in matrix_keyboard_of_fill_keymap(), as this would only be used by matrix_keyboard_of_free_keymap(). Instead create another routine matrix_keypad_of_build_keymap() which reads directly the property from struct device_node and builds keymap. With this eariler routines matrix_keyboard_of_fill_keymap() and matrix_keyboard_of_free_keymap() go away. This patch also fixes tegra driver according to these changes. Signed-off-by: Viresh Kumar <viresh.kumar@xxxxxx> --- V4: - check return value of MATRIX_SCAN_CODE() to guarantee that it doesn't overflow keycodemax sized buffer. drivers/input/keyboard/tegra-kbc.c | 48 ++++++++++-------- drivers/input/of_keymap.c | 98 ++++++++++++++++++++-------------- include/linux/input/matrix_keypad.h | 16 ++---- 3 files changed, 89 insertions(+), 73 deletions(-) diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 21c42f8..04967e0 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -619,11 +619,10 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, } #ifdef CONFIG_OF -static struct tegra_kbc_platform_data * __devinit -tegra_kbc_dt_parse_pdata(struct platform_device *pdev) +static struct tegra_kbc_platform_data * +__devinit tegra_kbc_dt_parse_pdata(struct device_node *np) { struct tegra_kbc_platform_data *pdata; - struct device_node *np = pdev->dev.of_node; u32 prop; int i; @@ -659,15 +658,11 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev) pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL; } - pdata->keymap_data = matrix_keyboard_of_fill_keymap(np, "linux,keymap"); - - /* FIXME: Add handling of linux,fn-keymap here */ - return pdata; } #else -static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata( - struct platform_device *pdev) +static struct tegra_kbc_platform_data * +__devinit tegra_kbc_dt_parse_pdata(struct device_node *np) { return NULL; } @@ -676,7 +671,7 @@ static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata( static int __devinit tegra_kbc_probe(struct platform_device *pdev) { const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data; + struct device_node *np = NULL; struct tegra_kbc *kbc; struct input_dev *input_dev; struct resource *res; @@ -686,8 +681,10 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) unsigned int debounce_cnt; unsigned int scan_time_rows; - if (!pdata) - pdata = tegra_kbc_dt_parse_pdata(pdev); + if (!pdata) { + np = pdev->dev.of_node; + pdata = tegra_kbc_dt_parse_pdata(np); + } if (!pdata) return -EINVAL; @@ -775,9 +772,23 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) kbc->use_fn_map = pdata->use_fn_map; kbc->use_ghost_filter = pdata->use_ghost_filter; - keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data; - matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT, - input_dev->keycode, input_dev->keybit); + + if (np) { + /* FIXME: Add handling of linux,fn-keymap here */ + err = matrix_keypad_of_build_keymap(input_dev, KBC_ROW_SHIFT, + "linux,keymap"); + if (err) { + dev_err(&pdev->dev, "OF: failed to build keymap\n"); + goto err_put_clk; + } + } else { + const struct matrix_keymap_data *keymap_data = + pdata->keymap_data ?: &tegra_kbc_default_keymap_data; + + matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT, + input_dev->keycode, input_dev->keybit); + } + kbc->wakeup_key = pdata->wakeup_key; err = request_irq(kbc->irq, tegra_kbc_isr, @@ -798,9 +809,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, kbc); device_init_wakeup(&pdev->dev, pdata->wakeup); - if (!pdev->dev.platform_data) - matrix_keyboard_of_free_keymap(pdata->keymap_data); - return 0; err_free_irq: @@ -815,10 +823,8 @@ err_free_mem: input_free_device(input_dev); kfree(kbc); err_free_pdata: - if (!pdev->dev.platform_data) { - matrix_keyboard_of_free_keymap(pdata->keymap_data); + if (!pdev->dev.platform_data) kfree(pdata); - } return err; } diff --git a/drivers/input/of_keymap.c b/drivers/input/of_keymap.c index 061493d..631054f 100644 --- a/drivers/input/of_keymap.c +++ b/drivers/input/of_keymap.c @@ -17,6 +17,7 @@ * */ +#include <linux/device.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/input.h> @@ -26,62 +27,79 @@ #include <linux/gfp.h> #include <linux/slab.h> -struct matrix_keymap_data * -matrix_keyboard_of_fill_keymap(struct device_node *np, - const char *propname) +/** + * matrix_keypad_of_build_keymap - convert platform DT keymap into matrix keymap + * @idev: pointer to struct input_dev; used for getting keycode, keybit and + * keycodemax. + * @row_shift: number of bits to shift row value by to advance to the next + * line in the keymap + * @propname: Device Tree property name to be used for reading keymap. If passed + * as NULL, "linux,keymap" is used. + * + * This function creates an array of keycodes, by reading propname property from + * device tree passed, that is suitable for using in a standard matrix keyboard + * driver that uses row and col as indices. + * + * Expectation from user driver: idev must be initialized with following fields: + * dev.parent, keycode, keybit and keycodemax. + */ +int matrix_keypad_of_build_keymap(struct input_dev *idev, + unsigned int row_shift, const char *propname) { - struct matrix_keymap_data *kd; - u32 *keymap; - int proplen, i; + struct device *dev = idev->dev.parent; + struct device_node *np = dev->of_node; + unsigned short *keycode; const __be32 *prop; + unsigned int proplen, i, size, col_range = 1 << row_shift, index; - if (!np) - return NULL; + if (!np || !idev) + return -ENODEV; if (!propname) propname = "linux,keymap"; prop = of_get_property(np, propname, &proplen); - if (!prop) - return NULL; + if (!prop) { + dev_err(dev, "OF: %s property not defined in %s\n", propname, + np->full_name); + return -ENODEV; + } if (proplen % sizeof(u32)) { - pr_warn("Malformed keymap property %s in %s\n", - propname, np->full_name); - return NULL; + dev_warn(dev, "Malformed keycode property %s in %s\n", propname, + np->full_name); + return -EINVAL; } - kd = kzalloc(sizeof(*kd), GFP_KERNEL); - if (!kd) - return NULL; - - kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL); - if (!kd->keymap) { - kfree(kd); - return NULL; + size = proplen / sizeof(u32); + if (size > idev->keycodemax) { + dev_err(dev, "OF: %s size overflow\n", propname); + return -EINVAL; } - kd->keymap_size = proplen / sizeof(u32); + keycode = idev->keycode; + for (i = 0; i < size; i++) { + unsigned int key = be32_to_cpup(prop + i); + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short code = KEY_VAL(key); - for (i = 0; i < kd->keymap_size; i++) { - u32 tmp = be32_to_cpup(prop + i); - int key_code, row, col; + if (col >= col_range) { + dev_err(dev, "OF: %s: column %x overflowed its range %d\n", + propname, col, col_range); + return -EINVAL; + } - row = (tmp >> 24) & 0xff; - col = (tmp >> 16) & 0xff; - key_code = tmp & 0xffff; - keymap[i] = KEY(row, col, key_code); + index = MATRIX_SCAN_CODE(row, col, row_shift); + if (index > idev->keycodemax) { + dev_err(dev, "OF: %s index overflow\n", propname); + return -EINVAL; + } + keycode[index] = code; + __set_bit(code, idev->keybit); } + __clear_bit(KEY_RESERVED, idev->keybit); - 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); - } + return 0; } -EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap); +EXPORT_SYMBOL_GPL(matrix_keypad_of_build_keymap); diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h index 6c07ced..341aca1 100644 --- a/include/linux/input/matrix_keypad.h +++ b/include/linux/input/matrix_keypad.h @@ -108,21 +108,13 @@ matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, } #ifdef CONFIG_INPUT_OF_MATRIX_KEYMAP -struct matrix_keymap_data * -matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname); - -void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd); +int matrix_keypad_of_build_keymap(struct input_dev *idev, + unsigned int row_shift, const char *propname); #else -static inline struct matrix_keymap_data * -matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname) +int matrix_keypad_of_build_keymap(struct input_dev *idev, + unsigned int row_shift, const char *propname) { return NULL; } - -static inline void -matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd) -{ -} #endif - #endif /* _MATRIX_KEYPAD_H */ -- 1.7.9 -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html