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.
* I hit SysRq, but nothing seems to happen, what's wrong?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are some keyboards that send different scancodes for SysRq than the
pre-defined 0x54. So if SysRq doesn't work out of the box for a certain
keyboard, run 'showkey -s' to find out the proper scancode sequence. Then
use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRq
code (84 is decimal for 0x54). It's probably best to put this command in a
boot script. Oh, and by the way, you exit 'showkey' by not typing anything
for ten seconds.
There are some keyboards that produce a different keycode for SysRq than the
pre-defined value of 99 (see KEY_SYSRQ in include/linux/input.h), or which
don't have a SysRq key at all. In these cases, run 'showkey -s' to find an
appropriate scancode sequence, and use 'setkeycodes <sequence> 99' to map
this sequence to the usual SysRq code (e.g., 'setkeycodes e05b 99'). It's
probably best to put this command in a boot script. Oh, and by the way, you
exit 'showkey' by not typing anything for ten seconds.
* 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
*
* (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
......@@ -10,8 +7,13 @@
* (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
* overhauled to use key registration
* 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/interrupt.h>
#include <linux/mm.h>
......@@ -39,33 +41,34 @@
#include <linux/hrtimer.h>
#include <linux/oom.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
/* Whether we react on sysrq keys or just ignore them */
int __read_mostly __sysrq_enabled = 1;
static int __read_mostly sysrq_always_enabled;
static int __read_mostly sysrq_enabled = 1;
static bool __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:
*/
static inline int sysrq_on_mask(int mask)
static bool sysrq_on_mask(int mask)
{
return sysrq_always_enabled || __sysrq_enabled == 1 ||
(__sysrq_enabled & mask);
return sysrq_always_enabled ||
sysrq_enabled == 1 ||
(sysrq_enabled & mask);
}
static int __init sysrq_always_enabled_setup(char *str)
{
sysrq_always_enabled = 1;
printk(KERN_INFO "debug: sysrq always enabled.\n");
sysrq_always_enabled = true;
pr_info("sysrq always enabled.\n");
return 1;
}
......@@ -76,6 +79,7 @@ __setup("sysrq_always_enabled", sysrq_always_enabled_setup);
static void sysrq_handle_loglevel(int key, struct tty_struct *tty)
{
int i;
i = key - '0';
console_loglevel = 7;
printk("Loglevel set to %d\n", i);
......@@ -101,7 +105,7 @@ static struct sysrq_key_op sysrq_SAK_op = {
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
#else
#define sysrq_SAK_op (*(struct sysrq_key_op *)0)
#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
#endif
#ifdef CONFIG_VT
......@@ -119,7 +123,7 @@ static struct sysrq_key_op sysrq_unraw_op = {
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
#else
#define sysrq_unraw_op (*(struct sysrq_key_op *)0)
#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
#endif /* CONFIG_VT */
static void sysrq_handle_crash(int key, struct tty_struct *tty)
......@@ -195,7 +199,7 @@ static struct sysrq_key_op sysrq_showlocks_op = {
.action_msg = "Show Locks Held",
};
#else
#define sysrq_showlocks_op (*(struct sysrq_key_op *)0)
#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
#endif
#ifdef CONFIG_SMP
......@@ -298,7 +302,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = {
.enable_mask = SYSRQ_ENABLE_DUMP,
};
#else
#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)0)
#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
#endif
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)
i = sysrq_key_table_key2index(key);
if (i != -1)
op_p = sysrq_key_table[i];
return 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;
}
/*
* 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)
static void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
{
struct sysrq_key_op *op_p;
int orig_log_level;
......@@ -544,10 +545,6 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
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)
{
if (sysrq_on())
......@@ -555,10 +552,177 @@ void handle_sysrq(int key, struct tty_struct *tty)
}
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,
struct sysrq_key_op *remove_op_p)
{
int retval;
unsigned long flags;
......@@ -599,6 +763,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
return -EFAULT;
__handle_sysrq(c, NULL, 0);
}
return count;
}
......@@ -606,10 +771,28 @@ static const struct file_operations proc_sysrq_trigger_operations = {
.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)
{
proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
sysrq_init_procfs();
if (sysrq_on())
sysrq_register_handler();
return 0;
}
module_init(sysrq_init);
#endif
......@@ -73,7 +73,7 @@ config KEYBOARD_ATKBD
default y
select SERIO
select SERIO_LIBPS2
select SERIO_I8042 if X86
select SERIO_I8042 if X86 && !X86_MRST
select SERIO_GSCPS2 if GSC
help
Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
......@@ -179,6 +179,22 @@ config KEYBOARD_GPIO
To compile this driver as a module, choose M here: the
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
tristate "GPIO driven matrix keypad support"
depends on GENERIC_GPIO
......
......@@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.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_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
......
......@@ -670,8 +670,6 @@ static int __devinit lm8323_probe(struct i2c_client *client,
goto fail1;
}
i2c_set_clientdata(client, lm);
lm->client = client;
lm->idev = idev;
mutex_init(&lm->lock);
......@@ -753,6 +751,8 @@ static int __devinit lm8323_probe(struct i2c_client *client,
goto fail4;
}
i2c_set_clientdata(client, lm);
device_init_wakeup(&client->dev, 1);
enable_irq_wake(client->irq);
......@@ -778,6 +778,8 @@ static int __devexit lm8323_remove(struct i2c_client *client)
struct lm8323_chip *lm = i2c_get_clientdata(client);
int i;
i2c_set_clientdata(client, NULL);
disable_irq_wake(client->irq);
free_irq(client->irq, lm);
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)
info->idev->phys = "88pm860x_on/input0";
info->idev->id.bustype = BUS_I2C;
info->idev->dev.parent = &pdev->dev;
info->irq = irq;
info->idev->evbit[0] = BIT_MASK(EV_KEY);
info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
......
......@@ -22,6 +22,36 @@ config INPUT_88PM860X_ONKEY
To compile this driver as a module, choose M here: the module
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
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
......@@ -277,6 +307,16 @@ config INPUT_PCF50633_PMU
Say Y to include support for delivering PMU events via input
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
tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO
......
......@@ -5,6 +5,9 @@
# Each configuration option enables a list of files.
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_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
......@@ -19,6 +22,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.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_POWERMATE) += powermate.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)
for (key = keymap; key->type != KE_END; key++)
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)
return -ENOMEM;
memcpy(new_keymap, keymap, length * sizeof(struct key_entry));
keymap = new_keymap;
return 0;
......
......@@ -17,7 +17,7 @@ config MOUSE_PS2
default y
select SERIO
select SERIO_LIBPS2
select SERIO_I8042 if X86
select SERIO_I8042 if X86 && !X86_MRST
select SERIO_GSCPS2 if GSC
help
Say Y here if you have a PS/2 mouse connected to your system. This
......
......@@ -10,6 +10,8 @@
* Trademarks are the property of their respective owners.
*/
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
......@@ -19,10 +21,10 @@
#include "psmouse.h"
#include "elantech.h"
#define elantech_debug(format, arg...) \
do { \
if (etd->debug) \
printk(KERN_DEBUG format, ##arg); \
#define elantech_debug(fmt, ...) \
do { \
if (etd->debug) \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
static bool force_elantech;
......@@ -37,7 +39,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c,
{
if (psmouse_sliced_command(psmouse, c) ||
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;
}
......@@ -60,13 +62,13 @@ static int elantech_ps2_command(struct psmouse *psmouse,
if (rc == 0)
break;
tries--;
elantech_debug("elantech.c: retrying ps2 command 0x%02x (%d).\n",
command, tries);
elantech_debug("retrying ps2 command 0x%02x (%d).\n",
command, tries);
msleep(ETP_PS2_COMMAND_DELAY);
} while (tries > 0);
if (rc)
pr_err("elantech.c: ps2 command 0x%02x failed.\n", command);
pr_err("ps2 command 0x%02x failed.\n", command);
return rc;
}
......@@ -108,7 +110,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
}
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
*val = param[0];
......@@ -154,7 +156,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
}
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);
return rc;
......@@ -167,7 +169,7 @@ static void elantech_packet_dump(unsigned char *packet, int size)
{
int i;
printk(KERN_DEBUG "elantech.c: PS/2 packet [");
printk(KERN_DEBUG pr_fmt("PS/2 packet ["));
for (i = 0; i < size; i++)
printk("%s0x%02x ", (i) ? ", " : " ", packet[i]);
printk("]\n");
......@@ -203,7 +205,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
if (etd->jumpy_cursor) {
/* Discard packets that are likely to have bogus coordinates */
if (fingers > old_fingers) {
elantech_debug("elantech.c: discarding packet\n");
elantech_debug("discarding packet\n");
goto discard_packet_v1;
}
}
......@@ -413,23 +415,21 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
if (rc == 0)
break;
tries--;
elantech_debug("elantech.c: retrying read (%d).\n",
tries);
elantech_debug("retrying read (%d).\n", tries);
msleep(ETP_READ_BACK_DELAY);
} while (tries > 0);
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 &&
!(val & ETP_R10_ABSOLUTE_MODE)) {
pr_err("elantech.c: touchpad refuses "
"to switch to absolute mode.\n");
pr_err("touchpad refuses to switch to absolute mode.\n");
rc = -1;
}
}
if (rc)
pr_err("elantech.c: failed to initialise registers.\n");
pr_err("failed to initialise registers.\n");
return rc;
}
......@@ -575,6 +575,24 @@ static struct attribute_group elantech_attr_group = {
.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
*/
......@@ -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, param, PSMOUSE_CMD_GETINFO)) {
pr_debug("elantech.c: sending Elantech magic knock failed.\n");
pr_debug("sending Elantech magic knock failed.\n");
return -1;
}
......@@ -599,8 +617,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
* set of magic numbers
*/
if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
pr_debug("elantech.c: "
"unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
param[0], param[1], param[2]);
return -1;
}
......@@ -611,20 +628,20 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
* to Elantech magic knock and there might be more.
*/
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;
}
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]);
if (param[0] == 0 || param[1] != 0) {
if (!elantech_is_signature_valid(param)) {
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;
}
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) {
......@@ -655,7 +672,7 @@ static int elantech_reconnect(struct psmouse *psmouse)
return -1;
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;
}
......@@ -683,7 +700,7 @@ int elantech_init(struct psmouse *psmouse)
* Do the version query again so we can store the result
*/
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;
}
......@@ -704,14 +721,14 @@ int elantech_init(struct psmouse *psmouse)
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]);
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;
}
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]);
etd->capabilities = param[0];
......@@ -721,13 +738,12 @@ int elantech_init(struct psmouse *psmouse)
* to jump. Enable a workaround.
*/
if (etd->fw_version == 0x020022) {
pr_info("elantech.c: firmware version 2.0.34 detected, "
"enabling jumpy cursor workaround\n");
pr_info("firmware version 2.0.34 detected, enabling jumpy cursor workaround\n");
etd->jumpy_cursor = 1;
}
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;
}
......@@ -736,8 +752,7 @@ int elantech_init(struct psmouse *psmouse)
error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
&elantech_attr_group);
if (error) {
pr_err("elantech.c: failed to create sysfs attributes, error: %d.\n",
error);
pr_err("failed to create sysfs attributes, error: %d.\n", error);
goto init_fail;
}
......
......@@ -40,8 +40,8 @@
#include "psmouse.h"
#include "hgpk.h"
static int tpdebug;
module_param(tpdebug, int, 0644);
static bool tpdebug;
module_param(tpdebug, bool, 0644);
MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
static int recalib_delta = 100;
......
......@@ -56,36 +56,36 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
/* Logitech extended packet */
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,
(int) (packet[2] & 8) - (int) (packet[2] & 7));
input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
(int) (packet[2] & 8) - (int) (packet[2] & 7));
input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 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_EXTRA, (packet[2] >> 1) & 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_TASK, (packet[2] >> 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_BACK, (packet[2] >> 3) & 1);
input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 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,
(int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
packet[0] = packet[2] | 0x08;
break;
input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
(int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
packet[0] = packet[2] | 0x08;
break;
#ifdef DEBUG
default:
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
(packet[1] >> 4) | (packet[0] & 0x30));
default:
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
(packet[1] >> 4) | (packet[0] & 0x30));
#endif
}
} else {
......@@ -250,7 +250,6 @@ static const struct ps2pp_info *get_model_info(unsigned char model)
if (model == ps2pp_list[i].model)
return &ps2pp_list[i];
printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
return NULL;
}
......@@ -285,31 +284,32 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
__set_bit(REL_HWHEEL, input_dev->relbit);
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:
psmouse->name = "TouchPad 3";
break;
case PS2PP_KIND_TRACKMAN:
psmouse->name = "TrackMan";
break;
default:
/*
* Set name to "Mouse" only when using PS2++,
* otherwise let other protocols define suitable
* name
*/
if (using_ps2pp)
psmouse->name = "Mouse";
break;
case PS2PP_KIND_WHEEL:
psmouse->name = "Wheel Mouse";
break;
case PS2PP_KIND_MX:
psmouse->name = "MX Mouse";
break;
case PS2PP_KIND_TP3:
psmouse->name = "TouchPad 3";
break;
case PS2PP_KIND_TRACKMAN:
psmouse->name = "TrackMan";
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)
if (!model || !buttons)
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.
......@@ -379,6 +380,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
use_ps2pp = true;
}
}
} else {
printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
}
if (set_properties) {
......
......@@ -147,18 +147,18 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
if (psmouse->type == PSMOUSE_IMEX) {
switch (packet[3] & 0xC0) {
case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
break;
case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
break;
case 0x00:
case 0xC0:
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_EXTRA, (packet[3] >> 5) & 1);
break;
case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
break;
case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
break;
case 0x00:
case 0xC0:
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_EXTRA, (packet[3] >> 5) & 1);
break;
}
}
......@@ -247,31 +247,31 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
switch (rc) {
case PSMOUSE_BAD_DATA:
if (psmouse->state == PSMOUSE_ACTIVATED) {
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->ps2dev.serio);
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);
case PSMOUSE_BAD_DATA:
if (psmouse->state == PSMOUSE_ACTIVATED) {
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->ps2dev.serio);
return -1;
}
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:
break;
case PSMOUSE_GOOD_DATA:
break;
}
return 0;
}
......@@ -1245,7 +1245,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse,
psmouse->pktsize = 3;
if (proto && (proto->detect || proto->init)) {
if (proto->detect && proto->detect(psmouse, 1) < 0)
if (proto->detect && proto->detect(psmouse, true) < 0)
return -1;
if (proto->init && proto->init(psmouse) < 0)
......
......@@ -36,6 +36,8 @@
* 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
* actual size of the sensor.
* Note that newer firmware allows querying device for maximum useable
* coordinates.
*/
#define XMIN_NOMINAL 1472
#define XMAX_NOMINAL 5472
......@@ -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
*/
static int synaptics_resolution(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
unsigned char res[3];
unsigned char max[3];
if (SYN_ID_MAJOR(priv->identity) < 4)
return 0;
if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res))
return 0;
if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 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)) {
priv->x_res = res[0]; /* x resolution in units/mm */
priv->y_res = res[2]; /* y resolution in units/mm */
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
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;
......@@ -520,19 +532,20 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha
return 0;
switch (pkt_type) {
case SYN_NEWABS:
case SYN_NEWABS_RELAXED:
return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
case SYN_NEWABS_STRICT:
return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
case SYN_NEWABS:
case SYN_NEWABS_RELAXED:
return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
case SYN_OLDABS:
return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
case SYN_NEWABS_STRICT:
return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
default:
printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
return 0;
case SYN_OLDABS:
return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
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)
int i;
__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_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_X,
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);
__set_bit(ABS_TOOL_WIDTH, dev->absbit);
......
......@@ -19,6 +19,7 @@
#define SYN_QUE_RESOLUTION 0x08
#define SYN_QUE_EXT_CAPAB 0x09
#define SYN_QUE_EXT_CAPAB_0C 0x0c
#define SYN_QUE_EXT_DIMENSIONS 0x0d
/* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
......@@ -51,6 +52,7 @@
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
......@@ -101,8 +103,8 @@ struct synaptics_data {
unsigned long int ext_cap; /* Extended Capabilities */
unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */
unsigned long int identity; /* Identification */
int x_res; /* X resolution in units/mm */
int y_res; /* Y resolution in units/mm */
unsigned int x_res, y_res; /* X/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 mode; /* current mode byte */
......
......@@ -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[] = {
{ .id = "PNP0300", .driver_data = 0 },
{ .id = "PNP0301", .driver_data = 0 },
{ .id = "PNP0302", .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 = "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 = "", },
};
......@@ -672,6 +685,7 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
};
static struct pnp_device_id pnp_aux_devids[] = {
{ .id = "AUI0200", .driver_data = 0 },
{ .id = "FJC6000", .driver_data = 0 },
{ .id = "FJC6001", .driver_data = 0 },
{ .id = "PNP0f03", .driver_data = 0 },
......
......@@ -66,18 +66,18 @@ static void usb_acecad_irq(struct urb *urb)
int prox, status;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __func__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __func__, urb->status);
goto resubmit;
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __func__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __func__, urb->status);
goto resubmit;
}
prox = (data[0] & 0x04) >> 2;
......@@ -135,7 +135,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
struct usb_acecad *acecad;
struct input_dev *input_dev;
int pipe, maxp;
int err = -ENOMEM;
int err;
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
......@@ -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->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) |
BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) |
BIT_MASK(BTN_STYLUS2);
switch (id->driver_info) {
case 0:
input_dev->absmax[ABS_X] = 5000;
input_dev->absmax[ABS_Y] = 3750;
input_dev->absmax[ABS_PRESSURE] = 512;
if (!strlen(acecad->name))
snprintf(acecad->name, sizeof(acecad->name),
"USB Acecad Flair Tablet %04x:%04x",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
break;
case 1:
input_dev->absmax[ABS_X] = 3000;
input_dev->absmax[ABS_Y] = 2250;
input_dev->absmax[ABS_PRESSURE] = 1024;
if (!strlen(acecad->name))
snprintf(acecad->name, sizeof(acecad->name),
"USB Acecad 302 Tablet %04x:%04x",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
break;
case 0:
input_set_abs_params(input_dev, ABS_X, 0, 5000, 4, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 3750, 4, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 512, 0, 0);
if (!strlen(acecad->name))
snprintf(acecad->name, sizeof(acecad->name),
"USB Acecad Flair Tablet %04x:%04x",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
break;
case 1:
input_set_abs_params(input_dev, ABS_X, 0, 53000, 4, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 2250, 4, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1024, 0, 0);
if (!strlen(acecad->name))
snprintf(acecad->name, sizeof(acecad->name),
"USB Acecad 302 Tablet %04x:%04x",
le16_to_cpu(dev->descriptor.idVendor),
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,
acecad->data, maxp > 8 ? 8 : maxp,
usb_acecad_irq, acecad, endpoint->bInterval);
......@@ -252,13 +246,11 @@ static void usb_acecad_disconnect(struct usb_interface *intf)
struct usb_acecad *acecad = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (acecad) {
usb_kill_urb(acecad->irq);
input_unregister_device(acecad->input);
usb_free_urb(acecad->irq);
usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
kfree(acecad);
}
input_unregister_device(acecad->input);
usb_free_urb(acecad->irq);
usb_buffer_free(acecad->usbdev, 8, acecad->data, acecad->data_dma);
kfree(acecad);
}
static struct usb_device_id usb_acecad_id_table [] = {
......
......@@ -34,10 +34,6 @@ struct kbtab {
struct input_dev *dev;
struct usb_device *usbdev;
struct urb *irq;
int x, y;
int button;
int pressure;
__u32 serial[2];
char phys[32];
};
......@@ -46,6 +42,7 @@ static void kbtab_irq(struct urb *urb)
struct kbtab *kbtab = urb->context;
unsigned char *data = kbtab->data;
struct input_dev *dev = kbtab->dev;
int pressure;
int retval;
switch (urb->status) {
......@@ -63,31 +60,27 @@ static void kbtab_irq(struct urb *urb)
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_abs(dev, ABS_X, kbtab->x);
input_report_abs(dev, ABS_Y, kbtab->y);
input_report_abs(dev, ABS_X, get_unaligned_le16(&data[1]));
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_RIGHT, data[0] & 0x02);
if (-1 == kb_pressure_click) {
input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
} else {
input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
};
pressure = data[5];
if (kb_pressure_click == -1)
input_report_abs(dev, ABS_PRESSURE, pressure);
else
input_report_key(dev, BTN_LEFT, pressure > kb_pressure_click ? 1 : 0);
input_sync(dev);
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
err("%s - usb_submit_urb failed with result %d",
__func__, retval);
}
......@@ -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->close = kbtab_close;
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
BIT_MASK(EV_MSC);
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) |
BIT_MASK(BTN_TOUCH);
input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_LEFT)] |=
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
input_dev->keybit[BIT_WORD(BTN_DIGI)] |=
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH);
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_PRESSURE, 0, 0xff, 0, 0);
......@@ -182,7 +173,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
return 0;
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);
kfree(kbtab);
return error;
......@@ -193,13 +184,11 @@ static void kbtab_disconnect(struct usb_interface *intf)
struct kbtab *kbtab = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (kbtab) {
usb_kill_urb(kbtab->irq);
input_unregister_device(kbtab->dev);
usb_free_urb(kbtab->irq);
usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma);
kfree(kbtab);
}
input_unregister_device(kbtab->dev);
usb_free_urb(kbtab->irq);
usb_buffer_free(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma);
kfree(kbtab);
}
static struct usb_driver kbtab_driver = {
......
......@@ -106,44 +106,18 @@ MODULE_LICENSE(DRIVER_LICENSE);
struct wacom {
dma_addr_t data_dma;
struct input_dev *dev;
struct usb_device *usbdev;
struct usb_interface *intf;
struct urb *irq;
struct wacom_wac *wacom_wac;
struct wacom_wac wacom_wac;
struct mutex lock;
unsigned int open:1;
bool open;
char phys[32];
};
struct wacom_combo {
struct wacom *wacom;
struct urb *urb;
};
extern const struct usb_device_id wacom_ids[];
extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
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);
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -9,6 +9,8 @@
#ifndef WACOM_WAC_H
#define WACOM_WAC_H
#include <linux/types.h>
/* maximum packet length for USB devices */
#define WACOM_PKGLEN_MAX 32
......@@ -71,13 +73,20 @@ struct wacom_features {
unsigned char unitExpo;
};
struct wacom_shared {
bool stylus_in_proximity;
};
struct wacom_wac {
char name[64];
unsigned char *data;
int tool[2];
int id[2];
int tool[3];
int id[3];
__u32 serial[2];
int last_finger;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
};
#endif
......@@ -119,6 +119,18 @@ config TOUCHSCREEN_DYNAPRO
To compile this driver as a module, choose M here: the
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
tristate "EETI touchscreen panel support"
depends on I2C
......
......@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.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)
struct tsc2007 *ts = i2c_get_clientdata(client);
struct tsc2007_platform_data *pdata = client->dev.platform_data;
i2c_set_clientdata(client, NULL);
tsc2007_free_irq(ts);
if (pdata->exit_platform_hw)
......
......@@ -811,12 +811,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
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)
goto err_priv;
memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt));
priv->ack = usb_alloc_urb(0, GFP_KERNEL);
if (!priv->ack) {
dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
......
......@@ -200,7 +200,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
mutex_lock(&wm->codec_mutex);
reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
if (status & WM97XX_GPIO_HIGH)
if (status == WM97XX_GPIO_HIGH)
reg |= gpio;
else
reg &= ~gpio;
......
......@@ -806,6 +806,7 @@ struct input_absinfo {
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
/*
* 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