aboutsummaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Kconfig12
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/apm-power.c131
-rw-r--r--drivers/input/evdev.c6
-rw-r--r--drivers/input/input-polldev.c18
-rw-r--r--drivers/input/input.c85
-rw-r--r--drivers/input/joystick/amijoy.c1
-rw-r--r--drivers/input/joystick/analog.c1
-rw-r--r--drivers/input/joystick/db9.c1
-rw-r--r--drivers/input/joystick/gamecon.c1
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c17
-rw-r--r--drivers/input/joystick/turbografx.c1
-rw-r--r--drivers/input/joystick/xpad.c1
-rw-r--r--drivers/input/keyboard/Kconfig29
-rw-r--r--drivers/input/keyboard/Makefile3
-rw-r--r--drivers/input/keyboard/atkbd.c91
-rw-r--r--drivers/input/keyboard/lkkbd.c1
-rw-r--r--drivers/input/keyboard/pxa27x_keyboard.c274
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c572
-rw-r--r--drivers/input/keyboard/tosakbd.c415
-rw-r--r--drivers/input/misc/Kconfig14
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/apanel.c378
-rw-r--r--drivers/input/misc/ati_remote.c1
-rw-r--r--drivers/input/misc/atlas_btns.c39
-rw-r--r--drivers/input/misc/cobalt_btns.c73
-rw-r--r--drivers/input/misc/keyspan_remote.c119
-rw-r--r--drivers/input/mouse/inport.c1
-rw-r--r--drivers/input/mouse/logibm.c1
-rw-r--r--drivers/input/mouse/psmouse-base.c1
-rw-r--r--drivers/input/mouse/trackpoint.c1
-rw-r--r--drivers/input/mousedev.c3
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h67
-rw-r--r--drivers/input/serio/i8042.c26
-rw-r--r--drivers/input/serio/libps2.c1
-rw-r--r--drivers/input/touchscreen/ads7846.c8
-rw-r--r--drivers/input/touchscreen/mk712.c1
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c1
38 files changed, 1938 insertions, 459 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 63512d906f0..9dea14db724 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -137,6 +137,18 @@ config INPUT_EVBUG
To compile this driver as a module, choose M here: the
module will be called evbug.
+config INPUT_APMPOWER
+ tristate "Input Power Event -> APM Bridge" if EMBEDDED
+ depends on INPUT && APM_EMULATION
+ ---help---
+ Say Y here if you want suspend key events to trigger a user
+ requested suspend through APM. This is useful on embedded
+ systems where such behviour is desired without userspace
+ interaction. If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apm-power.
+
comment "Input Device Drivers"
source "drivers/input/keyboard/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 99af903bd3c..2ae87b19caa 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_INPUT_TABLET) += tablet/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
+obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c
new file mode 100644
index 00000000000..c36d110b349
--- /dev/null
+++ b/drivers/input/apm-power.c
@@ -0,0 +1,131 @@
+/*
+ * Input Power Event -> APM Bridge
+ *
+ * Copyright (c) 2007 Richard Purdie
+ *
+ * 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/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/apm-emulation.h>
+
+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");
+ break;
+ default:
+ break;
+ }
+}
+
+static void apmpower_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+{
+ /* only react on key down events */
+ if (value != 1)
+ return;
+
+ switch (type) {
+ case EV_PWR:
+ system_power_event(code);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int apmpower_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct input_handle *handle;
+ int error;
+
+ handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = "apm-power";
+
+ handler->private = handle;
+
+ error = input_register_handle(handle);
+ if (error) {
+ printk(KERN_ERR
+ "apm-power: 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);
+ input_unregister_handle(handle);
+ kfree(handle);
+ return error;
+ }
+
+ return 0;
+}
+
+static void apmpower_disconnect(struct input_handle *handler)
+{
+ struct input_handle *handle = handler->private;
+
+ input_close_device(handle);
+ kfree(handle);
+}
+
+static const struct input_device_id apmpower_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_PWR) },
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(input, apmpower_ids);
+
+static struct input_handler apmpower_handler = {
+ .event = apmpower_event,
+ .connect = apmpower_connect,
+ .disconnect = apmpower_disconnect,
+ .name = "apm-power",
+ .id_table = apmpower_ids,
+};
+
+static int __init apmpower_init(void)
+{
+ return input_register_handler(&apmpower_handler);
+}
+
+static void __exit apmpower_exit(void)
+{
+ input_unregister_handler(&apmpower_handler);
+}
+
+module_init(apmpower_init);
+module_exit(apmpower_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Input Power Event -> APM Bridge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index e5b4e9bfbdc..0727b0a1255 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -617,7 +617,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
if (get_user(t, ip))
return -EFAULT;
- error = dev->getkeycode(dev, t, &v);
+ error = input_get_keycode(dev, t, &v);
if (error)
return error;
@@ -630,7 +630,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
if (get_user(t, ip) || get_user(v, ip + 1))
return -EFAULT;
- return dev->setkeycode(dev, t, v);
+ return input_set_keycode(dev, t, v);
case EVIOCSFF:
if (copy_from_user(&effect, p, sizeof(effect)))
@@ -683,7 +683,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
- }
+ }
return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
}
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 92b359894e8..490918a5d19 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -60,17 +60,21 @@ static void input_polled_device_work(struct work_struct *work)
{
struct input_polled_dev *dev =
container_of(work, struct input_polled_dev, work.work);
+ unsigned long delay;
dev->poll(dev);
- queue_delayed_work(polldev_wq, &dev->work,
- msecs_to_jiffies(dev->poll_interval));
+
+ delay = msecs_to_jiffies(dev->poll_interval);
+ if (delay >= HZ)
+ delay = round_jiffies_relative(delay);
+
+ queue_delayed_work(polldev_wq, &dev->work, delay);
}
static int input_open_polled_device(struct input_dev *input)
{
struct input_polled_dev *dev = input->private;
int error;
- unsigned long ticks;
error = input_polldev_start_workqueue();
if (error)
@@ -79,10 +83,8 @@ static int input_open_polled_device(struct input_dev *input)
if (dev->flush)
dev->flush(dev);
- ticks = msecs_to_jiffies(dev->poll_interval);
- if (ticks >= HZ)
- ticks = round_jiffies(ticks);
- queue_delayed_work(polldev_wq, &dev->work, ticks);
+ queue_delayed_work(polldev_wq, &dev->work,
+ msecs_to_jiffies(dev->poll_interval));
return 0;
}
@@ -91,7 +93,7 @@ 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);
+ cancel_delayed_work_sync(&dev->work);
input_polldev_stop_workqueue();
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a0be978501f..f02c242c311 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -493,7 +493,7 @@ static void input_disconnect_device(struct input_dev *dev)
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
for (code = 0; code <= KEY_MAX; code++) {
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
- test_bit(code, dev->key)) {
+ __test_and_clear_bit(code, dev->key)) {
input_pass_event(dev, EV_KEY, code, 0);
}
}
@@ -526,7 +526,7 @@ static int input_default_getkeycode(struct input_dev *dev,
if (!dev->keycodesize)
return -EINVAL;
- if (scancode < 0 || scancode >= dev->keycodemax)
+ if (scancode >= dev->keycodemax)
return -EINVAL;
*keycode = input_fetch_keycode(dev, scancode);
@@ -540,10 +540,7 @@ static int input_default_setkeycode(struct input_dev *dev,
int old_keycode;
int i;
- if (scancode < 0 || scancode >= dev->keycodemax)
- return -EINVAL;
-
- if (keycode < 0 || keycode > KEY_MAX)
+ if (scancode >= dev->keycodemax)
return -EINVAL;
if (!dev->keycodesize)
@@ -586,6 +583,75 @@ static int input_default_setkeycode(struct input_dev *dev,
return 0;
}
+/**
+ * input_get_keycode - retrieve keycode currently mapped to a given scancode
+ * @dev: input device which keymap is being queried
+ * @scancode: scancode (or its equivalent for device in question) for which
+ * keycode is needed
+ * @keycode: result
+ *
+ * This function should be called by anyone interested in retrieving current
+ * keymap. Presently keyboard and evdev handlers use it.
+ */
+int input_get_keycode(struct input_dev *dev, int scancode, int *keycode)
+{
+ if (scancode < 0)
+ return -EINVAL;
+
+ return dev->getkeycode(dev, scancode, keycode);
+}
+EXPORT_SYMBOL(input_get_keycode);
+
+/**
+ * input_get_keycode - assign new keycode to a given scancode
+ * @dev: input device which keymap is being updated
+ * @scancode: scancode (or its equivalent for device in question)
+ * @keycode: new keycode to be assigned to the scancode
+ *
+ * This function should be called by anyone needing to update current
+ * keymap. Presently keyboard and evdev handlers use it.
+ */
+int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
+{
+ unsigned long flags;
+ int old_keycode;
+ int retval;
+
+ if (scancode < 0)
+ return -EINVAL;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ retval = dev->getkeycode(dev, scancode, &old_keycode);
+ if (retval)
+ goto out;
+
+ retval = dev->setkeycode(dev, scancode, keycode);
+ if (retval)
+ goto out;
+
+ /*
+ * Simulate keyup event if keycode is not present
+ * in the keymap anymore
+ */
+ if (test_bit(EV_KEY, dev->evbit) &&
+ !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
+ __test_and_clear_bit(old_keycode, dev->key)) {
+
+ input_pass_event(dev, EV_KEY, old_keycode, 0);
+ if (dev->sync)
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ }
+
+ out:
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(input_set_keycode);
#define MATCH_BIT(bit, max) \
for (i = 0; i < BITS_TO_LONGS(max); i++) \
@@ -755,7 +821,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations input_devices_seq_ops = {
+static const struct seq_operations input_devices_seq_ops = {
.start = input_devices_seq_start,
.next = input_devices_seq_next,
.stop = input_devices_seq_stop,
@@ -808,7 +874,7 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations input_handlers_seq_ops = {
+static const struct seq_operations input_handlers_seq_ops = {
.start = input_handlers_seq_start,
.next = input_handlers_seq_next,
.stop = input_handlers_seq_stop,
@@ -1329,9 +1395,6 @@ int input_register_device(struct input_dev *dev)
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
- if (dev->cdev.dev)
- dev->dev.parent = dev->cdev.dev;
-
error = device_add(&dev->dev);
if (error)
return error;
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index 5cf9f3610e6..deb9f825f92 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -32,7 +32,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 15739880afc..f32e031dcb2 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/init.h>
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index a6ca9d5e252..960e501c60c 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/parport.h>
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index df2a9d02ca6..07a32aff5a3 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/parport.h>
#include <linux/input.h>
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 6f826b37d9a..a2517fa72eb 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -85,7 +85,7 @@ static struct iforce_device iforce_device[] = {
static int iforce_playback(struct input_dev *dev, int effect_id, int value)
{
- struct iforce* iforce = dev->private;
+ struct iforce *iforce = input_get_drvdata(dev);
struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
if (value > 0)
@@ -99,7 +99,7 @@ static int iforce_playback(struct input_dev *dev, int effect_id, int value)
static void iforce_set_gain(struct input_dev *dev, u16 gain)
{
- struct iforce* iforce = dev->private;
+ struct iforce *iforce = input_get_drvdata(dev);
unsigned char data[3];
data[0] = gain >> 9;
@@ -108,7 +108,7 @@ static void iforce_set_gain(struct input_dev *dev, u16 gain)
static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
{
- struct iforce* iforce = dev->private;
+ struct iforce *iforce = input_get_drvdata(dev);
unsigned char data[3];
data[0] = 0x03;
@@ -126,7 +126,7 @@ static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
*/
static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{
- struct iforce* iforce = dev->private;
+ struct iforce *iforce = input_get_drvdata(dev);
struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id];
int ret;
@@ -173,7 +173,7 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect,
*/
static int iforce_erase_effect(struct input_dev *dev, int effect_id)
{
- struct iforce *iforce = dev->private;
+ struct iforce *iforce = input_get_drvdata(dev);
struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
int err = 0;
@@ -191,7 +191,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id)
static int iforce_open(struct input_dev *dev)
{
- struct iforce *iforce = dev->private;
+ struct iforce *iforce = input_get_drvdata(dev);
switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
@@ -213,7 +213,7 @@ static int iforce_open(struct input_dev *dev)
static void iforce_release(struct input_dev *dev)
{
- struct iforce *iforce = dev->private;
+ struct iforce *iforce = input_get_drvdata(dev);
int i;
if (test_bit(EV_FF, dev->evbit)) {
@@ -298,7 +298,8 @@ int iforce_init_device(struct iforce *iforce)
#endif
}
- input_dev->private = iforce;
+ input_set_drvdata(input_dev, iforce);
+
input_dev->name = "Unknown I-Force device";
input_dev->open = iforce_open;
input_dev->close = iforce_release;
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index bbebd4e2ad7..989483f5316 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -35,7 +35,6 @@
#include <linux/parport.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/mutex.h>
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 6e9d75bd2b1..0380597249b 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -75,7 +75,6 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.0.6"
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 086d58c0ccb..8ea709be330 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -154,6 +154,27 @@ config KEYBOARD_SPITZ
To compile this driver as a module, choose M here: the
module will be called spitzkbd.
+config KEYBOARD_TOSA
+ tristate "Tosa keyboard"
+ depends on MACH_TOSA
+ default y
+ help
+ Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
+
+ To compile this driver as a module, choose M here: the
+ module will be called tosakbd.
+
+config KEYBOARD_TOSA_USE_EXT_KEYCODES
+ bool "Tosa keyboard: use extended keycodes"
+ depends on KEYBOARD_TOSA
+ default n
+ help
+ Say Y here to enable the tosa keyboard driver to generate extended
+ (>= 127) keycodes. Be aware, that they can't be correctly interpreted
+ by either console keyboard driver or by Kdrive keybd driver.
+
+ Say Y only if you know, what you are doing!
+
config KEYBOARD_AMIGA
tristate "Amiga keyboard"
depends on AMIGA
@@ -239,13 +260,13 @@ config KEYBOARD_OMAP
module will be called omap-keypad.
config KEYBOARD_PXA27x
- tristate "PXA27x keyboard support"
- depends on PXA27x
+ tristate "PXA27x/PXA3xx keypad support"
+ depends on PXA27x || PXA3xx
help
- Enable support for PXA27x matrix keyboard controller
+ Enable support for PXA27x/PXA3xx keypad controller
To compile this driver as a module, choose M here: the
- module will be called pxa27x_keyboard.
+ module will be called pxa27x_keypad.
config KEYBOARD_AAED2000
tristate "AAED-2000 keyboard"
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index e97455fdcc8..e741f403101 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -15,10 +15,11 @@ obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
+obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
-obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
+obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index b39c5b31e62..4a95adc4cc7 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -19,7 +19,6 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -28,6 +27,7 @@
#include <linux/workqueue.h>
#include <linux/libps2.h>
#include <linux/mutex.h>
+#include <linux/dmi.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver"
@@ -201,6 +201,7 @@ struct atkbd {
unsigned short id;
unsigned char keycode[512];
+ DECLARE_BITMAP(force_release_mask, 512);
unsigned char set;
unsigned char translated;
unsigned char extra;
@@ -225,6 +226,11 @@ struct atkbd {
unsigned long event_mask;
};
+/*
+ * System-specific ketymap fixup routine
+ */
+static void (*atkbd_platform_fixup)(struct atkbd *);
+
static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct atkbd *, char *));
static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
@@ -349,7 +355,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
struct atkbd *atkbd = serio_get_drvdata(serio);
struct input_dev *dev = atkbd->dev;
unsigned int code = data;
- int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
+ int scroll = 0, hscroll = 0, click = -1;
int value;
unsigned char keycode;
@@ -414,14 +420,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
"Some program might be trying access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
goto out;
- case ATKBD_RET_HANGEUL:
- case ATKBD_RET_HANJA:
- /*
- * These keys do not report release and thus need to be
- * flagged properly
- */
- add_release_event = 1;
- break;
case ATKBD_RET_ERR:
atkbd->err_count++;
#ifdef ATKBD_DEBUG
@@ -491,7 +489,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
input_event(dev, EV_KEY, keycode, value);
input_sync(dev);
- if (value && add_release_event) {
+ if (value && test_bit(code, atkbd->force_release_mask)) {
input_report_key(dev, keycode, 0);
input_sync(dev);
}
@@ -824,7 +822,6 @@ static void atkbd_disconnect(struct serio *serio)
atkbd_disable(atkbd);
/* make sure we don't have a command in flight */
- synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */
flush_scheduled_work();
sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
@@ -834,6 +831,22 @@ static void atkbd_disconnect(struct serio *serio)
kfree(atkbd);
}
+/*
+ * Most special keys (Fn+F?) on Dell Latitudes do not generate release
+ * events so we have to do it ourselves.
+ */
+static void atkbd_latitude_keymap_fixup(struct atkbd *atkbd)
+{
+ const unsigned int forced_release_keys[] = {
+ 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93,
+ };
+ int i;
+
+ if (atkbd->set == 2)
+ for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++)
+ __set_bit(forced_release_keys[i],
+ atkbd->force_release_mask);
+}
/*
* atkbd_set_keycode_table() initializes keyboard's keycode table
@@ -842,17 +855,20 @@ static void atkbd_disconnect(struct serio *serio)
static void atkbd_set_keycode_table(struct atkbd *atkbd)
{
+ unsigned int scancode;
int i, j;
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
+ bitmap_zero(atkbd->force_release_mask, 512);
if (atkbd->translated) {
for (i = 0; i < 128; i++) {
- atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
- atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+ scancode = atkbd_unxlate_table[i];
+ atkbd->keycode[i] = atkbd_set2_keycode[scancode];
+ atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
if (atkbd->scroll)
for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
- if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2)
+ if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
}
} else if (atkbd->set == 3) {
@@ -861,12 +877,29 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
if (atkbd->scroll)
- for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
- atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
+ for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
+ scancode = atkbd_scroll_keys[i].set2;
+ atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
+ }
}
- atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL;
- atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA;
+/*
+ * HANGEUL and HANJA keys do not send release events so we need to
+ * generate such events ourselves
+ */
+ scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
+ atkbd->keycode[scancode] = KEY_HANGEUL;
+ __set_bit(scancode, atkbd->force_release_mask);
+
+ scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
+ atkbd->keycode[scancode] = KEY_HANJA;
+ __set_bit(scancode, atkbd->force_release_mask);
+
+/*
+ * Perform additional fixups
+ */
+ if (atkbd_platform_fixup)
+ atkbd_platform_fixup(atkbd);
}
<