diff options
Diffstat (limited to 'drivers/input')
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(¶m, 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; |