Commit a0fe3cc5 authored by Linus Torvalds's avatar Linus Torvalds

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: (40 commits)
  Input: psmouse - small formatting changes to better follow coding style
  Input: synaptics - set dimensions as reported by firmware
  Input: elantech - relax signature checks
  Input: elantech - enforce common prefix on messages
  Input: wistron_btns - switch to using kmemdup()
  Input: usbtouchscreen - switch to using kmemdup()
  Input: do not force selecting i8042 on Moorestown
  Input: Documentation/sysrq.txt - update KEY_SYSRQ info
  Input: 88pm860x_onkey - remove invalid irq number assignment
  Input: i8042 - add a PNP entry to the aux device list
  Input: i8042 - add some extra PNP keyboard types
  Input: wm9712 - fix wm97xx_set_gpio() logic
  Input: add keypad driver for keys interfaced to TCA6416
  Input: remove obsolete {corgi,spitz,tosa}kbd.c
  Input: kbtab - do not advertise unsupported events
  Input: kbtab - simplify kbtab_disconnect()
  Input: kbtab - fix incorrect size parameter in usb_buffer_free
  Input: acecad - don't advertise mouse events
  Input: acecad - fix some formatting issues
  Input: acecad - simplify usb_acecad_disconnect()
  ...

Trivial conflict in Documentation/feature-removal-schedule.txt
parents 04afb405 a62f0d27
...@@ -177,13 +177,13 @@ virtual console (ALT+Fn) and then back again should also help. ...@@ -177,13 +177,13 @@ virtual console (ALT+Fn) and then back again should also help.
* I hit SysRq, but nothing seems to happen, what's wrong? * I hit SysRq, but nothing seems to happen, what's wrong?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are some keyboards that send different scancodes for SysRq than the There are some keyboards that produce a different keycode for SysRq than the
pre-defined 0x54. So if SysRq doesn't work out of the box for a certain pre-defined value of 99 (see KEY_SYSRQ in include/linux/input.h), or which
keyboard, run 'showkey -s' to find out the proper scancode sequence. Then don't have a SysRq key at all. In these cases, run 'showkey -s' to find an
use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRq appropriate scancode sequence, and use 'setkeycodes <sequence> 99' to map
code (84 is decimal for 0x54). It's probably best to put this command in a this sequence to the usual SysRq code (e.g., 'setkeycodes e05b 99'). It's
boot script. Oh, and by the way, you exit 'showkey' by not typing anything probably best to put this command in a boot script. Oh, and by the way, you
for ten seconds. exit 'showkey' by not typing anything for ten seconds.
* I want to add SysRQ key events to a module, how does it work? * I want to add SysRQ key events to a module, how does it work?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......
This diff is collapsed.
/* -*- linux-c -*- /*
*
* $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $
*
* Linux Magic System Request Key Hacks * Linux Magic System Request Key Hacks
* *
* (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
...@@ -10,8 +7,13 @@ ...@@ -10,8 +7,13 @@
* (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com> * (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
* overhauled to use key registration * overhauled to use key registration
* based upon discusions in irc://irc.openprojects.net/#kernelnewbies * based upon discusions in irc://irc.openprojects.net/#kernelnewbies
*
* Copyright (c) 2010 Dmitry Torokhov
* Input handler conversion
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -39,33 +41,34 @@ ...@@ -39,33 +41,34 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/input.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/irq_regs.h> #include <asm/irq_regs.h>
/* Whether we react on sysrq keys or just ignore them */ /* Whether we react on sysrq keys or just ignore them */
int __read_mostly __sysrq_enabled = 1; static int __read_mostly sysrq_enabled = 1;
static bool __read_mostly sysrq_always_enabled;
static int __read_mostly sysrq_always_enabled;
int sysrq_on(void) static bool sysrq_on(void)
{ {
return __sysrq_enabled || sysrq_always_enabled; return sysrq_enabled || sysrq_always_enabled;
} }
/* /*
* A value of 1 means 'all', other nonzero values are an op mask: * A value of 1 means 'all', other nonzero values are an op mask:
*/ */
static inline int sysrq_on_mask(int mask) static bool sysrq_on_mask(int mask)
{ {
return sysrq_always_enabled || __sysrq_enabled == 1 || return sysrq_always_enabled ||
(__sysrq_enabled & mask); sysrq_enabled == 1 ||
(sysrq_enabled & mask);
} }
static int __init sysrq_always_enabled_setup(char *str) static int __init sysrq_always_enabled_setup(char *str)
{ {
sysrq_always_enabled = 1; sysrq_always_enabled = true;
printk(KERN_INFO "debug: sysrq always enabled.\n"); pr_info("sysrq always enabled.\n");
return 1; return 1;
} }
...@@ -76,6 +79,7 @@ __setup("sysrq_always_enabled", sysrq_always_enabled_setup); ...@@ -76,6 +79,7 @@ __setup("sysrq_always_enabled", sysrq_always_enabled_setup);
static void sysrq_handle_loglevel(int key, struct tty_struct *tty) static void sysrq_handle_loglevel(int key, struct tty_struct *tty)
{ {
int i; int i;
i = key - '0'; i = key - '0';
console_loglevel = 7; console_loglevel = 7;
printk("Loglevel set to %d\n", i); printk("Loglevel set to %d\n", i);
...@@ -101,7 +105,7 @@ static struct sysrq_key_op sysrq_SAK_op = { ...@@ -101,7 +105,7 @@ static struct sysrq_key_op sysrq_SAK_op = {
.enable_mask = SYSRQ_ENABLE_KEYBOARD, .enable_mask = SYSRQ_ENABLE_KEYBOARD,
}; };
#else #else
#define sysrq_SAK_op (*(struct sysrq_key_op *)0) #define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
#endif #endif
#ifdef CONFIG_VT #ifdef CONFIG_VT
...@@ -119,7 +123,7 @@ static struct sysrq_key_op sysrq_unraw_op = { ...@@ -119,7 +123,7 @@ static struct sysrq_key_op sysrq_unraw_op = {
.enable_mask = SYSRQ_ENABLE_KEYBOARD, .enable_mask = SYSRQ_ENABLE_KEYBOARD,
}; };
#else #else
#define sysrq_unraw_op (*(struct sysrq_key_op *)0) #define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
#endif /* CONFIG_VT */ #endif /* CONFIG_VT */
static void sysrq_handle_crash(int key, struct tty_struct *tty) static void sysrq_handle_crash(int key, struct tty_struct *tty)
...@@ -195,7 +199,7 @@ static struct sysrq_key_op sysrq_showlocks_op = { ...@@ -195,7 +199,7 @@ static struct sysrq_key_op sysrq_showlocks_op = {
.action_msg = "Show Locks Held", .action_msg = "Show Locks Held",
}; };
#else #else
#define sysrq_showlocks_op (*(struct sysrq_key_op *)0) #define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
#endif #endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -298,7 +302,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = { ...@@ -298,7 +302,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = {
.enable_mask = SYSRQ_ENABLE_DUMP, .enable_mask = SYSRQ_ENABLE_DUMP,
}; };
#else #else
#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)0) #define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
#endif #endif
static void sysrq_handle_showmem(int key, struct tty_struct *tty) static void sysrq_handle_showmem(int key, struct tty_struct *tty)
...@@ -477,6 +481,7 @@ struct sysrq_key_op *__sysrq_get_key_op(int key) ...@@ -477,6 +481,7 @@ struct sysrq_key_op *__sysrq_get_key_op(int key)
i = sysrq_key_table_key2index(key); i = sysrq_key_table_key2index(key);
if (i != -1) if (i != -1)
op_p = sysrq_key_table[i]; op_p = sysrq_key_table[i];
return op_p; return op_p;
} }
...@@ -488,11 +493,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) ...@@ -488,11 +493,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
sysrq_key_table[i] = op_p; sysrq_key_table[i] = op_p;
} }
/* static void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
* This is the non-locking version of handle_sysrq. It must/can only be called
* by sysrq key handlers, as they are inside of the lock
*/
void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
{ {
struct sysrq_key_op *op_p; struct sysrq_key_op *op_p;
int orig_log_level; int orig_log_level;
...@@ -544,10 +545,6 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) ...@@ -544,10 +545,6 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
spin_unlock_irqrestore(&sysrq_key_table_lock, flags); spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
} }
/*
* This function is called by the keyboard handler when SysRq is pressed
* and any other keycode arrives.
*/
void handle_sysrq(int key, struct tty_struct *tty) void handle_sysrq(int key, struct tty_struct *tty)
{ {
if (sysrq_on()) if (sysrq_on())
...@@ -555,10 +552,177 @@ void handle_sysrq(int key, struct tty_struct *tty) ...@@ -555,10 +552,177 @@ void handle_sysrq(int key, struct tty_struct *tty)
} }
EXPORT_SYMBOL(handle_sysrq); EXPORT_SYMBOL(handle_sysrq);
#ifdef CONFIG_INPUT
/* Simple translation table for the SysRq keys */
static const unsigned char sysrq_xlate[KEY_MAX + 1] =
"\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
"qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
"dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
"bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
"\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
"\r\000/"; /* 0x60 - 0x6f */
static bool sysrq_down;
static int sysrq_alt_use;
static int sysrq_alt;
static bool sysrq_filter(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
if (type != EV_KEY)
goto out;
switch (code) {
case KEY_LEFTALT:
case KEY_RIGHTALT:
if (value)
sysrq_alt = code;
else if (sysrq_down && code == sysrq_alt_use)
sysrq_down = false;
break;
case KEY_SYSRQ:
if (value == 1 && sysrq_alt) {
sysrq_down = true;
sysrq_alt_use = sysrq_alt;
}
break;
default:
if (sysrq_down && value && value != 2)
__handle_sysrq(sysrq_xlate[code], NULL, 1);
break;
}
out:
return sysrq_down;
}
static int sysrq_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
struct input_handle *handle;
int error;
sysrq_down = false;
sysrq_alt = 0;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "sysrq";
error = input_register_handle(handle);
if (error) {
pr_err("Failed to register input sysrq handler, error %d\n",
error);
goto err_free;
}
error = input_open_device(handle);
if (error) {
pr_err("Failed to open input device, error %d\n", error);
goto err_unregister;
}
return 0;
err_unregister:
input_unregister_handle(handle);
err_free:
kfree(handle);
return error;
}
static void sysrq_disconnect(struct input_handle *handle)
{
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
}
/*
* We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all
* keyboards have SysRq ikey predefined and so user may add it to keymap
* later, but we expect all such keyboards to have left alt.
*/
static const struct input_device_id sysrq_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT_MASK(EV_KEY) },
.keybit = { BIT_MASK(KEY_LEFTALT) },
},
{ },
};
static struct input_handler sysrq_handler = {
.filter = sysrq_filter,
.connect = sysrq_connect,
.disconnect = sysrq_disconnect,
.name = "sysrq",
.id_table = sysrq_ids,
};
static bool sysrq_handler_registered;
static inline void sysrq_register_handler(void)
{
int error;
error = input_register_handler(&sysrq_handler);
if (error)
pr_err("Failed to register input handler, error %d", error);
else
sysrq_handler_registered = true;
}
static inline void sysrq_unregister_handler(void)
{
if (sysrq_handler_registered) {
input_unregister_handler(&sysrq_handler);
sysrq_handler_registered = false;
}
}
#else
static inline void sysrq_register_handler(void)
{
}
static inline void sysrq_unregister_handler(void)
{
}
#endif /* CONFIG_INPUT */
int sysrq_toggle_support(int enable_mask)
{
bool was_enabled = sysrq_on();
sysrq_enabled = enable_mask;
if (was_enabled != sysrq_on()) {
if (sysrq_on())
sysrq_register_handler();
else
sysrq_unregister_handler();
}
return 0;
}
static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
struct sysrq_key_op *remove_op_p) struct sysrq_key_op *remove_op_p)
{ {
int retval; int retval;
unsigned long flags; unsigned long flags;
...@@ -599,6 +763,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, ...@@ -599,6 +763,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
return -EFAULT; return -EFAULT;
__handle_sysrq(c, NULL, 0); __handle_sysrq(c, NULL, 0);
} }
return count; return count;
} }
...@@ -606,10 +771,28 @@ static const struct file_operations proc_sysrq_trigger_operations = { ...@@ -606,10 +771,28 @@ static const struct file_operations proc_sysrq_trigger_operations = {
.write = write_sysrq_trigger, .write = write_sysrq_trigger,
}; };
static void sysrq_init_procfs(void)
{
if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
&proc_sysrq_trigger_operations))
pr_err("Failed to register proc interface\n");
}
#else
static inline void sysrq_init_procfs(void)
{
}
#endif /* CONFIG_PROC_FS */
static int __init sysrq_init(void) static int __init sysrq_init(void)
{ {
proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations); sysrq_init_procfs();
if (sysrq_on())
sysrq_register_handler();
return 0; return 0;
} }
module_init(sysrq_init); module_init(sysrq_init);
#endif
...@@ -73,7 +73,7 @@ config KEYBOARD_ATKBD ...@@ -73,7 +73,7 @@ config KEYBOARD_ATKBD
default y default y
select SERIO select SERIO
select SERIO_LIBPS2 select SERIO_LIBPS2
select SERIO_I8042 if X86 select SERIO_I8042 if X86 && !X86_MRST
select SERIO_GSCPS2 if GSC select SERIO_GSCPS2 if GSC
help help
Say Y here if you want to use a standard AT or PS/2 keyboard. Usually Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
...@@ -179,6 +179,22 @@ config KEYBOARD_GPIO ...@@ -179,6 +179,22 @@ config KEYBOARD_GPIO
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 gpio_keys. module will be called gpio_keys.
config KEYBOARD_TCA6416
tristate "TCA6416 Keypad Support"
depends on I2C
help
This driver implements basic keypad functionality
for keys connected through TCA6416 IO expander
Say Y here if your device has keys connected to
TCA6416 IO expander. Your board-specific setup logic
must also provide pin-mask details(of which TCA6416 pins
are used for keypad).
If enabled the complete TCA6416 device will be managed through
this driver.
config KEYBOARD_MATRIX config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support" tristate "GPIO driven matrix keypad support"
depends on GENERIC_GPIO depends on GENERIC_GPIO
......
...@@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o ...@@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
......
...@@ -670,8 +670,6 @@ static int __devinit lm8323_probe(struct i2c_client *client, ...@@ -670,8 +670,6 @@ static int __devinit lm8323_probe(struct i2c_client *client,
goto fail1; goto fail1;
} }
i2c_set_clientdata(client, lm);
lm->client = client; lm->client = client;
lm->idev = idev; lm->idev = idev;
mutex_init(&lm->lock); mutex_init(&lm->lock);
...@@ -753,6 +751,8 @@ static int __devinit lm8323_probe(struct i2c_client *client, ...@@ -753,6 +751,8 @@ static int __devinit lm8323_probe(struct i2c_client *client,
goto fail4; goto fail4;
} }
i2c_set_clientdata(client, lm);
device_init_wakeup(&client->dev, 1); device_init_wakeup(&client->dev, 1);
enable_irq_wake(client->irq); enable_irq_wake(client->irq);
...@@ -778,6 +778,8 @@ static int __devexit lm8323_remove(struct i2c_client *client) ...@@ -778,6 +778,8 @@ static int __devexit lm8323_remove(struct i2c_client *client)
struct lm8323_chip *lm = i2c_get_clientdata(client); struct lm8323_chip *lm = i2c_get_clientdata(client);
int i; int i;
i2c_set_clientdata(client, NULL);
disable_irq_wake(client->irq); disable_irq_wake(client->irq);
free_irq(client->irq, lm); free_irq(client->irq, lm);
cancel_work_sync(&lm->work); cancel_work_sync(&lm->work);
......
/*
* Driver for keys on TCA6416 I2C IO expander
*
* Copyright (C) 2010 Texas Instruments
*
* Author : Sriramakrishnan.A.G. <srk@ti.com>
*
* 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/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/tca6416_keypad.h>
#define TCA6416_INPUT 0
#define TCA6416_OUTPUT 1
#define TCA6416_INVERT 2
#define TCA6416_DIRECTION 3
static const struct i2c_device_id tca6416_id[] = {
{ "tca6416-keys", 16, },
{ }
};
MODULE_DEVICE_TABLE(i2c, tca6416_id);
struct tca6416_drv_data {
struct input_dev *input;
struct tca6416_button data[0];
};
struct tca6416_keypad_chip {
uint16_t reg_output;
uint16_t reg_direction;
uint16_t reg_input;
struct i2c_client *client;
struct input_dev *input;
struct delayed_work dwork;
u16 pinmask;
int irqnum;
bool use_polling;
struct tca6416_button buttons[0];
};
static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
{
int error;
error = i2c_smbus_write_word_data(chip->client, reg << 1, val);
if (error < 0) {
dev_err(&chip->client->dev,
"%s failed, reg: %d, val: %d, error: %d\n",
__func__, reg, val, error);
return error;
}
return 0;
}
static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
{
int retval;
retval = i2c_smbus_read_word_data(chip->client, reg << 1);
if (retval < 0) {
dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
__func__, reg, retval);
return retval;
}
*val = (u16)retval;
return 0;
}
static void tca6416_keys_scan(struct tca6416_keypad_chip *chip)
{
struct input_dev *input = chip->input;
u16 reg_val, val;
int error, i, pin_index;
error = tca6416_read_reg(chip, TCA6416_INPUT, &reg_val);
if (error)
return;
reg_val &= chip->pinmask;
/* Figure out which lines have changed */
val = reg_val ^ chip->reg_input;
chip->reg_input = reg_val;
for (i = 0, pin_index = 0; i < 16; i++) {
if (val & (1 << i)) {
struct tca6416_button *button = &chip->buttons[pin_index];
unsigned int type = button->type ?: EV_KEY;
int state = ((reg_val & (1 << i)) ? 1 : 0)
^ button->active_low;
input_event(input, type, button->code, !!state);
input_sync(input);
}
if (chip->pinmask & (1 << i))
pin_index++;
}
}
/*
* This is threaded IRQ handler and this can (and will) sleep.
*/
static irqreturn_t tca6416_keys_isr(int irq, void *dev_id)
{
struct tca6416_keypad_chip *chip = dev_id;
tca6416_keys_scan(chip);
return IRQ_HANDLED;
}
static void tca6416_keys_work_func(struct work_struct *work)
{
struct tca6416_keypad_chip *chip =
container_of(work, struct tca6416_keypad_chip, dwork.work);
tca6416_keys_scan(chip);
schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100));
}
static int tca6416_keys_open(struct input_dev *dev)
{
struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
/* Get initial device state in case it has switches */
tca6416_keys_scan(chip);
if (chip->use_polling)
schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100));
else
enable_irq(chip->irqnum);
return 0;
}
static void tca6416_keys_close(struct input_dev *dev)
{
struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
if (chip->use_polling)
cancel_delayed_work_sync(&chip->dwork);
else
disable_irq(chip->irqnum);
}
static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip)
{
int error;
error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output);
if (error)
return error;
error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
if (error)
return error;
/* ensure that keypad pins are set to input */
error = tca6416_write_reg(chip, TCA6416_DIRECTION,
chip->reg_direction | chip->pinmask);
if (error)
return error;
error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
if (error)
return error;
error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input);
if (error)
return error;
chip->reg_input &= chip->pinmask;
return 0;
}
static int __devinit tca6416_keypad_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tca6416_keys_platform_data *pdata;
struct tca6416_keypad_chip *chip;
struct input_dev *input;
int error;
int i;
/* Check functionality */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
dev_err(&client->dev, "%s adapter not supported\n",
dev_driver_string(&client->adapter->dev));
return -ENODEV;
}
pdata = client->dev.platform_data;
if (!pdata) {
dev_dbg(&client->dev, "no platform data\n");
return -EINVAL;
}
chip = kzalloc(sizeof(struct tca6416_keypad_chip) +
pdata->nbuttons * sizeof(struct tca6416_button),
GFP_KERNEL);
input = input_allocate_device();
if (!chip || !input) {
error = -ENOMEM;
goto fail1;
}
chip->client = client;
chip->input = input;
chip->pinmask = pdata->pinmask;
chip->use_polling = pdata->use_polling;
INIT_DELAYED_WORK(&chip->dwork, tca6416_keys_work_func);
input->phys = "tca6416-keys/input0";
input->name = client->name;
input->dev.parent = &client->dev;
input->open = tca6416_keys_open;
input->close = tca6416_keys_close;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
/* Enable auto repeat feature of Linux input subsystem */
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
for (i = 0; i < pdata->nbuttons; i++) {
unsigned int type;
chip->buttons[i] = pdata->buttons[i];
type = (pdata->buttons[i].type) ?: EV_KEY;
input_set_capability(input, type, pdata->buttons[i].code);
}
input_set_drvdata(input, chip);
/*
* Initialize cached registers from their original values.
* we can't share this chip with another i2c master.
*/
error = tca6416_setup_registers(chip);
if (error)
goto fail1;
if (!chip->use_polling) {
if (pdata->irq_is_gpio)
chip->irqnum = gpio_to_irq(client->irq);
else
chip->irqnum = client->irq;
error = request_threaded_irq(chip->irqnum, NULL,
tca6416_keys_isr,
IRQF_TRIGGER_FALLING,
"tca6416-keypad", chip);
if (error) {
dev_dbg(&client->dev,
"Unable to claim irq %d; error %d\n",
chip->irqnum, error);
goto fail1;
}
disable_irq(chip->irqnum);
}
error = input_register_device(input);
if (error) {
dev_dbg(&client->dev,
"Unable to register input device, error: %d\n", error);
goto fail2;
}
i2c_set_clientdata(client, chip);
return 0;
fail2:
if (!chip->use_polling) {
free_irq(chip->irqnum, chip);
enable_irq(chip->irqnum);
}
fail1:
input_free_device(input);
kfree(chip);
return error;
}
static int __devexit tca6416_keypad_remove(struct i2c_client *client)
{
struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
if (!chip->use_polling) {
free_irq(chip->irqnum, chip);
enable_irq(chip->irqnum);
}
input_unregister_device(chip->input);
kfree(chip);
i2c_set_clientdata(client, NULL);
return 0;
}
static struct i2c_driver tca6416_keypad_driver = {
.driver = {
.name = "tca6416-keypad",
},
.probe = tca6416_keypad_probe,
.remove = __devexit_p(tca6416_keypad_remove),
.id_table = tca6416_id,
};
static int __init tca6416_keypad_init(void)
{
return i2c_add_driver(&tca6416_keypad_driver);
}
subsys_initcall(tca6416_keypad_init);
static void __exit tca6416_keypad_exit(void)
{
i2c_del_driver(&tca6416_keypad_driver);
}
module_exit(tca6416_keypad_exit);
MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
MODULE_DESCRIPTION("Keypad driver over tca6146 IO expander");
MODULE_LICENSE("GPL");
...@@ -87,7 +87,6 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev) ...@@ -87,7 +87,6 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
info->idev->phys = "88pm860x_on/input0"; info->idev->phys = "88pm860x_on/input0";
info->idev->id.bustype = BUS_I2C; info->idev->id.bustype = BUS_I2C;
info->idev->dev.parent = &pdev->dev; info->idev->dev.parent = &pdev->dev;
info->irq = irq;
info->idev->evbit[0] = BIT_MASK(EV_KEY); info->idev->evbit[0] = BIT_MASK(EV_KEY);
info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
......
...@@ -22,6 +22,36 @@ config INPUT_88PM860X_ONKEY ...@@ -22,6 +22,36 @@ config INPUT_88PM860X_ONKEY
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called 88pm860x_onkey. will be called 88pm860x_onkey.
config INPUT_AD714X
tristate "Analog Devices AD714x Capacitance Touch Sensor"
help
Say Y here if you want to support an AD7142/3/7/8/7A touch sensor.
You should select a bus connection too.
To compile this driver as a module, choose M here: the
module will be called ad714x.
config INPUT_AD714X_I2C
tristate "support I2C bus connection"
depends on INPUT_AD714X && I2C
default y
help
Say Y here if you have AD7142/AD7147 hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called ad714x-i2c.
config INPUT_AD714X_SPI
tristate "support SPI bus connection"
depends on INPUT_AD714X && SPI
default y
help
Say Y here if you have AD7142/AD7147 hooked to a SPI bus.
To compile this driver as a module, choose M here: the
module will be called ad714x-spi.
config INPUT_PCSPKR config INPUT_PCSPKR
tristate "PC Speaker support" tristate "PC Speaker support"
depends on PCSPKR_PLATFORM depends on PCSPKR_PLATFORM
...@@ -277,6 +307,16 @@ config INPUT_PCF50633_PMU ...@@ -277,6 +307,16 @@ config INPUT_PCF50633_PMU
Say Y to include support for delivering PMU events via input Say Y to include support for delivering PMU events via input
layer on NXP PCF50633. layer on NXP PCF50633.
config INPUT_PCF8574
tristate "PCF8574 Keypad input device"
depends on I2C && EXPERIMENTAL
help
Say Y here if you want to support a keypad connetced via I2C
with a PCF8574.
To compile this driver as a module, choose M here: the
module will be called pcf8574_keypad.
config INPUT_GPIO_ROTARY_ENCODER config INPUT_GPIO_ROTARY_ENCODER
tristate "Rotary encoders connected to GPIO pins" tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO depends on GPIOLIB && GENERIC_GPIO
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
...@@ -19,6 +22,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o ...@@ -19,6 +22,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
......
/*
* AD714X CapTouch Programmable Controller driver (I2C bus)
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_I2C */
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include "ad714x.h"
#ifdef CONFIG_PM
static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message)
{
return ad714x_disable(i2c_get_clientdata(client));
}
static int ad714x_i2c_resume(struct i2c_client *client)
{
return ad714x_enable(i2c_get_clientdata(client));
}
#else
# define ad714x_i2c_suspend NULL
# define ad714x_i2c_resume NULL
#endif
static int ad714x_i2c_write(struct device *dev, unsigned short reg,
unsigned short data)
{
struct i2c_client *client = to_i2c_client(dev);
int ret = 0;
u8 *_reg = (u8 *)&reg;
u8 *_data = (u8 *)&data;
u8 tx[4] = {
_reg[1],
_reg[0],
_data[1],
_data[0]
};
ret = i2c_master_send(client, tx, 4);
if (ret < 0)
dev_err(&client->dev, "I2C write error\n");
return ret;
}
static int ad714x_i2c_read(struct device *dev, unsigned short reg,
unsigned short *data)
{
struct i2c_client *client = to_i2c_client(dev);
int ret = 0;
u8 *_reg = (u8 *)&reg;
u8 *_data = (u8 *)data;
u8 tx[2] = {
_reg[1],
_reg[0]
};
u8 rx[2];
ret = i2c_master_send(client, tx, 2);
if (ret >= 0)
ret = i2c_master_recv(client, rx, 2);
if (unlikely(ret < 0)) {
dev_err(&client->dev, "I2C read error\n");
} else {
_data[0] = rx[1];
_data[1] = rx[0];
}
return ret;
}
static int __devinit ad714x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ad714x_chip *chip;
chip = ad714x_probe(&client->dev, BUS_I2C, client->irq,
ad714x_i2c_read, ad714x_i2c_write);
if (IS_ERR(chip))
return PTR_ERR(chip);
i2c_set_clientdata(client, chip);
return 0;
}
static int __devexit ad714x_i2c_remove(struct i2c_client *client)
{
struct ad714x_chip *chip = i2c_get_clientdata(client);
ad714x_remove(chip);
i2c_set_clientdata(client, NULL);
return 0;
}
static const struct i2c_device_id ad714x_id[] = {
{ "ad7142_captouch", 0 },
{ "ad7143_captouch", 0 },
{ "ad7147_captouch", 0 },
{ "ad7147a_captouch", 0 },
{ "ad7148_captouch", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad714x_id);
static struct i2c_driver ad714x_i2c_driver = {
.driver = {
.name = "ad714x_captouch",
},
.probe = ad714x_i2c_probe,
.remove = __devexit_p(ad714x_i2c_remove),
.suspend = ad714x_i2c_suspend,
.resume = ad714x_i2c_resume,
.id_table = ad714x_id,
};
static __init int ad714x_i2c_init(void)
{
return i2c_add_driver(&ad714x_i2c_driver);
}
module_init(ad714x_i2c_init);
static __exit void ad714x_i2c_exit(void)
{
i2c_del_driver(&ad714x_i2c_driver);
}
module_exit(ad714x_i2c_exit);
MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver");
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("GPL");
/*
* AD714X CapTouch Programmable Controller driver (SPI bus)
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_I2C */
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include "ad714x.h"
#define AD714x_SPI_CMD_PREFIX 0xE000 /* bits 15:11 */
#define AD714x_SPI_READ BIT(10)
#ifdef CONFIG_PM
static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message)
{
return ad714x_disable(spi_get_drvdata(spi));
}
static int ad714x_spi_resume(struct spi_device *spi)
{
return ad714x_enable(spi_get_drvdata(spi));
}
#else
# define ad714x_spi_suspend NULL
# define ad714x_spi_resume NULL
#endif
static int ad714x_spi_read(struct device *dev, unsigned short reg,
unsigned short *data)
{
struct spi_device *spi = to_spi_device(dev);
unsigned short tx = AD714x_SPI_CMD_PREFIX | AD714x_SPI_READ | reg;
return spi_write_then_read(spi, (u8 *)&tx, 2, (u8 *)data, 2);
}
static int ad714x_spi_write(struct device *dev, unsigned short reg,
unsigned short data)
{
struct spi_device *spi = to_spi_device(dev);
unsigned short tx[2] = {
AD714x_SPI_CMD_PREFIX | reg,
data
};
return spi_write(spi, (u8 *)tx, 4);
}
static int __devinit ad714x_spi_probe(struct spi_device *spi)
{
struct ad714x_chip *chip;
chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq,
ad714x_spi_read, ad714x_spi_write);
if (IS_ERR(chip))
return PTR_ERR(chip);
spi_set_drvdata(spi, chip);
return 0;
}
static int __devexit ad714x_spi_remove(struct spi_device *spi)
{
struct ad714x_chip *chip = spi_get_drvdata(spi);
ad714x_remove(chip);
spi_set_drvdata(spi, NULL);
return 0;
}
static struct spi_driver ad714x_spi_driver = {
.driver = {
.name = "ad714x_captouch",
.owner = THIS_MODULE,
},
.probe = ad714x_spi_probe,
.remove = __devexit_p(ad714x_spi_remove),
.suspend = ad714x_spi_suspend,
.resume = ad714x_spi_resume,
};
static __init int ad714x_spi_init(void)
{
return spi_register_driver(&ad714x_spi_driver);
}
module_init(ad714x_spi_init);
static __exit void ad714x_spi_exit(void)
{
spi_unregister_driver(&ad714x_spi_driver);
}
module_exit(ad714x_spi_exit);
MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver");
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("GPL");
This diff is collapsed.
/*
* AD714X CapTouch Programmable Controller driver (bus interfaces)
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef _AD714X_H_
#define _AD714X_H_
#include <linux/types.h>
struct device;
struct ad714x_chip;
typedef int (*ad714x_read_t)(struct device *, unsigned short, unsigned short *);
typedef int (*ad714x_write_t)(struct device *, unsigned short, unsigned short);
int ad714x_disable(struct ad714x_chip *ad714x);
int ad714x_enable(struct ad714x_chip *ad714x);
struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
ad714x_read_t read, ad714x_write_t write);
void ad714x_remove(struct ad714x_chip *ad714x);
#endif
/*
* Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander
*
* Copyright 2005-2008 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#define DRV_NAME "pcf8574_keypad"
static const unsigned char pcf8574_kp_btncode[] = {
[0] = KEY_RESERVED,
[1] = KEY_ENTER,
[2] = KEY_BACKSLASH,
[3] = KEY_0,
[4] = KEY_RIGHTBRACE,
[5] = KEY_C,
[6] = KEY_9,
[7] = KEY_8,
[8] = KEY_7,
[9] = KEY_B,
[10] = KEY_6,
[11] = KEY_5,
[12] = KEY_4,
[13] = KEY_A,
[14] = KEY_3,
[15] = KEY_2,
[16] = KEY_1
};
struct kp_data {
unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)];
struct input_dev *idev;
struct i2c_client *client;
char name[64];
char phys[32];
unsigned char laststate;
};
static short read_state(struct kp_data *lp)
{
unsigned char x, y, a, b;
i2c_smbus_write_byte(lp->client, 240);
x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4));
i2c_smbus_write_byte(lp->client, 15);
y = 0xF & (~i2c_smbus_read_byte(lp->client));
for (a = 0; x > 0; a++)
x = x >> 1;
for (b = 0; y > 0; b++)
y = y >> 1;
return ((a - 1) * 4) + b;
}
static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
{
struct kp_data *lp = dev_id;
unsigned char nextstate = read_state(lp);
if (lp->laststate != nextstate) {
int key_down = nextstate <= ARRAY_SIZE(lp->btncode);
unsigned short keycode = key_down ?
lp->btncode[nextstate] : lp->btncode[lp->laststate];
input_report_key(lp->idev, keycode, key_down);
input_sync(lp->idev);
lp->laststate = nextstate;
}
return IRQ_HANDLED;
}
static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int i, ret;
struct input_dev *idev;
struct kp_data *lp;
if (i2c_smbus_write_byte(client, 240) < 0) {
dev_err(&client->dev, "probe: write fail\n");
return -ENODEV;
}
lp = kzalloc(sizeof(*lp), GFP_KERNEL);
if (!lp)
return -ENOMEM;
idev = input_allocate_device();
if (!idev) {
dev_err(&client->dev, "Can't allocate input device\n");
ret = -ENOMEM;
goto fail_allocate;
}
lp->idev = idev;
lp->client = client;
idev->evbit[0] = BIT_MASK(EV_KEY);
idev->keycode = lp->btncode;
idev->keycodesize = sizeof(lp->btncode[0]);
idev->keycodemax = ARRAY_SIZE(lp->btncode);
for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) {
lp->btncode[i] = pcf8574_kp_btncode[i];
__set_bit(lp->btncode[i] & KEY_MAX, idev->keybit);
}
sprintf(lp->name, DRV_NAME);
sprintf(lp->phys, "kp_data/input0");
idev->name = lp->name;
idev->phys = lp->phys;
idev->id.bustype = BUS_I2C;
idev->id.vendor = 0x0001;
idev->id.product = 0x0001;
idev->id.version = 0x0100;
input_set_drvdata(idev, lp);
ret = input_register_device(idev);
if (ret) {
dev_err(&client->dev, "input_register_device() failed\n");
goto fail_register;
}
lp->laststate = read_state(lp);
ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
DRV_NAME, lp);
if (ret) {
dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
goto fail_irq;
}
i2c_set_clientdata(client, lp);
return 0;
fail_irq:
input_unregister_device(idev);
fail_register:
input_set_drvdata(idev, NULL);
input_free_device(idev);
fail_allocate:
kfree(lp);
return ret;
}
static int __devexit pcf8574_kp_remove(struct i2c_client *client)
{
struct kp_data *lp = i2c_get_clientdata(client);
free_irq(client->irq, lp);
input_unregister_device(lp->idev);
kfree(lp);
i2c_set_clientdata(client, NULL);
return 0;
}
#ifdef CONFIG_PM
static int pcf8574_kp_resume(struct i2c_client *client)
{
enable_irq(client->irq);
return 0;
}
static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg)
{
disable_irq(client->irq);
return 0;
}
#else
# define pcf8574_kp_resume NULL
# define pcf8574_kp_suspend NULL
#endif
static const struct i2c_device_id pcf8574_kp_id[] = {
{ DRV_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
static struct i2c_driver pcf8574_kp_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.probe = pcf8574_kp_probe,
.remove = __devexit_p(pcf8574_kp_remove),
.suspend = pcf8574_kp_suspend,
.resume = pcf8574_kp_resume,
.id_table = pcf8574_kp_id,
};
static int __init pcf8574_kp_init(void)
{
return i2c_add_driver(&pcf8574_kp_driver);
}
module_init(pcf8574_kp_init);
static void __exit pcf8574_kp_exit(void)
{
i2c_del_driver(&pcf8574_kp_driver);
}
module_exit(pcf8574_kp_exit);
MODULE_AUTHOR("Michael Hennerich");
MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574");
MODULE_LICENSE("GPL");
...@@ -983,11 +983,11 @@ static int __init copy_keymap(void) ...@@ -983,11 +983,11 @@ static int __init copy_keymap(void)
for (key = keymap; key->type != KE_END; key++) for (key = keymap; key->type != KE_END; key++)
length++; length++;
new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL); new_keymap = kmemdup(keymap, length * sizeof(struct key_entry),
GFP_KERNEL);
if (!new_keymap) if (!new_keymap)
return -ENOMEM; return -ENOMEM;
memcpy(new_keymap, keymap, length * sizeof(struct key_entry));
keymap = new_keymap; keymap = new_keymap;
return 0; return 0;
......
...@@ -17,7 +17,7 @@ config MOUSE_PS2 ...@@ -17,7 +17,7 @@ config MOUSE_PS2
default y default y
select SERIO select SERIO
select SERIO_LIBPS2 select SERIO_LIBPS2
select SERIO_I8042 if X86 select SERIO_I8042 if X86 && !X86_MRST
select SERIO_GSCPS2 if GSC select SERIO_GSCPS2 if GSC
help help
Say Y here if you have a PS/2 mouse connected to your system. This Say Y here if you have a PS/2 mouse connected to your system. This
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* Trademarks are the property of their respective owners. * Trademarks are the property of their respective owners.
*/ */
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -19,10 +21,10 @@ ...@@ -19,10 +21,10 @@
#include "psmouse.h" #include "psmouse.h"
#include "elantech.h" #include "elantech.h"
#define elantech_debug(format, arg...) \ #define elantech_debug(fmt, ...) \
do { \ do { \
if (etd->debug) \ if (etd->debug) \
printk(KERN_DEBUG format, ##arg); \ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
} while (0) } while (0)
static bool force_elantech; static bool force_elantech;
...@@ -37,7 +39,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, ...@@ -37,7 +39,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c,
{ {
if (psmouse_sliced_command(psmouse, c) || if (psmouse_sliced_command(psmouse, c) ||
ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
pr_err("elantech.c: synaptics_send_cmd query 0x%02x failed.\n", c); pr_err("synaptics_send_cmd query 0x%02x failed.\n", c);
return -1; return -1;
} }
...@@ -60,13 +62,13 @@ static int elantech_ps2_command(struct psmouse *psmouse, ...@@ -60,13 +62,13 @@ static int elantech_ps2_command(struct psmouse *psmouse,
if (rc == 0) if (rc == 0)
break; break;
tries--; tries--;
elantech_debug("elantech.c: retrying ps2 command 0x%02x (%d).\n", elantech_debug("retrying ps2 command 0x%02x (%d).\n",
command, tries); command, tries);
msleep(ETP_PS2_COMMAND_DELAY); msleep(ETP_PS2_COMMAND_DELAY);
} while (tries > 0); } while (tries > 0);
if (rc) if (rc)
pr_err("elantech.c: ps2 command 0x%02x failed.\n", command); pr_err("ps2 command 0x%02x failed.\n", command);
return rc; return rc;
} }
...@@ -108,7 +110,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, ...@@ -108,7 +110,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
} }
if (rc) if (rc)
pr_err("elantech.c: failed to read register 0x%02x.\n", reg); pr_err("failed to read register 0x%02x.\n", reg);
else else
*val = param[0]; *val = param[0];
...@@ -154,7 +156,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, ...@@ -154,7 +156,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
} }
if (rc) if (rc)
pr_err("elantech.c: failed to write register 0x%02x with value 0x%02x.\n", pr_err("failed to write register 0x%02x with value 0x%02x.\n",
reg, val); reg, val);
return rc; return rc;
...@@ -167,7 +169,7 @@ static void elantech_packet_dump(unsigned char *packet, int size) ...@@ -167,7 +169,7 @@ static void elantech_packet_dump(unsigned char *packet, int size)
{ {
int i; int i;
printk(KERN_DEBUG "elantech.c: PS/2 packet ["); printk(KERN_DEBUG pr_fmt("PS/2 packet ["));
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
printk("%s0x%02x ", (i) ? ", " : " ", packet[i]); printk("%s0x%02x ", (i) ? ", " : " ", packet[i]);
printk("]\n"); printk("]\n");
...@@ -203,7 +205,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) ...@@ -203,7 +205,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
if (etd->jumpy_cursor) { if (etd->jumpy_cursor) {
/* Discard packets that are likely to have bogus coordinates */ /* Discard packets that are likely to have bogus coordinates */
if (fingers > old_fingers) { if (fingers > old_fingers) {
elantech_debug("elantech.c: discarding packet\n"); elantech_debug("discarding packet\n");
goto discard_packet_v1; goto discard_packet_v1;
} }
} }
...@@ -413,23 +415,21 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) ...@@ -413,23 +415,21 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
if (rc == 0) if (rc == 0)
break; break;
tries--; tries--;
elantech_debug("elantech.c: retrying read (%d).\n", elantech_debug("retrying read (%d).\n", tries);
tries);
msleep(ETP_READ_BACK_DELAY); msleep(ETP_READ_BACK_DELAY);
} while (tries > 0); } while (tries > 0);
if (rc) { if (rc) {
pr_err("elantech.c: failed to read back register 0x10.\n"); pr_err("failed to read back register 0x10.\n");
} else if (etd->hw_version == 1 && } else if (etd->hw_version == 1 &&
!(val & ETP_R10_ABSOLUTE_MODE)) { !(val & ETP_R10_ABSOLUTE_MODE)) {
pr_err("elantech.c: touchpad refuses " pr_err("touchpad refuses to switch to absolute mode.\n");
"to switch to absolute mode.\n");
rc = -1; rc = -1;
} }
} }
if (rc) if (rc)
pr_err("elantech.c: failed to initialise registers.\n"); pr_err("failed to initialise registers.\n");
return rc; return rc;
} }
...@@ -575,6 +575,24 @@ static struct attribute_group elantech_attr_group = { ...@@ -575,6 +575,24 @@ static struct attribute_group elantech_attr_group = {
.attrs = elantech_attrs, .attrs = elantech_attrs,
}; };
static bool elantech_is_signature_valid(const unsigned char *param)
{
static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 };
int i;
if (param[0] == 0)
return false;
if (param[1] == 0)
return true;
for (i = 0; i < ARRAY_SIZE(rates); i++)
if (param[2] == rates[i])
return false;
return true;
}
/* /*
* Use magic knock to detect Elantech touchpad * Use magic knock to detect Elantech touchpad
*/ */
...@@ -590,7 +608,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) ...@@ -590,7 +608,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
pr_debug("elantech.c: sending Elantech magic knock failed.\n"); pr_debug("sending Elantech magic knock failed.\n");
return -1; return -1;
} }
...@@ -599,8 +617,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) ...@@ -599,8 +617,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
* set of magic numbers * set of magic numbers
*/ */
if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) { if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
pr_debug("elantech.c: " pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
"unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
param[0], param[1], param[2]); param[0], param[1], param[2]);
return -1; return -1;
} }
...@@ -611,20 +628,20 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) ...@@ -611,20 +628,20 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
* to Elantech magic knock and there might be more. * to Elantech magic knock and there might be more.
*/ */
if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
pr_debug("elantech.c: failed to query firmware version.\n"); pr_debug("failed to query firmware version.\n");
return -1; return -1;
} }
pr_debug("elantech.c: Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", pr_debug("Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n",
param[0], param[1], param[2]); param[0], param[1], param[2]);
if (param[0] == 0 || param[1] != 0) { if (!elantech_is_signature_valid(param)) {
if (!force_elantech) { if (!force_elantech) {
pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n"); pr_debug("Probably not a real Elantech touchpad. Aborting.\n");
return -1; return -1;
} }
pr_debug("elantech.c: Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n"); pr_debug("Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n");
} }
if (set_properties) { if (set_properties) {
...@@ -655,7 +672,7 @@ static int elantech_reconnect(struct psmouse *psmouse) ...@@ -655,7 +672,7 @@ static int elantech_reconnect(struct psmouse *psmouse)
return -1; return -1;
if (elantech_set_absolute_mode(psmouse)) { if (elantech_set_absolute_mode(psmouse)) {
pr_err("elantech.c: failed to put touchpad back into absolute mode.\n"); pr_err("failed to put touchpad back into absolute mode.\n");
return -1; return -1;
} }
...@@ -683,7 +700,7 @@ int elantech_init(struct psmouse *psmouse) ...@@ -683,7 +700,7 @@ int elantech_init(struct psmouse *psmouse)
* Do the version query again so we can store the result * Do the version query again so we can store the result
*/ */
if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
pr_err("elantech.c: failed to query firmware version.\n"); pr_err("failed to query firmware version.\n");
goto init_fail; goto init_fail;
} }
...@@ -704,14 +721,14 @@ int elantech_init(struct psmouse *psmouse) ...@@ -704,14 +721,14 @@ int elantech_init(struct psmouse *psmouse)
etd->paritycheck = 1; etd->paritycheck = 1;
} }
pr_info("elantech.c: assuming hardware version %d, firmware version %d.%d.%d\n", pr_info("assuming hardware version %d, firmware version %d.%d.%d\n",
etd->hw_version, param[0], param[1], param[2]); etd->hw_version, param[0], param[1], param[2]);
if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) { if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) {
pr_err("elantech.c: failed to query capabilities.\n"); pr_err("failed to query capabilities.\n");
goto init_fail; goto init_fail;
} }
pr_info("elantech.c: Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
param[0], param[1], param[2]); param[0], param[1], param[2]);
etd->capabilities = param[0]; etd->capabilities = param[0];
...@@ -721,13 +738,12 @@ int elantech_init(struct psmouse *psmouse) ...@@ -721,13 +738,12 @@ int elantech_init(struct psmouse *psmouse)
* to jump. Enable a workaround. * to jump. Enable a workaround.
*/ */
if (etd->fw_version == 0x020022) { if (etd->fw_version == 0x020022) {
pr_info("elantech.c: firmware version 2.0.34 detected, " pr_info("firmware version 2.0.34 detected, enabling jumpy cursor workaround\n");
"enabling jumpy cursor workaround\n");
etd->jumpy_cursor = 1; etd->jumpy_cursor = 1;
} }
if (elantech_set_absolute_mode(psmouse)) { if (elantech_set_absolute_mode(psmouse)) {
pr_err("elantech.c: failed to put touchpad into absolute mode.\n"); pr_err("failed to put touchpad into absolute mode.\n");
goto init_fail; goto init_fail;
} }
...@@ -736,8 +752,7 @@ int elantech_init(struct psmouse *psmouse) ...@@ -736,8 +752,7 @@ int elantech_init(struct psmouse *psmouse)
error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
&elantech_attr_group); &elantech_attr_group);
if (error) { if (error) {
pr_err("elantech.c: failed to create sysfs attributes, error: %d.\n", pr_err("failed to create sysfs attributes, error: %d.\n", error);
error);
goto init_fail; goto init_fail;
} }
......
...@@ -40,8 +40,8 @@ ...@@ -40,8 +40,8 @@
#include "psmouse.h" #include "psmouse.h"
#include "hgpk.h" #include "hgpk.h"
static int tpdebug; static bool tpdebug;
module_param(tpdebug, int, 0644); module_param(tpdebug, bool, 0644);
MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
static int recalib_delta = 100; static int recalib_delta = 100;
......
...@@ -56,36 +56,36 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) ...@@ -56,36 +56,36 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
/* Logitech extended packet */ /* Logitech extended packet */
switch ((packet[1] >> 4) | (packet[0] & 0x30)) { switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
case 0x0d: /* Mouse extra info */ case 0x0d: /* Mouse extra info */
input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
(int) (packet[2] & 8) - (int) (packet[2] & 7)); (int) (packet[2] & 8) - (int) (packet[2] & 7));
input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
break; break;
case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
input_report_key(dev, BTN_SIDE, (packet[2]) & 1); input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
break; break;
case 0x0f: /* TouchPad extra info */ case 0x0f: /* TouchPad extra info */
input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
(int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
packet[0] = packet[2] | 0x08; packet[0] = packet[2] | 0x08;
break; break;
#ifdef DEBUG #ifdef DEBUG
default: default:
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
(packet[1] >> 4) | (packet[0] & 0x30)); (packet[1] >> 4) | (packet[0] & 0x30));
#endif #endif
} }
} else { } else {
...@@ -250,7 +250,6 @@ static const struct ps2pp_info *get_model_info(unsigned char model) ...@@ -250,7 +250,6 @@ static const struct ps2pp_info *get_model_info(unsigned char model)
if (model == ps2pp_list[i].model) if (model == ps2pp_list[i].model)
return &ps2pp_list[i]; return &ps2pp_list[i];
printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
return NULL; return NULL;
} }
...@@ -285,31 +284,32 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, ...@@ -285,31 +284,32 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
__set_bit(REL_HWHEEL, input_dev->relbit); __set_bit(REL_HWHEEL, input_dev->relbit);
switch (model_info->kind) { switch (model_info->kind) {
case PS2PP_KIND_WHEEL:
psmouse->name = "Wheel Mouse";
break;
case PS2PP_KIND_MX:
psmouse->name = "MX Mouse";
break;
case PS2PP_KIND_TP3: case PS2PP_KIND_WHEEL:
psmouse->name = "TouchPad 3"; psmouse->name = "Wheel Mouse";
break; break;
case PS2PP_KIND_TRACKMAN: case PS2PP_KIND_MX:
psmouse->name = "TrackMan"; psmouse->name = "MX Mouse";
break; break;
default: case PS2PP_KIND_TP3:
/* psmouse->name = "TouchPad 3";
* Set name to "Mouse" only when using PS2++, break;
* otherwise let other protocols define suitable
* name case PS2PP_KIND_TRACKMAN:
*/ psmouse->name = "TrackMan";
if (using_ps2pp) break;
psmouse->name = "Mouse";
break; default:
/*
* Set name to "Mouse" only when using PS2++,
* otherwise let other protocols define suitable
* name
*/
if (using_ps2pp)
psmouse->name = "Mouse";
break;
} }
} }
...@@ -343,7 +343,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) ...@@ -343,7 +343,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
if (!model || !buttons) if (!model || !buttons)
return -1; return -1;
if ((model_info = get_model_info(model)) != NULL) { model_info = get_model_info(model);
if (model_info) {
/* /*
* Do Logitech PS2++ / PS2T++ magic init. * Do Logitech PS2++ / PS2T++ magic init.
...@@ -379,6 +380,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) ...@@ -379,6 +380,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
use_ps2pp = true; use_ps2pp = true;
} }
} }
} else {
printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
} }
if (set_properties) { if (set_properties) {
......
...@@ -147,18 +147,18 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) ...@@ -147,18 +147,18 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
if (psmouse->type == PSMOUSE_IMEX) { if (psmouse->type == PSMOUSE_IMEX) {
switch (packet[3] & 0xC0) { switch (packet[3] & 0xC0) {
case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
break; break;
case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
break; break;
case 0x00: case 0x00:
case 0xC0: case 0xC0:
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
break; break;
} }
} }
...@@ -247,31 +247,31 @@ static int psmouse_handle_byte(struct psmouse *psmouse) ...@@ -247,31 +247,31 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
psmouse_ret_t rc = psmouse->protocol_handler(psmouse); psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
switch (rc) { switch (rc) {
case PSMOUSE_BAD_DATA: case PSMOUSE_BAD_DATA:
if (psmouse->state == PSMOUSE_ACTIVATED) { if (psmouse->state == PSMOUSE_ACTIVATED) {
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->name, psmouse->phys, psmouse->pktcnt);
if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE); __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->ps2dev.serio); serio_reconnect(psmouse->ps2dev.serio);
return -1; return -1;
}
}
psmouse->pktcnt = 0;
break;
case PSMOUSE_FULL_PACKET:
psmouse->pktcnt = 0;
if (psmouse->out_of_sync_cnt) {
psmouse->out_of_sync_cnt = 0;
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
psmouse->name, psmouse->phys);
} }
break; }
psmouse->pktcnt = 0;
break;
case PSMOUSE_FULL_PACKET:
psmouse->pktcnt = 0;
if (psmouse->out_of_sync_cnt) {
psmouse->out_of_sync_cnt = 0;
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
psmouse->name, psmouse->phys);
}
break;
case PSMOUSE_GOOD_DATA: case PSMOUSE_GOOD_DATA:
break; break;
} }
return 0; return 0;
} }
...@@ -1245,7 +1245,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, ...@@ -1245,7 +1245,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse,
psmouse->pktsize = 3; psmouse->pktsize = 3;
if (proto && (proto->detect || proto->init)) { if (proto && (proto->detect || proto->init)) {
if (proto->detect && proto->detect(psmouse, 1) < 0) if (proto->detect && proto->detect(psmouse, true) < 0)
return -1; return -1;
if (proto->init && proto->init(psmouse) < 0) if (proto->init && proto->init(psmouse) < 0)
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
* The x/y limits are taken from the Synaptics TouchPad interfacing Guide, * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
* section 2.3.2, which says that they should be valid regardless of the * section 2.3.2, which says that they should be valid regardless of the
* actual size of the sensor. * actual size of the sensor.
* Note that newer firmware allows querying device for maximum useable
* coordinates.
*/ */
#define XMIN_NOMINAL 1472 #define XMIN_NOMINAL 1472
#define XMAX_NOMINAL 5472 #define XMAX_NOMINAL 5472
...@@ -194,23 +196,33 @@ static int synaptics_identify(struct psmouse *psmouse) ...@@ -194,23 +196,33 @@ static int synaptics_identify(struct psmouse *psmouse)
} }
/* /*
* Read touchpad resolution * Read touchpad resolution and maximum reported coordinates
* Resolution is left zero if touchpad does not support the query * Resolution is left zero if touchpad does not support the query
*/ */
static int synaptics_resolution(struct psmouse *psmouse) static int synaptics_resolution(struct psmouse *psmouse)
{ {
struct synaptics_data *priv = psmouse->private; struct synaptics_data *priv = psmouse->private;
unsigned char res[3]; unsigned char res[3];
unsigned char max[3];
if (SYN_ID_MAJOR(priv->identity) < 4) if (SYN_ID_MAJOR(priv->identity) < 4)
return 0;
if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res)) if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) {
return 0; if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) {
priv->x_res = res[0]; /* x resolution in units/mm */
priv->y_res = res[2]; /* y resolution in units/mm */
}
}
if ((res[0] != 0) && (res[1] & 0x80) && (res[2] != 0)) { if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
priv->x_res = res[0]; /* x resolution in units/mm */ SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
priv->y_res = res[2]; /* y resolution in units/mm */ if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_DIMENSIONS, max)) {
printk(KERN_ERR "Synaptics claims to have dimensions query,"
" but I'm not able to read it.\n");
} else {
priv->x_max = (max[0] << 5) | ((max[1] & 0x0f) << 1);
priv->y_max = (max[2] << 5) | ((max[1] & 0xf0) >> 3);
}
} }
return 0; return 0;
...@@ -520,19 +532,20 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha ...@@ -520,19 +532,20 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha
return 0; return 0;
switch (pkt_type) { switch (pkt_type) {
case SYN_NEWABS:
case SYN_NEWABS_RELAXED:
return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
case SYN_NEWABS_STRICT: case SYN_NEWABS:
return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; case SYN_NEWABS_RELAXED:
return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
case SYN_OLDABS: case SYN_NEWABS_STRICT:
return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
default: case SYN_OLDABS:
printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
return 0;
default:
printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
return 0;
} }
} }
...@@ -578,8 +591,10 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ...@@ -578,8 +591,10 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
int i; int i;
__set_bit(EV_ABS, dev->evbit); __set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); input_set_abs_params(dev, ABS_X,
input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_Y,
YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
__set_bit(ABS_TOOL_WIDTH, dev->absbit); __set_bit(ABS_TOOL_WIDTH, dev->absbit);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#define SYN_QUE_RESOLUTION 0x08 #define SYN_QUE_RESOLUTION 0x08
#define SYN_QUE_EXT_CAPAB 0x09 #define SYN_QUE_EXT_CAPAB 0x09
#define SYN_QUE_EXT_CAPAB_0C 0x0c #define SYN_QUE_EXT_CAPAB_0C 0x0c
#define SYN_QUE_EXT_DIMENSIONS 0x0d
/* synatics modes */ /* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7) #define SYN_BIT_ABSOLUTE_MODE (1 << 7)
...@@ -51,6 +52,7 @@ ...@@ -51,6 +52,7 @@
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100) #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
/* synaptics modes query bits */ /* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
...@@ -101,8 +103,8 @@ struct synaptics_data { ...@@ -101,8 +103,8 @@ struct synaptics_data {
unsigned long int ext_cap; /* Extended Capabilities */ unsigned long int ext_cap; /* Extended Capabilities */
unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */
unsigned long int identity; /* Identification */ unsigned long int identity; /* Identification */
int x_res; /* X resolution in units/mm */ unsigned int x_res, y_res; /* X/Y resolution in units/mm */
int y_res; /* Y resolution in units/mm */ unsigned int x_max, y_max; /* Max dimensions (from FW) */
unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char pkt_type; /* packet type - old, new, etc */
unsigned char mode; /* current mode byte */ unsigned char mode; /* current mode byte */
......
...@@ -660,8 +660,21 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id * ...@@ -660,8 +660,21 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *
} }
static struct pnp_device_id pnp_kbd_devids[] = { static struct pnp_device_id pnp_kbd_devids[] = {
{ .id = "PNP0300", .driver_data = 0 },
{ .id = "PNP0301", .driver_data = 0 },
{ .id = "PNP0302", .driver_data = 0 },
{ .id = "PNP0303", .driver_data = 0 }, { .id = "PNP0303", .driver_data = 0 },
{ .id = "PNP0304", .driver_data = 0 },
{ .id = "PNP0305", .driver_data = 0 },
{ .id = "PNP0306", .driver_data = 0 },
{ .id = "PNP0309", .driver_data = 0 },
{ .id = "PNP030a", .driver_data = 0 },
{ .id = "PNP030b", .driver_data = 0 }, { .id = "PNP030b", .driver_data = 0 },
{ .id = "PNP0320", .driver_data = 0 },
{ .id = "PNP0343", .driver_data = 0 },
{ .id = "PNP0344", .driver_data = 0 },
{ .id = "PNP0345", .driver_data = 0 },
{ .id = "CPQA0D7", .driver_data = 0 },
{ .id = "", }, { .id = "", },
}; };
...@@ -672,6 +685,7 @@ static struct pnp_driver i8042_pnp_kbd_driver = { ...@@ -672,6 +685,7 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
}; };
static struct pnp_device_id pnp_aux_devids[] = { static struct pnp_device_id pnp_aux_devids[] = {
{ .id = "AUI0200", .driver_data = 0 },
{ .id = "FJC6000", .driver_data = 0 }, { .id = "FJC6000", .driver_data = 0 },
{ .id = "FJC6001", .driver_data = 0 }, { .id = "FJC6001", .driver_data = 0 },
{ .id = "PNP0f03", .driver_data = 0 }, { .id = "PNP0f03", .driver_data = 0 },
......
...@@ -66,18 +66,18 @@ static void usb_acecad_irq(struct urb *urb) ...@@ -66,18 +66,18 @@ static void usb_acecad_irq(struct urb *urb)
int prox, status; int prox, status;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
/* success */ /* success */
break; break;
case -ECONNRESET: case -ECONNRESET:
case -ENOENT: case -ENOENT:
case -ESHUTDOWN: case -ESHUTDOWN:
/* this urb is terminated, clean up */ /* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __func__, urb->status); dbg("%s - urb shutting down with status: %d", __func__, urb->status);
return; return;
default: default:
dbg("%s - nonzero urb status received: %d", __func__, urb->status); dbg("%s - nonzero urb status received: %d", __func__, urb->status);
goto resubmit; goto resubmit;
} }
prox = (data[0] & 0x04) >> 2; prox = (data[0] & 0x04) >> 2;
...@@ -135,7 +135,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ ...@@ -135,7 +135,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
struct usb_acecad *acecad; struct usb_acecad *acecad;
struct input_dev *input_dev; struct input_dev *input_dev;
int pipe, maxp; int pipe, maxp;
int err = -ENOMEM; int err;
if (interface->desc.bNumEndpoints != 1) if (interface->desc.bNumEndpoints != 1)
return -ENODEV; return -ENODEV;
...@@ -193,40 +193,34 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ ...@@ -193,40 +193,34 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
input_dev->close = usb_acecad_close; input_dev->close = usb_acecad_close;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_PRESSURE);
input_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
input_dev->keybit[BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_TOOL_PEN) | input_dev->keybit[BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_TOOL_PEN) |
BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) | BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) |
BIT_MASK(BTN_STYLUS2); BIT_MASK(BTN_STYLUS2);
switch (id->driver_info) { switch (id->driver_info) {
case 0: case 0:
input_dev->absmax[ABS_X] = 5000; input_set_abs_params(input_dev, ABS_X, 0, 5000, 4, 0);
input_dev->absmax[ABS_Y] = 3750; input_set_abs_params(input_dev, ABS_Y, 0, 3750, 4, 0);
input_dev->absmax[ABS_PRESSURE] = 512; input_set_abs_params(input_dev, ABS_PRESSURE, 0, 512, 0, 0);
if (!strlen(acecad->name)) if (!strlen(acecad->name))
snprintf(acecad->name, sizeof(acecad->name), snprintf(acecad->name, sizeof(acecad->name),
"USB Acecad Flair Tablet %04x:%04x", "USB Acecad Flair Tablet %04x:%04x",
le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct)); le16_to_cpu(dev->descriptor.idProduct));
break; break;
case 1:
input_dev->absmax[ABS_X] = 3000; case 1:
input_dev->absmax[ABS_Y] = 2250; input_set_abs_params(input_dev, ABS_X, 0, 53000, 4, 0);
input_dev->absmax[ABS_PRESSURE] = 1024; input_set_abs_params(input_dev, ABS_Y, 0, 2250, 4, 0);
if (!strlen(acecad->name)) input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1024, 0, 0);
snprintf(acecad->name, sizeof(acecad->name), if (!strlen(acecad->name))
"USB Acecad 302 Tablet %04x:%04x", snprintf(acecad->name, sizeof(acecad->name),
le16_to_cpu(dev->descriptor.idVendor), "USB Acecad 302 Tablet %04x:%04x",
le16_to_cpu(dev->descriptor.idProduct)); le16_to_cpu(dev->descriptor.idVendor),
break; le16_to_cpu(dev->descriptor.idProduct));
break;
} }
input_dev->absfuzz[ABS_X] = 4;
input_dev->absfuzz[ABS_Y] = 4;
usb_fill_int_urb(acecad->irq, dev, pipe, usb_fill_int_urb(acecad->irq, dev, pipe,
acecad->data, maxp > 8 ? 8 : maxp, acecad->data, maxp > 8 ? 8 : maxp,
usb_acecad_irq, acecad, endpoint->bInterval); usb_acecad_irq, acecad, endpoint->bInterval);
...@@ -252,13 +246,11 @@ static void usb_acecad_disconnect(struct usb_interface *intf) ...@@ -252,13 +246,11 @@ static void usb_acecad_disconnect(struct usb_interface *intf)
struct usb_acecad *acecad = usb_get_intfdata(intf); struct usb_acecad *acecad = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (acecad) {
usb_kill_urb(acecad->irq); input_unregister_device(acecad->input);
input_unregister_device(acecad->input); usb_free_urb(acecad->irq);
usb_free_urb(acecad->irq); usb_buffer_free(acecad->usbdev, 8, acecad->data, acecad->data_dma);
usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma); kfree(acecad);
kfree(acecad);
}
} }
static struct usb_device_id usb_acecad_id_table [] = { static struct usb_device_id usb_acecad_id_table [] = {
......
...@@ -34,10 +34,6 @@ struct kbtab { ...@@ -34,10 +34,6 @@ struct kbtab {
struct input_dev *dev; struct input_dev *dev;
struct usb_device *usbdev; struct usb_device *usbdev;
struct urb *irq; struct urb *irq;
int x, y;
int button;
int pressure;
__u32 serial[2];
char phys[32]; char phys[32];
}; };
...@@ -46,6 +42,7 @@ static void kbtab_irq(struct urb *urb) ...@@ -46,6 +42,7 @@ static void kbtab_irq(struct urb *urb)
struct kbtab *kbtab = urb->context; struct kbtab *kbtab = urb->context;
unsigned char *data = kbtab->data; unsigned char *data = kbtab->data;
struct input_dev *dev = kbtab->dev; struct input_dev *dev = kbtab->dev;
int pressure;
int retval; int retval;
switch (urb->status) { switch (urb->status) {
...@@ -63,31 +60,27 @@ static void kbtab_irq(struct urb *urb) ...@@ -63,31 +60,27 @@ static void kbtab_irq(struct urb *urb)
goto exit; goto exit;
} }
kbtab->x = get_unaligned_le16(&data[1]);
kbtab->y = get_unaligned_le16(&data[3]);
kbtab->pressure = (data[5]);
input_report_key(dev, BTN_TOOL_PEN, 1); input_report_key(dev, BTN_TOOL_PEN, 1);
input_report_abs(dev, ABS_X, kbtab->x); input_report_abs(dev, ABS_X, get_unaligned_le16(&data[1]));
input_report_abs(dev, ABS_Y, kbtab->y); input_report_abs(dev, ABS_Y, get_unaligned_le16(&data[3]));
/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
input_report_key(dev, BTN_RIGHT, data[0] & 0x02); input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
if (-1 == kb_pressure_click) { pressure = data[5];
input_report_abs(dev, ABS_PRESSURE, kbtab->pressure); if (kb_pressure_click == -1)
} else { input_report_abs(dev, ABS_PRESSURE, pressure);
input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); else
}; input_report_key(dev, BTN_LEFT, pressure > kb_pressure_click ? 1 : 0);
input_sync(dev); input_sync(dev);
exit: exit:
retval = usb_submit_urb (urb, GFP_ATOMIC); retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval) if (retval)
err ("%s - usb_submit_urb failed with result %d", err("%s - usb_submit_urb failed with result %d",
__func__, retval); __func__, retval);
} }
...@@ -153,13 +146,11 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -153,13 +146,11 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
input_dev->open = kbtab_open; input_dev->open = kbtab_open;
input_dev->close = kbtab_close; input_dev->close = kbtab_close;
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
BIT_MASK(EV_MSC); input_dev->keybit[BIT_WORD(BTN_LEFT)] |=
input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); input_dev->keybit[BIT_WORD(BTN_DIGI)] |=
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH);
BIT_MASK(BTN_TOUCH);
input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0); input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
...@@ -182,7 +173,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -182,7 +173,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
return 0; return 0;
fail3: usb_free_urb(kbtab->irq); fail3: usb_free_urb(kbtab->irq);
fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); fail2: usb_buffer_free(dev, 8, kbtab->data, kbtab->data_dma);
fail1: input_free_device(input_dev); fail1: input_free_device(input_dev);
kfree(kbtab); kfree(kbtab);
return error; return error;
...@@ -193,13 +184,11 @@ static void kbtab_disconnect(struct usb_interface *intf) ...@@ -193,13 +184,11 @@ static void kbtab_disconnect(struct usb_interface *intf)
struct kbtab *kbtab = usb_get_intfdata(intf); struct kbtab *kbtab = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (kbtab) {
usb_kill_urb(kbtab->irq); input_unregister_device(kbtab->dev);
input_unregister_device(kbtab->dev); usb_free_urb(kbtab->irq);
usb_free_urb(kbtab->irq); usb_buffer_free(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma);
usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma); kfree(kbtab);
kfree(kbtab);
}
} }
static struct usb_driver kbtab_driver = { static struct usb_driver kbtab_driver = {
......
...@@ -106,44 +106,18 @@ MODULE_LICENSE(DRIVER_LICENSE); ...@@ -106,44 +106,18 @@ MODULE_LICENSE(DRIVER_LICENSE);
struct wacom { struct wacom {
dma_addr_t data_dma; dma_addr_t data_dma;
struct input_dev *dev;
struct usb_device *usbdev; struct usb_device *usbdev;
struct usb_interface *intf; struct usb_interface *intf;
struct urb *irq; struct urb *irq;
struct wacom_wac *wacom_wac; struct wacom_wac wacom_wac;
struct mutex lock; struct mutex lock;
unsigned int open:1; bool open;
char phys[32]; char phys[32];
}; };
struct wacom_combo {
struct wacom *wacom;
struct urb *urb;
};
extern const struct usb_device_id wacom_ids[]; extern const struct usb_device_id wacom_ids[];
extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo); void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data); void wacom_setup_input_capabilities(struct input_dev *input_dev,
extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data); struct wacom_wac *wacom_wac);
extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data);
extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value);
extern void wacom_input_sync(void *wcombo);
extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern __u16 wacom_le16_to_cpu(unsigned char *data);
extern __u16 wacom_be16_to_cpu(unsigned char *data);
#endif #endif
This diff is collapsed.
This diff is collapsed.
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#ifndef WACOM_WAC_H #ifndef WACOM_WAC_H
#define WACOM_WAC_H #define WACOM_WAC_H
#include <linux/types.h>
/* maximum packet length for USB devices */ /* maximum packet length for USB devices */
#define WACOM_PKGLEN_MAX 32 #define WACOM_PKGLEN_MAX 32
...@@ -71,13 +73,20 @@ struct wacom_features { ...@@ -71,13 +73,20 @@ struct wacom_features {
unsigned char unitExpo; unsigned char unitExpo;
}; };
struct wacom_shared {
bool stylus_in_proximity;
};
struct wacom_wac { struct wacom_wac {
char name[64]; char name[64];
unsigned char *data; unsigned char *data;
int tool[2]; int tool[3];
int id[2]; int id[3];
__u32 serial[2]; __u32 serial[2];
int last_finger;
struct wacom_features features; struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
}; };
#endif #endif
...@@ -119,6 +119,18 @@ config TOUCHSCREEN_DYNAPRO ...@@ -119,6 +119,18 @@ config TOUCHSCREEN_DYNAPRO
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 dynapro. module will be called dynapro.
config TOUCHSCREEN_HAMPSHIRE
tristate "Hampshire serial touchscreen"
select SERIO
help
Say Y here if you have a Hampshire serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called hampshire.
config TOUCHSCREEN_EETI config TOUCHSCREEN_EETI
tristate "EETI touchscreen panel support" tristate "EETI touchscreen panel support"
depends on I2C depends on I2C
......
...@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o ...@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
......
/*
* Hampshire serial touchscreen driver
*
* Copyright (c) 2010 Adam Bennett
* Based on the dynapro driver (c) Tias Guns
*
*/
/*
* 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.
*/
/*
* 2010/04/08 Adam Bennett <abennett72@gmail.com>
* Copied dynapro.c and edited for Hampshire 4-byte protocol
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Hampshire serial touchscreen driver"
MODULE_AUTHOR("Adam Bennett <abennett72@gmail.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
#define HAMPSHIRE_FORMAT_TOUCH_BIT 0x40
#define HAMPSHIRE_FORMAT_LENGTH 4
#define HAMPSHIRE_RESPONSE_BEGIN_BYTE 0x80
#define HAMPSHIRE_MIN_XC 0
#define HAMPSHIRE_MAX_XC 0x1000
#define HAMPSHIRE_MIN_YC 0
#define HAMPSHIRE_MAX_YC 0x1000
#define HAMPSHIRE_GET_XC(data) (((data[3] & 0x0c) >> 2) | (data[1] << 2) | ((data[0] & 0x38) << 6))
#define HAMPSHIRE_GET_YC(data) ((data[3] & 0x03) | (data[2] << 2) | ((data[0] & 0x07) << 9))
#define HAMPSHIRE_GET_TOUCHED(data) (HAMPSHIRE_FORMAT_TOUCH_BIT & data[0])
/*
* Per-touchscreen data.
*/
struct hampshire {
struct input_dev *dev;
struct serio *serio;
int idx;
unsigned char data[HAMPSHIRE_FORMAT_LENGTH];
char phys[32];
};
static void hampshire_process_data(struct hampshire *phampshire)
{
struct input_dev *dev = phampshire->dev;
if (HAMPSHIRE_FORMAT_LENGTH == ++phampshire->idx) {
input_report_abs(dev, ABS_X, HAMPSHIRE_GET_XC(phampshire->data));
input_report_abs(dev, ABS_Y, HAMPSHIRE_GET_YC(phampshire->data));
input_report_key(dev, BTN_TOUCH,
HAMPSHIRE_GET_TOUCHED(phampshire->data));
input_sync(dev);
phampshire->idx = 0;
}
}
static irqreturn_t hampshire_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct hampshire *phampshire = serio_get_drvdata(serio);
phampshire->data[phampshire->idx] = data;
if (HAMPSHIRE_RESPONSE_BEGIN_BYTE & phampshire->data[0])
hampshire_process_data(phampshire);
else
dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
phampshire->data[0]);
return IRQ_HANDLED;
}
static void hampshire_disconnect(struct serio *serio)
{
struct hampshire *phampshire = serio_get_drvdata(serio);
input_get_device(phampshire->dev);
input_unregister_device(phampshire->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(phampshire->dev);
kfree(phampshire);
}
/*
* hampshire_connect() is the routine that is called when someone adds a
* new serio device that supports hampshire protocol and registers it as
* an input device. This is usually accomplished using inputattach.
*/
static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
{
struct hampshire *phampshire;
struct input_dev *input_dev;
int err;
phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL);
input_dev = input_allocate_device();
if (!phampshire || !input_dev) {
err = -ENOMEM;
goto fail1;
}
phampshire->serio = serio;
phampshire->dev = input_dev;
snprintf(phampshire->phys, sizeof(phampshire->phys),
"%s/input0", serio->phys);
input_dev->name = "Hampshire Serial TouchScreen";
input_dev->phys = phampshire->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_HAMPSHIRE;
input_dev->id.product = 0;
input_dev->id.version = 0x0001;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(phampshire->dev, ABS_X,
HAMPSHIRE_MIN_XC, HAMPSHIRE_MAX_XC, 0, 0);
input_set_abs_params(phampshire->dev, ABS_Y,
HAMPSHIRE_MIN_YC, HAMPSHIRE_MAX_YC, 0, 0);
serio_set_drvdata(serio, phampshire);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(phampshire->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(phampshire);
return err;
}
/*
* The serio driver structure.
*/
static struct serio_device_id hampshire_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_HAMPSHIRE,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, hampshire_serio_ids);
static struct serio_driver hampshire_drv = {
.driver = {
.name = "hampshire",
},
.description = DRIVER_DESC,
.id_table = hampshire_serio_ids,
.interrupt = hampshire_interrupt,
.connect = hampshire_connect,
.disconnect = hampshire_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init hampshire_init(void)
{
return serio_register_driver(&hampshire_drv);
}
static void __exit hampshire_exit(void)
{
serio_unregister_driver(&hampshire_drv);
}
module_init(hampshire_init);
module_exit(hampshire_exit);
...@@ -347,6 +347,8 @@ static int __devexit tsc2007_remove(struct i2c_client *client) ...@@ -347,6 +347,8 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
struct tsc2007 *ts = i2c_get_clientdata(client); struct tsc2007 *ts = i2c_get_clientdata(client);
struct tsc2007_platform_data *pdata = client->dev.platform_data; struct tsc2007_platform_data *pdata = client->dev.platform_data;
i2c_set_clientdata(client, NULL);
tsc2007_free_irq(ts); tsc2007_free_irq(ts);
if (pdata->exit_platform_hw) if (pdata->exit_platform_hw)
......
...@@ -811,12 +811,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch) ...@@ -811,12 +811,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
priv = usbtouch->priv; priv = usbtouch->priv;
priv->ack_buf = kmalloc(sizeof(nexio_ack_pkt), GFP_KERNEL); priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
GFP_KERNEL);
if (!priv->ack_buf) if (!priv->ack_buf)
goto err_priv; goto err_priv;
memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt));
priv->ack = usb_alloc_urb(0, GFP_KERNEL); priv->ack = usb_alloc_urb(0, GFP_KERNEL);
if (!priv->ack) { if (!priv->ack) {
dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__); dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
......
...@@ -200,7 +200,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, ...@@ -200,7 +200,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
mutex_lock(&wm->codec_mutex); mutex_lock(&wm->codec_mutex);
reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS); reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
if (status & WM97XX_GPIO_HIGH) if (status == WM97XX_GPIO_HIGH)
reg |= gpio; reg |= gpio;
else else
reg &= ~gpio; reg &= ~gpio;
......
...@@ -806,6 +806,7 @@ struct input_absinfo { ...@@ -806,6 +806,7 @@ struct input_absinfo {
#define BUS_HOST 0x19 #define BUS_HOST 0x19
#define BUS_GSC 0x1A #define BUS_GSC 0x1A
#define BUS_ATARI 0x1B #define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
/* /*
* MT_TOOL types * MT_TOOL types
......
/*
* include/linux/input/ad714x.h
*
* AD714x is very flexible, it can be used as buttons, scrollwheel,
* slider, touchpad at the same time. That depends on the boards.
* The platform_data for the device's "struct device" holds this
* information.
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __LINUX_INPUT_AD714X_H__
#define __LINUX_INPUT_AD714X_H__
#define STAGE_NUM 12
#define STAGE_CFGREG_NUM 8
#define SYS_CFGREG_NUM 8
/* board information which need be initialized in arch/mach... */
struct ad714x_slider_plat {
int start_stage;
int end_stage;
int max_coord;
};
struct ad714x_wheel_plat {
int start_stage;
int end_stage;
int max_coord;
};
struct ad714x_touchpad_plat {
int x_start_stage;
int x_end_stage;
int x_max_coord;
int y_start_stage;
int y_end_stage;
int y_max_coord;
};
struct ad714x_button_plat {
int keycode;
unsigned short l_mask;
unsigned short h_mask;
};
struct ad714x_platform_data {
int slider_num;
int wheel_num;
int touchpad_num;
int button_num;
struct ad714x_slider_plat *slider;
struct ad714x_wheel_plat *wheel;
struct ad714x_touchpad_plat *touchpad;
struct ad714x_button_plat *button;
unsigned short stage_cfg_reg[STAGE_NUM][STAGE_CFGREG_NUM];
unsigned short sys_cfg_reg[SYS_CFGREG_NUM];
};
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment