Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: remove scan_keyb driver
  Input: i8042 - fix AUX IRQ delivery check
  Input: wistron - add support for Fujitsu-Siemens Amilo D88x0
  Input: inport - use correct config option for ATIXL
  Input: HIL - handle erros from input_register_device()
  Input: tsdev - schedule removal
  Input: add Atlas button driver
  Input: ads7846 - be more compatible with the hwmon framework
  Input: ads7846 - detect pen up from GPIO state
  Input: ads7846 - select correct SPI mode
  Input: ads7846 - switch to using hrtimer
  Input: ads7846 - optionally leave Vref on during differential measurements
  Input: ads7846 - pluggable filtering logic
  Input: gpio-keys - keyboard driver for GPIO buttons
  Input: hid-ff - add support for Logitech Momo racing wheel
  Input: i8042 - really suppress ACK/NAK during panic blink
  Input: pc110pad - return proper error
This commit is contained in:
Linus Torvalds 2007-02-11 11:50:24 -08:00
commit d68798374b
21 changed files with 887 additions and 415 deletions

View file

@ -319,3 +319,18 @@ Why: In kernel tree version of driver is unmaintained. Sk98lin driver
replaced by the skge driver.
Who: Stephen Hemminger <shemminger@osdl.org>
---------------------------
What: Compaq touchscreen device emulation
When: Oct 2007
Files: drivers/input/tsdev.c
Why: The code says it was obsolete when it was written in 2001.
tslib is a userspace library which does anything tsdev can do and
much more besides in userspace where this code belongs. There is no
longer any need for tsdev and applications should have converted to
use tslib by now.
The name "tsdev" is also extremely confusing and lots of people have
it loaded when they don't need/use it.
Who: Richard Purdie <rpurdie@rpsys.net>
---------------------------

View file

@ -1,149 +0,0 @@
/*
* $Id: scan_keyb.c,v 1.2 2000/07/04 06:24:42 yaegashi Exp $
* Copyright (C) 2000 YAEGASHI Takeshi
* Generic scan keyboard driver
*/
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/mm.h>
#include <linux/signal.h>
#include <linux/init.h>
#include <linux/kbd_ll.h>
#include <linux/delay.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/kbd_kern.h>
#include <linux/timer.h>
#define SCANHZ (HZ/20)
struct scan_keyboard {
struct scan_keyboard *next;
int (*scan)(unsigned char *buffer);
const unsigned char *table;
unsigned char *s0, *s1;
int length;
};
static int scan_jiffies=0;
static struct scan_keyboard *keyboards=NULL;
struct timer_list scan_timer;
static void check_kbd(const unsigned char *table,
unsigned char *new, unsigned char *old, int length)
{
int need_tasklet_schedule=0;
unsigned int xor, bit;
while(length-->0) {
if((xor=*new^*old)==0) {
table+=8;
}
else {
for(bit=0x01; bit<0x100; bit<<=1) {
if(xor&bit) {
handle_scancode(*table, !(*new&bit));
need_tasklet_schedule=1;
#if 0
printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed");
#endif
}
table++;
}
}
new++; old++;
}
if(need_tasklet_schedule)
tasklet_schedule(&keyboard_tasklet);
}
static void scan_kbd(unsigned long dummy)
{
struct scan_keyboard *kbd;
scan_jiffies++;
for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) {
if(scan_jiffies&1) {
if(!kbd->scan(kbd->s0))
check_kbd(kbd->table,
kbd->s0, kbd->s1, kbd->length);
else
memcpy(kbd->s0, kbd->s1, kbd->length);
}
else {
if(!kbd->scan(kbd->s1))
check_kbd(kbd->table,
kbd->s1, kbd->s0, kbd->length);
else
memcpy(kbd->s1, kbd->s0, kbd->length);
}
}
init_timer(&scan_timer);
scan_timer.expires = jiffies + SCANHZ;
scan_timer.data = 0;
scan_timer.function = scan_kbd;
add_timer(&scan_timer);
}
int register_scan_keyboard(int (*scan)(unsigned char *buffer),
const unsigned char *table,
int length)
{
struct scan_keyboard *kbd;
kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL);
if (kbd == NULL)
goto error_out;
kbd->scan=scan;
kbd->table=table;
kbd->length=length;
kbd->s0 = kmalloc(length, GFP_KERNEL);
if (kbd->s0 == NULL)
goto error_free_kbd;
kbd->s1 = kmalloc(length, GFP_KERNEL);
if (kbd->s1 == NULL)
goto error_free_s0;
memset(kbd->s0, -1, kbd->length);
memset(kbd->s1, -1, kbd->length);
kbd->next=keyboards;
keyboards=kbd;
return 0;
error_free_s0:
kfree(kbd->s0);
error_free_kbd:
kfree(kbd);
error_out:
return -ENOMEM;
}
void __init scan_kbd_init(void)
{
init_timer(&scan_timer);
scan_timer.expires = jiffies + SCANHZ;
scan_timer.data = 0;
scan_timer.function = scan_kbd;
add_timer(&scan_timer);
printk(KERN_INFO "Generic scan keyboard driver initialized\n");
}

View file

@ -1,15 +0,0 @@
#ifndef __DRIVER_CHAR_SCAN_KEYB_H
#define __DRIVER_CHAR_SCAN_KEYB_H
/*
* $Id: scan_keyb.h,v 1.1 2000/06/10 21:45:30 yaegashi Exp $
* Copyright (C) 2000 YAEGASHI Takeshi
* Generic scan keyboard driver
*/
int register_scan_keyboard(int (*scan)(unsigned char *buffer),
const unsigned char *table,
int length);
void __init scan_kbd_init(void);
#endif

View file

@ -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_PXA
help
This driver implements support for buttons connected
directly to GPIO pins of PXA 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

View file

@ -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

View file

@ -0,0 +1,147 @@
/*
* 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/arch/pxa-regs.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 == IRQ_GPIO(gpio)) {
int state = ((GPLR(gpio) & GPIO_bit(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 = IRQ_GPIO(pdata->buttons[i].gpio);
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
error = request_irq(irq, gpio_keys_isr, SA_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, ret);
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(IRQ_GPIO(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 = IRQ_GPIO(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");

View file

@ -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,63 @@ 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:
release_region(HILBASE + HIL_DATA, 2);
err1:
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 +314,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 +335,6 @@ static struct parisc_driver hil_driver = {
#endif /* CONFIG_PARISC */
static int __init hil_init(void)
{
#if defined(CONFIG_PARISC)
@ -349,4 +368,3 @@ static void __exit hil_exit(void)
module_init(hil_init);
module_exit(hil_exit);

View file

@ -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

View file

@ -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

View file

@ -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");

View file

@ -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, }
};

View file

@ -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

View file

@ -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")) {

View file

@ -371,7 +371,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 +543,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 +573,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 +598,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.
@ -838,13 +841,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;

View file

@ -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

View file

@ -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;
/* FIXME boards with ads7846 might use external vref instead ... */
use_internal = (ts->model == 7846);
/*
* 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;
/* 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;
/* 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);
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);
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,
static struct attribute *ads784x_attributes[] = {
&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,
&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,129 @@ 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_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;
}
struct input_dev *input = ts->input;
if (sync) {
input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev);
}
#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);
input_sync(input);
#ifdef VERBOSE
dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
#endif
}
ts->pendown = (Rt != 0);
mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
spin_unlock_irqrestore(&ts->lock, flags);
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_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 +667,34 @@ static void ads7846_debounce(void *ads)
status);
}
static void ads7846_timer(unsigned long handle)
static int 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 +704,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 +723,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_REL);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@ -632,6 +810,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 +844,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 +862,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_REL);
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
@ -689,14 +871,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 +911,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 +922,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 +932,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 +940,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 +950,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 +959,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 +969,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 +986,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 +1015,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 +1041,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 +1059,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");

View file

@ -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;

View file

@ -57,6 +57,7 @@ static struct hid_ff_initializer inits[] = {
{ 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
#endif
#ifdef CONFIG_PANTHERLORD_FF
{ 0x810, 0x0001, hid_plff_init },

View file

@ -52,6 +52,7 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble },
{ 0x046d, 0xc283, ff_joystick },
{ 0x046d, 0xca03, ff_joystick },
{ 0x0000, 0x0000, ff_joystick }
};

View file

@ -0,0 +1,17 @@
#ifndef _GPIO_KEYS_H
#define _GPIO_KEYS_H
struct gpio_keys_button {
/* Configuration parameters */
int keycode;
int gpio;
int active_low;
char *desc;
};
struct gpio_keys_platform_data {
struct gpio_keys_button *buttons;
int nbuttons;
};
#endif

View file

@ -5,9 +5,17 @@
*
* It's OK if the min/max values are zero.
*/
enum ads7846_filter {
ADS7846_FILTER_OK,
ADS7846_FILTER_REPEAT,
ADS7846_FILTER_IGNORE,
};
struct ads7846_platform_data {
u16 model; /* 7843, 7845, 7846. */
u16 vref_delay_usecs; /* 0 for external vref; etc */
int keep_vref_on:1; /* set to keep vref on for differential
* measurements as well */
u16 x_plate_ohms;
u16 y_plate_ohms;
@ -21,5 +29,9 @@ struct ads7846_platform_data {
u16 debounce_rep; /* additional consecutive good readings
* required after the first two */
int (*get_pendown_state)(void);
int (*filter_init) (struct ads7846_platform_data *pdata,
void **filter_data);
int (*filter) (void *filter_data, int data_idx, int *val);
void (*filter_cleanup)(void *filter_data);
};