From c8e4c77277ca5db0c4ddbfb4bc628b8abad585b0 Mon Sep 17 00:00:00 2001 From: Marvin Raaijmakers Date: Wed, 14 Mar 2007 22:50:42 -0400 Subject: Input: add getkeycode and setkeycode methods Allow drivers to implement their own get and set keycode methods. This will allow drivers to change their keymaps without allocating huge tables covering entire range of possible scancodes. Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/include/linux/input.h b/include/linux/input.h index bde65c8a3519..3a8b8c6f0ab5 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -913,33 +913,6 @@ struct ff_effect { #define BIT(x) (1UL<<((x)%BITS_PER_LONG)) #define LONG(x) ((x)/BITS_PER_LONG) -#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \ - ((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode]))) - -#define SET_INPUT_KEYCODE(dev, scancode, val) \ - ({ unsigned __old; \ - switch (dev->keycodesize) { \ - case 1: { \ - u8 *k = (u8 *)dev->keycode; \ - __old = k[scancode]; \ - k[scancode] = val; \ - break; \ - } \ - case 2: { \ - u16 *k = (u16 *)dev->keycode; \ - __old = k[scancode]; \ - k[scancode] = val; \ - break; \ - } \ - default: { \ - u32 *k = (u32 *)dev->keycode; \ - __old = k[scancode]; \ - k[scancode] = val; \ - break; \ - } \ - } \ - __old; }) - struct input_dev { void *private; @@ -962,6 +935,8 @@ struct input_dev { unsigned int keycodemax; unsigned int keycodesize; void *keycode; + int (*setkeycode)(struct input_dev *dev, int scancode, int keycode); + int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode); struct ff_device *ff; @@ -1104,7 +1079,7 @@ struct input_handle { }; #define to_dev(n) container_of(n,struct input_dev,node) -#define to_handler(n) container_of(n,struct input_handler,node); +#define to_handler(n) container_of(n,struct input_handler,node) #define to_handle(n) container_of(n,struct input_handle,d_node) #define to_handle_h(n) container_of(n,struct input_handle,h_node) -- cgit v1.2.3-58-ga151 From 9575499dfebc0f0fbbf122223f02e9e92630661d Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 16 Mar 2007 00:59:29 -0400 Subject: Input: HIL - fix rwlock recursion bug The following bug happens when insmoding hp_sdc_mlc.ko: HP SDC MLC: Registering the System Domain Controller's HIL MLC. BUG: rwlock recursion on CPU#0, hotplug/1814, 00854734 Backtrace: [<10267560>] _raw_write_lock+0x50/0x88 [<10104008>] _write_lock_irqsave+0x14/0x24 [<008537d4>] hp_sdc_mlc_out+0x38/0x25c [hp_sdc_mlc] [<0084ebd8>] hilse_donode+0x308/0x470 [hil_mlc] [<0084ed80>] hil_mlcs_process+0x40/0x6c [hil_mlc] [<10130f80>] tasklet_action+0x78/0xb8 [<10130cec>] __do_softirq+0x60/0xcc [<1010428c>] __lock_text_end+0x38/0x48 [<10108348>] do_cpu_irq_mask+0xf0/0x11c [<1010b068>] intr_return+0x0/0xc Signed-off-by: Helge Deller Signed-off-by: Dmitry Torokhov --- drivers/input/serio/hil_mlc.c | 2 ++ drivers/input/serio/hp_sdc.c | 22 ++++++++++++++-------- drivers/input/serio/hp_sdc_mlc.c | 19 ++----------------- include/linux/hp_sdc.h | 1 + 4 files changed, 19 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 485b0742842b..93a1a6ba216a 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -716,7 +716,9 @@ static int hilse_donode(hil_mlc *mlc) break; case HILSE_CTS: + write_lock_irqsave(&mlc->lock, flags); nextidx = mlc->cts(mlc) ? node->bad : node->good; + write_unlock_irqrestore(&mlc->lock, flags); break; default: diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 31826e601fba..6af199805ffc 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -100,6 +100,7 @@ EXPORT_SYMBOL(hp_sdc_release_timer_irq); EXPORT_SYMBOL(hp_sdc_release_hil_irq); EXPORT_SYMBOL(hp_sdc_release_cooked_irq); +EXPORT_SYMBOL(__hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_dequeue_transaction); @@ -593,18 +594,15 @@ unsigned long hp_sdc_put(void) } /******* Functions called in either user or kernel context ****/ -int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) +int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { - unsigned long flags; int i; if (this == NULL) { - tasklet_schedule(&hp_sdc.task); + BUG(); return -EINVAL; } - write_lock_irqsave(&hp_sdc.lock, flags); - /* Can't have same transaction on queue twice */ for (i = 0; i < HP_SDC_QUEUE_LEN; i++) if (hp_sdc.tq[i] == this) @@ -617,21 +615,29 @@ int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) for (i = 0; i < HP_SDC_QUEUE_LEN; i++) if (hp_sdc.tq[i] == NULL) { hp_sdc.tq[i] = this; - write_unlock_irqrestore(&hp_sdc.lock, flags); tasklet_schedule(&hp_sdc.task); return 0; } - write_unlock_irqrestore(&hp_sdc.lock, flags); printk(KERN_WARNING PREFIX "No free slot to add transaction.\n"); return -EBUSY; fail: - write_unlock_irqrestore(&hp_sdc.lock,flags); printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n"); return -EINVAL; } +int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { + unsigned long flags; + int ret; + + write_lock_irqsave(&hp_sdc.lock, flags); + ret = __hp_sdc_enqueue_transaction(this); + write_unlock_irqrestore(&hp_sdc.lock,flags); + + return ret; +} + int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) { unsigned long flags; diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c index cb0b28877e05..c45ea74d53e4 100644 --- a/drivers/input/serio/hp_sdc_mlc.c +++ b/drivers/input/serio/hp_sdc_mlc.c @@ -142,14 +142,11 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id, static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) { - unsigned long flags; struct hp_sdc_mlc_priv_s *priv; int rc = 2; priv = mlc->priv; - write_lock_irqsave(&mlc->lock, flags); - /* Try to down the semaphore */ if (down_trylock(&mlc->isem)) { struct timeval tv; @@ -178,21 +175,16 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) wasup: up(&mlc->isem); rc = 0; - goto done; done: - write_unlock_irqrestore(&mlc->lock, flags); return rc; } static int hp_sdc_mlc_cts(hil_mlc *mlc) { struct hp_sdc_mlc_priv_s *priv; - unsigned long flags; priv = mlc->priv; - write_lock_irqsave(&mlc->lock, flags); - /* Try to down the semaphores -- they should be up. */ BUG_ON(down_trylock(&mlc->isem)); BUG_ON(down_trylock(&mlc->osem)); @@ -221,26 +213,21 @@ static int hp_sdc_mlc_cts(hil_mlc *mlc) priv->tseq[2] = 1; priv->tseq[3] = 0; priv->tseq[4] = 0; - hp_sdc_enqueue_transaction(&priv->trans); + __hp_sdc_enqueue_transaction(&priv->trans); busy: - write_unlock_irqrestore(&mlc->lock, flags); return 1; done: priv->trans.act.semaphore = &mlc->osem; up(&mlc->csem); - write_unlock_irqrestore(&mlc->lock, flags); return 0; } static void hp_sdc_mlc_out(hil_mlc *mlc) { struct hp_sdc_mlc_priv_s *priv; - unsigned long flags; priv = mlc->priv; - write_lock_irqsave(&mlc->lock, flags); - /* Try to down the semaphore -- it should be up. */ BUG_ON(down_trylock(&mlc->osem)); @@ -250,7 +237,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc) do_data: if (priv->emtestmode) { up(&mlc->osem); - goto done; + return; } /* Shouldn't be sending commands when loop may be busy */ BUG_ON(down_trylock(&mlc->csem)); @@ -313,8 +300,6 @@ static void hp_sdc_mlc_out(hil_mlc *mlc) } enqueue: hp_sdc_enqueue_transaction(&priv->trans); - done: - write_unlock_irqrestore(&mlc->lock, flags); } static int __init hp_sdc_mlc_init(void) diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h index debd71515312..9db3d454887f 100644 --- a/include/linux/hp_sdc.h +++ b/include/linux/hp_sdc.h @@ -71,6 +71,7 @@ typedef struct { struct semaphore *semaphore; /* Semaphore to sleep on. */ } act; } hp_sdc_transaction; +int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this); int hp_sdc_enqueue_transaction(hp_sdc_transaction *this); int hp_sdc_dequeue_transaction(hp_sdc_transaction *this); -- cgit v1.2.3-58-ga151 From 5b2a08262a8c952fef008154933953f083ca5766 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Apr 2007 01:29:46 -0400 Subject: Input: rework handle creation code - consolidate code for binding handlers to a device - return error codes from handlers connect() methods back to input core and log failures Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 28 ++++++++++----- drivers/input/evbug.c | 32 ++++++++++++------ drivers/input/evdev.c | 47 ++++++++++++++++++++------ drivers/input/input.c | 88 ++++++++++++++++++++++++++++-------------------- drivers/input/joydev.c | 48 ++++++++++++++++++++------ drivers/input/mousedev.c | 61 ++++++++++++++++++++++++--------- drivers/input/power.c | 46 ++++++++++++++++--------- drivers/input/tsdev.c | 58 +++++++++++++++++++++---------- include/linux/input.h | 5 ++- 9 files changed, 288 insertions(+), 125 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 3d211e8553f7..59712546f911 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -41,7 +41,6 @@ #include #include -static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); /* @@ -1260,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, * likes it, it can open it and get events from it. In this (kbd_connect) * function, we should decide which VT to bind that keyboard to initially. */ -static struct input_handle *kbd_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) +static int kbd_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; + int error; int i; for (i = KEY_RESERVED; i < BTN_MISC; i++) @@ -1272,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler, break; if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) - return NULL; + return -ENODEV; handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); if (!handle) - return NULL; + return -ENOMEM; handle->dev = dev; handle->handler = handler; handle->name = "kbd"; - input_open_device(handle); + error = input_register_handle(handle); + if (error) + goto err_free_handle; + + error = input_open_device(handle); + if (error) + goto err_unregister_handle; + + return 0; - return handle; + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; } static void kbd_disconnect(struct input_handle *handle) { input_close_device(handle); + input_unregister_handle(handle); kfree(handle); } diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 5a9653c3128a..c21f2f127234 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input driver event debug module"); MODULE_LICENSE("GPL"); -static char evbug_name[] = "evbug"; - static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); } -static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static int evbug_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; + int error; - if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) - return NULL; + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; handle->dev = dev; handle->handler = handler; - handle->name = evbug_name; + handle->name = "evbug"; + + error = input_register_handle(handle); + if (error) + goto err_free_handle; - input_open_device(handle); + error = input_open_device(handle); + if (error) + goto err_unregister_handle; printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys); - return handle; + return 0; + + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; } static void evbug_disconnect(struct input_handle *handle) @@ -70,7 +82,7 @@ static void evbug_disconnect(struct input_handle *handle) printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys); input_close_device(handle); - + input_unregister_handle(handle); kfree(handle); } diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 64b47de052bb..840fa1986527 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -605,21 +605,24 @@ static const struct file_operations evdev_fops = { .flush = evdev_flush }; -static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static int evdev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct evdev *evdev; struct class_device *cdev; + dev_t devt; int minor; + int error; for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); if (minor == EVDEV_MINORS) { printk(KERN_ERR "evdev: no more free evdev devices\n"); - return NULL; + return -ENFILE; } - if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL))) - return NULL; + evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); + if (!evdev) + return -ENOMEM; INIT_LIST_HEAD(&evdev->list); init_waitqueue_head(&evdev->wait); @@ -634,15 +637,35 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct evdev_table[minor] = evdev; - cdev = class_device_create(&input_class, &dev->cdev, - MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - dev->cdev.dev, evdev->name); + devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), + + cdev = class_device_create(&input_class, &dev->cdev, devt, + dev->cdev.dev, evdev->name); + if (IS_ERR(cdev)) { + error = PTR_ERR(cdev); + goto err_free_evdev; + } /* temporary symlink to keep userspace happy */ - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, - evdev->name); + error = sysfs_create_link(&input_class.subsys.kset.kobj, + &cdev->kobj, evdev->name); + if (error) + goto err_cdev_destroy; + + error = input_register_handle(&evdev->handle); + if (error) + goto err_remove_link; - return &evdev->handle; + return 0; + + err_remove_link: + sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); + err_cdev_destroy: + class_device_destroy(&input_class, devt); + err_free_evdev: + kfree(evdev); + evdev_table[minor] = NULL; + return error; } static void evdev_disconnect(struct input_handle *handle) @@ -650,6 +673,8 @@ static void evdev_disconnect(struct input_handle *handle) struct evdev *evdev = handle->private; struct evdev_list *list; + input_unregister_handle(handle); + sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); diff --git a/drivers/input/input.c b/drivers/input/input.c index 5629e397520d..86b27079004a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -380,12 +380,6 @@ static int input_default_setkeycode(struct input_dev *dev, } -static void input_link_handle(struct input_handle *handle) -{ - list_add_tail(&handle->d_node, &handle->dev->h_list); - list_add_tail(&handle->h_node, &handle->handler->h_list); -} - #define MATCH_BIT(bit, max) \ for (i = 0; i < NBITS(max); i++) \ if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ @@ -432,6 +426,29 @@ static const struct input_device_id *input_match_device(const struct input_devic return NULL; } +static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) +{ + const struct input_device_id *id; + int error; + + if (handler->blacklist && input_match_device(handler->blacklist, dev)) + return -ENODEV; + + id = input_match_device(handler->id_table, dev); + if (!id) + return -ENODEV; + + error = handler->connect(handler, dev, id); + if (error && error != -ENODEV) + printk(KERN_ERR + "input: failed to attach handler %s to device %s, " + "error: %d\n", + handler->name, kobject_name(&dev->cdev.kobj), error); + + return error; +} + + #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -1032,9 +1049,7 @@ EXPORT_SYMBOL(input_free_device); int input_register_device(struct input_dev *dev) { static atomic_t input_no = ATOMIC_INIT(0); - struct input_handle *handle; struct input_handler *handler; - const struct input_device_id *id; const char *path; int error; @@ -1074,13 +1089,7 @@ int input_register_device(struct input_dev *dev) kfree(path); list_for_each_entry(handler, &input_handler_list, node) - if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) - if ((id = input_match_device(handler->id_table, dev))) - if ((handle = handler->connect(handler, dev, id))) { - input_link_handle(handle); - if (handler->start) - handler->start(handle); - } + input_attach_handler(dev, handler); input_wakeup_procfs_readers(); @@ -1090,7 +1099,7 @@ EXPORT_SYMBOL(input_register_device); void input_unregister_device(struct input_dev *dev) { - struct list_head *node, *next; + struct input_handle *handle, *next; int code; for (code = 0; code <= KEY_MAX; code++) @@ -1100,12 +1109,9 @@ void input_unregister_device(struct input_dev *dev) del_timer_sync(&dev->timer); - list_for_each_safe(node, next, &dev->h_list) { - struct input_handle * handle = to_handle(node); - list_del_init(&handle->d_node); - list_del_init(&handle->h_node); + list_for_each_entry_safe(handle, next, &dev->h_list, d_node) handle->handler->disconnect(handle); - } + WARN_ON(!list_empty(&dev->h_list)); list_del_init(&dev->node); @@ -1118,8 +1124,6 @@ EXPORT_SYMBOL(input_unregister_device); int input_register_handler(struct input_handler *handler) { struct input_dev *dev; - struct input_handle *handle; - const struct input_device_id *id; INIT_LIST_HEAD(&handler->h_list); @@ -1133,13 +1137,7 @@ int input_register_handler(struct input_handler *handler) list_add_tail(&handler->node, &input_handler_list); list_for_each_entry(dev, &input_dev_list, node) - if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) - if ((id = input_match_device(handler->id_table, dev))) - if ((handle = handler->connect(handler, dev, id))) { - input_link_handle(handle); - if (handler->start) - handler->start(handle); - } + input_attach_handler(dev, handler); input_wakeup_procfs_readers(); return 0; @@ -1148,14 +1146,11 @@ EXPORT_SYMBOL(input_register_handler); void input_unregister_handler(struct input_handler *handler) { - struct list_head *node, *next; + struct input_handle *handle, *next; - list_for_each_safe(node, next, &handler->h_list) { - struct input_handle * handle = to_handle_h(node); - list_del_init(&handle->h_node); - list_del_init(&handle->d_node); + list_for_each_entry_safe(handle, next, &handler->h_list, h_node) handler->disconnect(handle); - } + WARN_ON(!list_empty(&handler->h_list)); list_del_init(&handler->node); @@ -1166,6 +1161,27 @@ void input_unregister_handler(struct input_handler *handler) } EXPORT_SYMBOL(input_unregister_handler); +int input_register_handle(struct input_handle *handle) +{ + struct input_handler *handler = handle->handler; + + list_add_tail(&handle->d_node, &handle->dev->h_list); + list_add_tail(&handle->h_node, &handler->h_list); + + if (handler->start) + handler->start(handle); + + return 0; +} +EXPORT_SYMBOL(input_register_handle); + +void input_unregister_handle(struct input_handle *handle) +{ + list_del_init(&handle->h_node); + list_del_init(&handle->d_node); +} +EXPORT_SYMBOL(input_unregister_handle); + static int input_open_file(struct inode *inode, struct file *file) { struct input_handler *handler = input_table[iminor(inode) >> 5]; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 9f3529ad3fda..cf24a5bde539 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -465,21 +465,24 @@ static const struct file_operations joydev_fops = { .fasync = joydev_fasync, }; -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static int joydev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct joydev *joydev; struct class_device *cdev; + dev_t devt; int i, j, t, minor; + int error; for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); if (minor == JOYDEV_MINORS) { printk(KERN_ERR "joydev: no more free joydev devices\n"); - return NULL; + return -ENFILE; } - if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL))) - return NULL; + joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); + if (!joydev) + return -ENOMEM; INIT_LIST_HEAD(&joydev->list); init_waitqueue_head(&joydev->wait); @@ -534,22 +537,45 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct joydev_table[minor] = joydev; - cdev = class_device_create(&input_class, &dev->cdev, - MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - dev->cdev.dev, joydev->name); + devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), + + cdev = class_device_create(&input_class, &dev->cdev, devt, + dev->cdev.dev, joydev->name); + if (IS_ERR(cdev)) { + error = PTR_ERR(cdev); + goto err_free_joydev; + } /* temporary symlink to keep userspace happy */ - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, - joydev->name); + error = sysfs_create_link(&input_class.subsys.kset.kobj, + &cdev->kobj, joydev->name); + if (error) + goto err_cdev_destroy; + + error = input_register_handle(&joydev->handle); + if (error) + goto err_remove_link; + + return 0; - return &joydev->handle; + err_remove_link: + sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); + err_cdev_destroy: + class_device_destroy(&input_class, devt); + err_free_joydev: + joydev_table[minor] = NULL; + kfree(joydev); + return error; } + static void joydev_disconnect(struct input_handle *handle) { struct joydev *joydev = handle->private; struct joydev_list *list; + input_unregister_handle(handle); + sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); joydev->exist = 0; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 664bcc8116fc..007e72f80251 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -624,23 +624,27 @@ static const struct file_operations mousedev_fops = { .fasync = mousedev_fasync, }; -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct mousedev *mousedev; struct class_device *cdev; - int minor = 0; + dev_t devt; + int minor; + int error; for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); if (minor == MOUSEDEV_MINORS) { printk(KERN_ERR "mousedev: no more free mousedev devices\n"); - return NULL; + return -ENFILE; } - if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL))) - return NULL; + mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); + if (!mousedev) + return -ENOMEM; INIT_LIST_HEAD(&mousedev->list); + INIT_LIST_HEAD(&mousedev->mixdev_node); init_waitqueue_head(&mousedev->wait); mousedev->minor = minor; @@ -651,20 +655,45 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru mousedev->handle.private = mousedev; sprintf(mousedev->name, "mouse%d", minor); - if (mousedev_mix.open) - input_open_device(&mousedev->handle); - mousedev_table[minor] = mousedev; - cdev = class_device_create(&input_class, &dev->cdev, - MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - dev->cdev.dev, mousedev->name); + devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), + + cdev = class_device_create(&input_class, &dev->cdev, devt, + dev->cdev.dev, mousedev->name); + if (IS_ERR(cdev)) { + error = PTR_ERR(cdev); + goto err_free_mousedev; + } /* temporary symlink to keep userspace happy */ - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, - mousedev->name); + error = sysfs_create_link(&input_class.subsys.kset.kobj, + &cdev->kobj, mousedev->name); + if (error) + goto err_cdev_destroy; - return &mousedev->handle; + error = input_register_handle(&mousedev->handle); + if (error) + goto err_remove_link; + + if (mousedev_mix.open) { + error = input_open_device(&mousedev->handle); + if (error) + goto err_unregister_handle; + } + + return 0; + + err_unregister_handle: + input_unregister_handle(&mousedev->handle); + err_remove_link: + sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); + err_cdev_destroy: + class_device_destroy(&input_class, devt); + err_free_mousedev: + mousedev_table[minor] = NULL; + kfree(mousedev); + return error; } static void mousedev_disconnect(struct input_handle *handle) @@ -672,6 +701,8 @@ static void mousedev_disconnect(struct input_handle *handle) struct mousedev *mousedev = handle->private; struct mousedev_list *list; + input_unregister_handle(handle); + sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); diff --git a/drivers/input/power.c b/drivers/input/power.c index ee82464a2fa7..e28d264b9e06 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c @@ -41,14 +41,14 @@ static struct input_handler power_handler; * Power management can't be done in a interrupt context. So we have to * use keventd. */ -static int suspend_button_pushed = 0; -static void suspend_button_task_handler(void *data) +static int suspend_button_pushed; +static void suspend_button_task_handler(struct work_struct *work) { udelay(200); /* debounce */ suspend_button_pushed = 0; } -static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); +static DECLARE_WORK(suspend_button_task, suspend_button_task_handler); static void power_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) @@ -63,9 +63,9 @@ static void power_event(struct input_handle *handle, unsigned int type, printk("Powering down entire device\n"); if (!suspend_button_pushed) { - suspend_button_pushed = 1; - schedule_work(&suspend_button_task); - } + suspend_button_pushed = 1; + schedule_work(&suspend_button_task); + } break; case KEY_POWER: /* Hum power down the machine. */ @@ -84,7 +84,7 @@ static void power_event(struct input_handle *handle, unsigned int type, dev->state = PM_RESUME; else dev->state = PM_SUSPEND; - pm_send(dev->pm_dev, dev->state, dev); + /* pm_send(dev->pm_dev, dev->state, dev); */ break; case KEY_POWER: /* Turn the input device off completely ? */ @@ -96,27 +96,41 @@ static void power_event(struct input_handle *handle, unsigned int type, return; } -static struct input_handle *power_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) +static int power_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; + int error; - if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) - return NULL; + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; handle->dev = dev; handle->handler = handler; + handle->name = "power"; - input_open_device(handle); + error = input_register_handle(handle); + if (error) + goto err_free_handle; - printk(KERN_INFO "power.c: Adding power management to input layer\n"); - return handle; + error = input_open_device(handle); + if (error) + goto err_unregister_handle; + + return 0; + + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; } static void power_disconnect(struct input_handle *handle) { input_close_device(handle); + input_unregister_handle(handle); kfree(handle); } @@ -135,7 +149,7 @@ static const struct input_device_id power_ids[] = { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_PWR) }, }, - { }, /* Terminating entry */ + { }, /* Terminating entry */ }; MODULE_DEVICE_TABLE(input, power_ids); diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 0300dca8591d..a23aedc64ab1 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -155,7 +155,7 @@ static int tsdev_open(struct inode *inode, struct file *file) "for removal.\nSee Documentation/feature-removal-schedule.txt " "for details.\n"); - if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) + if (i >= TSDEV_MINORS) return -ENODEV; if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL))) @@ -246,14 +246,14 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, switch (cmd) { case TS_GET_CAL: - if (copy_to_user ((void __user *)arg, &tsdev->cal, - sizeof (struct ts_calibration))) + if (copy_to_user((void __user *)arg, &tsdev->cal, + sizeof (struct ts_calibration))) retval = -EFAULT; break; case TS_SET_CAL: - if (copy_from_user (&tsdev->cal, (void __user *)arg, - sizeof (struct ts_calibration))) + if (copy_from_user(&tsdev->cal, (void __user *)arg, + sizeof (struct ts_calibration))) retval = -EFAULT; break; @@ -370,23 +370,25 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, wake_up_interruptible(&tsdev->wait); } -static struct input_handle *tsdev_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) +static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct tsdev *tsdev; struct class_device *cdev; + dev_t devt; int minor, delta; + int error; for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); if (minor >= TSDEV_MINORS / 2) { printk(KERN_ERR "tsdev: You have way too many touchscreens\n"); - return NULL; + return -ENFILE; } - if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL))) - return NULL; + tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL); + if (!tsdev) + return -ENOMEM; INIT_LIST_HEAD(&tsdev->list); init_waitqueue_head(&tsdev->wait); @@ -415,15 +417,35 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev_table[minor] = tsdev; - cdev = class_device_create(&input_class, &dev->cdev, - MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - dev->cdev.dev, tsdev->name); + devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), + + cdev = class_device_create(&input_class, &dev->cdev, devt, + dev->cdev.dev, tsdev->name); + if (IS_ERR(cdev)) { + error = PTR_ERR(cdev); + goto err_free_tsdev; + } /* temporary symlink to keep userspace happy */ - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, - tsdev->name); + error = sysfs_create_link(&input_class.subsys.kset.kobj, + &cdev->kobj, tsdev->name); + if (error) + goto err_cdev_destroy; - return &tsdev->handle; + error = input_register_handle(&tsdev->handle); + if (error) + goto err_remove_link; + + return 0; + + err_remove_link: + sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); + err_cdev_destroy: + class_device_destroy(&input_class, devt); + err_free_tsdev: + tsdev_table[minor] = NULL; + kfree(tsdev); + return error; } static void tsdev_disconnect(struct input_handle *handle) @@ -431,6 +453,8 @@ static void tsdev_disconnect(struct input_handle *handle) struct tsdev *tsdev = handle->private; struct tsdev_list *list; + input_unregister_handle(handle); + sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); diff --git a/include/linux/input.h b/include/linux/input.h index 3a8b8c6f0ab5..a51d6cf6824c 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1049,7 +1049,7 @@ struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); - struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); + int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); @@ -1102,6 +1102,9 @@ void input_unregister_device(struct input_dev *); int input_register_handler(struct input_handler *); void input_unregister_handler(struct input_handler *); +int input_register_handle(struct input_handle *); +void input_unregister_handle(struct input_handle *); + int input_grab_device(struct input_handle *); void input_release_device(struct input_handle *); -- cgit v1.2.3-58-ga151 From 6480e2a275ff8ff48ae23a011616fcf819ed7a4e Mon Sep 17 00:00:00 2001 From: Eric Piel Date: Thu, 12 Apr 2007 01:32:34 -0400 Subject: Input: wistron - add acerhk laptop database Acerhk supports already a lot of laptops. Lets import its database so that everyone can benefit of the work of Olaf Tauber. Only the "tm_new" laptops were imported. "tm_old" laptops could be possible but requires more testing and probably only few laptops are still alive. "dritek" laptops should probably be imported into a different driver. Also compress the keymaps by fitting each entry on an int. Most of the dmi matching was written based on google searches, so it's rather prone to errors. That's why I'm asking people to confirm it works. Support to generate switch input events was added as some laptops indicate lid open/close through this interface. This adds the following hardware: Acer TravelMate 370 Acer TravelMate 380 Acer TravelMate C300 Acer TravelMate C100 Acer TravelMate C110 Acer TravelMate 250 Acer TravelMate 350 Acer TravelMate 620 Acer TravelMate 630 Acer TravelMate 220 Acer TravelMate 230 Acer TravelMate 260 Acer TravelMate 280 Acer TravelMate 360 Acer TravelMate 2100 Acer TravelMate 2410 Acer Aspire 1500 Acer Aspire 1600 Acer Aspire 3020 Acer Aspire 5020 Medion MD 2900 Medion MD 40100 Medion MD 95400 Medion MD 96500 Fujitsu Siemens Amilo 7820 Signed-off-by: Eric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 595 +++++++++++++++++++++++++++++++++----- include/linux/input.h | 1 + 2 files changed, 524 insertions(+), 72 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 39e437599d35..47de377330b8 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -233,10 +233,20 @@ static void bios_set_state(u8 subsys, int enable) struct key_entry { char type; /* See KE_* below */ u8 code; - unsigned keycode; /* For KE_KEY */ + union { + u16 keycode; /* For KE_KEY */ + struct { /* For KE_SW */ + u8 code; + u8 value; + } sw; + }; }; -enum { KE_END, KE_KEY, KE_WIFI, KE_BLUETOOTH }; +enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; + +#define FE_MAIL_LED 0x01 +#define FE_WIFI_LED 0x02 +#define FE_UNTESTED 0x80 static const struct key_entry *keymap; /* = NULL; Current key map */ static int have_wifi; @@ -261,104 +271,301 @@ static struct key_entry keymap_empty[] = { }; static struct key_entry keymap_fs_amilo_pro_v2000[] = { - { KE_KEY, 0x01, KEY_HELP }, - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_WIFI, 0x30, 0 }, - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, { KE_END, 0 } }; static struct key_entry keymap_fujitsu_n3510[] = { - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_KEY, 0x36, KEY_WWW }, - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x71, KEY_STOPCD }, - { KE_KEY, 0x72, KEY_PLAYPAUSE }, - { KE_KEY, 0x74, KEY_REWIND }, - { KE_KEY, 0x78, KEY_FORWARD }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x71, {KEY_STOPCD} }, + { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, + { KE_KEY, 0x74, {KEY_REWIND} }, + { KE_KEY, 0x78, {KEY_FORWARD} }, { KE_END, 0 } }; static struct key_entry keymap_wistron_ms2111[] = { - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_KEY, 0x13, KEY_PROG3 }, - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x36, KEY_WWW }, - { KE_END, 0 } + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x13, {KEY_PROG3} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_END, FE_MAIL_LED } +}; + +static struct key_entry keymap_wistron_md40100[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ + { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } }; static struct key_entry keymap_wistron_ms2141[] = { - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_WIFI, 0x30, 0 }, - { KE_KEY, 0x22, KEY_REWIND }, - { KE_KEY, 0x23, KEY_FORWARD }, - { KE_KEY, 0x24, KEY_PLAYPAUSE }, - { KE_KEY, 0x25, KEY_STOPCD }, - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x22, {KEY_REWIND} }, + { KE_KEY, 0x23, {KEY_FORWARD} }, + { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, + { KE_KEY, 0x25, {KEY_STOPCD} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, { KE_END, 0 } }; static struct key_entry keymap_acer_aspire_1500[] = { - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_WIFI, 0x30, 0 }, - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x36, KEY_WWW }, - { KE_BLUETOOTH, 0x44, 0 }, - { KE_END, 0 } + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x03, {KEY_POWER} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x49, {KEY_CONFIG} }, + { KE_BLUETOOTH, 0x44 }, + { KE_END, FE_UNTESTED } +}; + +static struct key_entry keymap_acer_aspire_1600[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x03, {KEY_POWER} }, + { KE_KEY, 0x08, {KEY_MUTE} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x13, {KEY_PROG3} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x49, {KEY_CONFIG} }, + { KE_WIFI, 0x30 }, + { KE_BLUETOOTH, 0x44 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } +}; + +/* 3020 has been tested */ +static struct key_entry keymap_acer_aspire_5020[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x03, {KEY_POWER} }, + { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x6a, {KEY_CONFIG} }, + { KE_WIFI, 0x30 }, + { KE_BLUETOOTH, 0x44 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_acer_travelmate_2410[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x6d, {KEY_POWER} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x6a, {KEY_CONFIG} }, + { KE_WIFI, 0x30 }, + { KE_BLUETOOTH, 0x44 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_acer_travelmate_110[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x03, {KEY_POWER} }, + { KE_KEY, 0x08, {KEY_MUTE} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x20, {KEY_VOLUMEUP} }, + { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ + { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ + { KE_WIFI, 0x30 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_acer_travelmate_300[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x03, {KEY_POWER} }, + { KE_KEY, 0x08, {KEY_MUTE} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x20, {KEY_VOLUMEUP} }, + { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_WIFI, 0x30 }, + { KE_BLUETOOTH, 0x44 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_acer_travelmate_380[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */ + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x13, {KEY_PROG3} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_WIFI, 0x30 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } +}; + +/* unusual map */ +static struct key_entry keymap_acer_travelmate_220[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x11, {KEY_MAIL} }, + { KE_KEY, 0x12, {KEY_WWW} }, + { KE_KEY, 0x13, {KEY_PROG2} }, + { KE_KEY, 0x31, {KEY_PROG1} }, + { KE_END, FE_WIFI_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_acer_travelmate_230[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_END, FE_WIFI_LED | FE_UNTESTED } }; static struct key_entry keymap_acer_travelmate_240[] = { - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x36, KEY_WWW }, - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_BLUETOOTH, 0x44, 0 }, - { KE_WIFI, 0x30, 0 }, - { KE_END, 0 } + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x03, {KEY_POWER} }, + { KE_KEY, 0x08, {KEY_MUTE} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_BLUETOOTH, 0x44 }, + { KE_WIFI, 0x30 }, + { KE_END, FE_UNTESTED } +}; + +static struct key_entry keymap_acer_travelmate_350[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x13, {KEY_MAIL} }, + { KE_KEY, 0x14, {KEY_PROG3} }, + { KE_KEY, 0x15, {KEY_WWW} }, + { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_acer_travelmate_360[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x13, {KEY_MAIL} }, + { KE_KEY, 0x14, {KEY_PROG3} }, + { KE_KEY, 0x15, {KEY_WWW} }, + { KE_KEY, 0x40, {KEY_WLAN} }, + { KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */ }; /* Wifi subsystem only activates the led. Therefore we need to pass * wifi event as a normal key, then userspace can really change the wifi state. * TODO we need to export led state to userspace (wifi and mail) */ static struct key_entry keymap_acer_travelmate_610[] = { - { KE_KEY, 0x01, KEY_HELP }, - { KE_KEY, 0x02, KEY_CONFIG }, - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_KEY, 0x13, KEY_PROG3 }, - { KE_KEY, 0x14, KEY_MAIL }, - { KE_KEY, 0x15, KEY_WWW }, - { KE_KEY, 0x40, KEY_WLAN }, /* Wifi */ - { KE_END, 0 } + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG3} }, + { KE_KEY, 0x13, {KEY_PROG3} }, + { KE_KEY, 0x14, {KEY_MAIL} }, + { KE_KEY, 0x15, {KEY_WWW} }, + { KE_KEY, 0x40, {KEY_WLAN} }, + { KE_END, FE_MAIL_LED | FE_WIFI_LED } +}; + +static struct key_entry keymap_acer_travelmate_630[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x03, {KEY_POWER} }, + { KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */ + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x13, {KEY_PROG3} }, + { KE_KEY, 0x20, {KEY_VOLUMEUP} }, + { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_WIFI, 0x30 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } }; static struct key_entry keymap_aopen_1559as[] = { - { KE_KEY, 0x01, KEY_HELP }, - { KE_KEY, 0x06, KEY_PROG3 }, - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_WIFI, 0x30, 0 }, - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x06, {KEY_PROG3} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, { KE_END, 0 }, }; static struct key_entry keymap_fs_amilo_d88x0[] = { - { KE_KEY, 0x01, KEY_HELP }, - { KE_KEY, 0x08, KEY_MUTE }, - { KE_KEY, 0x31, KEY_MAIL }, - { KE_KEY, 0x36, KEY_WWW }, - { KE_KEY, 0x11, KEY_PROG1 }, - { KE_KEY, 0x12, KEY_PROG2 }, - { KE_KEY, 0x13, KEY_PROG3 }, - { KE_END, 0 } + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x08, {KEY_MUTE} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x13, {KEY_PROG3} }, + { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_wistron_md2900[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_WIFI, 0x30 }, + { KE_END, FE_MAIL_LED | FE_UNTESTED } +}; + +static struct key_entry keymap_wistron_md96500[] = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x02, {KEY_CONFIG} }, + { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ + { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ + { KE_KEY, 0x08, {KEY_MUTE} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_KEY, 0x20, {KEY_VOLUMEUP} }, + { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, + { KE_KEY, 0x22, {KEY_REWIND} }, + { KE_KEY, 0x23, {KEY_FORWARD} }, + { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, + { KE_KEY, 0x25, {KEY_STOPCD} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_WIFI, 0x30 }, + { KE_BLUETOOTH, 0x44 }, + { KE_END, FE_UNTESTED } }; /* @@ -403,6 +610,133 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_acer_aspire_1500 }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 1600", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), + }, + .driver_data = keymap_acer_aspire_1600 + }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 3020", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), + }, + .driver_data = keymap_acer_aspire_5020 + }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 5020", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), + }, + .driver_data = keymap_acer_aspire_5020 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 2100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), + }, + .driver_data = keymap_acer_aspire_5020 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 2410", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), + }, + .driver_data = keymap_acer_travelmate_2410 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate C300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), + }, + .driver_data = keymap_acer_travelmate_300 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate C100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), + }, + .driver_data = keymap_acer_travelmate_300 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate C110", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), + }, + .driver_data = keymap_acer_travelmate_110 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 380", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), + }, + .driver_data = keymap_acer_travelmate_380 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 370", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), + }, + .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 220", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), + }, + .driver_data = keymap_acer_travelmate_220 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 260", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), + }, + .driver_data = keymap_acer_travelmate_220 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 230", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), + /* acerhk looks for "TravelMate F4..." ?! */ + }, + .driver_data = keymap_acer_travelmate_230 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 280", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), + }, + .driver_data = keymap_acer_travelmate_230 + }, { .callback = dmi_matched, .ident = "Acer TravelMate 240", @@ -412,6 +746,15 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_acer_travelmate_240 }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 250", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), + }, + .driver_data = keymap_acer_travelmate_240 + }, { .callback = dmi_matched, .ident = "Acer TravelMate 2424NWXCi", @@ -421,6 +764,24 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_acer_travelmate_240 }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 350", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), + }, + .driver_data = keymap_acer_travelmate_350 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), + }, + .driver_data = keymap_acer_travelmate_360 + }, { .callback = dmi_matched, .ident = "Acer TravelMate 610", @@ -430,6 +791,24 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_acer_travelmate_610 }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 620", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), + }, + .driver_data = keymap_acer_travelmate_630 + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 630", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), + }, + .driver_data = keymap_acer_travelmate_630 + }, { .callback = dmi_matched, .ident = "AOpen 1559AS", @@ -448,6 +827,51 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_wistron_ms2111 }, + { + .callback = dmi_matched, + .ident = "Medion MD 40100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), + DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), + }, + .driver_data = keymap_wistron_md40100 + }, + { + .callback = dmi_matched, + .ident = "Medion MD 2900", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), + DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), + }, + .driver_data = keymap_wistron_md2900 + }, + { + .callback = dmi_matched, + .ident = "Medion MD 96500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), + DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), + }, + .driver_data = keymap_wistron_md96500 + }, + { + .callback = dmi_matched, + .ident = "Medion MD 95400", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), + DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), + }, + .driver_data = keymap_wistron_md96500 + }, + { + .callback = dmi_matched, + .ident = "Fujitsu Siemens Amilo D7820", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ + DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), + }, + .driver_data = keymap_fs_amilo_d88x0 + }, { .callback = dmi_matched, .ident = "Fujitsu Siemens Amilo D88x0", @@ -500,12 +924,28 @@ static int __devinit setup_input_dev(void) input_dev->cdev.dev = &wistron_device->dev; for (key = keymap; key->type != KE_END; key++) { - if (key->type == KE_KEY) { - input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY); - set_bit(key->keycode, input_dev->keybit); + switch (key->type) { + case KE_KEY: + set_bit(EV_KEY, input_dev->evbit); + set_bit(key->keycode, input_dev->keybit); + break; + + case KE_SW: + set_bit(EV_SW, input_dev->evbit); + set_bit(key->sw.code, input_dev->swbit); + break; + + default: + ; } } + /* reads information flags on KE_END */ + if (key->code & FE_UNTESTED) + printk(KERN_WARNING "Untested laptop multimedia keys, " + "please report success or failure to eric.piel" + "@tremplin-utc.net\n"); + error = input_register_device(input_dev); if (error) { input_free_device(input_dev); @@ -523,6 +963,12 @@ static void report_key(unsigned keycode) input_sync(input_dev); } +static void report_switch(unsigned code, int value) +{ + input_report_switch(input_dev, code, value); + input_sync(input_dev); +} + /* Driver core */ static int wifi_enabled; @@ -543,6 +989,10 @@ static void handle_key(u8 code) report_key(key->keycode); break; + case KE_SW: + report_switch(key->sw.code, key->sw.value); + break; + case KE_WIFI: if (have_wifi) { wifi_enabled = !wifi_enabled; @@ -558,6 +1008,7 @@ static void handle_key(u8 code) break; case KE_END: + break; default: BUG(); } diff --git a/include/linux/input.h b/include/linux/input.h index a51d6cf6824c..9bd984b2d122 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -506,6 +506,7 @@ struct input_absinfo { #define KEY_VOICEMAIL 0x1ac #define KEY_ADDRESSBOOK 0x1ad #define KEY_MESSENGER 0x1ae +#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ #define KEY_DEL_EOL 0x1c0 #define KEY_DEL_EOS 0x1c1 -- cgit v1.2.3-58-ga151 From 3abccf36081ac827cf5d14db6837117f088937eb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Apr 2007 01:33:51 -0400 Subject: Input: add input_{get|set}_drvdata() helpers Add helpers to set up and access driver-specific data in input device structure. Once conversion to struct driver is complete we will drop input_dev->private and will use dev_get_drvdata() and dev_set_drvdata(). Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/input.h b/include/linux/input.h index 9bd984b2d122..d0bea9755186 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1097,6 +1097,16 @@ static inline void input_put_device(struct input_dev *dev) class_device_put(&dev->cdev); } +static inline void *input_get_drvdata(struct input_dev *dev) +{ + return dev->private; +} + +static inline void input_set_drvdata(struct input_dev *dev, void *data) +{ + dev->private = data; +} + int input_register_device(struct input_dev *); void input_unregister_device(struct input_dev *); -- cgit v1.2.3-58-ga151 From 88a447a030bfec9f1e8666daf27d9d73c8c92448 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Apr 2007 01:34:47 -0400 Subject: Input: prepare to switching to struct device In preparation to switching to struct device and class device going away provide an alias to allow drivers that create devices to use either input_dev->cdev.dev or input_dev->dev.parent to put them into sysfs tree. The former will go away once conversion to struct device is complete. Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 3 +++ include/linux/input.h | 3 +++ 2 files changed, 6 insertions(+) (limited to 'include/linux') diff --git a/drivers/input/input.c b/drivers/input/input.c index 86b27079004a..173c2861ec58 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1079,6 +1079,9 @@ int input_register_device(struct input_dev *dev) snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); + if (!dev->cdev.dev) + dev->cdev.dev = dev->dev.parent; + error = class_device_add(&dev->cdev); if (error) return error; diff --git a/include/linux/input.h b/include/linux/input.h index d0bea9755186..7b6d7c408b07 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -972,6 +972,9 @@ struct input_dev { unsigned int users; struct class_device cdev; + union { /* temporarily so while we switching to struct device */ + struct device *parent; + } dev; struct list_head h_list; struct list_head node; -- cgit v1.2.3-58-ga151 From 534565f254490227e3bec20d50f387800960acd9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 25 Apr 2007 00:53:18 -0400 Subject: Input: add input_set_capability() helper Add input_set_capability() helper used to indicate that an input device supports a certain event without need to manipulate bitmaps directly. Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/input.h | 2 ++ 2 files changed, 58 insertions(+) (limited to 'include/linux') diff --git a/drivers/input/input.c b/drivers/input/input.c index 173c2861ec58..915e9ab7cab0 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1046,6 +1046,62 @@ void input_free_device(struct input_dev *dev) } EXPORT_SYMBOL(input_free_device); +/** + * input_set_capability - mark device as capable of a certain event + * @dev: device that is capable of emitting or accepting event + * @type: type of the event (EV_KEY, EV_REL, etc...) + * @code: event code + * + * In addition to setting up corresponding bit in appropriate capability + * bitmap the function also adjusts dev->evbit. + */ +void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) +{ + switch (type) { + case EV_KEY: + __set_bit(code, dev->keybit); + break; + + case EV_REL: + __set_bit(code, dev->relbit); + break; + + case EV_ABS: + __set_bit(code, dev->absbit); + break; + + case EV_MSC: + __set_bit(code, dev->mscbit); + break; + + case EV_SW: + __set_bit(code, dev->swbit); + break; + + case EV_LED: + __set_bit(code, dev->ledbit); + break; + + case EV_SND: + __set_bit(code, dev->sndbit); + break; + + case EV_FF: + __set_bit(code, dev->ffbit); + break; + + default: + printk(KERN_ERR + "input_set_capability: unknown type %u (code %u)\n", + type, code); + dump_stack(); + return; + } + + __set_bit(type, dev->evbit); +} +EXPORT_SYMBOL(input_set_capability); + int input_register_device(struct input_dev *dev) { static atomic_t input_no = ATOMIC_INIT(0); diff --git a/include/linux/input.h b/include/linux/input.h index 7b6d7c408b07..1789ee9df4dd 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1160,6 +1160,8 @@ static inline void input_sync(struct input_dev *dev) input_event(dev, EV_SYN, SYN_REPORT, 0); } +void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code); + static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) { dev->absmin[axis] = min; -- cgit v1.2.3-58-ga151 From 0dcd8073673115eeb67343787f244905f62532f2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Apr 2007 23:42:45 -0400 Subject: Input: add skeleton for simple polled devices input-polldev provides a skeleton for supporting simple input devices that need to be periodically scanned or polled to detect changes in their state. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 11 +++ drivers/input/misc/Makefile | 1 + drivers/input/misc/input-polldev.c | 171 +++++++++++++++++++++++++++++++++++++ include/linux/input-polldev.h | 46 ++++++++++ 4 files changed, 229 insertions(+) create mode 100644 drivers/input/misc/input-polldev.c create mode 100644 include/linux/input-polldev.h (limited to 'include/linux') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 56941155ec87..696c9609d714 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -90,6 +90,17 @@ config INPUT_UINPUT To compile this driver as a module, choose M here: the module will be called uinput. +config INPUT_POLLDEV + tristate "Polled input device skeleton" + help + Say Y here if you are using a driver for an input + device that periodically polls hardware state. This + option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. + + To compile this driver as a module, choose M here: the + module will be called input-polldev. + config HP_SDC_RTC tristate "HP SDC Real Time Clock" depends on GSC || HP300 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9f08f27b06de..21e3cca0d33e 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o diff --git a/drivers/input/misc/input-polldev.c b/drivers/input/misc/input-polldev.c new file mode 100644 index 000000000000..1b2b9c9c5d88 --- /dev/null +++ b/drivers/input/misc/input-polldev.c @@ -0,0 +1,171 @@ +/* + * Generic implementation of a polled input device + + * Copyright (c) 2007 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include + +static DEFINE_MUTEX(polldev_mutex); +static int polldev_users; +static struct workqueue_struct *polldev_wq; + +static int input_polldev_start_workqueue(void) +{ + int retval; + + retval = mutex_lock_interruptible(&polldev_mutex); + if (retval) + return retval; + + if (!polldev_users) { + polldev_wq = create_singlethread_workqueue("ipolldevd"); + if (!polldev_wq) { + printk(KERN_ERR "input-polldev: failed to create " + "ipolldevd workqueue\n"); + retval = -ENOMEM; + goto out; + } + } + + polldev_users++; + + out: + mutex_unlock(&polldev_mutex); + return retval; +} + +static void input_polldev_stop_workqueue(void) +{ + mutex_lock(&polldev_mutex); + + if (!--polldev_users) + destroy_workqueue(polldev_wq); + + mutex_unlock(&polldev_mutex); +} + +static void input_polled_device_work(struct work_struct *work) +{ + struct input_polled_dev *dev = + container_of(work, struct input_polled_dev, work.work); + + dev->poll(dev); + queue_delayed_work(polldev_wq, &dev->work, + msecs_to_jiffies(dev->poll_interval)); +} + +static int input_open_polled_device(struct input_dev *input) +{ + struct input_polled_dev *dev = input->private; + int error; + + error = input_polldev_start_workqueue(); + if (error) + return error; + + if (dev->flush) + dev->flush(dev); + + queue_delayed_work(polldev_wq, &dev->work, + msecs_to_jiffies(dev->poll_interval)); + + return 0; +} + +static void input_close_polled_device(struct input_dev *input) +{ + struct input_polled_dev *dev = input->private; + + cancel_rearming_delayed_workqueue(polldev_wq, &dev->work); + input_polldev_stop_workqueue(); +} + +/** + * input_allocate_polled_device - allocated memory polled device + * + * The function allocates memory for a polled device and also + * for an input device associated with this polled device. + */ +struct input_polled_dev *input_allocate_polled_device(void) +{ + struct input_polled_dev *dev; + + dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->input = input_allocate_device(); + if (!dev->input) { + kfree(dev); + return NULL; + } + + return dev; +} +EXPORT_SYMBOL(input_allocate_polled_device); + +/** + * input_free_polled_device - free memory allocated for polled device + * @dev: device to free + * + * The function frees memory allocated for polling device and drops + * reference to the associated input device (if present). + */ +void input_free_polled_device(struct input_polled_dev *dev) +{ + if (dev) { + input_free_device(dev->input); + kfree(dev); + } +} +EXPORT_SYMBOL(input_free_polled_device); + +/** + * input_register_polled_device - register polled device + * @dev: device to register + * + * The function registers previously initialized polled input device + * with input layer. The device should be allocated with call to + * input_allocate_polled_device(). Callers should also set up poll() + * method and set up capabilities (id, name, phys, bits) of the + * corresponing input_dev structure. + */ +int input_register_polled_device(struct input_polled_dev *dev) +{ + struct input_dev *input = dev->input; + + INIT_DELAYED_WORK(&dev->work, input_polled_device_work); + if (!dev->poll_interval) + dev->poll_interval = 500; + input->private = dev; + input->open = input_open_polled_device; + input->close = input_close_polled_device; + + return input_register_device(input); +} +EXPORT_SYMBOL(input_register_polled_device); + +/** + * input_unregister_polled_device - unregister polled device + * @dev: device to unregister + * + * The function unregisters previously registered polled input + * device from input layer. Polling is stopped and device is + * ready to be freed with call to input_free_polled_device(). + * Callers should not attempt to access dev->input pointer + * after calling this function. + */ +void input_unregister_polled_device(struct input_polled_dev *dev) +{ + input_unregister_device(dev->input); + dev->input = NULL; +} +EXPORT_SYMBOL(input_unregister_polled_device); + diff --git a/include/linux/input-polldev.h b/include/linux/input-polldev.h new file mode 100644 index 000000000000..597a0077b3c5 --- /dev/null +++ b/include/linux/input-polldev.h @@ -0,0 +1,46 @@ +#ifndef _INPUT_POLLDEV_H +#define _INPUT_POLLDEV_H + +/* + * Copyright (c) 2007 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include + +/** + * struct input_polled_dev - simple polled input device + * @private: private driver data + * @flush: driver-supplied method that flushes device's state upon + * opening (optional) + * @poll: driver-supplied method that polls the device and posts + * input events (mandatory). + * @poll_interval: specifies how often the poll() method shoudl be called. + * @input: input device structire associated with the polled device. + * Must be properly initialized by the driver (id, name, phys, bits). + * + * Polled input device provides a skeleton for supporting simple input + * devices that do not raise interrupts but have to be periodically + * scanned or polled to detect changes in their state. + */ +struct input_polled_dev { + void *private; + + void (*flush)(struct input_polled_dev *dev); + void (*poll)(struct input_polled_dev *dev); + unsigned int poll_interval; /* msec */ + + struct input_dev *input; + struct delayed_work work; +}; + +struct input_polled_dev *input_allocate_polled_device(void); +void input_free_polled_device(struct input_polled_dev *dev); +int input_register_polled_device(struct input_polled_dev *dev); +void input_unregister_polled_device(struct input_polled_dev *dev); + +#endif -- cgit v1.2.3-58-ga151 From 84767d00a8fd54dd97866561f6e2ee246c8e1cdc Mon Sep 17 00:00:00 2001 From: Roman Moravcik Date: Tue, 1 May 2007 00:39:13 -0400 Subject: Input: gpio_keys - add support for switches (EV_SW) Signed-off-by: Roman Moravcik Signed-off-by: Paul Sokolovsky Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 19 ++++++++++++------- include/linux/gpio_keys.h | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 0d2796cdf738..739212252b09 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -35,11 +35,14 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) struct input_dev *input = platform_get_drvdata(pdev); for (i = 0; i < pdata->nbuttons; i++) { - int gpio = pdata->buttons[i].gpio; + struct gpio_keys_button *button = &pdata->buttons[i]; + int gpio = button->gpio; + if (irq == gpio_to_irq(gpio)) { - int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low); + unsigned int type = button->type ?: EV_KEY; + int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; - input_report_key(input, pdata->buttons[i].keycode, state); + input_event(input, type, button->code, !!state); input_sync(input); } } @@ -71,19 +74,21 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) input->id.version = 0x0100; for (i = 0; i < pdata->nbuttons; i++) { - int code = pdata->buttons[i].keycode; - int irq = gpio_to_irq(pdata->buttons[i].gpio); + struct gpio_keys_button *button = &pdata->buttons[i]; + int irq = gpio_to_irq(button->gpio); + unsigned int type = button->type ?: EV_KEY; set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, - pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys", + button->desc ? button->desc : "gpio_keys", pdev); if (error) { printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, error); goto fail; } - set_bit(code, input->keybit); + + input_set_capability(input, type, button->code); } error = input_register_device(input); diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index 2b217c7b9312..265d17830a0f 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -3,10 +3,11 @@ struct gpio_keys_button { /* Configuration parameters */ - int keycode; + int code; /* input event code (KEY_*, SW_*) */ int gpio; int active_low; char *desc; + int type; /* input event type (EV_KEY, EV_SW) */ }; struct gpio_keys_platform_data { -- cgit v1.2.3-58-ga151