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