|
@@ -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
|