summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Kconfig6
-rw-r--r--drivers/input/gameport/gameport.c2
-rw-r--r--drivers/input/input.c37
-rw-r--r--drivers/input/joystick/Kconfig10
-rw-r--r--drivers/input/joystick/Makefile1
-rw-r--r--drivers/input/joystick/as5011.c367
-rw-r--r--drivers/input/keyboard/Kconfig26
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/aaed2000_kbd.c186
-rw-r--r--drivers/input/keyboard/gpio_keys.c6
-rw-r--r--drivers/input/keyboard/tegra-kbc.c783
-rw-r--r--drivers/input/keyboard/tnetv107x-keypad.c5
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c6
-rw-r--r--drivers/input/misc/rotary_encoder.c4
-rw-r--r--drivers/input/mouse/Kconfig10
-rw-r--r--drivers/input/mouse/bcm5974.c40
-rw-r--r--drivers/input/mouse/synaptics.c32
-rw-r--r--drivers/input/mouse/synaptics.h23
-rw-r--r--drivers/input/serio/Kconfig8
-rw-r--r--drivers/input/serio/ct82c710.c8
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h21
-rw-r--r--drivers/input/serio/i8042.c6
-rw-r--r--drivers/input/serio/serio.c13
-rw-r--r--drivers/input/serio/serport.c24
-rw-r--r--drivers/input/sparse-keymap.c1
-rw-r--r--drivers/input/tablet/wacom_sys.c2
-rw-r--r--drivers/input/tablet/wacom_wac.c27
-rw-r--r--drivers/input/touchscreen/Kconfig30
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c17
-rw-r--r--drivers/input/touchscreen/ads7846.c38
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c39
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c15
-rw-r--r--drivers/input/touchscreen/eeti_ts.c16
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c17
-rw-r--r--drivers/input/touchscreen/migor_ts.c12
-rw-r--r--drivers/input/touchscreen/tnetv107x-ts.c5
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c191
37 files changed, 1660 insertions, 376 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 07c2cd43109..1903c0f5b92 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -6,7 +6,7 @@ menu "Input device support"
depends on !S390
config INPUT
- tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
+ tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
default y
help
Say Y here if you have any input device (mouse, keyboard, tablet,
@@ -67,7 +67,7 @@ config INPUT_SPARSEKMAP
comment "Userland interfaces"
config INPUT_MOUSEDEV
- tristate "Mouse interface" if EMBEDDED
+ tristate "Mouse interface" if EXPERT
default y
help
Say Y here if you want your mouse to be accessible as char devices
@@ -150,7 +150,7 @@ config INPUT_EVBUG
module will be called evbug.
config INPUT_APMPOWER
- tristate "Input Power Event -> APM Bridge" if EMBEDDED
+ tristate "Input Power Event -> APM Bridge" if EXPERT
depends on INPUT && APM_EMULATION
help
Say Y here if you want suspend key events to trigger a user
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 23cf8fc933e..5b8f59d6c3e 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -360,7 +360,7 @@ static int gameport_queue_event(void *object, struct module *owner,
event->owner = owner;
list_add_tail(&event->node, &gameport_event_list);
- schedule_work(&gameport_event_work);
+ queue_work(system_long_wq, &gameport_event_work);
out:
spin_unlock_irqrestore(&gameport_event_lock, flags);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7985114beac..11905b6a302 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -75,7 +75,6 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
- struct input_handler *src_handler,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
@@ -94,15 +93,6 @@ static void input_pass_event(struct input_dev *dev,
continue;
handler = handle->handler;
-
- /*
- * If this is the handler that injected this
- * particular event we want to skip it to avoid
- * filters firing again and again.
- */
- if (handler == src_handler)
- continue;
-
if (!handler->filter) {
if (filtered)
break;
@@ -132,7 +122,7 @@ static void input_repeat_key(unsigned long data)
if (test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
- input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2);
+ input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
if (dev->sync) {
/*
@@ -141,7 +131,7 @@ static void input_repeat_key(unsigned long data)
* Otherwise assume that the driver will send
* SYN_REPORT once it's done.
*/
- input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
if (dev->rep[REP_PERIOD])
@@ -174,7 +164,6 @@ static void input_stop_autorepeat(struct input_dev *dev)
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
static int input_handle_abs_event(struct input_dev *dev,
- struct input_handler *src_handler,
unsigned int code, int *pval)
{
bool is_mt_event;
@@ -218,15 +207,13 @@ static int input_handle_abs_event(struct input_dev *dev,
/* Flush pending "slot" event */
if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
- input_pass_event(dev, src_handler,
- EV_ABS, ABS_MT_SLOT, dev->slot);
+ input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
}
return INPUT_PASS_TO_HANDLERS;
}
static void input_handle_event(struct input_dev *dev,
- struct input_handler *src_handler,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT;
@@ -279,8 +266,7 @@ static void input_handle_event(struct input_dev *dev,
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX))
- disposition = input_handle_abs_event(dev, src_handler,
- code, &value);
+ disposition = input_handle_abs_event(dev, code, &value);
break;
@@ -338,7 +324,7 @@ static void input_handle_event(struct input_dev *dev,
dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS)
- input_pass_event(dev, src_handler, type, code, value);
+ input_pass_event(dev, type, code, value);
}
/**
@@ -367,7 +353,7 @@ void input_event(struct input_dev *dev,
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);
- input_handle_event(dev, NULL, type, code, value);
+ input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
@@ -397,8 +383,7 @@ void input_inject_event(struct input_handle *handle,
rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
- input_handle_event(dev, handle->handler,
- type, code, value);
+ input_handle_event(dev, type, code, value);
rcu_read_unlock();
spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -611,10 +596,10 @@ static void input_dev_release_keys(struct input_dev *dev)
for (code = 0; code <= KEY_MAX; code++) {
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(code, dev->key)) {
- input_pass_event(dev, NULL, EV_KEY, code, 0);
+ input_pass_event(dev, EV_KEY, code, 0);
}
}
- input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
}
@@ -889,9 +874,9 @@ int input_set_keycode(struct input_dev *dev,
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(old_keycode, dev->key)) {
- input_pass_event(dev, NULL, EV_KEY, old_keycode, 0);
+ input_pass_event(dev, EV_KEY, old_keycode, 0);
if (dev->sync)
- input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
out:
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 5b596165b57..56eb471b557 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -255,6 +255,16 @@ config JOYSTICK_AMIGA
To compile this driver as a module, choose M here: the
module will be called amijoy.
+config JOYSTICK_AS5011
+ tristate "Austria Microsystem AS5011 joystick"
+ depends on I2C
+ help
+ Say Y here if you have an AS5011 digital joystick connected to your
+ system.
+
+ To compile this driver as a module, choose M here: the
+ module will be called as5011.
+
config JOYSTICK_JOYDUMP
tristate "Gameport data dumper"
select GAMEPORT
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index f3a8cbe2abb..92dc0de9dfe 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_JOYSTICK_A3D) += a3d.o
obj-$(CONFIG_JOYSTICK_ADI) += adi.o
obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o
+obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o
obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o
obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o
obj-$(CONFIG_JOYSTICK_DB9) += db9.o
diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c
new file mode 100644
index 00000000000..f6732b57ca0
--- /dev/null
+++ b/drivers/input/joystick/as5011.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com>
+ * Sponsored by ARMadeus Systems
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Driver for Austria Microsystems joysticks AS5011
+ *
+ * TODO:
+ * - Power on the chip when open() and power down when close()
+ * - Manage power mode
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/input/as5011.h>
+#include <linux/slab.h>
+
+#define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick"
+#define MODULE_DEVICE_ALIAS "as5011"
+
+MODULE_AUTHOR("Fabien Marteau <fabien.marteau@armadeus.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* registers */
+#define AS5011_CTRL1 0x76
+#define AS5011_CTRL2 0x75
+#define AS5011_XP 0x43
+#define AS5011_XN 0x44
+#define AS5011_YP 0x53
+#define AS5011_YN 0x54
+#define AS5011_X_REG 0x41
+#define AS5011_Y_REG 0x42
+#define AS5011_X_RES_INT 0x51
+#define AS5011_Y_RES_INT 0x52
+
+/* CTRL1 bits */
+#define AS5011_CTRL1_LP_PULSED 0x80
+#define AS5011_CTRL1_LP_ACTIVE 0x40
+#define AS5011_CTRL1_LP_CONTINUE 0x20
+#define AS5011_CTRL1_INT_WUP_EN 0x10
+#define AS5011_CTRL1_INT_ACT_EN 0x08
+#define AS5011_CTRL1_EXT_CLK_EN 0x04
+#define AS5011_CTRL1_SOFT_RST 0x02
+#define AS5011_CTRL1_DATA_VALID 0x01
+
+/* CTRL2 bits */
+#define AS5011_CTRL2_EXT_SAMPLE_EN 0x08
+#define AS5011_CTRL2_RC_BIAS_ON 0x04
+#define AS5011_CTRL2_INV_SPINNING 0x02
+
+#define AS5011_MAX_AXIS 80
+#define AS5011_MIN_AXIS (-80)
+#define AS5011_FUZZ 8
+#define AS5011_FLAT 40
+
+struct as5011_device {
+ struct input_dev *input_dev;
+ struct i2c_client *i2c_client;
+ unsigned int button_gpio;
+ unsigned int button_irq;
+ unsigned int axis_irq;
+};
+
+static int as5011_i2c_write(struct i2c_client *client,
+ uint8_t aregaddr,
+ uint8_t avalue)
+{
+ uint8_t data[2] = { aregaddr, avalue };
+ struct i2c_msg msg = {
+ client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data
+ };
+ int error;
+
+ error = i2c_transfer(client->adapter, &msg, 1);
+ return error < 0 ? error : 0;
+}
+
+static int as5011_i2c_read(struct i2c_client *client,
+ uint8_t aregaddr, signed char *value)
+{
+ uint8_t data[2] = { aregaddr };
+ struct i2c_msg msg_set[2] = {
+ { client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data },
+ { client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data }
+ };
+ int error;
+
+ error = i2c_transfer(client->adapter, msg_set, 2);
+ if (error < 0)
+ return error;
+
+ *value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0];
+ return 0;
+}
+
+static irqreturn_t as5011_button_interrupt(int irq, void *dev_id)
+{
+ struct as5011_device *as5011 = dev_id;
+ int val = gpio_get_value_cansleep(as5011->button_gpio);
+
+ input_report_key(as5011->input_dev, BTN_JOYSTICK, !val);
+ input_sync(as5011->input_dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t as5011_axis_interrupt(int irq, void *dev_id)
+{
+ struct as5011_device *as5011 = dev_id;
+ int error;
+ signed char x, y;
+
+ error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x);
+ if (error < 0)
+ goto out;
+
+ error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y);
+ if (error < 0)
+ goto out;
+
+ input_report_abs(as5011->input_dev, ABS_X, x);
+ input_report_abs(as5011->input_dev, ABS_Y, y);
+ input_sync(as5011->input_dev);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int __devinit as5011_configure_chip(struct as5011_device *as5011,
+ const struct as5011_platform_data *plat_dat)
+{
+ struct i2c_client *client = as5011->i2c_client;
+ int error;
+ signed char value;
+
+ /* chip soft reset */
+ error = as5011_i2c_write(client, AS5011_CTRL1,
+ AS5011_CTRL1_SOFT_RST);
+ if (error < 0) {
+ dev_err(&client->dev, "Soft reset failed\n");
+ return error;
+ }
+
+ mdelay(10);
+
+ error = as5011_i2c_write(client, AS5011_CTRL1,
+ AS5011_CTRL1_LP_PULSED |
+ AS5011_CTRL1_LP_ACTIVE |
+ AS5011_CTRL1_INT_ACT_EN);
+ if (error < 0) {
+ dev_err(&client->dev, "Power config failed\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_CTRL2,
+ AS5011_CTRL2_INV_SPINNING);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't invert spinning\n");
+ return error;
+ }
+
+ /* write threshold */
+ error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ /* to free irq gpio in chip */
+ error = as5011_i2c_read(client, AS5011_X_RES_INT, &value);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't read i2c X resolution value\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static int __devinit as5011_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct as5011_platform_data *plat_data;
+ struct as5011_device *as5011;
+ struct input_dev *input_dev;
+ int irq;
+ int error;
+
+ plat_data = client->dev.platform_data;
+ if (!plat_data)
+ return -EINVAL;
+
+ if (!plat_data->axis_irq) {
+ dev_err(&client->dev, "No axis IRQ?\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_PROTOCOL_MANGLING)) {
+ dev_err(&client->dev,
+ "need i2c bus that supports protocol mangling\n");
+ return -ENODEV;
+ }
+
+ as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!as5011 || !input_dev) {
+ dev_err(&client->dev,
+ "Can't allocate memory for device structure\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ as5011->i2c_client = client;
+ as5011->input_dev = input_dev;
+ as5011->button_gpio = plat_data->button_gpio;
+ as5011->axis_irq = plat_data->axis_irq;
+
+ input_dev->name = "Austria Microsystem as5011 joystick";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(BTN_JOYSTICK, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_X,
+ AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
+ input_set_abs_params(as5011->input_dev, ABS_Y,
+ AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
+
+ error = gpio_request(as5011->button_gpio, "AS5011 button");
+ if (error < 0) {
+ dev_err(&client->dev, "Failed to request button gpio\n");
+ goto err_free_mem;
+ }
+
+ irq = gpio_to_irq(as5011->button_gpio);
+ if (irq < 0) {
+ dev_err(&client->dev,
+ "Failed to get irq number for button gpio\n");
+ goto err_free_button_gpio;
+ }
+
+ as5011->button_irq = irq;
+
+ error = request_threaded_irq(as5011->button_irq,
+ NULL, as5011_button_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "as5011_button", as5011);
+ if (error < 0) {
+ dev_err(&client->dev,
+ "Can't allocate button irq %d\n", as5011->button_irq);
+ goto err_free_button_gpio;
+ }
+
+ error = as5011_configure_chip(as5011, plat_data);
+ if (error)
+ goto err_free_button_irq;
+
+ error = request_threaded_irq(as5011->axis_irq, NULL,
+ as5011_axis_interrupt,
+ plat_data->axis_irqflags,
+ "as5011_joystick", as5011);
+ if (error) {
+ dev_err(&client->dev,
+ "Can't allocate axis irq %d\n", plat_data->axis_irq);
+ goto err_free_button_irq;
+ }
+
+ error = input_register_device(as5011->input_dev);
+ if (error) {
+ dev_err(&client->dev, "Failed to register input device\n");
+ goto err_free_axis_irq;
+ }
+
+ i2c_set_clientdata(client, as5011);
+
+ return 0;
+
+err_free_axis_irq:
+ free_irq(as5011->axis_irq, as5011);
+err_free_button_irq:
+ free_irq(as5011->button_irq, as5011);
+err_free_button_gpio:
+ gpio_free(as5011->button_gpio);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(as5011);
+
+ return error;
+}
+
+static int __devexit as5011_remove(struct i2c_client *client)
+{
+ struct as5011_device *as5011 = i2c_get_clientdata(client);
+
+ free_irq(as5011->axis_irq, as5011);
+ free_irq(as5011->button_irq, as5011);
+ gpio_free(as5011->button_gpio);
+
+ input_unregister_device(as5011->input_dev);
+ kfree(as5011);
+
+ return 0;
+}
+
+static const struct i2c_device_id as5011_id[] = {
+ { MODULE_DEVICE_ALIAS, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, as5011_id);
+
+static struct i2c_driver as5011_driver = {
+ .driver = {
+ .name = "as5011",
+ },
+ .probe = as5011_probe,
+ .remove = __devexit_p(as5011_remove),
+ .id_table = as5011_id,
+};
+
+static int __init as5011_init(void)
+{
+ return i2c_add_driver(&as5011_driver);
+}
+module_init(as5011_init);
+
+static void __exit as5011_exit(void)
+{
+ i2c_del_driver(&as5011_driver);
+}
+module_exit(as5011_exit);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f829998fabe..c7a92028f45 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -2,7 +2,7 @@
# Input core configuration
#
menuconfig INPUT_KEYBOARD
- bool "Keyboards" if EMBEDDED || !X86
+ bool "Keyboards" if EXPERT || !X86
default y
help
Say Y here, and a list of supported keyboards will be displayed.
@@ -12,18 +12,6 @@ menuconfig INPUT_KEYBOARD
if INPUT_KEYBOARD
-config KEYBOARD_AAED2000
- tristate "AAED-2000 keyboard"
- depends on MACH_AAED2000
- select INPUT_POLLDEV
- default y
- help
- Say Y here to enable the keyboard on the Agilent AAED-2000
- development board.
-
- To compile this driver as a module, choose M here: the
- module will be called aaed2000_kbd.
-
config KEYBOARD_ADP5520
tristate "Keypad Support for ADP5520 PMIC"
depends on PMIC_ADP5520
@@ -69,7 +57,7 @@ config KEYBOARD_ATARI
module will be called atakbd.
config KEYBOARD_ATKBD
- tristate "AT keyboard" if EMBEDDED || !X86
+ tristate "AT keyboard" if EXPERT || !X86
default y
select SERIO
select SERIO_LIBPS2
@@ -355,6 +343,16 @@ config KEYBOARD_NOMADIK
To compile this driver as a module, choose M here: the
module will be called nmk-ske-keypad.
+config KEYBOARD_TEGRA
+ tristate "NVIDIA Tegra internal matrix keyboard controller support"
+ depends on ARCH_TEGRA
+ help
+ Say Y here if you want to use a matrix keyboard connected directly
+ to the internal keyboard controller on Tegra SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tegra-kbc.
+
config KEYBOARD_OPENCORES
tristate "OpenCores Keyboard Controller"
help
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 8933e9ca938..468c627a284 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -4,7 +4,6 @@
# Each configuration option enables a list of files.
-obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
@@ -43,6 +42,7 @@ obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
+obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
deleted file mode 100644
index 18222a689a0..00000000000
--- a/drivers/input/keyboard/aaed2000_kbd.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Keyboard driver for the AAED-2000 dev board
- *
- * Copyright (c) 2006 Nicolas Bellido Y Ortega
- *
- * Based on corgikbd.c
- *
- * 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/delay.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/input-polldev.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <mach/hardware.h>
-#include <mach/aaed2000.h>
-
-#define KB_ROWS 12
-#define KB_COLS 8
-#define KB_ROWMASK(r) (1 << (r))
-#define SCANCODE(r,c) (((c) * KB_ROWS) + (r))
-#define NR_SCANCODES (KB_COLS * KB_ROWS)
-
-#define SCAN_INTERVAL (50) /* ms */
-#define KB_ACTIVATE_DELAY (20) /* us */
-
-static unsigned char aaedkbd_keycode[NR_SCANCODES] = {
- KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, 0, KEY_SPACE, KEY_KP6, 0, KEY_KPDOT, 0, 0,
- KEY_K, KEY_M, KEY_O, KEY_DOT, KEY_SLASH, 0, KEY_F, 0, 0, 0, KEY_LEFTSHIFT, 0,
- KEY_I, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, 0, 0, 0, 0, KEY_RIGHTSHIFT, 0,
- KEY_8, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0,
- KEY_J, KEY_H, KEY_B, KEY_KP8, KEY_KP4, 0, KEY_C, KEY_D, KEY_S, KEY_A, 0, KEY_CAPSLOCK,
- KEY_Y, KEY_U, KEY_N, KEY_T, 0, 0, KEY_R, KEY_E, KEY_W, KEY_Q, 0, KEY_TAB,
- KEY_7, KEY_6, KEY_G, 0, KEY_5, 0, KEY_4, KEY_3, KEY_2, KEY_1, 0, KEY_GRAVE,
- 0, 0, KEY_COMMA, 0, KEY_KP2, 0, KEY_V, KEY_LEFTALT, KEY_X, KEY_Z, 0, KEY_LEFTCTRL
-};
-
-struct aaedkbd {
- unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)];
- struct input_polled_dev *poll_dev;
- int kbdscan_state[KB_COLS];
- int kbdscan_count[KB_COLS];
-};
-
-#define KBDSCAN_STABLE_COUNT 2
-
-static void aaedkbd_report_col(struct aaedkbd *aaedkbd,
- unsigned int col, unsigned int rowd)
-{
- unsigned int scancode, pressed;
- unsigned int row;
-
- for (row = 0; row < KB_ROWS; row++) {
- scancode = SCANCODE(row, col);
- pressed = rowd & KB_ROWMASK(row);
-
- input_report_key(aaedkbd->poll_dev->input,
- aaedkbd->keycode[scancode], pressed);
- }
-}
-
-/* Scan the hardware keyboard and push any changes up through the input layer */
-static void aaedkbd_poll(struct input_polled_dev *dev)
-{
- struct aaedkbd *aaedkbd = dev->private;
- unsigned int col, rowd;
-
- col = 0;
- do {
- AAEC_GPIO_KSCAN = col + 8;
- udelay(KB_ACTIVATE_DELAY);
- rowd = AAED_EXT_GPIO & AAED_EGPIO_KBD_SCAN;
-
- if (rowd != aaedkbd->kbdscan_state[col]) {
- aaedkbd->kbdscan_count[col] = 0;
- aaedkbd->kbdscan_state[col] = rowd;
- } else if (++aaedkbd->kbdscan_count[col] >= KBDSCAN_STABLE_COUNT) {
- aaedkbd_report_col(aaedkbd, col, rowd);
- col++;
- }
- } while (col < KB_COLS);
-
- AAEC_GPIO_KSCAN = 0x07;
- input_sync(dev->input);
-}
-
-static int __devinit aaedkbd_probe(struct platform_device *pdev)
-{
- struct aaedkbd *aaedkbd;
- struct input_polled_dev *poll_dev;
- struct input_dev *input_dev;
- int i;
- int error;
-
- aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL);
- poll_dev = input_allocate_polled_device();
- if (!aaedkbd || !poll_dev) {
- error = -ENOMEM;
- goto fail;
- }
-
- platform_set_drvdata(pdev, aaedkbd);
-
- aaedkbd->poll_dev = poll_dev;
- memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode));
-
- poll_dev->private = aaedkbd;
- poll_dev->poll = aaedkbd_poll;
- poll_dev->poll_interval = SCAN_INTERVAL;
-
- input_dev = poll_dev->input;
- input_dev->name = "AAED-2000 Keyboard";
- input_dev->phys = "aaedkbd/input0";
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &pdev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
- input_dev->keycode = aaedkbd->keycode;
- input_dev->keycodesize = sizeof(unsigned char);
- input_dev->keycodemax = ARRAY_SIZE(aaedkbd_keycode);
-
- for (i = 0; i < ARRAY_SIZE(aaedkbd_keycode); i++)
- set_bit(aaedkbd->keycode[i], input_dev->keybit);
- clear_bit(0, input_dev->keybit);
-
- error = input_register_polled_device(aaedkbd->poll_dev);
- if (error)
- goto fail;
-
- return 0;
-
- fail: kfree(aaedkbd);
- input_free_polled_device(poll_dev);
- return error;
-}
-
-static int __devexit aaedkbd_remove(struct platform_device *pdev)
-{
- struct aaedkbd *aaedkbd = platform_get_drvdata(pdev);
-
- input_unregister_polled_device(aaedkbd->poll_dev);
- input_free_polled_device(aaedkbd->poll_dev);
- kfree(aaedkbd);
-
- return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:aaed2000-keyboard");
-
-static struct platform_driver aaedkbd_driver = {
- .probe = aaedkbd_probe,
- .remove = __devexit_p(aaedkbd_remove),
- .driver = {
- .name = "aaed2000-keyboard",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init aaedkbd_init(void)
-{
- return platform_driver_register(&aaedkbd_driver);
-}
-
-static void __exit aaedkbd_exit(void)
-{
- platform_driver_unregister(&aaedkbd_driver);
-}
-
-module_init(aaedkbd_init);
-module_exit(aaedkbd_exit);
-
-MODULE_AUTHOR("Nicolas Bellido Y Ortega");
-MODULE_DESCRIPTION("AAED-2000 Keyboard Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 6069abe31e4..eb3006361ee 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -322,7 +322,7 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
- int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
+ int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
input_event(input, type, button->code, !!state);
input_sync(input);
@@ -410,8 +410,8 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
if (!button->can_disable)
irqflags |= IRQF_SHARED;
- error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
- if (error) {
+ error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
+ if (error < 0) {
dev_err(dev, "Unable to claim irq %d; error %d\n",
irq, error);
goto fail3;
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
new file mode 100644
index 00000000000..99ce9032d08
--- /dev/null
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -0,0 +1,783 @@
+/*
+ * Keyboard class input driver for the NVIDIA Tegra SoC internal matrix
+ * keyboard controller
+ *
+ * Copyright (c) 2009-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <mach/clk.h>
+#include <mach/kbc.h>
+
+#define KBC_MAX_DEBOUNCE_CNT 0x3ffu
+
+/* KBC row scan time and delay for beginning the row scan. */
+#define KBC_ROW_SCAN_TIME 16
+#define KBC_ROW_SCAN_DLY 5
+
+/* KBC uses a 32KHz clock so a cycle = 1/32Khz */
+#define KBC_CYCLE_USEC 32
+
+/* KBC Registers */
+
+/* KBC Control Register */
+#define KBC_CONTROL_0 0x0
+#define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14)
+#define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4)
+#define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3)
+#define KBC_CONTROL_KBC_EN (1 << 0)
+
+/* KBC Interrupt Register */
+#define KBC_INT_0 0x4
+#define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2)
+
+#define KBC_ROW_CFG0_0 0x8
+#define KBC_COL_CFG0_0 0x18
+#define KBC_INIT_DLY_0 0x28
+#define KBC_RPT_DLY_0 0x2c
+#define KBC_KP_ENT0_0 0x30
+#define KBC_KP_ENT1_0 0x34
+#define KBC_ROW0_MASK_0 0x38
+
+#define KBC_ROW_SHIFT 3
+
+struct tegra_kbc {
+ void __iomem *mmio;
+ struct input_dev *idev;
+ unsigned int irq;
+ unsigned int wake_enable_rows;
+ unsigned int wake_enable_cols;
+ spinlock_t lock;
+ unsigned int repoll_dly;
+ unsigned long cp_dly_jiffies;
+ bool use_fn_map;
+ const struct tegra_kbc_platform_data *pdata;
+ unsigned short keycode[KBC_MAX_KEY * 2];
+ unsigned short current_keys[KBC_MAX_KPENT];
+ unsigned int num_pressed_keys;
+ struct timer_list timer;
+ struct clk *clk;
+};
+
+static const u32 tegra_kbc_default_keymap[] = {
+ KEY(0, 2, KEY_W),
+ KEY(0, 3, KEY_S),
+ KEY(0, 4, KEY_A),
+ KEY(0, 5, KEY_Z),
+ KEY(0, 7, KEY_FN),
+
+ KEY(1, 7, KEY_LEFTMETA),
+
+ KEY(2, 6, KEY_RIGHTALT),
+ KEY(2, 7, KEY_LEFTALT),
+
+ KEY(3, 0, KEY_5),
+ KEY(3, 1, KEY_4),
+ KEY(3, 2, KEY_R),
+ KEY(3, 3, KEY_E),
+ KEY(3, 4, KEY_F),
+ KEY(3, 5, KEY_D),
+ KEY(3, 6, KEY_X),
+
+ KEY(4, 0, KEY_7),
+ KEY(4, 1, KEY_6),
+ KEY(4, 2, KEY_T),
+ KEY(4, 3, KEY_H),
+ KEY(4, 4, KEY_G),
+ KEY(4, 5, KEY_V),
+ KEY(4, 6, KEY_C),
+ KEY(4, 7, KEY_SPACE),
+
+ KEY(5, 0, KEY_9),
+ KEY(5, 1, KEY_8),
+ KEY(5, 2, KEY_U),
+ KEY(5, 3, KEY_Y),
+ KEY(5, 4, KEY_J),
+ KEY(5, 5, KEY_N),
+ KEY(5, 6, KEY_B),
+ KEY(5, 7, KEY_BACKSLASH),
+
+ KEY(6, 0, KEY_MINUS),
+ KEY(6, 1, KEY_0),
+ KEY(6, 2, KEY_O),
+ KEY(6, 3, KEY_I),
+ KEY(6, 4, KEY_L),
+ KEY(6, 5, KEY_K),
+ KEY(6, 6, KEY_COMMA),
+ KEY(6, 7, KEY_M),
+
+ KEY(7, 1, KEY_EQUAL),
+ KEY(7, 2, KEY_RIGHTBRACE),
+ KEY(7, 3, KEY_ENTER),
+ KEY(7, 7, KEY_MENU),
+
+ KEY(8, 4, KEY_RIGHTSHIFT),
+ KEY(8, 5, KEY_LEFTSHIFT),
+
+ KEY(9, 5, KEY_RIGHTCTRL),
+ KEY(9, 7, KEY_LEFTCTRL),
+
+ KEY(11, 0, KEY_LEFTBRACE),
+ KEY(11, 1, KEY_P),
+ KEY(11, 2, KEY_APOSTROPHE),
+ KEY(11, 3, KEY_SEMICOLON),
+ KEY(11, 4, KEY_SLASH),
+ KEY(11, 5, KEY_DOT),
+
+ KEY(12, 0, KEY_F10),
+ KEY(12, 1, KEY_F9),
+ KEY(12, 2, KEY_BACKSPACE),
+ KEY(12, 3, KEY_3),
+ KEY(12, 4, KEY_2),
+ KEY(12, 5, KEY_UP),
+ KEY(12, 6, KEY_PRINT),
+ KEY(12, 7, KEY_PAUSE),
+
+ KEY(13, 0, KEY_INSERT),
+ KEY(13, 1, KEY_DELETE),
+ KEY(13, 3, KEY_PAGEUP),
+ KEY(13, 4, KEY_PAGEDOWN),
+ KEY(13, 5, KEY_RIGHT),
+ KEY(13, 6, KEY_DOWN),
+ KEY(13, 7, KEY_LEFT),
+
+ KEY(14, 0, KEY_F11),
+ KEY(14, 1, KEY_F12),
+ KEY(14, 2, KEY_F8),
+ KEY(14, 3, KEY_Q),
+ KEY(14, 4, KEY_F4),
+ KEY(14, 5, KEY_F3),
+ KEY(14, 6, KEY_1),
+ KEY(14, 7, KEY_F7),
+
+ KEY(15, 0, KEY_ESC),
+ KEY(15, 1, KEY_GRAVE),
+ KEY(15, 2, KEY_F5),
+ KEY(15, 3, KEY_TAB),
+ KEY(15, 4, KEY_F1),
+ KEY(15, 5, KEY_F2),
+ KEY(15, 6, KEY_CAPSLOCK),
+ KEY(15, 7, KEY_F6),
+
+ /* Software Handled Function Keys */
+ KEY(20, 0, KEY_KP7),
+
+ KEY(21, 0, KEY_KP9),
+ KEY(21, 1, KEY_KP8),
+ KEY(21, 2, KEY_KP4),
+ KEY(21, 4, KEY_KP1),
+
+ KEY(22, 1, KEY_KPSLASH),
+ KEY(22, 2, KEY_KP6),
+ KEY(22, 3, KEY_KP5),
+ KEY(22, 4, KEY_KP3),
+ KEY(22, 5, KEY_KP2),
+ KEY(22, 7, KEY_KP0),
+
+ KEY(27, 1, KEY_KPASTERISK),
+ KEY(27, 3, KEY_KPMINUS),
+ KEY(27, 4, KEY_KPPLUS),
+ KEY(27, 5, KEY_KPDOT),
+
+ KEY(28, 5, KEY_VOLUMEUP),
+
+ KEY(29, 3, KEY_HOME),
+ KEY(29, 4, KEY_END),
+ KEY(29, 5, KEY_BRIGHTNESSDOWN),
+ KEY(29, 6, KEY_VOLUMEDOWN),
+ KEY(29, 7, KEY_BRIGHTNESSUP),
+
+ KEY(30, 0, KEY_NUMLOCK),
+ KEY(30, 1, KEY_SCROLLLOCK),
+ KEY(30, 2, KEY_MUTE),
+
+ KEY(31, 4, KEY_HELP),
+};
+
+static const struct matrix_keymap_data tegra_kbc_default_keymap_data = {
+ .keymap = tegra_kbc_default_keymap,
+ .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap),
+};
+
+static void tegra_kbc_report_released_keys(struct input_dev *input,
+ unsigned short old_keycodes[],
+ unsigned int old_num_keys,
+ unsigned short new_keycodes[],
+ unsigned int new_num_keys)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < old_num_keys; i++) {
+ for (j = 0; j < new_num_keys; j++)
+ if (old_keycodes[i] == new_keycodes[j])
+ break;
+
+ if (j == new_num_keys)
+ input_report_key(input, old_keycodes[i], 0);
+ }
+}
+
+static void tegra_kbc_report_pressed_keys(struct input_dev *input,
+ unsigned char scancodes[],
+ unsigned short keycodes[],
+ unsigned int num_pressed_keys)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_pressed_keys; i++) {
+ input_event(input, EV_MSC, MSC_SCAN, scancodes[i]);
+ input_report_key(input, keycodes[i], 1);
+ }
+}
+
+static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
+{
+ unsigned char scancodes[KBC_MAX_KPENT];
+ unsigned short keycodes[KBC_MAX_KPENT];
+ u32 val = 0;
+ unsigned int i;
+ unsigned int num_down = 0;
+ unsigned long flags;
+ bool fn_keypress = false;
+
+ spin_lock_irqsave(&kbc->lock, flags);
+ for (i = 0; i < KBC_MAX_KPENT; i++) {
+ if ((i % 4) == 0)
+ val = readl(kbc->mmio + KBC_KP_ENT0_0 + i);
+
+ if (val & 0x80) {
+ unsigned int col = val & 0x07;
+ unsigned int row = (val >> 3) & 0x0f;
+ unsigned char scancode =
+ MATRIX_SCAN_CODE(row, col, KBC_ROW_SHIFT);
+
+ scancodes[num_down] = scancode;
+ keycodes[num_down] = kbc->keycode[scancode];
+ /* If driver uses Fn map, do not report the Fn key. */
+ if ((keycodes[num_down] == KEY_FN) && kbc->use_fn_map)
+ fn_keypress = true;
+ else
+ num_down++;
+ }
+
+ val >>= 8;
+ }
+
+ /*
+ * If the platform uses Fn keymaps, translate keys on a Fn keypress.
+ * Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
+ */
+ if (fn_keypress) {
+ for (i = 0; i < num_down; i++) {
+ scancodes[i] += KBC_MAX_KEY;
+ keycodes[i] = kbc->keycode[scancodes[i]];
+ }
+ }
+
+ spin_unlock_irqrestore(&kbc->lock, flags);
+
+ tegra_kbc_report_released_keys(kbc->idev,
+ kbc->current_keys, kbc->num_pressed_keys,
+ keycodes, num_down);
+ tegra_kbc_report_pressed_keys(kbc->idev, scancodes, keycodes, num_down);
+ input_sync(kbc->idev);
+
+ memcpy(kbc->current_keys, keycodes, sizeof(kbc->current_keys));
+ kbc->num_pressed_keys = num_down;
+}
+
+static void tegra_kbc_keypress_timer(unsigned long data)
+{
+ struct tegra_kbc *kbc = (struct tegra_kbc *)data;
+ unsigned long flags;
+ u32 val;
+ unsigned int i;
+
+ val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf;
+ if (val) {
+ unsigned long dly;
+
+ tegra_kbc_report_keys(kbc);
+
+ /*
+ * If more than one keys are pressed we need not wait
+ * for the repoll delay.
+ */
+ dly = (val == 1) ? kbc->repoll_dly : 1;
+ mod_timer(&kbc->timer, jiffies + msecs_to_jiffies(dly));
+ } else {
+ /* Release any pressed keys and exit the polling loop */
+ for (i = 0; i < kbc->num_pressed_keys; i++)
+ input_report_key(kbc->idev, kbc->current_keys[i], 0);
+ input_sync(kbc->idev);
+
+ kbc->num_pressed_keys = 0;
+
+ /* All keys are released so enable the keypress interrupt */
+ spin_lock_irqsave(&kbc->lock, flags);
+ val = readl(kbc->mmio + KBC_CONTROL_0);
+ val |= KBC_CONTROL_FIFO_CNT_INT_EN;
+ writel(val, kbc->mmio + KBC_CONTROL_0);
+ spin_unlock_irqrestore(&kbc->lock, flags);
+ }
+}
+
+static irqreturn_t tegra_kbc_isr(int irq, void *args)
+{
+ struct tegra_kbc *kbc = args;
+ u32 val, ctl;
+
+ /*
+ * Until all keys are released, defer further processing to
+ * the polling loop in tegra_kbc_keypress_timer
+ */
+ ctl = readl(kbc->mmio + KBC_CONTROL_0);
+ ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
+ writel(ctl, kbc->mmio + KBC_CONTROL_0);
+
+ /*
+ * Quickly bail out & reenable interrupts if the fifo threshold
+ * count interrupt wasn't the interrupt source
+ */
+ val = readl(kbc->mmio + KBC_INT_0);
+ writel(val, kbc->mmio + KBC_INT_0);
+
+ if (val & KBC_INT_FIFO_CNT_INT_STATUS) {
+ /*
+ * Schedule timer to run when hardware is in continuous
+ * polling mode.
+ */
+ mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
+ } else {
+ ctl |= KBC_CONTROL_FIFO_CNT_INT_EN;
+ writel(ctl, kbc->mmio + KBC_CONTROL_0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
+{
+ const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+ int i;
+ unsigned int rst_val;
+
+ BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
+ rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
+
+ for (i = 0; i < KBC_MAX_ROW; i++)
+ writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
+
+ if (filter) {
+ for (i = 0; i < pdata->wake_cnt; i++) {
+ u32 val, addr;
+ addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
+ val = readl(kbc->mmio + addr);
+ val &= ~(1 << pdata->wake_cfg[i].col);
+ writel(val, kbc->mmio + addr);
+ }
+ }
+}
+
+static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
+{
+ const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+ int i;
+
+ for (i = 0; i < KBC_MAX_GPIO; i++) {
+ u32 r_shft = 5 * (i % 6);
+ u32 c_shft = 4 * (i % 8);
+ u32 r_mask = 0x1f << r_shft;
+ u32 c_mask = 0x0f << c_shft;
+ u32 r_offs = (i / 6) * 4 + KBC_ROW_CFG0_0;
+ u32 c_offs = (i / 8) * 4 + KBC_COL_CFG0_0;
+ u32 row_cfg = readl(kbc->mmio + r_offs);
+ u32 col_cfg = readl(kbc->mmio + c_offs);
+
+ row_cfg &= ~r_mask;
+ col_cfg &= ~c_mask;
+
+ if (pdata->pin_cfg[i].is_row)
+ row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
+ else
+ col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
+
+ writel(row_cfg, kbc->mmio + r_offs);
+ writel(col_cfg, kbc->mmio + c_offs);
+ }
+}
+
+static int tegra_kbc_start(struct tegra_kbc *kbc)
+{
+ const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+ unsigned long flags;
+ unsigned int debounce_cnt;
+ u32 val = 0;
+
+ clk_enable(kbc->clk);
+
+ /* Reset the KBC controller to clear all previous status.*/
+ tegra_periph_reset_assert(kbc->clk);
+ udelay(100);
+ tegra_periph_reset_deassert(kbc->clk);
+ udelay(100);
+
+ tegra_kbc_config_pins(kbc);
+ tegra_kbc_setup_wakekeys(kbc, false);
+
+ writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
+
+ /* Keyboard debounce count is maximum of 12 bits. */
+ debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+ val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt);
+ val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */
+ val |= KBC_CONTROL_FIFO_CNT_INT_EN; /* interrupt on FIFO threshold */
+ val |= KBC_CONTROL_KBC_EN; /* enable */
+ writel(val, kbc->mmio + KBC_CONTROL_0);
+
+ /*
+ * Compute the delay(ns) from interrupt mode to continuous polling
+ * mode so the timer routine is scheduled appropriately.
+ */
+ val = readl(kbc->mmio + KBC_INIT_DLY_0);
+ kbc->cp_dly_jiffies = usecs_to_jiffies((val & 0xfffff) * 32);
+
+ kbc->num_pressed_keys = 0;
+
+ /*
+ * Atomically clear out any remaining entries in the key FIFO
+ * and enable keyboard interrupts.
+ */
+ spin_lock_irqsave(&kbc->lock, flags);
+ while (1) {
+ val = readl(kbc->mmio + KBC_INT_0);
+ val >>= 4;
+ if (!val)
+ break;
+
+ val = readl(kbc->mmio + KBC_KP_ENT0_0);
+ val = readl(kbc->mmio + KBC_KP_ENT1_0);
+ }
+ writel(0x7, kbc->mmio + KBC_INT_0);
+ spin_unlock_irqrestore(&kbc->lock, flags);
+
+ enable_irq(kbc->irq);
+
+ return 0;
+}
+
+static void tegra_kbc_stop(struct tegra_kbc *kbc)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&kbc->lock, flags);
+ val = readl(kbc->mmio + KBC_CONTROL_0);
+ val &= ~1;
+ writel(val, kbc->mmio + KBC_CONTROL_0);
+ spin_unlock_irqrestore(&kbc->lock, flags);
+
+ disable_irq(kbc->irq);
+ del_timer_sync(&kbc->timer);
+
+ clk_disable(kbc->clk);
+}
+
+static int tegra_kbc_open(struct input_dev *dev)
+{
+ struct tegra_kbc *kbc = input_get_drvdata(dev);
+
+ return tegra_kbc_start(kbc);
+}
+
+static void tegra_kbc_close(struct input_dev *dev)
+{
+ struct tegra_kbc *kbc = input_get_drvdata(dev);
+
+ return tegra_kbc_stop(kbc);
+}
+
+static bool __devinit
+tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
+ struct device *dev, unsigned int *num_rows)
+{
+ int i;
+
+ *num_rows = 0;
+
+ for (i = 0; i < KBC_MAX_GPIO; i++) {
+ const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
+
+ if (pin_cfg->is_row) {
+ if (pin_cfg->num >= KBC_MAX_ROW) {
+ dev_err(dev,
+ "pin_cfg[%d]: invalid row number %d\n",
+ i, pin_cfg->num);
+ return false;
+ }
+ (*num_rows)++;
+ } else {
+ if (pin_cfg->num >= KBC_MAX_COL) {
+ dev_err(dev,
+ "pin_cfg[%d]: invalid column number %d\n",
+ i, pin_cfg->num);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int __devinit tegra_kbc_probe(struct platform_device *pdev)
+{
+ const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
+ const struct matrix_keymap_data *keymap_data;
+ struct tegra_kbc *kbc;
+ struct input_dev *input_dev;
+ struct resource *res;
+ int irq;
+ int err;
+ int i;
+ int num_rows = 0;
+ unsigned int debounce_cnt;
+ unsigned int scan_time_rows;
+
+ if (!pdata)
+ return -EINVAL;
+
+ if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows))
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
+ return -ENXIO;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
+ return -ENXIO;
+ }
+
+ kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!kbc || !input_dev) {
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ kbc->pdata = pdata;
+ kbc->idev = input_dev;
+ kbc->irq = irq;
+ spin_lock_init(&kbc->lock);
+ setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ err = -EBUSY;
+ goto err_free_mem;
+ }
+
+ kbc->mmio = ioremap(res->start, resource_size(res));
+ if (!kbc->mmio) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ err = -ENXIO;
+ goto err_free_mem_region;
+ }
+
+ kbc->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(kbc->clk)) {
+ dev_err(&pdev->dev, "failed to get keyboard clock\n");
+ err = PTR_ERR(kbc->clk);
+ goto err_iounmap;
+ }
+
+ kbc->wake_enable_rows = 0;
+ kbc->wake_enable_cols = 0;
+ for (i = 0; i < pdata->wake_cnt; i++) {
+ kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
+ kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
+ }
+
+ /*
+ * The time delay between two consecutive reads of the FIFO is
+ * the sum of the repeat time and the time taken for scanning
+ * the rows. There is an additional delay before the row scanning
+ * starts. The repoll delay is computed in milliseconds.
+ */
+ debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+ scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows;
+ kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
+ kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000;
+
+ input_dev->name = pdev->name;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->open = tegra_kbc_open;
+ input_dev->close = tegra_kbc_close;
+
+ input_set_drvdata(input_dev, kbc);
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ input_dev->keycode = kbc->keycode;
+ input_dev->keycodesize = sizeof(kbc->keycode[0]);
+ input_dev->keycodemax = KBC_MAX_KEY;
+ if (pdata->use_fn_map)
+ input_dev->keycodemax *= 2;
+
+ kbc->use_fn_map = pdata->use_fn_map;
+ keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
+ matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
+ input_dev->keycode, input_dev->keybit);
+
+ err = request_irq(kbc->irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH,
+ pdev->name, kbc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
+ goto err_put_clk;
+ }
+
+ disable_irq(kbc->irq);
+
+ err = input_register_device(kbc->idev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ goto err_free_irq;
+ }
+
+ platform_set_drvdata(pdev, kbc);
+ device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+ return 0;
+
+err_free_irq:
+ free_irq(kbc->irq, pdev);
+err_put_clk:
+ clk_put(kbc->clk);
+err_iounmap:
+ iounmap(kbc->mmio);
+err_free_mem_region:
+ release_mem_region(res->start, resource_size(res));
+err_free_mem:
+ input_free_device(kbc->idev);
+ kfree(kbc);
+
+ return err;
+}
+
+static int __devexit tegra_kbc_remove(struct platform_device *pdev)
+{
+ struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ free_irq(kbc->irq, pdev);
+ clk_put(kbc->clk);
+
+ input_unregister_device(kbc->idev);
+ iounmap(kbc->mmio);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(kbc);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_kbc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev)) {
+ tegra_kbc_setup_wakekeys(kbc, true);
+ enable_irq_wake(kbc->irq);
+ /* Forcefully clear the interrupt status */
+ writel(0x7, kbc->mmio + KBC_INT_0);
+ msleep(30);
+ } else {
+ mutex_lock(&kbc->idev->mutex);
+ if (kbc->idev->users)
+ tegra_kbc_stop(kbc);
+ mutex_unlock(&kbc->idev->mutex);
+ }
+
+ return 0;
+}
+
+static int tegra_kbc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+ int err = 0;
+
+ if (device_may_wakeup(&pdev->dev)) {
+ disable_irq_wake(kbc->irq);
+ tegra_kbc_setup_wakekeys(kbc, false);
+ } else {
+ mutex_lock(&kbc->idev->mutex);
+ if (kbc->idev->users)
+ err = tegra_kbc_start(kbc);
+ mutex_unlock(&kbc->idev->mutex);
+ }
+
+ return err;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume);
+
+static struct platform_driver tegra_kbc_driver = {
+ .probe = tegra_kbc_probe,
+ .remove = __devexit_p(tegra_kbc_remove),
+ .driver = {
+ .name = "tegra-kbc",
+ .owner = THIS_MODULE,
+ .pm = &tegra_kbc_pm_ops,
+ },
+};
+
+static void __exit tegra_kbc_exit(void)
+{
+ platform_driver_unregister(&tegra_kbc_driver);
+}
+module_exit(tegra_kbc_exit);
+
+static int __init tegra_kbc_init(void)
+{
+ return platform_driver_register(&tegra_kbc_driver);
+}
+module_init(tegra_kbc_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rakesh Iyer <riyer@nvidia.com>");
+MODULE_DESCRIPTION("Tegra matrix keyboard controller driver");
+MODULE_ALIAS("platform:tegra-kbc");
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
index b4a81ebfab9..c8f097a15d8 100644
--- a/drivers/input/keyboard/tnetv107x-keypad.c
+++ b/drivers/input/keyboard/tnetv107x-keypad.c
@@ -14,6 +14,7 @@
*/
#include <linux/kernel.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/platform_device.h>
@@ -219,9 +220,9 @@ static int __devinit keypad_probe(struct platform_device *pdev)
}
kp->clk = clk_get(dev, NULL);
- if (!kp->clk) {
+ if (IS_ERR(kp->clk)) {
dev_err(dev, "cannot claim device clock\n");
- error = -EINVAL;
+ error = PTR_ERR(kp->clk);
goto error_clk;
}
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 9dfd6e5f786..1f38302a595 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -69,11 +69,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned
}
if (value > 20 && value < 32767)
-#ifndef FREQ
- count = (ixp4xx_get_board_tick_rate() / (value * 4)) - 1;
-#else
- count = (FREQ / (value * 4)) - 1;
-#endif
+ count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1;
ixp4xx_spkr_control(pin, count);
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 1f8e0108962..7e64d01da2b 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -176,7 +176,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
/* request the IRQs */
err = request_irq(encoder->irq_a, &rotary_encoder_irq,
- IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(&pdev->dev, "unable to request IRQ %d\n",
@@ -185,7 +185,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
}
err = request_irq(encoder->irq_b, &rotary_encoder_irq,
- IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(&pdev->dev, "unable to request IRQ %d\n",
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index bf5fd7f6a31..9c1e6ee8353 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -39,7 +39,7 @@ config MOUSE_PS2
module will be called psmouse.
config MOUSE_PS2_ALPS
- bool "ALPS PS/2 mouse protocol extension" if EMBEDDED
+ bool "ALPS PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
@@ -49,7 +49,7 @@ config MOUSE_PS2_ALPS
If unsure, say Y.
config MOUSE_PS2_LOGIPS2PP
- bool "Logitech PS/2++ mouse protocol extension" if EMBEDDED
+ bool "Logitech PS/2++ mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
@@ -59,7 +59,7 @@ config MOUSE_PS2_LOGIPS2PP
If unsure, say Y.
config MOUSE_PS2_SYNAPTICS
- bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED
+ bool "Synaptics PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
@@ -69,7 +69,7 @@ config MOUSE_PS2_SYNAPTICS
If unsure, say Y.
config MOUSE_PS2_LIFEBOOK
- bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
+ bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2 && X86 && DMI
help
@@ -79,7 +79,7 @@ config MOUSE_PS2_LIFEBOOK
If unsure, say Y.
config MOUSE_PS2_TRACKPOINT
- bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED
+ bool "IBM Trackpoint PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index b9523176391..ee82851afe3 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -55,6 +55,14 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
+/* MacbookAir3,2 (unibody), aka wellspring5 */
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
+/* MacbookAir3,1 (unibody), aka wellspring4 */
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@@ -80,6 +88,14 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
+ /* MacbookAir3,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
+ /* MacbookAir3,1 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
/* Terminating entry */
{}
};
@@ -234,6 +250,30 @@ static const struct bcm5974_config bcm5974_config_table[] = {
{ DIM_X, DIM_X / SN_COORD, -4460, 5166 },
{ DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING4_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+ },
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4616, 5112 },
+ { DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
+ },
{}
};
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index da392c22fc6..aa186cf6c51 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -755,23 +755,26 @@ static int synaptics_reconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
struct synaptics_data old_priv = *priv;
+ int retry = 0;
+ int error;
- psmouse_reset(psmouse);
+ do {
+ psmouse_reset(psmouse);
+ error = synaptics_detect(psmouse, 0);
+ } while (error && ++retry < 3);
- if (synaptics_detect(psmouse, 0))
+ if (error)
return -1;
+ if (retry > 1)
+ printk(KERN_DEBUG "Synaptics reconnected after %d tries\n",
+ retry);
+
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
return -1;
}
- if (old_priv.identity != priv->identity ||
- old_priv.model_id != priv->model_id ||
- old_priv.capabilities != priv->capabilities ||
- old_priv.ext_cap != priv->ext_cap)
- return -1;
-
if (synaptics_set_absolute_mode(psmouse)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
return -1;
@@ -782,6 +785,19 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return -1;
}
+ if (old_priv.identity != priv->identity ||
+ old_priv.model_id != priv->model_id ||
+ old_priv.capabilities != priv->capabilities ||
+ old_priv.ext_cap != priv->ext_cap) {
+ printk(KERN_ERR "Synaptics hardware appears to be different: "
+ "id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
+ old_priv.identity, priv->identity,
+ old_priv.model_id, priv->model_id,
+ old_priv.capabilities, priv->capabilities,
+ old_priv.ext_cap, priv->ext_cap);
+ return -1;
+ }
+
return 0;
}
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 25e5d042a72..7453938bf5e 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -51,6 +51,29 @@
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
+
+/*
+ * The following describes response for the 0x0c query.
+ *
+ * byte mask name meaning
+ * ---- ---- ------- ------------
+ * 1 0x01 adjustable threshold capacitive button sensitivity
+ * can be adjusted
+ * 1 0x02 report max query 0x0d gives max coord reported
+ * 1 0x04 clearpad sensor is ClearPad product
+ * 1 0x08 advanced gesture not particularly meaningful
+ * 1 0x10 clickpad bit 0 1-button ClickPad
+ * 1 0x60 multifinger mode identifies firmware finger counting
+ * (not reporting!) algorithm.
+ * Not particularly meaningful
+ * 1 0x80 covered pad W clipped to 14, 15 == pad mostly covered
+ * 2 0x01 clickpad bit 1 2-button ClickPad
+ * 2 0x02 deluxe LED controls touchpad support LED commands
+ * ala multimedia control bar
+ * 2 0x04 reduced filtering firmware does less filtering on
+ * position data, driver should watch
+ * for noise.
+ */
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index bcb1fdedb59..55f2c2293ec 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -2,7 +2,7 @@
# Input core configuration
#
config SERIO
- tristate "Serial I/O support" if EMBEDDED || !X86
+ tristate "Serial I/O support" if EXPERT || !X86
default y
help
Say Yes here if you have any input device that uses serial I/O to
@@ -19,7 +19,7 @@ config SERIO
if SERIO
config SERIO_I8042
- tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
+ tristate "i8042 PC Keyboard controller" if EXPERT || !X86
default y
depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
(!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN
@@ -168,7 +168,7 @@ config SERIO_MACEPS2
module will be called maceps2.
config SERIO_LIBPS2
- tristate "PS/2 driver library" if EMBEDDED
+ tristate "PS/2 driver library" if EXPERT
depends on SERIO_I8042 || SERIO_I8042=n
help
Say Y here if you are using a driver for device connected
@@ -229,7 +229,7 @@ config SERIO_PS2MULT
tristate "TQC PS/2 multiplexer"
help
Say Y here if you have the PS/2 line multiplexer like the one
- present on TQC boads.
+ present on TQC boards.
To compile this driver as a module, choose M here: the
module will be called ps2mult.
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index 448c7724beb..85281656724 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -111,9 +111,11 @@ static void ct82c710_close(struct serio *serio)
static int ct82c710_open(struct serio *serio)
{
unsigned char status;
+ int err;
- if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL))
- return -1;
+ err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL);
+ if (err)
+ return err;
status = inb_p(CT82C710_STATUS);
@@ -131,7 +133,7 @@ static int ct82c710_open(struct serio *serio)
status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
outb_p(status, CT82C710_STATUS);
free_irq(CT82C710_IRQ, NULL);
- return -1;
+ return -EBUSY;
}
return 0;
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 5ae0fc4578f..bb9f5d31f0d 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -424,6 +424,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
},
},
+ {
+ /* Dell Vostro V13 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+ },
+ },
{ }
};
@@ -545,6 +552,17 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
};
#endif
+static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
+ {
+ /* Dell Vostro V13 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+ },
+ },
+ { }
+};
+
/*
* Some Wistron based laptops need us to explicitly enable the 'Dritek
* keyboard extension' to make their extra keys start generating scancodes.
@@ -896,6 +914,9 @@ static int __init i8042_platform_init(void)
if (dmi_check_system(i8042_dmi_nomux_table))
i8042_nomux = true;
+ if (dmi_check_system(i8042_dmi_notimeout_table))
+ i8042_notimeout = true;
+
if (dmi_check_system(i8042_dmi_dritek_table))
i8042_dritek = true;
#endif /* CONFIG_X86 */
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index c04ff00a366..ac4c93689ab 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -63,6 +63,10 @@ static bool i8042_noloop;
module_param_named(noloop, i8042_noloop, bool, 0);
MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
+static bool i8042_notimeout;
+module_param_named(notimeout, i8042_notimeout, bool, 0);
+MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
+
#ifdef CONFIG_X86
static bool i8042_dritek;
module_param_named(dritek, i8042_dritek, bool, 0);
@@ -504,7 +508,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
} else {
dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
- ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+ ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
port_no = (str & I8042_STR_AUXDATA) ?
I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index db5b0bca1a1..ba70058e2be 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -188,7 +188,8 @@ static void serio_free_event(struct serio_event *event)
kfree(event);
}
-static void serio_remove_duplicate_events(struct serio_event *event)
+static void serio_remove_duplicate_events(void *object,
+ enum serio_event_type type)
{
struct serio_event *e, *next;
unsigned long flags;
@@ -196,13 +197,13 @@ static void serio_remove_duplicate_events(struct serio_event *event)
spin_lock_irqsave(&serio_event_lock, flags);
list_for_each_entry_safe(e, next, &serio_event_list, node) {
- if (event->object == e->object) {
+ if (object == e->object) {
/*
* If this event is of different type we should not
* look further - we only suppress duplicate events
* that were sent back-to-back.
*/
- if (event->type != e->type)
+ if (type != e->type)
break;
list_del_init(&e->node);
@@ -245,7 +246,7 @@ static void serio_handle_event(struct work_struct *work)
break;
}
- serio_remove_duplicate_events(event);
+ serio_remove_duplicate_events(event->object, event->type);
serio_free_event(event);
}
@@ -298,7 +299,7 @@ static int serio_queue_event(void *object, struct module *owner,
event->owner = owner;
list_add_tail(&event->node, &serio_event_list);
- schedule_work(&serio_event_work);
+ queue_work(system_long_wq, &serio_event_work);
out:
spin_unlock_irqrestore(&serio_event_lock, flags);
@@ -436,10 +437,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
} else if (!strncmp(buf, "rescan", count)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
+ serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
serio_disconnect_port(serio);
error = serio_bind_driver(serio, to_serio_driver(drv));
put_driver(drv);
+ serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
} else {
error = -EINVAL;
}
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 6e362de3f41..8755f5f3ad3 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -116,14 +116,15 @@ static void serport_ldisc_close(struct tty_struct *tty)
/*
* serport_ldisc_receive() is called by the low level tty driver when characters
- * are ready for us. We forward the characters, one by one to the 'interrupt'
- * routine.
+ * are ready for us. We forward the characters and flags, one by one to the
+ * 'interrupt' routine.
*/
static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
+ unsigned int ch_flags;
int i;
spin_lock_irqsave(&serport->lock, flags);
@@ -131,8 +132,23 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
if (!test_bit(SERPORT_ACTIVE, &serport->flags))
goto out;
- for (i = 0; i < count; i++)
- serio_interrupt(serport->serio, cp[i], 0);
+ for (i = 0; i < count; i++) {
+ switch (fp[i]) {
+ case TTY_FRAME:
+ ch_flags = SERIO_FRAME;
+ break;
+
+ case TTY_PARITY:
+ ch_flags = SERIO_PARITY;
+ break;
+
+ default:
+ ch_flags = 0;
+ break;
+ }
+
+ serio_interrupt(serport->serio, cp[i], ch_flags);
+ }
out:
spin_unlock_irqrestore(&serport->lock, flags);
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index a29a7812bd4..7729e547ba6 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -201,6 +201,7 @@ int sparse_keymap_setup(struct input_dev *dev,
break;
case KE_SW:
+ case KE_VSW:
__set_bit(EV_SW, dev->evbit);
__set_bit(entry->sw.code, dev->swbit);
break;
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index fc381498b79..cf8fb9f5d4a 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -519,7 +519,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
/* Retrieve the physical and logical size for OEM devices */
error = wacom_retrieve_hid_descriptor(intf, features);
if (error)
- goto fail2;
+ goto fail3;
wacom_setup_device_quirks(features);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 518782999fe..367fa82a607 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -1101,6 +1101,13 @@ void wacom_setup_device_quirks(struct wacom_features *features)
}
}
+static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
+ unsigned int physical_max)
+{
+ /* Touch physical dimensions are in 100th of mm */
+ return (logical_max * 100) / physical_max;
+}
+
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
{
@@ -1228,8 +1235,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
case TABLETPC:
if (features->device_type == BTN_TOOL_DOUBLETAP ||
features->device_type == BTN_TOOL_TRIPLETAP) {
- input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0);
- input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0);
+ input_abs_set_res(input_dev, ABS_X,
+ wacom_calculate_touch_res(features->x_max,
+ features->x_phy));
+ input_abs_set_res(input_dev, ABS_Y,
+ wacom_calculate_touch_res(features->y_max,
+ features->y_phy));
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
}
@@ -1272,6 +1283,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, features->pressure_max,
features->pressure_fuzz, 0);
+ input_abs_set_res(input_dev, ABS_X,
+ wacom_calculate_touch_res(features->x_max,
+ features->x_phy));
+ input_abs_set_res(input_dev, ABS_Y,
+ wacom_calculate_touch_res(features->y_max,
+ features->y_phy));
} else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
@@ -1426,6 +1443,10 @@ static struct wacom_features wacom_features_0xD3 =
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
static const struct wacom_features wacom_features_0xD4 =
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD6 =
+ { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD7 =
+ { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
static struct wacom_features wacom_features_0xD8 =
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
static struct wacom_features wacom_features_0xDA =
@@ -1507,6 +1528,8 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xD2) },
{ USB_DEVICE_WACOM(0xD3) },
{ USB_DEVICE_WACOM(0xD4) },
+ { USB_DEVICE_WACOM(0xD6) },
+ { USB_DEVICE_WACOM(0xD7) },
{ USB_DEVICE_WACOM(0xD8) },
{ USB_DEVICE_WACOM(0xDA) },
{ USB_DEVICE_WACOM(0xDB) },
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 07ac77d393a..61834ae282e 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -540,62 +540,62 @@ config TOUCHSCREEN_MC13783
config TOUCHSCREEN_USB_EGALAX
default y
- bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
+ bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_PANJIT
default y
- bool "PanJit device support" if EMBEDDED
+ bool "PanJit device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_3M
default y
- bool "3M/Microtouch EX II series device support" if EMBEDDED
+ bool "3M/Microtouch EX II series device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ITM
default y
- bool "ITM device support" if EMBEDDED
+ bool "ITM device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETURBO
default y
- bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+ bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GUNZE
default y
- bool "Gunze AHL61 device support" if EMBEDDED
+ bool "Gunze AHL61 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_DMC_TSC10
default y
- bool "DMC TSC-10/25 device support" if EMBEDDED
+ bool "DMC TSC-10/25 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IRTOUCH
default y
- bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
+ bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IDEALTEK
default y
- bool "IdealTEK URTC1000 device support" if EMBEDDED
+ bool "IdealTEK URTC1000 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GENERAL_TOUCH
default y
- bool "GeneralTouch Touchscreen device support" if EMBEDDED
+ bool "GeneralTouch Touchscreen device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GOTOP
default y
- bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
+ bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_JASTEC
default y
- bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
+ bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_E2I
@@ -605,17 +605,17 @@ config TOUCHSCREEN_USB_E2I
config TOUCHSCREEN_USB_ZYTRONIC
default y
- bool "Zytronic controller" if EMBEDDED
+ bool "Zytronic controller" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETT_TC45USB
default y
- bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
+ bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_NEXIO
default y
- bool "NEXIO/iNexio device support" if EMBEDDED
+ bool "NEXIO/iNexio device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_TOUCHIT213
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
index d82a38ee9a3..4e4e58cec6c 100644
--- a/drivers/input/touchscreen/ad7879-i2c.c
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -10,14 +10,16 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/pm.h>
#include "ad7879.h"
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
#ifdef CONFIG_PM
-static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
+static int ad7879_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_suspend(ts);
@@ -25,17 +27,17 @@ static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
return 0;
}
-static int ad7879_i2c_resume(struct i2c_client *client)
+static int ad7879_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_resume(ts);
return 0;
}
-#else
-# define ad7879_i2c_suspend NULL
-# define ad7879_i2c_resume NULL
+
+static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
#endif
/* All registers are word-sized.
@@ -117,11 +119,12 @@ static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ad7879_i2c_pm,
+#endif
},
.probe = ad7879_i2c_probe,
.remove = __devexit_p(ad7879_i2c_remove),
- .suspend = ad7879_i2c_suspend,
- .resume = ad7879_i2c_resume,
.id_table = ad7879_id,
};
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 14ea54b78e4..4bf2316e328 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -941,28 +941,29 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
struct ads7846_platform_data *pdata = spi->dev.platform_data;
int err;
- /* REVISIT when the irq can be triggered active-low, or if for some
+ /*
+ * REVISIT when the irq can be triggered active-low, or if for some
* reason the touchscreen isn't hooked up, we don't need to access
* the pendown state.
*/
- if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) {
- dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
- return -EINVAL;
- }
if (pdata->get_pendown_state) {
ts->get_pendown_state = pdata->get_pendown_state;
- return 0;
- }
+ } else if (gpio_is_valid(pdata->gpio_pendown)) {
- err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
- if (err) {
- dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
- pdata->gpio_pendown);
- return err;
- }
+ err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
+ if (err) {
+ dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
+ pdata->gpio_pendown);
+ return err;
+ }
- ts->gpio_pendown = pdata->gpio_pendown;
+ ts->gpio_pendown = pdata->gpio_pendown;
+
+ } else {
+ dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -1353,7 +1354,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
err_put_regulator:
regulator_put(ts->reg);
err_free_gpio:
- if (ts->gpio_pendown != -1)
+ if (!ts->get_pendown_state)
gpio_free(ts->gpio_pendown);
err_cleanup_filter:
if (ts->filter_cleanup)
@@ -1383,8 +1384,13 @@ static int __devexit ads7846_remove(struct spi_device *spi)
regulator_disable(ts->reg);
regulator_put(ts->reg);
- if (ts->gpio_pendown != -1)
+ if (!ts->get_pendown_state) {
+ /*
+ * If we are not using specialized pendown method we must
+ * have been relying on gpio we set up ourselves.
+ */
gpio_free(ts->gpio_pendown);
+ }
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index f7fa9ef4cd6..1507ce108d5 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -12,6 +12,7 @@
#include <linux/input.h>
#include <linux/input/bu21013.h>
#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
#define PEN_DOWN_INTR 0
#define MAX_FINGERS 2
@@ -139,6 +140,7 @@
* @chip: pointer to the touch panel controller
* @in_dev: pointer to the input device structure
* @intr_pin: interrupt pin value
+ * @regulator: pointer to the Regulator used for touch screen
*
* Touch panel device data structure
*/
@@ -149,6 +151,7 @@ struct bu21013_ts_data {
const struct bu21013_platform_device *chip;
struct input_dev *in_dev;
unsigned int intr_pin;
+ struct regulator *regulator;
};
/**
@@ -456,6 +459,20 @@ static int __devinit bu21013_probe(struct i2c_client *client,
bu21013_data->in_dev = in_dev;
bu21013_data->chip = pdata;
bu21013_data->client = client;
+
+ bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH");
+ if (IS_ERR(bu21013_data->regulator)) {
+ dev_err(&client->dev, "regulator_get failed\n");
+ error = PTR_ERR(bu21013_data->regulator);
+ goto err_free_mem;
+ }
+
+ error = regulator_enable(bu21013_data->regulator);
+ if (error < 0) {
+ dev_err(&client->dev, "regulator enable failed\n");
+ goto err_put_regulator;
+ }
+
bu21013_data->touch_stopped = false;
init_waitqueue_head(&bu21013_data->wait);
@@ -464,7 +481,7 @@ static int __devinit bu21013_probe(struct i2c_client *client,
error = pdata->cs_en(pdata->cs_pin);
if (error < 0) {
dev_err(&client->dev, "chip init failed\n");
- goto err_free_mem;
+ goto err_disable_regulator;
}
}
@@ -485,9 +502,9 @@ static int __devinit bu21013_probe(struct i2c_client *client,
__set_bit(EV_ABS, in_dev->evbit);
input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
- pdata->x_max_res, 0, 0);
+ pdata->touch_x_max, 0, 0);
input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
- pdata->y_max_res, 0, 0);
+ pdata->touch_y_max, 0, 0);
input_set_drvdata(in_dev, bu21013_data);
error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
@@ -513,6 +530,10 @@ err_free_irq:
bu21013_free_irq(bu21013_data);
err_cs_disable:
pdata->cs_dis(pdata->cs_pin);
+err_disable_regulator:
+ regulator_disable(bu21013_data->regulator);
+err_put_regulator:
+ regulator_put(bu21013_data->regulator);
err_free_mem:
input_free_device(in_dev);
kfree(bu21013_data);
@@ -535,6 +556,10 @@ static int __devexit bu21013_remove(struct i2c_client *client)
bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
input_unregister_device(bu21013_data->in_dev);
+
+ regulator_disable(bu21013_data->regulator);
+ regulator_put(bu21013_data->regulator);
+
kfree(bu21013_data);
device_init_wakeup(&client->dev, false);
@@ -561,6 +586,8 @@ static int bu21013_suspend(struct device *dev)
else
disable_irq(bu21013_data->chip->irq);
+ regulator_disable(bu21013_data->regulator);
+
return 0;
}
@@ -577,6 +604,12 @@ static int bu21013_resume(struct device *dev)
struct i2c_client *client = bu21013_data->client;
int retval;
+ retval = regulator_enable(bu21013_data->regulator);
+ if (retval < 0) {
+ dev_err(&client->dev, "bu21013 regulator enable failed\n");
+ return retval;
+ }
+
retval = bu21013_init_chip(bu21013_data);
if (retval < 0) {
dev_err(&client->dev, "bu21013 controller config failed\n");
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index d0c3a7229ad..a93c5c26ab3 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -280,8 +280,9 @@ err_free_mem:
}
#ifdef CONFIG_PM
-static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
+static int cy8ctmg110_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
@@ -293,8 +294,9 @@ static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int cy8ctmg110_resume(struct i2c_client *client)
+static int cy8ctmg110_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
@@ -305,6 +307,8 @@ static int cy8ctmg110_resume(struct i2c_client *client)
}
return 0;
}
+
+static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
#endif
static int __devexit cy8ctmg110_remove(struct i2c_client *client)
@@ -335,14 +339,13 @@ static struct i2c_driver cy8ctmg110_driver = {
.driver = {
.owner = THIS_MODULE,
.name = CY8CTMG110_DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &cy8ctmg110_pm,
+#endif
},
.id_table = cy8ctmg110_idtable,
.probe = cy8ctmg110_probe,
.remove = __devexit_p(cy8ctmg110_remove),
-#ifdef CONFIG_PM
- .suspend = cy8ctmg110_suspend,
- .resume = cy8ctmg110_resume,
-#endif
};
static int __init cy8ctmg110_init(void)
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 7a3a916f84a..7f8f538a980 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -261,8 +261,9 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+static int eeti_ts_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
@@ -279,8 +280,9 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int eeti_ts_resume(struct i2c_client *client)
+static int eeti_ts_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
@@ -296,9 +298,8 @@ static int eeti_ts_resume(struct i2c_client *client)
return 0;
}
-#else
-#define eeti_ts_suspend NULL
-#define eeti_ts_resume NULL
+
+static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
#endif
static const struct i2c_device_id eeti_ts_id[] = {
@@ -310,11 +311,12 @@ MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
static struct i2c_driver eeti_ts_driver = {
.driver = {
.name = "eeti_ts",
+#ifdef CONFIG_PM
+ .pm = &eeti_ts_pm,
+#endif
},
.probe = eeti_ts_probe,
.remove = __devexit_p(eeti_ts_remove),
- .suspend = eeti_ts_suspend,
- .resume = eeti_ts_resume,
.id_table = eeti_ts_id,
};
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index 6ee9940aaf5..2d84c80ceb6 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -261,25 +261,27 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+static int mcs5000_ts_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
/* Touch sleep mode */
i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
return 0;
}
-static int mcs5000_ts_resume(struct i2c_client *client)
+static int mcs5000_ts_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
mcs5000_ts_phys_init(data);
return 0;
}
-#else
-#define mcs5000_ts_suspend NULL
-#define mcs5000_ts_resume NULL
+
+static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
#endif
static const struct i2c_device_id mcs5000_ts_id[] = {
@@ -291,10 +293,11 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
static struct i2c_driver mcs5000_ts_driver = {
.probe = mcs5000_ts_probe,
.remove = __devexit_p(mcs5000_ts_remove),
- .suspend = mcs5000_ts_suspend,
- .resume = mcs5000_ts_resume,
.driver = {
.name = "mcs5000_ts",
+#ifdef CONFIG_PM
+ .pm = &mcs5000_ts_pm,
+#endif
},
.id_table = mcs5000_ts_id,
};
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index defe5dd3627..5803bd0c1cc 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/pm.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/i2c.h>
@@ -226,8 +227,9 @@ static int migor_ts_remove(struct i2c_client *client)
return 0;
}
-static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+static int migor_ts_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
if (device_may_wakeup(&client->dev))
@@ -236,8 +238,9 @@ static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int migor_ts_resume(struct i2c_client *client)
+static int migor_ts_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
if (device_may_wakeup(&client->dev))
@@ -246,6 +249,8 @@ static int migor_ts_resume(struct i2c_client *client)
return 0;
}
+static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
+
static const struct i2c_device_id migor_ts_id[] = {
{ "migor_ts", 0 },
{ }
@@ -255,11 +260,10 @@ MODULE_DEVICE_TABLE(i2c, migor_ts);
static struct i2c_driver migor_ts_driver = {
.driver = {
.name = "migor_ts",
+ .pm = &migor_ts_pm,
},
.probe = migor_ts_probe,
.remove = migor_ts_remove,
- .suspend = migor_ts_suspend,
- .resume = migor_ts_resume,
.id_table = migor_ts_id,
};
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c
index cf1dba2e267..22a3411e93c 100644
--- a/drivers/input/touchscreen/tnetv107x-ts.c
+++ b/drivers/input/touchscreen/tnetv107x-ts.c
@@ -14,6 +14,7 @@
*/
#include <linux/kernel.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/platform_device.h>
@@ -289,9 +290,9 @@ static int __devinit tsc_probe(struct platform_device *pdev)
}
ts->clk = clk_get(dev, NULL);
- if (!ts->clk) {
+ if (IS_ERR(ts->clk)) {
dev_err(dev, "cannot claim device clock\n");
- error = -EINVAL;
+ error = PTR_ERR(ts->clk);
goto error_clk;
}
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 8ed53aded2d..c14412ef464 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2008 Jaya Kumar
* Copyright (c) 2010 Red Hat, Inc.
+ * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. <pingc@wacom.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
@@ -50,6 +51,10 @@ MODULE_LICENSE("GPL");
#define W8001_PKTLEN_TPCCTL 11 /* control packet */
#define W8001_PKTLEN_TOUCH2FG 13
+/* resolution in points/mm */
+#define W8001_PEN_RESOLUTION 100
+#define W8001_TOUCH_RESOLUTION 10
+
struct w8001_coord {
u8 rdy;
u8 tsw;
@@ -64,11 +69,11 @@ struct w8001_coord {
/* touch query reply packet */
struct w8001_touch_query {
+ u16 x;
+ u16 y;
u8 panel_res;
u8 capacity_res;
u8 sensor_id;
- u16 x;
- u16 y;
};
/*
@@ -87,9 +92,14 @@ struct w8001 {
char phys[32];
int type;
unsigned int pktlen;
+ u16 max_touch_x;
+ u16 max_touch_y;
+ u16 max_pen_x;
+ u16 max_pen_y;
+ char name[64];
};
-static void parse_data(u8 *data, struct w8001_coord *coord)
+static void parse_pen_data(u8 *data, struct w8001_coord *coord)
{
memset(coord, 0, sizeof(*coord));
@@ -113,11 +123,30 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
coord->tilt_y = data[8] & 0x7F;
}
-static void parse_touch(struct w8001 *w8001)
+static void parse_single_touch(u8 *data, struct w8001_coord *coord)
+{
+ coord->x = (data[1] << 7) | data[2];
+ coord->y = (data[3] << 7) | data[4];
+ coord->tsw = data[0] & 0x01;
+}
+
+static void scale_touch_coordinates(struct w8001 *w8001,
+ unsigned int *x, unsigned int *y)
+{
+ if (w8001->max_pen_x && w8001->max_touch_x)
+ *x = *x * w8001->max_pen_x / w8001->max_touch_x;
+
+ if (w8001->max_pen_y && w8001->max_touch_y)
+ *y = *y * w8001->max_pen_y / w8001->max_touch_y;
+}
+
+static void parse_multi_touch(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
unsigned char *data = w8001->data;
+ unsigned int x, y;
int i;
+ int count = 0;
for (i = 0; i < 2; i++) {
bool touch = data[0] & (1 << i);
@@ -125,15 +154,29 @@ static void parse_touch(struct w8001 *w8001)
input_mt_slot(dev, i);
input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
if (touch) {
- int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
- int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
+ x = (data[6 * i + 1] << 7) | data[6 * i + 2];
+ y = (data[6 * i + 3] << 7) | data[6 * i + 4];
/* data[5,6] and [11,12] is finger capacity */
+ /* scale to pen maximum */
+ scale_touch_coordinates(w8001, &x, &y);
+
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ count++;
}
}
+ /* emulate single touch events when stylus is out of proximity.
+ * This is to make single touch backward support consistent
+ * across all Wacom single touch devices.
+ */
+ if (w8001->type != BTN_TOOL_PEN &&
+ w8001->type != BTN_TOOL_RUBBER) {
+ w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED;
+ input_mt_report_pointer_emulation(dev, true);
+ }
+
input_sync(dev);
}
@@ -152,6 +195,15 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
query->y = data[5] << 9;
query->y |= data[6] << 2;
query->y |= (data[2] >> 3) & 0x3;
+
+ /* Early days' single-finger touch models need the following defaults */
+ if (!query->x && !query->y) {
+ query->x = 1024;
+ query->y = 1024;
+ if (query->panel_res)
+ query->x = query->y = (1 << query->panel_res);
+ query->panel_res = W8001_TOUCH_RESOLUTION;
+ }
}
static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
@@ -161,16 +213,15 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
/*
* We have 1 bit for proximity (rdy) and 3 bits for tip, side,
* side2/eraser. If rdy && f2 are set, this can be either pen + side2,
- * or eraser. assume
+ * or eraser. Assume:
* - if dev is already in proximity and f2 is toggled → pen + side2
* - if dev comes into proximity with f2 set → eraser
* If f2 disappears after assuming eraser, fake proximity out for
* eraser and in for pen.
*/
- if (!w8001->type) {
- w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
- } else if (w8001->type == BTN_TOOL_RUBBER) {
+ switch (w8001->type) {
+ case BTN_TOOL_RUBBER:
if (!coord->f2) {
input_report_abs(dev, ABS_PRESSURE, 0);
input_report_key(dev, BTN_TOUCH, 0);
@@ -180,8 +231,21 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
input_sync(dev);
w8001->type = BTN_TOOL_PEN;
}
- } else {
+ break;
+
+ case BTN_TOOL_FINGER:
+ input_report_key(dev, BTN_TOUCH, 0);
+ input_report_key(dev, BTN_TOOL_FINGER, 0);
+ input_sync(dev);
+ /* fall through */
+
+ case KEY_RESERVED:
+ w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ break;
+
+ default:
input_report_key(dev, BTN_STYLUS2, coord->f2);
+ break;
}
input_report_abs(dev, ABS_X, coord->x);
@@ -193,7 +257,26 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
input_sync(dev);
if (!coord->rdy)
- w8001->type = 0;
+ w8001->type = KEY_RESERVED;
+}
+
+static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
+{
+ struct input_dev *dev = w8001->dev;
+ unsigned int x = coord->x;
+ unsigned int y = coord->y;
+
+ /* scale to pen maximum */
+ scale_touch_coordinates(w8001, &x, &y);
+
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ input_report_key(dev, BTN_TOUCH, coord->tsw);
+ input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
+
+ input_sync(dev);
+
+ w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED;
}
static irqreturn_t w8001_interrupt(struct serio *serio,
@@ -214,9 +297,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
case W8001_PKTLEN_TOUCH93 - 1:
case W8001_PKTLEN_TOUCH9A - 1:
- /* ignore one-finger touch packet. */
- if (w8001->pktlen == w8001->idx)
+ tmp = w8001->data[0] & W8001_TOUCH_BYTE;
+ if (tmp != W8001_TOUCH_BYTE)
+ break;
+
+ if (w8001->pktlen == w8001->idx) {
w8001->idx = 0;
+ if (w8001->type != BTN_TOOL_PEN &&
+ w8001->type != BTN_TOOL_RUBBER) {
+ parse_single_touch(w8001->data, &coord);
+ report_single_touch(w8001, &coord);
+ }
+ }
break;
/* Pen coordinates packet */
@@ -225,18 +317,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
if (unlikely(tmp == W8001_TAB_BYTE))
break;
- tmp = (w8001->data[0] & W8001_TOUCH_BYTE);
+ tmp = w8001->data[0] & W8001_TOUCH_BYTE;
if (tmp == W8001_TOUCH_BYTE)
break;
w8001->idx = 0;
- parse_data(w8001->data, &coord);
+ parse_pen_data(w8001->data, &coord);
report_pen_events(w8001, &coord);
break;
/* control packet */
case W8001_PKTLEN_TPCCTL - 1:
- tmp = (w8001->data[0] & W8001_TOUCH_MASK);
+ tmp = w8001->data[0] & W8001_TOUCH_MASK;
if (tmp == W8001_TOUCH_BYTE)
break;
@@ -249,7 +341,7 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
/* 2 finger touch packet */
case W8001_PKTLEN_TOUCH2FG - 1:
w8001->idx = 0;
- parse_touch(w8001);
+ parse_multi_touch(w8001);
break;
}
@@ -279,6 +371,7 @@ static int w8001_setup(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
struct w8001_coord coord;
+ struct w8001_touch_query touch;
int error;
error = w8001_command(w8001, W8001_CMD_STOP, false);
@@ -287,22 +380,33 @@ static int w8001_setup(struct w8001 *w8001)
msleep(250); /* wait 250ms before querying the device */
+ dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
+
/* penabled? */
error = w8001_command(w8001, W8001_CMD_QUERY, true);
if (!error) {
+ __set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_PEN, dev->keybit);
__set_bit(BTN_TOOL_RUBBER, dev->keybit);
__set_bit(BTN_STYLUS, dev->keybit);
__set_bit(BTN_STYLUS2, dev->keybit);
- parse_data(w8001->response, &coord);
+
+ parse_pen_data(w8001->response, &coord);
+ w8001->max_pen_x = coord.x;
+ w8001->max_pen_y = coord.y;
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+ input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
+ input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
if (coord.tilt_x && coord.tilt_y) {
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
}
+ w8001->id = 0x90;
+ strlcat(w8001->name, " Penabled", sizeof(w8001->name));
}
/* Touch enabled? */
@@ -313,24 +417,41 @@ static int w8001_setup(struct w8001 *w8001)
* second byte is empty, which indicates touch is not supported.
*/
if (!error && w8001->response[1]) {
- struct w8001_touch_query touch;
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, dev->keybit);
parse_touchquery(w8001->response, &touch);
+ w8001->max_touch_x = touch.x;
+ w8001->max_touch_y = touch.y;
+
+ if (w8001->max_pen_x && w8001->max_pen_y) {
+ /* if pen is supported scale to pen maximum */
+ touch.x = w8001->max_pen_x;
+ touch.y = w8001->max_pen_y;
+ touch.panel_res = W8001_PEN_RESOLUTION;
+ }
input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
- __set_bit(BTN_TOOL_FINGER, dev->keybit);
+ input_abs_set_res(dev, ABS_X, touch.panel_res);
+ input_abs_set_res(dev, ABS_Y, touch.panel_res);
switch (touch.sensor_id) {
case 0:
case 2:
w8001->pktlen = W8001_PKTLEN_TOUCH93;
+ w8001->id = 0x93;
+ strlcat(w8001->name, " 1FG", sizeof(w8001->name));
break;
+
case 1:
case 3:
case 4:
w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+ strlcat(w8001->name, " 1FG", sizeof(w8001->name));
+ w8001->id = 0x9a;
break;
+
case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
@@ -341,10 +462,18 @@ static int w8001_setup(struct w8001 *w8001)
0, touch.y, 0, 0);
input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
+
+ strlcat(w8001->name, " 2FG", sizeof(w8001->name));
+ if (w8001->max_pen_x && w8001->max_pen_y)
+ w8001->id = 0xE3;
+ else
+ w8001->id = 0xE2;
break;
}
}
+ strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
+
return w8001_command(w8001, W8001_CMD_START, false);
}
@@ -384,22 +513,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
}
w8001->serio = serio;
- w8001->id = serio->id.id;
w8001->dev = input_dev;
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
- input_dev->name = "Wacom W8001 Penabled Serial TouchScreen";
- input_dev->phys = w8001->phys;
- input_dev->id.bustype = BUS_RS232;
- input_dev->id.vendor = SERIO_W8001;
- input_dev->id.product = w8001->id;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &serio->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- __set_bit(BTN_TOUCH, input_dev->keybit);
-
serio_set_drvdata(serio, w8001);
err = serio_open(serio, drv);
if (err)
@@ -409,6 +526,14 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
if (err)
goto fail3;
+ input_dev->name = w8001->name;
+ input_dev->phys = w8001->phys;
+ input_dev->id.product = w8001->id;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = 0x056a;
+ input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
+
err = input_register_device(w8001->dev);
if (err)
goto fail3;