diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 14:45:47 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 14:45:47 -0800 |
commit | 31b6ca0af758a88e5e769b48cc6dde037ee37b96 (patch) | |
tree | e1968d7168affb25e33e2be2d1d102f94af98af0 /drivers/input | |
parent | 56b85f32d530d09d6805488ad00775d4e0e3baab (diff) | |
parent | 554738da71004d96e06fb75f4772dfc3b0f47810 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (58 commits)
Input: wacom_w8001 - support pen or touch only devices
Input: wacom_w8001 - use __set_bit to set keybits
Input: bu21013_ts - fix misuse of logical operation in place of bitop
Input: i8042 - add Acer Aspire 5100 to the Dritek list
Input: wacom - add support for digitizer in Lenovo W700
Input: psmouse - disable the synaptics extension on OLPC machines
Input: psmouse - fix up Synaptics comment
Input: synaptics - ignore bogus mt packet
Input: synaptics - add multi-finger and semi-mt support
Input: synaptics - report clickpad property
input: mt: Document interface updates
Input: fix double equality sign in uevent
Input: introduce device properties
hid: egalax: Add support for Wetab (726b)
Input: include MT library as source for kerneldoc
MAINTAINERS: Update input-mt entry
hid: egalax: Add support for Samsung NB30 netbook
hid: egalax: Document the new devices in Kconfig
hid: egalax: Add support for Wetab
hid: egalax: Convert to MT slots
...
Fixed up trivial conflict in drivers/input/keyboard/Kconfig
Diffstat (limited to 'drivers/input')
49 files changed, 2698 insertions, 610 deletions
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 7ad212d31f9..09614ce7496 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -5,7 +5,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_INPUT) += input-core.o -input-core-objs := input.o input-compat.o ff-core.o +input-core-y := input.o input-compat.o input-mt.o ff-core.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c index 7d61a966080..e90ee3d3061 100644 --- a/drivers/input/apm-power.c +++ b/drivers/input/apm-power.c @@ -9,6 +9,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/input.h> #include <linux/slab.h> @@ -23,8 +25,7 @@ static void system_power_event(unsigned int keycode) switch (keycode) { case KEY_SUSPEND: apm_queue_event(APM_USER_SUSPEND); - - printk(KERN_INFO "apm-power: Requesting system suspend...\n"); + pr_info("Requesting system suspend...\n"); break; default: break; @@ -65,18 +66,15 @@ static int apmpower_connect(struct input_handler *handler, error = input_register_handle(handle); if (error) { - printk(KERN_ERR - "apm-power: Failed to register input power handler, " - "error %d\n", error); + pr_err("Failed to register input power handler, error %d\n", + error); kfree(handle); return error; } error = input_open_device(handle); if (error) { - printk(KERN_ERR - "apm-power: Failed to open input power device, " - "error %d\n", error); + pr_err("Failed to open input power device, error %d\n", error); input_unregister_handle(handle); kfree(handle); return error; diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index f7c5c14ec12..cd4e6679d61 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -26,6 +26,8 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/slab.h> #include <linux/module.h> #include <linux/input.h> @@ -38,8 +40,8 @@ MODULE_LICENSE("GPL"); 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", - dev_name(&handle->dev->dev), type, code, value); + printk(KERN_DEBUG pr_fmt("Event. Dev: %s, Type: %d, Code: %d, Value: %d\n"), + dev_name(&handle->dev->dev), type, code, value); } static int evbug_connect(struct input_handler *handler, struct input_dev *dev, @@ -64,10 +66,10 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev, if (error) goto err_unregister_handle; - printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n", - dev_name(&dev->dev), - dev->name ?: "unknown", - dev->phys ?: "unknown"); + printk(KERN_DEBUG pr_fmt("Connected device: %s (%s at %s)\n"), + dev_name(&dev->dev), + dev->name ?: "unknown", + dev->phys ?: "unknown"); return 0; @@ -80,8 +82,8 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev, static void evbug_disconnect(struct input_handle *handle) { - printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", - dev_name(&handle->dev->dev)); + printk(KERN_DEBUG pr_fmt("Disconnected device: %s\n"), + dev_name(&handle->dev->dev)); input_close_device(handle); input_unregister_handle(handle); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 68f09a86843..c8471a2552e 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -8,6 +8,8 @@ * the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 #define EVDEV_MIN_BUFFER_SIZE 64U @@ -522,12 +524,11 @@ static int handle_eviocgbit(struct input_dev *dev, if (type == EV_KEY && size == OLD_KEY_MAX) { len = OLD_KEY_MAX; if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) - printk(KERN_WARNING - "evdev.c(EVIOCGBIT): Suspicious buffer size %u, " - "limiting output to %zu bytes. See " - "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", - OLD_KEY_MAX, - BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); + pr_warning("(EVIOCGBIT): Suspicious buffer size %u, " + "limiting output to %zu bytes. See " + "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", + OLD_KEY_MAX, + BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); } return bits_to_user(bits, len, size, p, compat_mode); @@ -686,6 +687,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, #define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) switch (EVIOC_MASK_SIZE(cmd)) { + case EVIOCGPROP(0): + return bits_to_user(dev->propbit, INPUT_PROP_MAX, + size, p, compat_mode); + case EVIOCGKEY(0): return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); @@ -897,7 +902,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, break; if (minor == EVDEV_MINORS) { - printk(KERN_ERR "evdev: no more free evdev devices\n"); + pr_err("no more free evdev devices\n"); return -ENFILE; } diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 03078c08309..3367f760d75 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -23,7 +23,7 @@ /* #define DEBUG */ -#define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg) +#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt #include <linux/input.h> #include <linux/module.h> @@ -116,7 +116,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || !test_bit(effect->type, dev->ffbit)) { - debug("invalid or not supported effect type in upload"); + pr_debug("invalid or not supported effect type in upload\n"); return -EINVAL; } @@ -124,7 +124,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, (effect->u.periodic.waveform < FF_WAVEFORM_MIN || effect->u.periodic.waveform > FF_WAVEFORM_MAX || !test_bit(effect->u.periodic.waveform, dev->ffbit))) { - debug("invalid or not supported wave form in upload"); + pr_debug("invalid or not supported wave form in upload\n"); return -EINVAL; } @@ -246,7 +246,7 @@ static int flush_effects(struct input_dev *dev, struct file *file) struct ff_device *ff = dev->ff; int i; - debug("flushing now"); + pr_debug("flushing now\n"); mutex_lock(&ff->mutex); @@ -315,8 +315,7 @@ int input_ff_create(struct input_dev *dev, int max_effects) int i; if (!max_effects) { - printk(KERN_ERR - "ff-core: cannot allocate device without any effects\n"); + pr_err("cannot allocate device without any effects\n"); return -EINVAL; } diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index 1d881c96ba8..117a59aaa70 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -23,7 +23,7 @@ /* #define DEBUG */ -#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg) +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/slab.h> #include <linux/input.h> @@ -129,7 +129,7 @@ static void ml_schedule_timer(struct ml_device *ml) int events = 0; int i; - debug("calculating next timer"); + pr_debug("calculating next timer\n"); for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { @@ -149,10 +149,10 @@ static void ml_schedule_timer(struct ml_device *ml) } if (!events) { - debug("no actions"); + pr_debug("no actions\n"); del_timer(&ml->timer); } else { - debug("timer set"); + pr_debug("timer set\n"); mod_timer(&ml->timer, earliest); } } @@ -173,8 +173,8 @@ static int apply_envelope(struct ml_effect_state *state, int value, if (envelope->attack_length && time_before(now, state->play_at + msecs_to_jiffies(envelope->attack_length))) { - debug("value = 0x%x, attack_level = 0x%x", value, - envelope->attack_level); + pr_debug("value = 0x%x, attack_level = 0x%x\n", + value, envelope->attack_level); time_from_level = jiffies_to_msecs(now - state->play_at); time_of_envelope = envelope->attack_length; envelope_level = min_t(__s16, envelope->attack_level, 0x7fff); @@ -191,13 +191,13 @@ static int apply_envelope(struct ml_effect_state *state, int value, difference = abs(value) - envelope_level; - debug("difference = %d", difference); - debug("time_from_level = 0x%x", time_from_level); - debug("time_of_envelope = 0x%x", time_of_envelope); + pr_debug("difference = %d\n", difference); + pr_debug("time_from_level = 0x%x\n", time_from_level); + pr_debug("time_of_envelope = 0x%x\n", time_of_envelope); difference = difference * time_from_level / time_of_envelope; - debug("difference = %d", difference); + pr_debug("difference = %d\n", difference); return value < 0 ? -(difference + envelope_level) : (difference + envelope_level); @@ -215,8 +215,7 @@ static int get_compatible_type(struct ff_device *ff, int effect_type) if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit)) return FF_RUMBLE; - printk(KERN_ERR - "ff-memless: invalid type in get_compatible_type()\n"); + pr_err("invalid type in get_compatible_type()\n"); return 0; } @@ -312,7 +311,7 @@ static void ml_combine_effects(struct ff_effect *effect, break; default: - printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n"); + pr_err("invalid type in ml_combine_effects()\n"); break; } @@ -406,7 +405,7 @@ static void ml_effect_timer(unsigned long timer_data) struct ml_device *ml = dev->ff->private; unsigned long flags; - debug("timer: updating effects"); + pr_debug("timer: updating effects\n"); spin_lock_irqsave(&dev->event_lock, flags); ml_play_effects(ml); @@ -438,7 +437,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) struct ml_effect_state *state = &ml->states[effect_id]; if (value > 0) { - debug("initiated play"); + pr_debug("initiated play\n"); __set_bit(FF_EFFECT_STARTED, &state->flags); state->count = value; @@ -449,7 +448,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) state->adj_at = state->play_at; } else { - debug("initiated stop"); + pr_debug("initiated stop\n"); if (test_bit(FF_EFFECT_PLAYING, &state->flags)) __set_bit(FF_EFFECT_ABORTING, &state->flags); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 46239e47a26..dbf741c9583 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -18,13 +18,11 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/gameport.h> -#include <linux/wait.h> #include <linux/slab.h> #include <linux/delay.h> -#include <linux/kthread.h> +#include <linux/workqueue.h> #include <linux/sched.h> /* HZ */ #include <linux/mutex.h> -#include <linux/freezer.h> /*#include <asm/io.h>*/ @@ -234,58 +232,22 @@ struct gameport_event { static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */ static LIST_HEAD(gameport_event_list); -static DECLARE_WAIT_QUEUE_HEAD(gameport_wait); -static struct task_struct *gameport_task; -static int gameport_queue_event(void *object, struct module *owner, - enum gameport_event_type event_type) +static struct gameport_event *gameport_get_event(void) { + struct gameport_event *event = NULL; unsigned long flags; - struct gameport_event *event; - int retval = 0; spin_lock_irqsave(&gameport_event_lock, flags); - /* - * Scan event list for the other events for the same gameport port, - * starting with the most recent one. If event is the same we - * do not need add new one. If event is of different type we - * need to add this event and should not look further because - * we need to preseve sequence of distinct events. - */ - list_for_each_entry_reverse(event, &gameport_event_list, node) { - if (event->object == object) { - if (event->type == event_type) - goto out; - break; - } - } - - event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC); - if (!event) { - pr_err("Not enough memory to queue event %d\n", event_type); - retval = -ENOMEM; - goto out; - } - - if (!try_module_get(owner)) { - pr_warning("Can't get module reference, dropping event %d\n", - event_type); - kfree(event); - retval = -EINVAL; - goto out; + if (!list_empty(&gameport_event_list)) { + event = list_first_entry(&gameport_event_list, + struct gameport_event, node); + list_del_init(&event->node); } - event->type = event_type; - event->object = object; - event->owner = owner; - - list_add_tail(&event->node, &gameport_event_list); - wake_up(&gameport_wait); - -out: spin_unlock_irqrestore(&gameport_event_lock, flags); - return retval; + return event; } static void gameport_free_event(struct gameport_event *event) @@ -319,24 +281,8 @@ static void gameport_remove_duplicate_events(struct gameport_event *event) spin_unlock_irqrestore(&gameport_event_lock, flags); } -static struct gameport_event *gameport_get_event(void) -{ - struct gameport_event *event = NULL; - unsigned long flags; - - spin_lock_irqsave(&gameport_event_lock, flags); - - if (!list_empty(&gameport_event_list)) { - event = list_first_entry(&gameport_event_list, - struct gameport_event, node); - list_del_init(&event->node); - } - - spin_unlock_irqrestore(&gameport_event_lock, flags); - return event; -} -static void gameport_handle_event(void) +static void gameport_handle_events(struct work_struct *work) { struct gameport_event *event; @@ -368,6 +314,59 @@ static void gameport_handle_event(void) mutex_unlock(&gameport_mutex); } +static DECLARE_WORK(gameport_event_work, gameport_handle_events); + +static int gameport_queue_event(void *object, struct module *owner, + enum gameport_event_type event_type) +{ + unsigned long flags; + struct gameport_event *event; + int retval = 0; + + spin_lock_irqsave(&gameport_event_lock, flags); + + /* + * Scan event list for the other events for the same gameport port, + * starting with the most recent one. If event is the same we + * do not need add new one. If event is of different type we + * need to add this event and should not look further because + * we need to preserve sequence of distinct events. + */ + list_for_each_entry_reverse(event, &gameport_event_list, node) { + if (event->object == object) { + if (event->type == event_type) + goto out; + break; + } + } + + event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC); + if (!event) { + pr_err("Not enough memory to queue event %d\n", event_type); + retval = -ENOMEM; + goto out; + } + + if (!try_module_get(owner)) { + pr_warning("Can't get module reference, dropping event %d\n", + event_type); + kfree(event); + retval = -EINVAL; + goto out; + } + + event->type = event_type; + event->object = object; + event->owner = owner; + + list_add_tail(&event->node, &gameport_event_list); + schedule_work(&gameport_event_work); + +out: + spin_unlock_irqrestore(&gameport_event_lock, flags); + return retval; +} + /* * Remove all events that have been submitted for a given object, * be it a gameport port or a driver. @@ -419,19 +418,6 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent) return child; } -static int gameport_thread(void *nothing) -{ - set_freezable(); - do { - gameport_handle_event(); - wait_event_freezable(gameport_wait, - kthread_should_stop() || !list_empty(&gameport_event_list)); - } while (!kthread_should_stop()); - - return 0; -} - - /* * Gameport port operations */ @@ -814,13 +800,6 @@ static int __init gameport_init(void) return error; } - gameport_task = kthread_run(gameport_thread, NULL, "kgameportd"); - if (IS_ERR(gameport_task)) { - bus_unregister(&gameport_bus); - error = PTR_ERR(gameport_task); - pr_err("Failed to start kgameportd, error: %d\n", error); - return error; - } return 0; } @@ -828,7 +807,12 @@ static int __init gameport_init(void) static void __exit gameport_exit(void) { bus_unregister(&gameport_bus); - kthread_stop(gameport_task); + + /* + * There should not be any outstanding events but work may + * still be scheduled so simply cancel it. + */ + cancel_work_sync(&gameport_event_work); } subsys_initcall(gameport_init); diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c new file mode 100644 index 00000000000..c48c81f0308 --- /dev/null +++ b/drivers/input/input-mt.c @@ -0,0 +1,170 @@ +/* + * Input Multitouch Library + * + * Copyright (c) 2008-2010 Henrik Rydberg + * + * 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 <linux/input/mt.h> +#include <linux/slab.h> + +#define TRKID_SGN ((TRKID_MAX + 1) >> 1) + +/** + * input_mt_init_slots() - initialize MT input slots + * @dev: input device supporting MT events and finger tracking + * @num_slots: number of slots used by the device + * + * This function allocates all necessary memory for MT slot handling + * in the input device, prepares the ABS_MT_SLOT and + * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers. + * May be called repeatedly. Returns -EINVAL if attempting to + * reinitialize with a different number of slots. + */ +int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots) +{ + int i; + + if (!num_slots) + return 0; + if (dev->mt) + return dev->mtsize != num_slots ? -EINVAL : 0; + + dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL); + if (!dev->mt) + return -ENOMEM; + + dev->mtsize = num_slots; + input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); + input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0); + input_set_events_per_packet(dev, 6 * num_slots); + + /* Mark slots as 'unused' */ + for (i = 0; i < num_slots; i++) + input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1); + + return 0; +} +EXPORT_SYMBOL(input_mt_init_slots); + +/** + * input_mt_destroy_slots() - frees the MT slots of the input device + * @dev: input device with allocated MT slots + * + * This function is only needed in error path as the input core will + * automatically free the MT slots when the device is destroyed. + */ +void input_mt_destroy_slots(struct input_dev *dev) +{ + kfree(dev->mt); + dev->mt = NULL; + dev->mtsize = 0; + dev->slot = 0; + dev->trkid = 0; +} +EXPORT_SYMBOL(input_mt_destroy_slots); + +/** + * input_mt_report_slot_state() - report contact state + * @dev: input device with allocated MT slots + * @tool_type: the tool type to use in this slot + * @active: true if contact is active, false otherwise + * + * Reports a contact via ABS_MT_TRACKING_ID, and optionally + * ABS_MT_TOOL_TYPE. If active is true and the slot is currently + * inactive, or if the tool type is changed, a new tracking id is + * assigned to the slot. The tool type is only reported if the + * corresponding absbit field is set. + */ +void input_mt_report_slot_state(struct input_dev *dev, + unsigned int tool_type, bool active) +{ + struct input_mt_slot *mt; + int id; + + if (!dev->mt || !active) { + input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); + return; + } + + mt = &dev->mt[dev->slot]; + id = input_mt_get_value(mt, ABS_MT_TRACKING_ID); + if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type) + id = input_mt_new_trkid(dev); + + input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); + input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); +} +EXPORT_SYMBOL(input_mt_report_slot_state); + +/** + * input_mt_report_finger_count() - report contact count + * @dev: input device with allocated MT slots + * @count: the number of contacts + * + * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, + * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP. + * + * The input core ensures only the KEY events already setup for + * this device will produce output. + */ +void input_mt_report_finger_count(struct input_dev *dev, int count) +{ + input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1); + input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2); + input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == |