1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/device.h>
21#include <linux/gfp.h>
22#include <linux/kernel.h>
23#include <linux/types.h>
24#include <linux/input.h>
25#include <linux/of.h>
26#include <linux/export.h>
27#include <linux/module.h>
28#include <linux/input/matrix_keypad.h>
29
30static bool matrix_keypad_map_key(struct input_dev *input_dev,
31 unsigned int rows, unsigned int cols,
32 unsigned int row_shift, unsigned int key)
33{
34 unsigned short *keymap = input_dev->keycode;
35 unsigned int row = KEY_ROW(key);
36 unsigned int col = KEY_COL(key);
37 unsigned short code = KEY_VAL(key);
38
39 if (row >= rows || col >= cols) {
40 dev_err(input_dev->dev.parent,
41 "%s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d)\n",
42 __func__, key, row, col, rows, cols);
43 return false;
44 }
45
46 keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
47 __set_bit(code, input_dev->keybit);
48
49 return true;
50}
51
52#ifdef CONFIG_OF
53int matrix_keypad_parse_of_params(struct device *dev,
54 unsigned int *rows, unsigned int *cols)
55{
56 struct device_node *np = dev->of_node;
57
58 if (!np) {
59 dev_err(dev, "missing DT data");
60 return -EINVAL;
61 }
62 of_property_read_u32(np, "keypad,num-rows", rows);
63 of_property_read_u32(np, "keypad,num-columns", cols);
64 if (!*rows || !*cols) {
65 dev_err(dev, "number of keypad rows/columns not specified\n");
66 return -EINVAL;
67 }
68
69 return 0;
70}
71EXPORT_SYMBOL_GPL(matrix_keypad_parse_of_params);
72
73static int matrix_keypad_parse_of_keymap(const char *propname,
74 unsigned int rows, unsigned int cols,
75 struct input_dev *input_dev)
76{
77 struct device *dev = input_dev->dev.parent;
78 struct device_node *np = dev->of_node;
79 unsigned int row_shift = get_count_order(cols);
80 unsigned int max_keys = rows << row_shift;
81 unsigned int proplen, i, size;
82 const __be32 *prop;
83
84 if (!np)
85 return -ENOENT;
86
87 if (!propname)
88 propname = "linux,keymap";
89
90 prop = of_get_property(np, propname, &proplen);
91 if (!prop) {
92 dev_err(dev, "OF: %s property not defined in %s\n",
93 propname, np->full_name);
94 return -ENOENT;
95 }
96
97 if (proplen % sizeof(u32)) {
98 dev_err(dev, "OF: Malformed keycode property %s in %s\n",
99 propname, np->full_name);
100 return -EINVAL;
101 }
102
103 size = proplen / sizeof(u32);
104 if (size > max_keys) {
105 dev_err(dev, "OF: %s size overflow\n", propname);
106 return -EINVAL;
107 }
108
109 for (i = 0; i < size; i++) {
110 unsigned int key = be32_to_cpup(prop + i);
111
112 if (!matrix_keypad_map_key(input_dev, rows, cols,
113 row_shift, key))
114 return -EINVAL;
115 }
116
117 return 0;
118}
119#else
120static int matrix_keypad_parse_of_keymap(const char *propname,
121 unsigned int rows, unsigned int cols,
122 struct input_dev *input_dev)
123{
124 return -ENOSYS;
125}
126#endif
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
156 const char *keymap_name,
157 unsigned int rows, unsigned int cols,
158 unsigned short *keymap,
159 struct input_dev *input_dev)
160{
161 unsigned int row_shift = get_count_order(cols);
162 size_t max_keys = rows << row_shift;
163 int i;
164 int error;
165
166 if (WARN_ON(!input_dev->dev.parent))
167 return -EINVAL;
168
169 if (!keymap) {
170 keymap = devm_kzalloc(input_dev->dev.parent,
171 max_keys * sizeof(*keymap),
172 GFP_KERNEL);
173 if (!keymap) {
174 dev_err(input_dev->dev.parent,
175 "Unable to allocate memory for keymap");
176 return -ENOMEM;
177 }
178 }
179
180 input_dev->keycode = keymap;
181 input_dev->keycodesize = sizeof(*keymap);
182 input_dev->keycodemax = max_keys;
183
184 __set_bit(EV_KEY, input_dev->evbit);
185
186 if (keymap_data) {
187 for (i = 0; i < keymap_data->keymap_size; i++) {
188 unsigned int key = keymap_data->keymap[i];
189
190 if (!matrix_keypad_map_key(input_dev, rows, cols,
191 row_shift, key))
192 return -EINVAL;
193 }
194 } else {
195 error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols,
196 input_dev);
197 if (error)
198 return error;
199 }
200
201 __clear_bit(KEY_RESERVED, input_dev->keybit);
202
203 return 0;
204}
205EXPORT_SYMBOL(matrix_keypad_build_keymap);
206
207MODULE_LICENSE("GPL");
208