summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/ff-memless.c2
-rw-r--r--drivers/input/gameport/ns558.c1
-rw-r--r--drivers/input/input.c24
-rw-r--r--drivers/input/joystick/amijoy.c2
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/db9.c4
-rw-r--r--drivers/input/joystick/gamecon.c6
-rw-r--r--drivers/input/joystick/turbografx.c4
-rw-r--r--drivers/input/keyboard/Kconfig19
-rw-r--r--drivers/input/keyboard/Makefile5
-rw-r--r--drivers/input/keyboard/atkbd.c4
-rw-r--r--drivers/input/keyboard/gpio_keys.c148
-rw-r--r--drivers/input/keyboard/hilkbd.c116
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/atlas_btns.c170
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c2
-rw-r--r--drivers/input/misc/uinput.c2
-rw-r--r--drivers/input/misc/wistron_btns.c20
-rw-r--r--drivers/input/mouse/inport.c4
-rw-r--r--drivers/input/mouse/logibm.c2
-rw-r--r--drivers/input/mouse/pc110pad.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c34
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/rpcmouse.c1
-rw-r--r--drivers/input/mouse/synaptics.c1
-rw-r--r--drivers/input/serio/hil_mlc.c1
-rw-r--r--drivers/input/serio/hp_sdc.c1
-rw-r--r--drivers/input/serio/i8042.c75
-rw-r--r--drivers/input/serio/libps2.c2
-rw-r--r--drivers/input/serio/serio.c42
-rw-r--r--drivers/input/serio/serio_raw.c2
-rw-r--r--drivers/input/touchscreen/Kconfig9
-rw-r--r--drivers/input/touchscreen/ads7846.c582
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c2
-rw-r--r--drivers/input/tsdev.c4
36 files changed, 956 insertions, 351 deletions
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index eba18b6ac5e4..d226d935b0dc 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -29,7 +29,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
-#include <linux/sched.h>
+#include <linux/jiffies.h>
#include "fixp-arith.h"
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index f68dbe6f7f04..7b7a546323cf 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -151,7 +151,6 @@ static int ns558_isa_probe(int io)
return -ENOMEM;
}
- memset(ns558, 0, sizeof(struct ns558));
ns558->io = io;
ns558->size = 1 << i;
ns558->gameport = port;
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7cf2b4f603a3..a9a706f8fff9 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -11,7 +11,6 @@
*/
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/module.h>
@@ -482,7 +481,7 @@ static int input_proc_devices_open(struct inode *inode, struct file *file)
return seq_open(file, &input_devices_seq_ops);
}
-static struct file_operations input_devices_fileops = {
+static const struct file_operations input_devices_fileops = {
.owner = THIS_MODULE,
.open = input_proc_devices_open,
.poll = input_proc_devices_poll,
@@ -533,7 +532,7 @@ static int input_proc_handlers_open(struct inode *inode, struct file *file)
return seq_open(file, &input_handlers_seq_ops);
}
-static struct file_operations input_handlers_fileops = {
+static const struct file_operations input_handlers_fileops = {
.owner = THIS_MODULE,
.open = input_proc_handlers_open,
.read = seq_read,
@@ -589,18 +588,9 @@ static inline void input_proc_exit(void) { }
static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \
{ \
struct input_dev *input_dev = to_input_dev(dev); \
- int retval; \
\
- retval = mutex_lock_interruptible(&input_dev->mutex); \
- if (retval) \
- return retval; \
- \
- retval = scnprintf(buf, PAGE_SIZE, \
- "%s\n", input_dev->name ? input_dev->name : ""); \
- \
- mutex_unlock(&input_dev->mutex); \
- \
- return retval; \
+ return scnprintf(buf, PAGE_SIZE, "%s\n", \
+ input_dev->name ? input_dev->name : ""); \
} \
static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL);
@@ -1050,10 +1040,6 @@ void input_unregister_device(struct input_dev *dev)
sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
- mutex_lock(&dev->mutex);
- dev->name = dev->phys = dev->uniq = NULL;
- mutex_unlock(&dev->mutex);
-
class_device_unregister(&dev->cdev);
input_wakeup_procfs_readers();
@@ -1142,7 +1128,7 @@ static int input_open_file(struct inode *inode, struct file *file)
return err;
}
-static struct file_operations input_fops = {
+static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index e608691b5a61..b0f5541ec3e6 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -50,8 +50,6 @@ static int amijoy[2] = { 0, 1 };
module_param_array_named(map, amijoy, uint, NULL, 0);
MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)");
-__obsolete_setup("amijoy=");
-
static int amijoy_used;
static DEFINE_MUTEX(amijoy_mutex);
static struct input_dev *amijoy_dev[2];
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 7ef68456d7d6..51f1e4bfff3e 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -58,8 +58,6 @@ static int analog_options[ANALOG_PORTS];
module_param_array_named(map, js, charp, &js_nargs, 0);
MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities");
-__obsolete_setup("js=");
-
/*
* Times, feature definitions.
*/
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 5080e15c6d30..b41bd2eb37dd 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -59,10 +59,6 @@ MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0);
MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
-__obsolete_setup("db9=");
-__obsolete_setup("db9_2=");
-__obsolete_setup("db9_3=");
-
#define DB9_ARG_PARPORT 0
#define DB9_ARG_MODE 1
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index fe12aa37393d..711e4b3e9e61 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices");
module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0);
MODULE_PARM_DESC(map3, "Describes third set of devices");
-__obsolete_setup("gc=");
-__obsolete_setup("gc_2=");
-__obsolete_setup("gc_3=");
-
/* see also gs_psx_delay parameter in PSX support section */
#define GC_SNES 1
@@ -403,8 +399,6 @@ static int gc_psx_delay = GC_PSX_DELAY;
module_param_named(psx_delay, gc_psx_delay, uint, 0);
MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
-__obsolete_setup("gc_psx_delay=");
-
static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 5570fd5487c7..037d3487fcc7 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices");
module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0);
MODULE_PARM_DESC(map3, "Describes third set of devices");
-__obsolete_setup("tgfx=");
-__obsolete_setup("tgfx_2=");
-__obsolete_setup("tgfx_3=");
-
#define TGFX_REFRESH_TIME HZ/100 /* 10 ms */
#define TGFX_TRIGGER 0x08
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 049f2f544e75..64509689fa65 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -135,12 +135,12 @@ config KEYBOARD_STOWAWAY
config KEYBOARD_CORGI
tristate "Corgi keyboard"
depends on PXA_SHARPSL
- default y
+ default y
help
- Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
+ Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
series of PDAs.
- To compile this driver as a module, choose M here: the
+ To compile this driver as a module, choose M here: the
module will be called corgikbd.
config KEYBOARD_SPITZ
@@ -214,4 +214,17 @@ config KEYBOARD_AAED2000
To compile this driver as a module, choose M here: the
module will be called aaed2000_kbd.
+config KEYBOARD_GPIO
+ tristate "Buttons on CPU GPIOs (PXA)"
+ depends on (ARCH_SA1100 || ARCH_PXA || ARCH_S3C2410)
+ help
+ This driver implements support for buttons connected
+ directly to GPIO pins of SA1100, PXA or S3C24xx CPUs.
+
+ Say Y here if your device has buttons connected
+ directly to GPIO pins of the CPU.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gpio-keys.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 568797907347..586a0fe53be6 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.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_AAED2000) += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index c621a9177a56..663877076bc7 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -63,10 +63,6 @@ static int atkbd_extra;
module_param_named(extra, atkbd_extra, bool, 0);
MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
-__obsolete_setup("atkbd_set=");
-__obsolete_setup("atkbd_reset");
-__obsolete_setup("atkbd_softrepeat=");
-
/*
* Scancode to keycode tables. These are just the default setting, and
* are loadable via an userland utility.
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
new file mode 100644
index 000000000000..fa03a00b4c6d
--- /dev/null
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -0,0 +1,148 @@
+/*
+ * Driver for keys on GPIO lines capable of generating interrupts.
+ *
+ * Copyright 2005 Phil Blundell
+ *
+ * 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/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/hardware/gpio_keys.h>
+
+static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
+{
+ int i;
+ struct platform_device *pdev = dev_id;
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ int gpio = pdata->buttons[i].gpio;
+ if (irq == gpio_to_irq(gpio)) {
+ int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low);
+
+ input_report_key(input, pdata->buttons[i].keycode, state);
+ input_sync(input);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit gpio_keys_probe(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input;
+ int i, error;
+
+ input = input_allocate_device();
+ if (!input)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, input);
+
+ input->evbit[0] = BIT(EV_KEY);
+
+ input->name = pdev->name;
+ input->phys = "gpio-keys/input0";
+ input->cdev.dev = &pdev->dev;
+ input->private = pdata;
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ 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);
+
+ 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",
+ 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);
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ printk(KERN_ERR "Unable to register gpio-keys input device\n");
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ for (i = i - 1; i >= 0; i--)
+ free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
+
+ input_free_device(input);
+
+ return error;
+}
+
+static int __devexit gpio_keys_remove(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ int irq = gpio_to_irq(pdata->buttons[i].gpio);
+ free_irq(irq, pdev);
+ }
+
+ input_unregister_device(input);
+
+ return 0;
+}
+
+struct platform_driver gpio_keys_device_driver = {
+ .probe = gpio_keys_probe,
+ .remove = __devexit_p(gpio_keys_remove),
+ .driver = {
+ .name = "gpio-keys",
+ }
+};
+
+static int __init gpio_keys_init(void)
+{
+ return platform_driver_register(&gpio_keys_device_driver);
+}
+
+static void __exit gpio_keys_exit(void)
+{
+ platform_driver_unregister(&gpio_keys_device_driver);
+}
+
+module_init(gpio_keys_init);
+module_exit(gpio_keys_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
+MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 35461eab2faf..4de4dc297d50 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -6,10 +6,10 @@
* Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
*
* Very basic HP Human Interface Loop (HIL) driver.
- * This driver handles the keyboard on HP300 (m68k) and on some
+ * This driver handles the keyboard on HP300 (m68k) and on some
* HP700 (parisc) series machines.
*
- *
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License version 2. See the file COPYING in the main directory of this
* archive for more details.
@@ -64,9 +64,9 @@ MODULE_LICENSE("GPL v2");
#endif
-
+
/* HIL helper functions */
-
+
#define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)
#define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
#define hil_status() (hil_readb(HILBASE + HIL_CMD))
@@ -75,7 +75,7 @@ MODULE_LICENSE("GPL v2");
#define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)
/* HIL constants */
-
+
#define HIL_BUSY 0x02
#define HIL_DATA_RDY 0x01
@@ -86,10 +86,10 @@ MODULE_LICENSE("GPL v2");
#define HIL_INTON 0x5C /* Turn on interrupts. */
#define HIL_INTOFF 0x5D /* Turn off interrupts. */
-#define HIL_READKBDSADR 0xF9
-#define HIL_WRITEKBDSADR 0xE9
+#define HIL_READKBDSADR 0xF9
+#define HIL_WRITEKBDSADR 0xE9
-static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
+static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
{ HIL_KEYCODES_SET1 };
/* HIL structure */
@@ -97,11 +97,11 @@ static struct {
struct input_dev *dev;
unsigned int curdev;
-
+
unsigned char s;
unsigned char c;
int valid;
-
+
unsigned char data[16];
unsigned int ptr;
spinlock_t lock;
@@ -115,7 +115,7 @@ static void poll_finished(void)
int down;
int key;
unsigned char scode;
-
+
switch (hil_dev.data[0]) {
case 0x40:
down = (hil_dev.data[1] & 1) == 0;
@@ -127,6 +127,7 @@ static void poll_finished(void)
hil_dev.curdev = 0;
}
+
static inline void handle_status(unsigned char s, unsigned char c)
{
if (c & 0x8) {
@@ -143,6 +144,7 @@ static inline void handle_status(unsigned char s, unsigned char c)
}
}
+
static inline void handle_data(unsigned char s, unsigned char c)
{
if (hil_dev.curdev) {
@@ -152,13 +154,11 @@ static inline void handle_data(unsigned char s, unsigned char c)
}
-/*
- * Handle HIL interrupts.
- */
+/* handle HIL interrupts */
static irqreturn_t hil_interrupt(int irq, void *handle)
{
unsigned char s, c;
-
+
s = hil_status();
c = hil_read_data();
@@ -179,10 +179,8 @@ static irqreturn_t hil_interrupt(int irq, void *handle)
return IRQ_HANDLED;
}
-/*
- * Send a command to the HIL
- */
+/* send a command to the HIL */
static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
{
unsigned long flags;
@@ -200,16 +198,14 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
}
-/*
- * Initialise HIL.
- */
-
+/* initialise HIL */
static int __init
hil_keyb_init(void)
{
unsigned char c;
unsigned int i, kbid;
wait_queue_head_t hil_wait;
+ int err;
if (hil_dev.dev) {
return -ENODEV; /* already initialized */
@@ -219,15 +215,25 @@ hil_keyb_init(void)
if (!hil_dev.dev)
return -ENOMEM;
hil_dev.dev->private = &hil_dev;
-
+
#if defined(CONFIG_HP300)
- if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
- return -ENODEV;
-
- request_region(HILBASE+HIL_DATA, 2, "hil");
+ if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
+ printk(KERN_ERR "HIL: hardware register was not found\n");
+ err = -ENODEV;
+ goto err1;
+ }
+ if (!request_region(HILBASE + HIL_DATA, 2, "hil")) {
+ printk(KERN_ERR "HIL: IOPORT region already used\n");
+ err = -EIO;
+ goto err1;
+ }
#endif
-
- request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+
+ err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+ if (err) {
+ printk(KERN_ERR "HIL: Can't get IRQ\n");
+ goto err2;
+ }
/* Turn on interrupts */
hil_do(HIL_INTON, NULL, 0);
@@ -239,47 +245,65 @@ hil_keyb_init(void)
init_waitqueue_head(&hil_wait);
wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ);
if (!hil_dev.valid) {
- printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n");
+ printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n");
}
- c = hil_dev.c;
+ c = hil_dev.c;
hil_dev.valid = 0;
if (c == 0) {
kbid = -1;
- printk(KERN_WARNING "HIL: no keyboard present.\n");
+ printk(KERN_WARNING "HIL: no keyboard present\n");
} else {
kbid = ffz(~c);
- /* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */
+ printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid);
}
/* set it to raw mode */
c = 0;
hil_do(HIL_WRITEKBDSADR, &c, 1);
-
+
for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
if (hphilkeyb_keycode[i] != KEY_RESERVED)
set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
- hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
- hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
- hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
- hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]);
- hil_dev.dev->keycode = hphilkeyb_keycode;
- hil_dev.dev->name = "HIL keyboard";
- hil_dev.dev->phys = "hpkbd/input0";
+ hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+ hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
+ hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]);
+ hil_dev.dev->keycode = hphilkeyb_keycode;
+ hil_dev.dev->name = "HIL keyboard";
+ hil_dev.dev->phys = "hpkbd/input0";
hil_dev.dev->id.bustype = BUS_HIL;
hil_dev.dev->id.vendor = PCI_VENDOR_ID_HP;
hil_dev.dev->id.product = 0x0001;
hil_dev.dev->id.version = 0x0010;
- input_register_device(hil_dev.dev);
+ err = input_register_device(hil_dev.dev);
+ if (err) {
+ printk(KERN_ERR "HIL: Can't register device\n");
+ goto err3;
+ }
printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
- hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
+ hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
return 0;
+
+err3:
+ hil_do(HIL_INTOFF, NULL, 0);
+ disable_irq(HIL_IRQ);
+ free_irq(HIL_IRQ, hil_dev.dev_id);
+err2:
+#if defined(CONFIG_HP300)
+ release_region(HILBASE + HIL_DATA, 2);
+err1:
+#endif
+ input_free_device(hil_dev.dev);
+ hil_dev.dev = NULL;
+ return err;
}
+
#if defined(CONFIG_PARISC)
static int __init
hil_init_chip(struct parisc_device *dev)
@@ -292,7 +316,7 @@ hil_init_chip(struct parisc_device *dev)
hil_base = dev->hpa.start;
hil_irq = dev->irq;
hil_dev.dev_id = dev;
-
+
printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq);
return hil_keyb_init();
@@ -313,9 +337,6 @@ static struct parisc_driver hil_driver = {
#endif /* CONFIG_PARISC */
-
-
-
static int __init hil_init(void)
{
#if defined(CONFIG_PARISC)
@@ -349,4 +370,3 @@ static void __exit hil_exit(void)
module_init(hil_init);
module_exit(hil_exit);
-
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index ba0e88c64e1e..41b42587f5e9 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -50,6 +50,16 @@ config INPUT_WISTRON_BTNS
To compile this driver as a module, choose M here: the module will
be called wistron_btns.
+config INPUT_ATLAS_BTNS
+ tristate "x86 Atlas button interface"
+ depends on X86 && ACPI
+ help
+ Say Y here for support of Atlas wallmount touchscreen buttons.
+ The events will show up as scancodes F1 through F9 via evdev.
+
+ To compile this driver as a module, choose M here: the module will
+ be called atlas_btns.
+
config INPUT_IXP4XX_BEEPER
tristate "IXP4XX Beeper support"
depends on ARCH_IXP4XX
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 415c49178985..e0a8d58c9e9b 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -9,5 +9,6 @@ obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
+obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
new file mode 100644
index 000000000000..0acc3a123604
--- /dev/null
+++ b/drivers/input/misc/atlas_btns.c
@@ -0,0 +1,170 @@
+/*
+ * atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras
+ *
+ * Copyright (C) 2006 Jaya Kumar
+ * Based on Toshiba ACPI by John Belmonte and ASUS ACPI
+ * This work was sponsored by CIS(M) Sdn Bhd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_ATLAS_NAME "Atlas ACPI"
+#define ACPI_ATLAS_CLASS "Atlas"
+#define ACPI_ATLAS_BUTTON_HID "ASIM0000"
+
+static struct input_dev *input_dev;
+
+/* button handling code */
+static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
+ u32 function, void *handler_context, void **return_context)
+{
+ *return_context =
+ (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
+
+ return AE_OK;
+}
+
+static acpi_status acpi_atlas_button_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width, acpi_integer *value,
+ void *handler_context, void *region_context)
+{
+ acpi_status status;
+ int keycode;
+
+ if (function == ACPI_WRITE) {
+ keycode = KEY_F1 + (address & 0x0F);
+ input_report_key(input_dev, keycode, !(address & 0x10));
+ input_sync(input_dev);
+ status = 0;
+ } else {
+ printk(KERN_WARNING "atlas: shrugged on unexpected function"
+ ":function=%x,address=%lx,value=%x\n",
+ function, (unsigned long)address, (u32)*value);
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+static int atlas_acpi_button_add(struct acpi_device *device)
+{
+ acpi_status status;
+ int err;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ printk(KERN_ERR "atlas: unable to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ input_dev->name = "Atlas ACPI button driver";
+ input_dev->phys = "ASIM0000/atlas/input0";
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
+
+ set_bit(KEY_F1, input_dev->keybit);
+ set_bit(KEY_F2, input_dev->keybit);
+ set_bit(KEY_F3, input_dev->keybit);
+ set_bit(KEY_F4, input_dev->keybit);
+ set_bit(KEY_F5, input_dev->keybit);
+ set_bit(KEY_F6, input_dev->keybit);
+ set_bit(KEY_F7, input_dev->keybit);
+ set_bit(KEY_F8, input_dev->keybit);
+ set_bit(KEY_F9, input_dev->keybit);
+
+ err = input_register_device(input_dev);
+ if (err) {
+ printk(KERN_ERR "atlas: couldn't register input device\n");
+ input_free_device(input_dev);
+ return err;
+ }
+
+ /* hookup button handler */
+ status = acpi_install_address_space_handler(device->handle,
+ 0x81, &acpi_atlas_button_handler,
+ &acpi_atlas_button_setup, device);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
+ input_unregister_device(input_dev);
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+static int atlas_acpi_button_remove(struct acpi_device *device, int type)
+{
+ acpi_status status;
+
+ status = acpi_remove_address_space_handler(device->handle,
+ 0x81, &acpi_atlas_button_handler);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
+ status = -EINVAL;
+ }
+
+ input_unregister_device(input_dev);
+
+ return status;
+}
+
+static struct acpi_driver atlas_acpi_driver = {
+ .name = ACPI_ATLAS_NAME,
+ .class = ACPI_ATLAS_CLASS,
+ .ids = ACPI_ATLAS_BUTTON_HID,
+ .ops = {
+ .add = atlas_acpi_button_add,
+ .remove = atlas_acpi_button_remove,
+ },
+};
+
+static int __init atlas_acpi_init(void)
+{
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&atlas_acpi_driver);
+ if (result < 0) {
+ printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit atlas_acpi_exit(void)
+{
+ acpi_bus_unregister_driver(&atlas_acpi_driver);
+}
+
+module_init(atlas_acpi_init);
+module_exit(atlas_acpi_exit);
+
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atlas button driver");
+
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index 31d5a13bfd6b..ab76ea442fa5 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -670,7 +670,7 @@ static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
#endif
}
-static struct file_operations hp_sdc_rtc_fops = {
+static const struct file_operations hp_sdc_rtc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = hp_sdc_rtc_read,
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 9516439b7c78..42556232c523 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -627,7 +627,7 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return retval;
}
-static struct file_operations uinput_fops = {
+static const struct file_operations uinput_fops = {
.owner = THIS_MODULE,
.open = uinput_open,
.release = uinput_release,
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 7b9d1c1da41a..e1183aeb8ed5 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -335,6 +335,17 @@ static struct key_entry keymap_aopen_1559as[] = {
{ 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 }
+};
+
/*
* If your machine is not here (which is currently rather likely), please send
* a list of buttons and their key codes (reported when loading this module
@@ -413,6 +424,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
.driver_data = keymap_wistron_ms2111
},
+ {
+ .callback = dmi_matched,
+ .ident = "Fujitsu Siemens Amilo D88x0",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
+ },
+ .driver_data = keymap_fs_amilo_d88x0
+ },
{ NULL, }
};
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index 13dd96785e39..79b624fe8994 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
#define INPORT_REG_MODE 0x07
#define INPORT_RESET 0x80
-#ifdef CONFIG_INPUT_ATIXL
+#ifdef CONFIG_MOUSE_ATIXL
#define INPORT_NAME "ATI XL Mouse"
#define INPORT_VENDOR 0x0002
#define INPORT_SPEED_30HZ 0x01
@@ -84,8 +84,6 @@ static int inport_irq = INPORT_IRQ;
module_param_named(irq, inport_irq, uint, 0);
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
-__obsolete_setup("inport_irq=");
-
static struct input_dev *inport_dev;
static irqreturn_t inport_interrupt(int irq, void *dev_id)
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index db205995bffd..26c3b2e2ca94 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -75,8 +75,6 @@ static int logibm_irq = LOGIBM_IRQ;
module_param_named(irq, logibm_irq, uint, 0);
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
-__obsolete_setup("logibm_irq=");
-
static struct input_dev *logibm_dev;
static irqreturn_t logibm_interrupt(int irq, void *dev_id)
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index f155c1fea04e..05d992e514f0 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -113,7 +113,7 @@ static int __init pc110pad_init(void)
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
if (dev) {
pci_dev_put(dev);
- return -ENOENT;
+ return -ENODEV;
}
if (!request_region(pc110pad_io, 4, "pc110pad")) {
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index a0e4a033e2db..0fe5869d7d4c 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -93,12 +93,6 @@ static struct attribute_group psmouse_attribute_group = {
.attrs = psmouse_attributes,
};
-__obsolete_setup("psmouse_noext");
-__obsolete_setup("psmouse_resolution=");
-__obsolete_setup("psmouse_smartscroll=");
-__obsolete_setup("psmouse_resetafter=");
-__obsolete_setup("psmouse_rate=");
-
/*
* psmouse_mutex protects all operations changing state of mouse
* (connecting, disconnecting, changing rate or resolution via
@@ -987,8 +981,36 @@ static void psmouse_resync(struct work_struct *work)
static void psmouse_cleanup(struct serio *serio)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
+ struct psmouse *parent = NULL;
+
+ mutex_lock(&psmouse_mutex);
+
+ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+ parent = serio_get_drvdata(serio->parent);
+ psmouse_deactivate(parent);
+ }
+
+ psmouse_deactivate(psmouse);
+
+ if (psmouse->cleanup)
+ psmouse->cleanup(psmouse);
psmouse_reset(psmouse);
+
+/*
+ * Some boxes, such as HP nx7400, get terribly confused if mouse
+ * is not fully enabled before suspending/shutting down.
+ */
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+ if (parent) {
+ if (parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+
+ psmouse_activate(parent);
+ }
+
+ mutex_unlock(&psmouse_mutex);
}
/*
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 1b74cae8a556..cf1de95b6f27 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -68,6 +68,7 @@ struct psmouse {
int (*reconnect)(struct psmouse *psmouse);
void (*disconnect)(struct psmouse *psmouse);
+ void (*cleanup)(struct psmouse *psmouse);
int (*poll)(struct psmouse *psmouse);
void (*pt_activate)(struct psmouse *psmouse);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index fbdcfd8eb4e9..355efd0423e7 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -18,7 +18,6 @@
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 49ac696d6cff..f0f9413d762c 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -652,6 +652,7 @@ int synaptics_init(struct psmouse *psmouse)
psmouse->set_rate = synaptics_set_rate;
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
+ psmouse->cleanup = synaptics_reset;
psmouse->pktsize = 6;
/* Synaptics can usually stay in sync without extra help */
psmouse->resync_time = 0;
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index 49e11e2c1d5d..4fa93ff30919 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -59,7 +59,6 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/list.h>
MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 9907ad3bea23..b57370dc4e3d 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -62,7 +62,6 @@
*/
#include <linux/hp_sdc.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index debe9445488c..ec195a36e8f6 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -76,13 +76,6 @@ module_param_named(debug, i8042_debug, bool, 0600);
MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
#endif
-__obsolete_setup("i8042_noaux");
-__obsolete_setup("i8042_nomux");
-__obsolete_setup("i8042_unlock");
-__obsolete_setup("i8042_reset");
-__obsolete_setup("i8042_direct");
-__obsolete_setup("i8042_dumbkbd");
-
#include "i8042.h"
static DEFINE_SPINLOCK(i8042_lock);
@@ -371,7 +364,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
if (unlikely(i8042_suppress_kbd_ack))
if (port_no == I8042_KBD_PORT_NO &&
(data == 0xfa || data == 0xfe)) {
- i8042_suppress_kbd_ack = 0;
+ i8042_suppress_kbd_ack--;
goto out;
}
@@ -543,6 +536,7 @@ static int __devinit i8042_check_aux(void)
{
int retval = -1;
int irq_registered = 0;
+ int aux_loop_broken = 0;
unsigned long flags;
unsigned char param;
@@ -572,6 +566,8 @@ static int __devinit i8042_check_aux(void)
if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
(param && param != 0xfa && param != 0xff))
return -1;
+
+ aux_loop_broken = 1;
}
/*
@@ -595,7 +591,7 @@ static int __devinit i8042_check_aux(void)
* used it for a PCI card or somethig else.
*/
- if (i8042_noloop) {
+ if (i8042_noloop || aux_loop_broken) {
/*
* Without LOOP command we can't test AUX IRQ delivery. Assume the port
* is working and hope we are right.
@@ -721,7 +717,7 @@ static int i8042_controller_init(void)
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
- else
+ else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
}
spin_unlock_irqrestore(&i8042_lock, flags);
@@ -788,27 +784,6 @@ static void i8042_controller_reset(void)
/*
- * Here we try to reset everything back to a state in which the BIOS will be
- * able to talk to the hardware when rebooting.
- */
-
-static void i8042_controller_cleanup(void)
-{
- int i;
-
-/*
- * Reset anything that is connected to the ports.
- */
-
- for (i = 0; i < I8042_NUM_PORTS; i++)
- if (i8042_ports[i].serio)
- serio_cleanup(i8042_ports[i].serio);
-
- i8042_controller_reset();
-}
-
-
-/*
* i8042_panic_blink() will flash the keyboard LEDs and is called when
* kernel panics. Flashing LEDs is useful for users running X who may
* not see the console and will help distingushing panics from "real"
@@ -838,13 +813,14 @@ static long i8042_panic_blink(long count)
led ^= 0x01 | 0x04;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
- i8042_suppress_kbd_ack = 1;
+ dbg("%02x -> i8042 (panic blink)", 0xed);
+ i8042_suppress_kbd_ack = 2;
i8042_write_data(0xed); /* set leds */
DELAY;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
DELAY;
- i8042_suppress_kbd_ack = 1;
+ dbg("%02x -> i8042 (panic blink)", led);
i8042_write_data(led);
DELAY;
last_blink = count;
@@ -853,13 +829,22 @@ static long i8042_panic_blink(long count)
#undef DELAY
+#ifdef CONFIG_PM
/*
- * Here we try to restore the original BIOS settings
+ * Here we try to restore the original BIOS settings. We only want to
+ * do that once, when we really suspend, not when we taking memory
+ * snapshot for swsusp (in this case we'll perform required cleanup
+ * as part of shutdown process).
*/
static int i8042_suspend(struct platform_device *dev, pm_message_t state)
{
- i8042_controller_cleanup();
+ if (dev->dev.power.power_state.event != state.event) {
+ if (state.event == PM_EVENT_SUSPEND)
+ i8042_controller_reset();
+
+ dev->dev.power.power_state = state;
+ }
return 0;
}
@@ -873,6 +858,12 @@ static int i8042_resume(struct platform_device *dev)
{
int error;
+/*
+ * Do not bother with restoring state if we haven't suspened yet
+ */
+ if (dev->dev.power.power_state.event == PM_EVENT_ON)
+ return 0;
+
error = i8042_controller_check();
if (error)
return error;
@@ -882,9 +873,12 @@ static int i8042_resume(struct platform_device *dev)
return error;
/*
- * Restore pre-resume CTR value and disable all ports
+ * Restore original CTR value and disable all ports
*/
+ i8042_ctr = i8042_initial_ctr;
+ if (i8042_direct)
+ i8042_ctr &= ~I8042_CTR_XLATE;
i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
@@ -905,8 +899,11 @@ static int i8042_resume(struct platform_device *dev)
i8042_interrupt(0, NULL);
+ dev->dev.power.power_state = PMSG_ON;
+
return 0;
}
+#endif /* CONFIG_PM */
/*
* We need to reset the 8042 back to original mode on system shutdown,
@@ -915,7 +912,7 @@ static int i8042_resume(struct platform_device *dev)
static void i8042_shutdown(struct platform_device *dev)
{
- i8042_controller_cleanup();
+ i8042_controller_reset();
}
static int __devinit i8042_create_kbd_port(void)
@@ -1150,9 +1147,11 @@ static struct platform_driver i8042_driver = {
},
.probe = i8042_probe,
.remove = __devexit_p(i8042_remove),
+ .shutdown = i8042_shutdown,
+#ifdef CONFIG_PM
.suspend = i8042_suspend,
.resume = i8042_resume,
- .shutdown = i8042_shutdown,
+#endif
};
static int __init i8042_init(void)
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index b3e84d3bb7f7..10d9d74ae43a 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL(ps2_drain);
int ps2_is_keyboard_id(char id_byte)
{
- const static char keyboard_ids[] = {
+ static const char keyboard_ids[] = {
0xab, /* Regular keyboards */
0xac, /* NCD Sun keyboard */
0x2b, /* Trust keyboard, translated */
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index f0ce822c1028..a15e531ec755 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
@@ -778,6 +778,19 @@ static int serio_driver_remove(struct device *dev)
return 0;
}
+static void serio_cleanup(struct serio *serio)
+{
+ if (serio->drv && serio->drv->cleanup)
+ serio->drv->cleanup(serio);
+}
+
+static void serio_shutdown(struct device *dev)
+{
+ struct serio *serio = to_serio_port(dev);
+
+ serio_cleanup(serio);
+}
+
static void serio_attach_driver(struct serio_driver *drv)
{
int error;
@@ -789,12 +802,14 @@ static void serio_attach_driver(struct serio_driver *drv)
drv->driver.name, error);
}
-int serio_register_driver(struct serio_driver *drv)
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
{
int manual_bind = drv->manual_bind;
int error;
drv->driver.bus = &serio_bus;
+ drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
/*
* Temporarily disable automatic binding because probing
@@ -908,11 +923,25 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
#endif /* CONFIG_HOTPLUG */
+#ifdef CONFIG_PM
+static int serio_suspend(struct device *dev, pm_message_t state)
+{
+ if (dev->power.power_state.event != state.event) {
+ if (state.event == PM_EVENT_SUSPEND)
+ serio_cleanup(to_serio_port(dev));
+
+ dev->power.power_state = state;
+ }
+
+ return 0;
+}
+
static int serio_resume(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- if (serio_reconnect_driver(serio)) {
+ if (dev->power.power_state.event != PM_EVENT_ON &&
+ serio_reconnect_driver(serio)) {
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.
@@ -920,8 +949,11 @@ static int serio_resume(struct device *dev)
serio_rescan(serio);
}
+ dev->power.power_state = PMSG_ON;
+
return 0;
}
+#endif /* CONFIG_PM */
/* called from serio_driver->connect/disconnect methods under serio_mutex */
int serio_open(struct serio *serio, struct serio_driver *drv)
@@ -972,7 +1004,11 @@ static struct bus_type serio_bus = {
.uevent = serio_uevent,
.probe = serio_driver_probe,
.remove = serio_driver_remove,
+ .shutdown = serio_shutdown,
+#ifdef CONFIG_PM
+ .suspend = serio_suspend,
.resume = serio_resume,
+#endif
};
static int __init serio_init(void)
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 088ebc348ba3..887357666c68 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -234,7 +234,7 @@ static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
return 0;
}
-static struct file_operations serio_raw_fops = {
+static const struct file_operations serio_raw_fops = {
.owner = THIS_MODULE,
.open = serio_raw_open,
.release = serio_raw_release,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6b46c9bf1d20..971618059a6f 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -12,13 +12,18 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN
config TOUCHSCREEN_ADS7846
- tristate "ADS 7846 based touchscreens"
+ tristate "ADS 7846/7843 based touchscreens"
depends on SPI_MASTER
+ depends on HWMON = n || HWMON
help
Say Y here if you have a touchscreen interface using the
- ADS7846 controller, and your board-specific initialization
+ ADS7846 or ADS7843 controller, and your board-specific setup
code includes that in its table of SPI devices.
+ If HWMON is selected, and the driver is told the reference voltage
+ on your board, you will also get hwmon interfaces for the voltage
+ (and on ads7846, temperature) sensors of this chip.
+
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index c6164b6f476a..0a26e0663542 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -17,8 +17,9 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/device.h>
+#include <linux/hwmon.h>
#include <linux/init.h>
+#include <linux/err.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -54,7 +55,8 @@
* files.
*/
-#define TS_POLL_PERIOD msecs_to_jiffies(10)
+#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */
+#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
@@ -63,12 +65,12 @@ struct ts_event {
/* For portability, we can't read 12 bit values using SPI (which
* would make the controller deliver them as native byteorder u16
* with msbs zeroed). Instead, we read them as two 8-bit values,
- * which need byteswapping then range adjustment.
+ * *** WHICH NEED BYTESWAPPING *** and range adjustment.
*/
- __be16 x;
- __be16 y;
- __be16 z1, z2;
- int ignore;
+ u16 x;
+ u16 y;
+ u16 z1, z2;
+ int ignore;
};
struct ads7846 {
@@ -76,7 +78,12 @@ struct ads7846 {
char phys[32];
struct spi_device *spi;
+
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
struct attribute_group *attr_group;
+ struct class_device *hwmon;
+#endif
+
u16 model;
u16 vref_delay_usecs;
u16 x_plate_ohms;
@@ -99,13 +106,16 @@ struct ads7846 {
u16 debounce_rep;
spinlock_t lock;
- struct timer_list timer; /* P: lock */
+ struct hrtimer timer;
unsigned pendown:1; /* P: lock */
unsigned pending:1; /* P: lock */
// FIXME remove "irq_disabled"
unsigned irq_disabled:1; /* P: lock */
unsigned disabled:1;
+ int (*filter)(void *data, int data_idx, int *val);
+ void *filter_data;
+ void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
};
@@ -142,15 +152,16 @@ struct ads7846 {
#define MAX_12BIT ((1<<12)-1)
/* leave ADC powered up (disables penirq) between differential samples */
-#define READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
- | ADS_12_BIT | ADS_DFR)
+#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
+ | ADS_12_BIT | ADS_DFR | \
+ (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
-#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON)
-#define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
-#define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
+#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
+#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
+#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
-#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON)
-#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */
+#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
+#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
/* single-ended samples need to first power up reference voltage;
* we leave both ADC and VREF powered
@@ -158,14 +169,19 @@ struct ads7846 {
#define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
| ADS_12_BIT | ADS_SER)
-#define REF_ON (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
-#define REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN)
+#define REF_ON (READ_12BIT_DFR(x, 1, 1))
+#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
/*--------------------------------------------------------------------------*/
/*
* Non-touchscreen sensors only use single-ended conversions.
+ * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
+ * ads7846 lets that pin be unconnected, to use internal vREF.
*/
+static unsigned vREF_mV;
+module_param(vREF_mV, uint, 0);
+MODULE_PARM_DESC(vREF_mV, "external vREF voltage, in milliVolts");
struct ser_req {
u8 ref_on;
@@ -193,50 +209,55 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
int status;
int sample;
- int i;
+ int use_internal;
if (!req)
return -ENOMEM;
spi_message_init(&req->msg);
- /* activate reference, so it has time to settle; */
- req->ref_on = REF_ON;
- req->xfer[0].tx_buf = &req->ref_on;
- req->xfer[0].len = 1;
- req->xfer[1].rx_buf = &req->scratch;
- req->xfer[1].len = 2;
-
- /*
- * for external VREF, 0 usec (and assume it's always on);
- * for 1uF, use 800 usec;
- * no cap, 100 usec.
- */
- req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ /* FIXME boards with ads7846 might use external vref instead ... */
+ use_internal = (ts->model == 7846);
+
+ /* maybe turn on internal vREF, and let it settle */
+ if (use_internal) {
+ req->ref_on = REF_ON;
+ req->xfer[0].tx_buf = &req->ref_on;
+ req->xfer[0].len = 1;
+ spi_message_add_tail(&req->xfer[0], &req->msg);
+
+ req->xfer[1].rx_buf = &req->scratch;
+ req->xfer[1].len = 2;
+
+ /* for 1uF, settle for 800 usec; no cap, 100 usec. */
+ req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ spi_message_add_tail(&req->xfer[1], &req->msg);
+ }
/* take sample */
req->command = (u8) command;
req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 1;
+ spi_message_add_tail(&req->xfer[2], &req->msg);
+
req->xfer[3].rx_buf = &req->sample;
req->xfer[3].len = 2;
+ spi_message_add_tail(&req->xfer[3], &req->msg);
/* REVISIT: take a few more samples, and compare ... */
- /* turn off reference */
- req->ref_off = REF_OFF;
- req->xfer[4].tx_buf = &req->ref_off;
- req->xfer[4].len = 1;
- req->xfer[5].rx_buf = &req->scratch;
- req->xfer[5].len = 2;
-
- CS_CHANGE(req->xfer[5]);
-
- /* group all the transfers together, so we can't interfere with
- * reading touchscreen state; disable penirq while sampling
- */
- for (i = 0; i < 6; i++)
- spi_message_add_tail(&req->xfer[i], &req->msg);
+ /* maybe off internal vREF */
+ if (use_internal) {
+ req->ref_off = REF_OFF;
+ req->xfer[4].tx_buf = &req->ref_off;
+ req->xfer[4].len = 1;
+ spi_message_add_tail(&req->xfer[4], &req->msg);
+
+ req->xfer[5].rx_buf = &req->scratch;
+ req->xfer[5].len = 2;
+ CS_CHANGE(req->xfer[5]);
+ spi_message_add_tail(&req->xfer[5], &req->msg);
+ }
ts->irq_disabled = 1;
disable_irq(spi->irq);
@@ -256,25 +277,173 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
return status ? status : sample;
}
-#define SHOW(name) static ssize_t \
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
+
+#define SHOW(name, var, adjust) static ssize_t \
name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
+ struct ads7846 *ts = dev_get_drvdata(dev); \
ssize_t v = ads7846_read12_ser(dev, \
- READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+ READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
if (v < 0) \
return v; \
- return sprintf(buf, "%u\n", (unsigned) v); \
+ return sprintf(buf, "%u\n", adjust(ts, v)); \
} \
static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
-SHOW(temp0)
-SHOW(temp1)
-SHOW(vaux)
-SHOW(vbatt)
+
+/* Sysfs conventions report temperatures in millidegrees Celcius.
+ * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
+ * accuracy scheme without calibration data. For now we won't try either;
+ * userspace sees raw sensor values, and must scale/calibrate appropriately.
+ */
+static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
+{
+ return v;
+}
+
+SHOW(temp0, temp0, null_adjust) /* temp1_input */
+SHOW(temp1, temp1, null_adjust) /* temp2_input */
+
+
+/* sysfs conventions report voltages in millivolts. We can convert voltages
+ * if we know vREF. userspace may need to scale vAUX to match the board's
+ * external resistors; we assume that vBATT only uses the internal ones.
+ */
+static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
+{
+ unsigned retval = v;
+
+ /* external resistors may scale vAUX into 0..vREF */
+ retval *= vREF_mV;
+ retval = retval >> 12;
+ return retval;
+}
+
+static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
+{
+ unsigned retval = vaux_adjust(ts, v);
+
+ /* ads7846 has a resistor ladder to scale this signal down */
+ if (ts->model == 7846)
+ retval *= 4;
+ return retval;
+}
+
+SHOW(in0_input, vaux, vaux_adjust)
+SHOW(in1_input, vbatt, vbatt_adjust)
+
+
+static struct attribute *ads7846_attributes[] = {
+ &dev_attr_temp0.attr,
+ &dev_attr_temp1.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ NULL,
+};
+
+static struct attribute_group ads7846_attr_group = {
+ .attrs = ads7846_attributes,
+};
+
+static struct attribute *ads7843_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ NULL,
+};
+
+static struct attribute_group ads7843_attr_group = {
+ .attrs = ads7843_attributes,
+};
+
+static struct attribute *ads7845_attributes[] = {
+ &dev_attr_in0_input.attr,
+ NULL,
+};
+
+static struct attribute_group ads7845_attr_group = {
+ .attrs = ads7845_attributes,
+};
+
+static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
+{
+ struct class_device *hwmon;
+ int err;
+
+ /* hwmon sensors need a reference voltage */
+ switch (ts->model) {
+ case 7846:
+ if (!vREF_mV) {
+ dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
+ vREF_mV = 2500;
+ }
+ break;
+ case 7845:
+ case 7843:
+ if (!vREF_mV) {
+ dev_warn(&spi->dev,
+ "external vREF for ADS%d not specified\n",
+ ts->model);
+ return 0;
+ }
+ break;
+ }
+
+ /* different chips have different sensor groups */
+ switch (ts->model) {
+ case 7846:
+ ts->attr_group = &ads7846_attr_group;
+ break;
+ case 7845:
+ ts->attr_group = &ads7845_attr_group;
+ break;
+ case 7843:
+ ts->attr_group = &ads7843_attr_group;
+ break;
+ default:
+ dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model);
+ return 0;
+ }
+
+ err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+ if (err)
+ return err;
+
+ hwmon = hwmon_device_register(&spi->dev);
+ if (IS_ERR(hwmon)) {
+ sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ return PTR_ERR(hwmon);
+ }
+
+ ts->hwmon = hwmon;
+ return 0;
+}
+
+static void ads784x_hwmon_unregister(struct spi_device *spi,
+ struct ads7846 *ts)
+{
+ if (ts->hwmon) {
+ sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ hwmon_device_unregister(ts->hwmon);
+ }
+}
+
+#else
+static inline int ads784x_hwmon_register(struct spi_device *spi,
+ struct ads7846 *ts)
+{
+ return 0;
+}
+
+static inline void ads784x_hwmon_unregister(struct spi_device *spi,
+ struct ads7846 *ts)
+{
+}
+#endif
static int is_pen_down(struct device *dev)
{
- struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
return ts->pendown;
}
@@ -318,46 +487,14 @@ static ssize_t ads7846_disable_store(struct device *dev,
static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
-static struct attribute *ads7846_attributes[] = {
- &dev_attr_temp0.attr,
- &dev_attr_temp1.attr,
- &dev_attr_vbatt.attr,
- &dev_attr_vaux.attr,
- &dev_attr_pen_down.attr,
- &dev_attr_disable.attr,
- NULL,
-};
-
-static struct attribute_group ads7846_attr_group = {
- .attrs = ads7846_attributes,
-};
-
-/*
- * ads7843/7845 don't have temperature sensors, and
- * use the other sensors a bit differently too
- */
-
-static struct attribute *ads7843_attributes[] = {
- &dev_attr_vbatt.attr,
- &dev_attr_vaux.attr,
+static struct attribute *ads784x_attributes[] = {
&dev_attr_pen_down.attr,
&dev_attr_disable.attr,
NULL,
};
-static struct attribute_group ads7843_attr_group = {
- .attrs = ads7843_attributes,
-};
-
-static struct attribute *ads7845_attributes[] = {
- &dev_attr_vaux.attr,
- &dev_attr_pen_down.attr,
- &dev_attr_disable.attr,
- NULL,
-};
-
-static struct attribute_group ads7845_attr_group = {
- .attrs = ads7845_attributes,
+static struct attribute_group ads784x_attr_group = {
+ .attrs = ads784x_attributes,
};
/*--------------------------------------------------------------------------*/
@@ -373,25 +510,22 @@ static struct attribute_group ads7845_attr_group = {
static void ads7846_rx(void *ads)
{
struct ads7846 *ts = ads;
- struct input_dev *input_dev = ts->input;
unsigned Rt;
- unsigned sync = 0;
u16 x, y, z1, z2;
- unsigned long flags;
- /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
- * built from two 8 bit values written msb-first.
+ /* ads7846_rx_val() did in-place conversion (including byteswap) from
+ * on-the-wire format as part of debouncing to get stable readings.
*/
- x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
- y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
- z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
- z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
+ x = ts->tc.x;
+ y = ts->tc.y;
+ z1 = ts->tc.z1;
+ z2 = ts->tc.z2;
/* range filtering */
if (x == MAX_12BIT)
x = 0;
- if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
+ if (likely(x && z1)) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
Rt -= z1;
@@ -403,100 +537,130 @@ static void ads7846_rx(void *ads)
Rt = 0;
/* Sample found inconsistent by debouncing or pressure is beyond
- * the maximum. Don't report it to user space, repeat at least
- * once more the measurement */
+ * the maximum. Don't report it to user space, repeat at least
+ * once more the measurement
+ */
if (ts->tc.ignore || Rt > ts->pressure_max) {
- mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+#ifdef VERBOSE
+ pr_debug("%s: ignored %d pressure %d\n",
+ ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+#endif
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
return;
}
- /* NOTE: "pendown" is inferred from pressure; we don't rely on
- * being able to check nPENIRQ status, or "friendly" trigger modes
- * (both-edges is much better than just-falling or low-level).
+ /* NOTE: We can't rely on the pressure to determine the pen down
+ * state, even this controller has a pressure sensor. The pressure
+ * value can fluctuate for quite a while after lifting the pen and
+ * in some cases may not even settle at the expected value.
*
- * REVISIT: some boards may require reading nPENIRQ; it's
- * needed on 7843. and 7845 reads pressure differently...
- *
- * REVISIT: the touchscreen might not be connected; this code
- * won't notice that, even if nPENIRQ never fires ...
+ * The only safe way to check for the pen up condition is in the
+ * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
*/
- if (!ts->pendown && Rt != 0) {
- input_report_key(input_dev, BTN_TOUCH, 1);
- sync = 1;
- } else if (ts->pendown && Rt == 0) {
- input_report_key(input_dev, BTN_TOUCH, 0);
- sync = 1;
- }
-
if (Rt) {
- input_report_abs(input_dev, ABS_X, x);
- input_report_abs(input_dev, ABS_Y, y);
- sync = 1;
- }
-
- if (sync) {
- input_report_abs(input_dev, ABS_PRESSURE, Rt);
- input_sync(input_dev);
- }
+ struct input_dev *input = ts->input;
-#ifdef VERBOSE
- if (Rt || ts->pendown)
- pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
- x, y, Rt, Rt ? "" : " UP");
+ if (!ts->pendown) {
+ input_report_key(input, BTN_TOUCH, 1);
+ ts->pendown = 1;
+#ifdef VERBOSE
+ dev_dbg(&ts->spi->dev, "DOWN\n");
#endif
+ }
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_PRESSURE, Rt);
- spin_lock_irqsave(&ts->lock, flags);
-
- ts->pendown = (Rt != 0);
- mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+ input_sync(input);
+#ifdef VERBOSE
+ dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
+#endif
+ }
- spin_unlock_irqrestore(&ts->lock, flags);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
}
-static void ads7846_debounce(void *ads)
+static int ads7846_debounce(void *ads, int data_idx, int *val)
{
struct ads7846 *ts = ads;
- struct spi_message *m;
- struct spi_transfer *t;
- int val;
- int status;
- m = &ts->msg[ts->msg_idx];
- t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
- if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+ if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+ /* Start over collecting consistent readings. */
+ ts->read_rep = 0;
/* Repeat it, if this was the first read or the read
* wasn't consistent enough. */
if (ts->read_cnt < ts->debounce_max) {
- ts->last_read = val;
+ ts->last_read = *val;
ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
} else {
/* Maximum number of debouncing reached and still
* not enough number of consistent readings. Abort
* the whole sample, repeat it in the next sampling
* period.
*/
- ts->tc.ignore = 1;
ts->read_cnt = 0;
- /* Last message will contain ads7846_rx() as the
- * completion function.
- */
- m = ts->last_msg;
+ return ADS7846_FILTER_IGNORE;
}
- /* Start over collecting consistent readings. */
- ts->read_rep = 0;
} else {
if (++ts->read_rep > ts->debounce_rep) {
/* Got a good reading for this coordinate,
* go for the next one. */
- ts->tc.ignore = 0;
- ts->msg_idx++;
ts->read_cnt = 0;
ts->read_rep = 0;
- m++;
- } else
+ return ADS7846_FILTER_OK;
+ } else {
/* Read more values that are consistent. */
ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
+ }
+ }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+ return ADS7846_FILTER_OK;
+}
+
+static void ads7846_rx_val(void *ads)
+{
+ struct ads7846 *ts = ads;
+ struct spi_message *m;
+ struct spi_transfer *t;
+ u16 *rx_val;
+ int val;
+ int action;
+ int status;
+
+ m = &ts->msg[ts->msg_idx];
+ t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ rx_val = t->rx_buf;
+
+ /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
+ * built from two 8 bit values written msb-first.
+ */
+ val = be16_to_cpu(*rx_val) >> 3;
+
+ action = ts->filter(ts->filter_data, ts->msg_idx, &val);
+ switch (action) {
+ case ADS7846_FILTER_REPEAT:
+ break;
+ case ADS7846_FILTER_IGNORE:
+ ts->tc.ignore = 1;
+ /* Last message will contain ads7846_rx() as the
+ * completion function.
+ */
+ m = ts->last_msg;
+ break;
+ case ADS7846_FILTER_OK:
+ *rx_val = val;
+ ts->tc.ignore = 0;
+ m = &ts->msg[++ts->msg_idx];
+ break;
+ default:
+ BUG();
}
status = spi_async(ts->spi, m);
if (status)
@@ -504,21 +668,34 @@ static void ads7846_debounce(void *ads)
status);
}
-static void ads7846_timer(unsigned long handle)
+static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
{
- struct ads7846 *ts = (void *)handle;
+ struct ads7846 *ts = container_of(handle, struct ads7846, timer);
int status = 0;
spin_lock_irq(&ts->lock);
- if (unlikely(ts->msg_idx && !ts->pendown)) {
+ if (unlikely(!ts->get_pendown_state() ||
+ device_suspended(&ts->spi->dev))) {
+ if (ts->pendown) {
+ struct input_dev *input = ts->input;
+
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
+
+ ts->pendown = 0;
+#ifdef VERBOSE
+ dev_dbg(&ts->spi->dev, "UP\n");
+#endif
+ }
+
/* measurement cycle ended */
if (!device_suspended(&ts->spi->dev)) {
ts->irq_disabled = 0;
enable_irq(ts->spi->irq);
}
ts->pending = 0;
- ts->msg_idx = 0;
} else {
/* pen is still down, continue with the measurement */
ts->msg_idx = 0;
@@ -528,6 +705,7 @@ static void ads7846_timer(unsigned long handle)
}
spin_unlock_irq(&ts->lock);
+ return HRTIMER_NORESTART;
}
static irqreturn_t ads7846_irq(int irq, void *handle)
@@ -546,7 +724,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
ts->irq_disabled = 1;
disable_irq(ts->spi->irq);
ts->pending = 1;
- mod_timer(&ts->timer, jiffies);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
+ HRTIMER_MODE_REL);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@@ -632,6 +811,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
struct ads7846_platform_data *pdata = spi->dev.platform_data;
struct spi_message *m;
struct spi_transfer *x;
+ int vref;
int err;
if (!spi->irq) {
@@ -665,6 +845,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
* may not. So we stick to very-portable 8 bit words, both RX and TX.
*/
spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_1;
+ err = spi_setup(spi);
+ if (err < 0)
+ return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -679,8 +863,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->spi = spi;
ts->input = input_dev;
- init_timer(&ts->timer);
- ts->timer.data = (unsigned long) ts;
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
@@ -689,14 +872,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->pressure_max = pdata->pressure_max ? : ~0;
- if (pdata->debounce_max) {
+
+ if (pdata->filter != NULL) {
+ if (pdata->filter_init != NULL) {
+ err = pdata->filter_init(pdata, &ts->filter_data);
+ if (err < 0)
+ goto err_free_mem;
+ }
+ ts->filter = pdata->filter;
+ ts->filter_cleanup = pdata->filter_cleanup;
+ } else if (pdata->debounce_max) {
ts->debounce_max = pdata->debounce_max;
+ if (ts->debounce_max < 2)
+ ts->debounce_max = 2;
ts->debounce_tol = pdata->debounce_tol;
ts->debounce_rep = pdata->debounce_rep;
- if (ts->debounce_rep > ts->debounce_max + 1)
- ts->debounce_rep = ts->debounce_max - 1;
+ ts->filter = ads7846_debounce;
+ ts->filter_data = ts;
} else
- ts->debounce_tol = ~0;
+ ts->filter = ads7846_no_filter;
ts->get_pendown_state = pdata->get_pendown_state;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
@@ -718,6 +912,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
+ vref = pdata->keep_vref_on;
+
/* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
@@ -727,7 +923,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
/* y- still on; turn on only y+ (and ADC) */
- ts->read_y = READ_Y;
+ ts->read_y = READ_Y(vref);
x->tx_buf = &ts->read_y;
x->len = 1;
spi_message_add_tail(x, m);
@@ -737,7 +933,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
m++;
@@ -745,7 +941,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* turn y- off, x+ on, then leave in lowpower */
x++;
- ts->read_x = READ_X;
+ ts->read_x = READ_X(vref);
x->tx_buf = &ts->read_x;
x->len = 1;
spi_message_add_tail(x, m);
@@ -755,7 +951,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
/* turn y+ off, x- on; we'll use formula #2 */
@@ -764,7 +960,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
x++;
- ts->read_z1 = READ_Z1;
+ ts->read_z1 = READ_Z1(vref);
x->tx_buf = &ts->read_z1;
x->len = 1;
spi_message_add_tail(x, m);
@@ -774,14 +970,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
m++;
spi_message_init(m);
x++;
- ts->read_z2 = READ_Z2;
+ ts->read_z2 = READ_Z2(vref);
x->tx_buf = &ts->read_z2;
x->len = 1;
spi_message_add_tail(x, m);
@@ -791,7 +987,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
}
@@ -820,31 +1016,24 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
- goto err_free_mem;
+ goto err_cleanup_filter;
}
+ err = ads784x_hwmon_register(spi, ts);
+ if (err)
+ goto err_free_irq;
+
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
- /* take a first sample, leaving nPENIRQ active; avoid
+ /* take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
(void) ads7846_read12_ser(&spi->dev,
READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
- switch (ts->model) {
- case 7846:
- ts->attr_group = &ads7846_attr_group;
- break;
- case 7845:
- ts->attr_group = &ads7845_attr_group;
- break;
- default:
- ts->attr_group = &ads7843_attr_group;
- break;
- }
- err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+ err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
if (err)
- goto err_free_irq;
+ goto err_remove_hwmon;
err = input_register_device(input_dev);
if (err)
@@ -853,9 +1042,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return 0;
err_remove_attr_group:
- sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ err_remove_hwmon:
+ ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
+ err_cleanup_filter:
+ if (ts->filter_cleanup)
+ ts->filter_cleanup(ts->filter_data);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
@@ -866,16 +1060,20 @@ static int __devexit ads7846_remove(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ ads784x_hwmon_unregister(spi, ts);
input_unregister_device(ts->input);
ads7846_suspend(spi, PMSG_SUSPEND);
- sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
free_irq(ts->spi->irq, ts);
/* suspend left the IRQ disabled */
enable_irq(ts->spi->irq);
+ if (ts->filter_cleanup)
+ ts->filter_cleanup(ts->filter_data);
+
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 4358a0a78eaa..c7db4032ef02 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -83,7 +83,7 @@
struct ucb1400 {
- ac97_t *ac97;
+ struct snd_ac97 *ac97;
struct input_dev *ts_idev;
int irq;
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index a730c461227f..0300dca8591d 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -151,6 +151,10 @@ static int tsdev_open(struct inode *inode, struct file *file)
int i = iminor(inode) - TSDEV_MINOR_BASE;
struct tsdev_list *list;
+ printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
+ "for removal.\nSee Documentation/feature-removal-schedule.txt "
+ "for details.\n");
+
if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
return -ENODEV;