blob: 82fefdff366a236df578318e5345343850459666 [file] [log] [blame]
Mike Lockwood630a1e72008-12-15 14:51:56 -05001/*
2 * drivers/input/misc/keychord.c
3 *
4 * Copyright (C) 2008 Google, Inc.
5 * Author: Mike Lockwood <lockwood@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16*/
17
18#include <linux/poll.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/spinlock.h>
23#include <linux/fs.h>
24#include <linux/miscdevice.h>
25#include <linux/keychord.h>
26#include <linux/sched.h>
27
28#define KEYCHORD_NAME "keychord"
29#define BUFFER_SIZE 16
30
31MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
32MODULE_DESCRIPTION("Key chord input driver");
33MODULE_SUPPORTED_DEVICE("keychord");
34MODULE_LICENSE("GPL");
35
36#define NEXT_KEYCHORD(kc) ((struct input_keychord *) \
37 ((char *)kc + sizeof(struct input_keychord) + \
38 kc->count * sizeof(kc->keycodes[0])))
39
40struct keychord_device {
41 struct input_handler input_handler;
42 int registered;
43
44 /* list of keychords to monitor */
45 struct input_keychord *keychords;
46 int keychord_count;
47
48 /* bitmask of keys contained in our keychords */
49 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
50 /* current state of the keys */
51 unsigned long keystate[BITS_TO_LONGS(KEY_CNT)];
52 /* number of keys that are currently pressed */
53 int key_down;
54
55 /* second input_device_id is needed for null termination */
56 struct input_device_id device_ids[2];
57
58 spinlock_t lock;
59 wait_queue_head_t waitq;
60 unsigned char head;
61 unsigned char tail;
62 __u16 buff[BUFFER_SIZE];
Mohan Srinivasan59584702017-08-09 12:16:56 -070063 /* Bit to serialize writes to this device */
64#define KEYCHORD_BUSY 0x01
65 unsigned long flags;
66 wait_queue_head_t write_waitq;
Mike Lockwood630a1e72008-12-15 14:51:56 -050067};
68
69static int check_keychord(struct keychord_device *kdev,
70 struct input_keychord *keychord)
71{
72 int i;
73
74 if (keychord->count != kdev->key_down)
75 return 0;
76
77 for (i = 0; i < keychord->count; i++) {
78 if (!test_bit(keychord->keycodes[i], kdev->keystate))
79 return 0;
80 }
81
82 /* we have a match */
83 return 1;
84}
85
86static void keychord_event(struct input_handle *handle, unsigned int type,
87 unsigned int code, int value)
88{
89 struct keychord_device *kdev = handle->private;
90 struct input_keychord *keychord;
91 unsigned long flags;
92 int i, got_chord = 0;
93
94 if (type != EV_KEY || code >= KEY_MAX)
95 return;
96
97 spin_lock_irqsave(&kdev->lock, flags);
98 /* do nothing if key state did not change */
99 if (!test_bit(code, kdev->keystate) == !value)
100 goto done;
101 __change_bit(code, kdev->keystate);
102 if (value)
103 kdev->key_down++;
104 else
105 kdev->key_down--;
106
107 /* don't notify on key up */
108 if (!value)
109 goto done;
110 /* ignore this event if it is not one of the keys we are monitoring */
111 if (!test_bit(code, kdev->keybit))
112 goto done;
113
114 keychord = kdev->keychords;
115 if (!keychord)
116 goto done;
117
118 /* check to see if the keyboard state matches any keychords */
119 for (i = 0; i < kdev->keychord_count; i++) {
120 if (check_keychord(kdev, keychord)) {
121 kdev->buff[kdev->head] = keychord->id;
122 kdev->head = (kdev->head + 1) % BUFFER_SIZE;
123 got_chord = 1;
124 break;
125 }
126 /* skip to next keychord */
127 keychord = NEXT_KEYCHORD(keychord);
128 }
129
130done:
131 spin_unlock_irqrestore(&kdev->lock, flags);
132
JP Abgrallc4be12a2013-03-05 14:25:36 -0800133 if (got_chord) {
134 pr_info("keychord: got keychord id %d. Any tasks: %d\n",
135 keychord->id,
136 !list_empty_careful(&kdev->waitq.task_list));
Mike Lockwood630a1e72008-12-15 14:51:56 -0500137 wake_up_interruptible(&kdev->waitq);
JP Abgrallc4be12a2013-03-05 14:25:36 -0800138 }
Mike Lockwood630a1e72008-12-15 14:51:56 -0500139}
140
141static int keychord_connect(struct input_handler *handler,
142 struct input_dev *dev,
143 const struct input_device_id *id)
144{
145 int i, ret;
146 struct input_handle *handle;
147 struct keychord_device *kdev =
148 container_of(handler, struct keychord_device, input_handler);
149
150 /*
151 * ignore this input device if it does not contain any keycodes
152 * that we are monitoring
153 */
154 for (i = 0; i < KEY_MAX; i++) {
155 if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit))
156 break;
157 }
158 if (i == KEY_MAX)
159 return -ENODEV;
160
161 handle = kzalloc(sizeof(*handle), GFP_KERNEL);
162 if (!handle)
163 return -ENOMEM;
164
165 handle->dev = dev;
166 handle->handler = handler;
167 handle->name = KEYCHORD_NAME;
168 handle->private = kdev;
169
170 ret = input_register_handle(handle);
171 if (ret)
172 goto err_input_register_handle;
173
174 ret = input_open_device(handle);
175 if (ret)
176 goto err_input_open_device;
177
178 pr_info("keychord: using input dev %s for fevent\n", dev->name);
Mike Lockwood630a1e72008-12-15 14:51:56 -0500179 return 0;
180
181err_input_open_device:
182 input_unregister_handle(handle);
183err_input_register_handle:
184 kfree(handle);
185 return ret;
186}
187
188static void keychord_disconnect(struct input_handle *handle)
189{
190 input_close_device(handle);
191 input_unregister_handle(handle);
192 kfree(handle);
193}
194
195/*
196 * keychord_read is used to read keychord events from the driver
197 */
198static ssize_t keychord_read(struct file *file, char __user *buffer,
199 size_t count, loff_t *ppos)
200{
201 struct keychord_device *kdev = file->private_data;
202 __u16 id;
203 int retval;
204 unsigned long flags;
205
206 if (count < sizeof(id))
207 return -EINVAL;
208 count = sizeof(id);
209
210 if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK))
211 return -EAGAIN;
212
213 retval = wait_event_interruptible(kdev->waitq,
214 kdev->head != kdev->tail);
215 if (retval)
216 return retval;
217
218 spin_lock_irqsave(&kdev->lock, flags);
219 /* pop a keychord ID off the queue */
220 id = kdev->buff[kdev->tail];
221 kdev->tail = (kdev->tail + 1) % BUFFER_SIZE;
222 spin_unlock_irqrestore(&kdev->lock, flags);
223
224 if (copy_to_user(buffer, &id, count))
225 return -EFAULT;
226
227 return count;
228}
229
230/*
Mohan Srinivasan59584702017-08-09 12:16:56 -0700231 * serializes writes on a device. can use mutex_lock_interruptible()
232 * for this particular use case as well - a matter of preference.
233 */
234static int
235keychord_write_lock(struct keychord_device *kdev)
236{
237 int ret;
238 unsigned long flags;
239
240 spin_lock_irqsave(&kdev->lock, flags);
241 while (kdev->flags & KEYCHORD_BUSY) {
242 spin_unlock_irqrestore(&kdev->lock, flags);
243 ret = wait_event_interruptible(kdev->write_waitq,
244 ((kdev->flags & KEYCHORD_BUSY) == 0));
245 if (ret)
246 return ret;
247 spin_lock_irqsave(&kdev->lock, flags);
248 }
249 kdev->flags |= KEYCHORD_BUSY;
250 spin_unlock_irqrestore(&kdev->lock, flags);
251 return 0;
252}
253
254static void
255keychord_write_unlock(struct keychord_device *kdev)
256{
257 unsigned long flags;
258
259 spin_lock_irqsave(&kdev->lock, flags);
260 kdev->flags &= ~KEYCHORD_BUSY;
261 spin_unlock_irqrestore(&kdev->lock, flags);
262 wake_up_interruptible(&kdev->write_waitq);
263}
264
265/*
Mike Lockwood630a1e72008-12-15 14:51:56 -0500266 * keychord_write is used to configure the driver
267 */
268static ssize_t keychord_write(struct file *file, const char __user *buffer,
269 size_t count, loff_t *ppos)
270{
271 struct keychord_device *kdev = file->private_data;
272 struct input_keychord *keychords = 0;
Mohan Srinivasan913d9802017-07-26 12:14:41 -0700273 struct input_keychord *keychord;
Mike Lockwood630a1e72008-12-15 14:51:56 -0500274 int ret, i, key;
275 unsigned long flags;
Mohan Srinivasan913d9802017-07-26 12:14:41 -0700276 size_t resid = count;
277 size_t key_bytes;
Mike Lockwood630a1e72008-12-15 14:51:56 -0500278
Suren Baghdasaryanf6738522018-03-01 16:35:31 -0800279 if (count < sizeof(struct input_keychord) || count > PAGE_SIZE)
Mike Lockwood630a1e72008-12-15 14:51:56 -0500280 return -EINVAL;
281 keychords = kzalloc(count, GFP_KERNEL);
282 if (!keychords)
283 return -ENOMEM;
284
285 /* read list of keychords from userspace */
286 if (copy_from_user(keychords, buffer, count)) {
287 kfree(keychords);
288 return -EFAULT;
289 }
290
Mohan Srinivasan59584702017-08-09 12:16:56 -0700291 /*
292 * Serialize writes to this device to prevent various races.
293 * 1) writers racing here could do duplicate input_unregister_handler()
294 * calls, resulting in attempting to unlink a node from a list that
295 * does not exist.
296 * 2) writers racing here could do duplicate input_register_handler() calls
297 * below, resulting in a duplicate insertion of a node into the list.
298 * 3) a double kfree of keychords can occur (in the event that
299 * input_register_handler() fails below.
300 */
301 ret = keychord_write_lock(kdev);
302 if (ret) {
303 kfree(keychords);
304 return ret;
305 }
306
Mike Lockwood630a1e72008-12-15 14:51:56 -0500307 /* unregister handler before changing configuration */
308 if (kdev->registered) {
309 input_unregister_handler(&kdev->input_handler);
310 kdev->registered = 0;
311 }
312
313 spin_lock_irqsave(&kdev->lock, flags);
314 /* clear any existing configuration */
315 kfree(kdev->keychords);
316 kdev->keychords = 0;
317 kdev->keychord_count = 0;
318 kdev->key_down = 0;
319 memset(kdev->keybit, 0, sizeof(kdev->keybit));
320 memset(kdev->keystate, 0, sizeof(kdev->keystate));
321 kdev->head = kdev->tail = 0;
322
323 keychord = keychords;
Mike Lockwood630a1e72008-12-15 14:51:56 -0500324
Mohan Srinivasan913d9802017-07-26 12:14:41 -0700325 while (resid > 0) {
326 /* Is the entire keychord entry header present ? */
327 if (resid < sizeof(struct input_keychord)) {
Mohan Srinivasana1e4c7952017-07-27 11:30:32 -0700328 pr_err("keychord: Insufficient bytes present for header %zu\n",
Mohan Srinivasan913d9802017-07-26 12:14:41 -0700329 resid);
330 goto err_unlock_return;
331 }
332 resid -= sizeof(struct input_keychord);
333 if (keychord->count <= 0) {
Mike Lockwood630a1e72008-12-15 14:51:56 -0500334 pr_err("keychord: invalid keycode count %d\n",
335 keychord->count);
336 goto err_unlock_return;
337 }
Mohan Srinivasan913d9802017-07-26 12:14:41 -0700338 key_bytes = keychord->count * sizeof(keychord->keycodes[0]);
339 /* Do we have all the expected keycodes ? */
340 if (resid < key_bytes) {
Mohan Srinivasana1e4c7952017-07-27 11:30:32 -0700341 pr_err("keychord: Insufficient bytes present for keycount %zu\n",
Mohan Srinivasan913d9802017-07-26 12:14:41 -0700342 resid);
343 goto err_unlock_return;
344 }
345 resid -= key_bytes;
346
Mike Lockwood630a1e72008-12-15 14:51:56 -0500347 if (keychord->version != KEYCHORD_VERSION) {
348 pr_err("keychord: unsupported version %d\n",
349 keychord->version);
350 goto err_unlock_return;
351 }
352
353 /* keep track of the keys we are monitoring in keybit */
354 for (i = 0; i < keychord->count; i++) {
355 key = keychord->keycodes[i];
356 if (key < 0 || key >= KEY_CNT) {
357 pr_err("keychord: keycode %d out of range\n",
358 key);
359 goto err_unlock_return;
360 }
361 __set_bit(key, kdev->keybit);
362 }
363
364 kdev->keychord_count++;
Mohan Srinivasan913d9802017-07-26 12:14:41 -0700365 keychord = NEXT_KEYCHORD(keychord);
Mike Lockwood630a1e72008-12-15 14:51:56 -0500366 }
367
368 kdev->keychords = keychords;
369 spin_unlock_irqrestore(&kdev->lock, flags);
370
371 ret = input_register_handler(&kdev->input_handler);
372 if (ret) {
373 kfree(keychords);
374 kdev->keychords = 0;
Mohan Srinivasan59584702017-08-09 12:16:56 -0700375 keychord_write_unlock(kdev);
Mike Lockwood630a1e72008-12-15 14:51:56 -0500376 return ret;
377 }
378 kdev->registered = 1;
379
Mohan Srinivasan59584702017-08-09 12:16:56 -0700380 keychord_write_unlock(kdev);
381
Mike Lockwood630a1e72008-12-15 14:51:56 -0500382 return count;
383
384err_unlock_return:
385 spin_unlock_irqrestore(&kdev->lock, flags);
386 kfree(keychords);
Mohan Srinivasan59584702017-08-09 12:16:56 -0700387 keychord_write_unlock(kdev);
Mike Lockwood630a1e72008-12-15 14:51:56 -0500388 return -EINVAL;
389}
390
391static unsigned int keychord_poll(struct file *file, poll_table *wait)
392{
393 struct keychord_device *kdev = file->private_data;
394
395 poll_wait(file, &kdev->waitq, wait);
396
397 if (kdev->head != kdev->tail)
398 return POLLIN | POLLRDNORM;
399
400 return 0;
401}
402
403static int keychord_open(struct inode *inode, struct file *file)
404{
405 struct keychord_device *kdev;
406
407 kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL);
408 if (!kdev)
409 return -ENOMEM;
410
411 spin_lock_init(&kdev->lock);
412 init_waitqueue_head(&kdev->waitq);
Mohan Srinivasan59584702017-08-09 12:16:56 -0700413 init_waitqueue_head(&kdev->write_waitq);
Mike Lockwood630a1e72008-12-15 14:51:56 -0500414
415 kdev->input_handler.event = keychord_event;
416 kdev->input_handler.connect = keychord_connect;
417 kdev->input_handler.disconnect = keychord_disconnect;
418 kdev->input_handler.name = KEYCHORD_NAME;
419 kdev->input_handler.id_table = kdev->device_ids;
420
421 kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT;
422 __set_bit(EV_KEY, kdev->device_ids[0].evbit);
423
424 file->private_data = kdev;
425
426 return 0;
427}
428
429static int keychord_release(struct inode *inode, struct file *file)
430{
431 struct keychord_device *kdev = file->private_data;
432
433 if (kdev->registered)
434 input_unregister_handler(&kdev->input_handler);
Mohan Srinivasan72a8dae2017-08-09 12:36:33 -0700435 kfree(kdev->keychords);
Mike Lockwood630a1e72008-12-15 14:51:56 -0500436 kfree(kdev);
437
438 return 0;
439}
440
441static const struct file_operations keychord_fops = {
442 .owner = THIS_MODULE,
443 .open = keychord_open,
444 .release = keychord_release,
445 .read = keychord_read,
446 .write = keychord_write,
447 .poll = keychord_poll,
448};
449
450static struct miscdevice keychord_misc = {
451 .fops = &keychord_fops,
452 .name = KEYCHORD_NAME,
453 .minor = MISC_DYNAMIC_MINOR,
454};
455
456static int __init keychord_init(void)
457{
458 return misc_register(&keychord_misc);
459}
460
461static void __exit keychord_exit(void)
462{
463 misc_deregister(&keychord_misc);
464}
465
466module_init(keychord_init);
467module_exit(keychord_exit);