1/* 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]; 63}; 64 65static int check_keychord(struct keychord_device *kdev, 66 struct input_keychord *keychord) 67{ 68 int i; 69 70 if (keychord->count != kdev->key_down) 71 return 0; 72 73 for (i = 0; i < keychord->count; i++) { 74 if (!test_bit(keychord->keycodes[i], kdev->keystate)) 75 return 0; 76 } 77 78 /* we have a match */ 79 return 1; 80} 81 82static void keychord_event(struct input_handle *handle, unsigned int type, 83 unsigned int code, int value) 84{ 85 struct keychord_device *kdev = handle->private; 86 struct input_keychord *keychord; 87 unsigned long flags; 88 int i, got_chord = 0; 89 90 if (type != EV_KEY || code >= KEY_MAX) 91 return; 92 93 spin_lock_irqsave(&kdev->lock, flags); 94 /* do nothing if key state did not change */ 95 if (!test_bit(code, kdev->keystate) == !value) 96 goto done; 97 __change_bit(code, kdev->keystate); 98 if (value) 99 kdev->key_down++; 100 else 101 kdev->key_down--; 102 103 /* don't notify on key up */ 104 if (!value) 105 goto done; 106 /* ignore this event if it is not one of the keys we are monitoring */ 107 if (!test_bit(code, kdev->keybit)) 108 goto done; 109 110 keychord = kdev->keychords; 111 if (!keychord) 112 goto done; 113 114 /* check to see if the keyboard state matches any keychords */ 115 for (i = 0; i < kdev->keychord_count; i++) { 116 if (check_keychord(kdev, keychord)) { 117 kdev->buff[kdev->head] = keychord->id; 118 kdev->head = (kdev->head + 1) % BUFFER_SIZE; 119 got_chord = 1; 120 break; 121 } 122 /* skip to next keychord */ 123 keychord = NEXT_KEYCHORD(keychord); 124 } 125 126done: 127 spin_unlock_irqrestore(&kdev->lock, flags); 128 129 if (got_chord) 130 wake_up_interruptible(&kdev->waitq); 131} 132 133static int keychord_connect(struct input_handler *handler, 134 struct input_dev *dev, 135 const struct input_device_id *id) 136{ 137 int i, ret; 138 struct input_handle *handle; 139 struct keychord_device *kdev = 140 container_of(handler, struct keychord_device, input_handler); 141 142 /* 143 * ignore this input device if it does not contain any keycodes 144 * that we are monitoring 145 */ 146 for (i = 0; i < KEY_MAX; i++) { 147 if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit)) 148 break; 149 } 150 if (i == KEY_MAX) 151 return -ENODEV; 152 153 handle = kzalloc(sizeof(*handle), GFP_KERNEL); 154 if (!handle) 155 return -ENOMEM; 156 157 handle->dev = dev; 158 handle->handler = handler; 159 handle->name = KEYCHORD_NAME; 160 handle->private = kdev; 161 162 ret = input_register_handle(handle); 163 if (ret) 164 goto err_input_register_handle; 165 166 ret = input_open_device(handle); 167 if (ret) 168 goto err_input_open_device; 169 170 pr_info("keychord: using input dev %s for fevent\n", dev->name); 171 172 return 0; 173 174err_input_open_device: 175 input_unregister_handle(handle); 176err_input_register_handle: 177 kfree(handle); 178 return ret; 179} 180 181static void keychord_disconnect(struct input_handle *handle) 182{ 183 input_close_device(handle); 184 input_unregister_handle(handle); 185 kfree(handle); 186} 187 188/* 189 * keychord_read is used to read keychord events from the driver 190 */ 191static ssize_t keychord_read(struct file *file, char __user *buffer, 192 size_t count, loff_t *ppos) 193{ 194 struct keychord_device *kdev = file->private_data; 195 __u16 id; 196 int retval; 197 unsigned long flags; 198 199 if (count < sizeof(id)) 200 return -EINVAL; 201 count = sizeof(id); 202 203 if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK)) 204 return -EAGAIN; 205 206 retval = wait_event_interruptible(kdev->waitq, 207 kdev->head != kdev->tail); 208 if (retval) 209 return retval; 210 211 spin_lock_irqsave(&kdev->lock, flags); 212 /* pop a keychord ID off the queue */ 213 id = kdev->buff[kdev->tail]; 214 kdev->tail = (kdev->tail + 1) % BUFFER_SIZE; 215 spin_unlock_irqrestore(&kdev->lock, flags); 216 217 if (copy_to_user(buffer, &id, count)) 218 return -EFAULT; 219 220 return count; 221} 222 223/* 224 * keychord_write is used to configure the driver 225 */ 226static ssize_t keychord_write(struct file *file, const char __user *buffer, 227 size_t count, loff_t *ppos) 228{ 229 struct keychord_device *kdev = file->private_data; 230 struct input_keychord *keychords = 0; 231 struct input_keychord *keychord, *next, *end; 232 int ret, i, key; 233 unsigned long flags; 234 235 if (count < sizeof(struct input_keychord)) 236 return -EINVAL; 237 keychords = kzalloc(count, GFP_KERNEL); 238 if (!keychords) 239 return -ENOMEM; 240 241 /* read list of keychords from userspace */ 242 if (copy_from_user(keychords, buffer, count)) { 243 kfree(keychords); 244 return -EFAULT; 245 } 246 247 /* unregister handler before changing configuration */ 248 if (kdev->registered) { 249 input_unregister_handler(&kdev->input_handler); 250 kdev->registered = 0; 251 } 252 253 spin_lock_irqsave(&kdev->lock, flags); 254 /* clear any existing configuration */ 255 kfree(kdev->keychords); 256 kdev->keychords = 0; 257 kdev->keychord_count = 0; 258 kdev->key_down = 0; 259 memset(kdev->keybit, 0, sizeof(kdev->keybit)); 260 memset(kdev->keystate, 0, sizeof(kdev->keystate)); 261 kdev->head = kdev->tail = 0; 262 263 keychord = keychords; 264 end = (struct input_keychord *)((char *)keychord + count); 265 266 while (keychord < end) { 267 next = NEXT_KEYCHORD(keychord); 268 if (keychord->count <= 0 || next > end) { 269 pr_err("keychord: invalid keycode count %d\n", 270 keychord->count); 271 goto err_unlock_return; 272 } 273 if (keychord->version != KEYCHORD_VERSION) { 274 pr_err("keychord: unsupported version %d\n", 275 keychord->version); 276 goto err_unlock_return; 277 } 278 279 /* keep track of the keys we are monitoring in keybit */ 280 for (i = 0; i < keychord->count; i++) { 281 key = keychord->keycodes[i]; 282 if (key < 0 || key >= KEY_CNT) { 283 pr_err("keychord: keycode %d out of range\n", 284 key); 285 goto err_unlock_return; 286 } 287 __set_bit(key, kdev->keybit); 288 } 289 290 kdev->keychord_count++; 291 keychord = next; 292 } 293 294 kdev->keychords = keychords; 295 spin_unlock_irqrestore(&kdev->lock, flags); 296 297 ret = input_register_handler(&kdev->input_handler); 298 if (ret) { 299 kfree(keychords); 300 kdev->keychords = 0; 301 return ret; 302 } 303 kdev->registered = 1; 304 305 return count; 306 307err_unlock_return: 308 spin_unlock_irqrestore(&kdev->lock, flags); 309 kfree(keychords); 310 return -EINVAL; 311} 312 313static unsigned int keychord_poll(struct file *file, poll_table *wait) 314{ 315 struct keychord_device *kdev = file->private_data; 316 317 poll_wait(file, &kdev->waitq, wait); 318 319 if (kdev->head != kdev->tail) 320 return POLLIN | POLLRDNORM; 321 322 return 0; 323} 324 325static int keychord_open(struct inode *inode, struct file *file) 326{ 327 struct keychord_device *kdev; 328 329 kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL); 330 if (!kdev) 331 return -ENOMEM; 332 333 spin_lock_init(&kdev->lock); 334 init_waitqueue_head(&kdev->waitq); 335 336 kdev->input_handler.event = keychord_event; 337 kdev->input_handler.connect = keychord_connect; 338 kdev->input_handler.disconnect = keychord_disconnect; 339 kdev->input_handler.name = KEYCHORD_NAME; 340 kdev->input_handler.id_table = kdev->device_ids; 341 342 kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT; 343 __set_bit(EV_KEY, kdev->device_ids[0].evbit); 344 345 file->private_data = kdev; 346 347 return 0; 348} 349 350static int keychord_release(struct inode *inode, struct file *file) 351{ 352 struct keychord_device *kdev = file->private_data; 353 354 if (kdev->registered) 355 input_unregister_handler(&kdev->input_handler); 356 kfree(kdev); 357 358 return 0; 359} 360 361static const struct file_operations keychord_fops = { 362 .owner = THIS_MODULE, 363 .open = keychord_open, 364 .release = keychord_release, 365 .read = keychord_read, 366 .write = keychord_write, 367 .poll = keychord_poll, 368}; 369 370static struct miscdevice keychord_misc = { 371 .fops = &keychord_fops, 372 .name = KEYCHORD_NAME, 373 .minor = MISC_DYNAMIC_MINOR, 374}; 375 376static int __init keychord_init(void) 377{ 378 return misc_register(&keychord_misc); 379} 380 381static void __exit keychord_exit(void) 382{ 383 misc_deregister(&keychord_misc); 384} 385 386module_init(keychord_init); 387module_exit(keychord_exit); 388