106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood/* 206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * drivers/input/misc/keychord.c 306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * 406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * Copyright (C) 2008 Google, Inc. 506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * Author: Mike Lockwood <lockwood@android.com> 606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * 706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * This software is licensed under the terms of the GNU General Public 806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * License version 2, as published by the Free Software Foundation, and 906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * may be copied, distributed, and modified under those terms. 1006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * 1106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * This program is distributed in the hope that it will be useful, 1206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * but WITHOUT ANY WARRANTY; without even the implied warranty of 1306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * GNU General Public License for more details. 1506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * 1606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood*/ 1706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 1806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/poll.h> 1906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/slab.h> 2006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/module.h> 2106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/init.h> 2206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/spinlock.h> 2306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/fs.h> 2406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/miscdevice.h> 2506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/keychord.h> 2606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#include <linux/sched.h> 2706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 2806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#define KEYCHORD_NAME "keychord" 2906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#define BUFFER_SIZE 16 3006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 3106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike LockwoodMODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); 3206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike LockwoodMODULE_DESCRIPTION("Key chord input driver"); 3306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike LockwoodMODULE_SUPPORTED_DEVICE("keychord"); 3406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike LockwoodMODULE_LICENSE("GPL"); 3506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 3606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood#define NEXT_KEYCHORD(kc) ((struct input_keychord *) \ 3706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood ((char *)kc + sizeof(struct input_keychord) + \ 3806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kc->count * sizeof(kc->keycodes[0]))) 3906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 4006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstruct keychord_device { 4106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_handler input_handler; 4206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int registered; 4306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 4406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* list of keychords to monitor */ 4506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_keychord *keychords; 4606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int keychord_count; 4706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 4806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* bitmask of keys contained in our keychords */ 4906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 5006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* current state of the keys */ 5106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned long keystate[BITS_TO_LONGS(KEY_CNT)]; 5206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* number of keys that are currently pressed */ 5306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int key_down; 5406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 5506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* second input_device_id is needed for null termination */ 5606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_device_id device_ids[2]; 5706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 5806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spinlock_t lock; 5906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood wait_queue_head_t waitq; 6006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned char head; 6106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned char tail; 6206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood __u16 buff[BUFFER_SIZE]; 6306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood}; 6406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 6506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic int check_keychord(struct keychord_device *kdev, 6606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_keychord *keychord) 6706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 6806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int i; 6906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 7006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (keychord->count != kdev->key_down) 7106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return 0; 7206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 7306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood for (i = 0; i < keychord->count; i++) { 7406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!test_bit(keychord->keycodes[i], kdev->keystate)) 7506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return 0; 7606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 7706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 7806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* we have a match */ 7906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return 1; 8006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 8106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 8206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic void keychord_event(struct input_handle *handle, unsigned int type, 8306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned int code, int value) 8406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 8506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct keychord_device *kdev = handle->private; 8606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_keychord *keychord; 8706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned long flags; 8806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int i, got_chord = 0; 8906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 9006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (type != EV_KEY || code >= KEY_MAX) 9106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return; 9206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 9306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_lock_irqsave(&kdev->lock, flags); 9406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* do nothing if key state did not change */ 9506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!test_bit(code, kdev->keystate) == !value) 9606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto done; 9706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood __change_bit(code, kdev->keystate); 9806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (value) 9906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->key_down++; 10006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood else 10106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->key_down--; 10206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 10306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* don't notify on key up */ 10406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!value) 10506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto done; 10606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* ignore this event if it is not one of the keys we are monitoring */ 10706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!test_bit(code, kdev->keybit)) 10806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto done; 10906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 11006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood keychord = kdev->keychords; 11106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!keychord) 11206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto done; 11306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 11406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* check to see if the keyboard state matches any keychords */ 11506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood for (i = 0; i < kdev->keychord_count; i++) { 11606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (check_keychord(kdev, keychord)) { 11706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->buff[kdev->head] = keychord->id; 11806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->head = (kdev->head + 1) % BUFFER_SIZE; 11906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood got_chord = 1; 12006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood break; 12106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 12206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* skip to next keychord */ 12306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood keychord = NEXT_KEYCHORD(keychord); 12406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 12506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 12606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwooddone: 12706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_unlock_irqrestore(&kdev->lock, flags); 12806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 1290153a506236fd16ff836e8117ead155dc981ad32JP Abgrall if (got_chord) { 1300153a506236fd16ff836e8117ead155dc981ad32JP Abgrall pr_info("keychord: got keychord id %d. Any tasks: %d\n", 1310153a506236fd16ff836e8117ead155dc981ad32JP Abgrall keychord->id, 1320153a506236fd16ff836e8117ead155dc981ad32JP Abgrall !list_empty_careful(&kdev->waitq.task_list)); 13306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood wake_up_interruptible(&kdev->waitq); 1340153a506236fd16ff836e8117ead155dc981ad32JP Abgrall } 13506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 13606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 13706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic int keychord_connect(struct input_handler *handler, 13806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_dev *dev, 13906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood const struct input_device_id *id) 14006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 14106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int i, ret; 14206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_handle *handle; 14306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct keychord_device *kdev = 14406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood container_of(handler, struct keychord_device, input_handler); 14506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 14606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* 14706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * ignore this input device if it does not contain any keycodes 14806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * that we are monitoring 14906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood */ 15006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood for (i = 0; i < KEY_MAX; i++) { 15106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit)) 15206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood break; 15306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 15406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (i == KEY_MAX) 15506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -ENODEV; 15606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 15706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood handle = kzalloc(sizeof(*handle), GFP_KERNEL); 15806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!handle) 15906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -ENOMEM; 16006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 16106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood handle->dev = dev; 16206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood handle->handler = handler; 16306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood handle->name = KEYCHORD_NAME; 16406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood handle->private = kdev; 16506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 16606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood ret = input_register_handle(handle); 16706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (ret) 16806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto err_input_register_handle; 16906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 17006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood ret = input_open_device(handle); 17106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (ret) 17206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto err_input_open_device; 17306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 17406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood pr_info("keychord: using input dev %s for fevent\n", dev->name); 17506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 17606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return 0; 17706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 17806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwooderr_input_open_device: 17906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood input_unregister_handle(handle); 18006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwooderr_input_register_handle: 18106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kfree(handle); 18206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return ret; 18306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 18406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 18506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic void keychord_disconnect(struct input_handle *handle) 18606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 18706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood input_close_device(handle); 18806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood input_unregister_handle(handle); 18906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kfree(handle); 19006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 19106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 19206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood/* 19306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * keychord_read is used to read keychord events from the driver 19406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood */ 19506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic ssize_t keychord_read(struct file *file, char __user *buffer, 19606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood size_t count, loff_t *ppos) 19706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 19806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct keychord_device *kdev = file->private_data; 19906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood __u16 id; 20006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int retval; 20106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned long flags; 20206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 20306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (count < sizeof(id)) 20406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -EINVAL; 20506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood count = sizeof(id); 20606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 20706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK)) 20806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -EAGAIN; 20906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 21006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood retval = wait_event_interruptible(kdev->waitq, 21106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->head != kdev->tail); 21206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (retval) 21306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return retval; 21406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 21506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_lock_irqsave(&kdev->lock, flags); 21606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* pop a keychord ID off the queue */ 21706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood id = kdev->buff[kdev->tail]; 21806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->tail = (kdev->tail + 1) % BUFFER_SIZE; 21906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_unlock_irqrestore(&kdev->lock, flags); 22006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 22106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (copy_to_user(buffer, &id, count)) 22206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -EFAULT; 22306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 22406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return count; 22506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 22606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 22706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood/* 22806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood * keychord_write is used to configure the driver 22906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood */ 23006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic ssize_t keychord_write(struct file *file, const char __user *buffer, 23106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood size_t count, loff_t *ppos) 23206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 23306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct keychord_device *kdev = file->private_data; 23406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_keychord *keychords = 0; 23506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct input_keychord *keychord, *next, *end; 23606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood int ret, i, key; 23706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood unsigned long flags; 23806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 23906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (count < sizeof(struct input_keychord)) 24006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -EINVAL; 24106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood keychords = kzalloc(count, GFP_KERNEL); 24206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!keychords) 24306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -ENOMEM; 24406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 24506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* read list of keychords from userspace */ 24606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (copy_from_user(keychords, buffer, count)) { 24706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kfree(keychords); 24806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -EFAULT; 24906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 25006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 25106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* unregister handler before changing configuration */ 25206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (kdev->registered) { 25306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood input_unregister_handler(&kdev->input_handler); 25406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->registered = 0; 25506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 25606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 25706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_lock_irqsave(&kdev->lock, flags); 25806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* clear any existing configuration */ 25906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kfree(kdev->keychords); 26006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->keychords = 0; 26106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->keychord_count = 0; 26206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->key_down = 0; 26306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood memset(kdev->keybit, 0, sizeof(kdev->keybit)); 26406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood memset(kdev->keystate, 0, sizeof(kdev->keystate)); 26506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->head = kdev->tail = 0; 26606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 26706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood keychord = keychords; 26806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood end = (struct input_keychord *)((char *)keychord + count); 26906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 27006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood while (keychord < end) { 27106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood next = NEXT_KEYCHORD(keychord); 27206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (keychord->count <= 0 || next > end) { 27306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood pr_err("keychord: invalid keycode count %d\n", 27406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood keychord->count); 27506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto err_unlock_return; 27606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 27706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (keychord->version != KEYCHORD_VERSION) { 27806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood pr_err("keychord: unsupported version %d\n", 27906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood keychord->version); 28006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto err_unlock_return; 28106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 28206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 28306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood /* keep track of the keys we are monitoring in keybit */ 28406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood for (i = 0; i < keychord->count; i++) { 28506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood key = keychord->keycodes[i]; 28606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (key < 0 || key >= KEY_CNT) { 28706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood pr_err("keychord: keycode %d out of range\n", 28806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood key); 28906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood goto err_unlock_return; 29006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 29106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood __set_bit(key, kdev->keybit); 29206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 29306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 29406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->keychord_count++; 29506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood keychord = next; 29606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 29706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 29806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->keychords = keychords; 29906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_unlock_irqrestore(&kdev->lock, flags); 30006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 30106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood ret = input_register_handler(&kdev->input_handler); 30206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (ret) { 30306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kfree(keychords); 30406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->keychords = 0; 30506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return ret; 30606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood } 30706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->registered = 1; 30806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 30906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return count; 31006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 31106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwooderr_unlock_return: 31206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_unlock_irqrestore(&kdev->lock, flags); 31306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kfree(keychords); 31406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -EINVAL; 31506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 31606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 31706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic unsigned int keychord_poll(struct file *file, poll_table *wait) 31806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 31906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct keychord_device *kdev = file->private_data; 32006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 32106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood poll_wait(file, &kdev->waitq, wait); 32206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 32306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (kdev->head != kdev->tail) 32406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return POLLIN | POLLRDNORM; 32506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 32606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return 0; 32706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 32806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 32906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic int keychord_open(struct inode *inode, struct file *file) 33006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 33106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct keychord_device *kdev; 33206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 33306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL); 33406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (!kdev) 33506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return -ENOMEM; 33606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 33706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood spin_lock_init(&kdev->lock); 33806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood init_waitqueue_head(&kdev->waitq); 33906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 34006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->input_handler.event = keychord_event; 34106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->input_handler.connect = keychord_connect; 34206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->input_handler.disconnect = keychord_disconnect; 34306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->input_handler.name = KEYCHORD_NAME; 34406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->input_handler.id_table = kdev->device_ids; 34506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 34606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT; 34706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood __set_bit(EV_KEY, kdev->device_ids[0].evbit); 34806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 34906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood file->private_data = kdev; 35006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 35106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return 0; 35206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 35306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 35406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic int keychord_release(struct inode *inode, struct file *file) 35506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 35606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood struct keychord_device *kdev = file->private_data; 35706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 35806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood if (kdev->registered) 35906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood input_unregister_handler(&kdev->input_handler); 36006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood kfree(kdev); 36106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 36206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return 0; 36306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 36406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 36506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic const struct file_operations keychord_fops = { 36606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .owner = THIS_MODULE, 36706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .open = keychord_open, 36806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .release = keychord_release, 36906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .read = keychord_read, 37006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .write = keychord_write, 37106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .poll = keychord_poll, 37206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood}; 37306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 37406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic struct miscdevice keychord_misc = { 37506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .fops = &keychord_fops, 37606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .name = KEYCHORD_NAME, 37706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood .minor = MISC_DYNAMIC_MINOR, 37806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood}; 37906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 38006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic int __init keychord_init(void) 38106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 38206bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood return misc_register(&keychord_misc); 38306bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 38406bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 38506bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodstatic void __exit keychord_exit(void) 38606bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood{ 38706bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood misc_deregister(&keychord_misc); 38806bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood} 38906bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwood 39006bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodmodule_init(keychord_init); 39106bf8b116ac5f7feefa8e88788b9663f8ca809d0Mike Lockwoodmodule_exit(keychord_exit); 392