summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.osdl.org>2003-09-20 04:18:59 -0700
committerLinus Torvalds <torvalds@home.osdl.org>2003-09-20 04:18:59 -0700
commit834ae7f12afa0d4350e3874a135aa5a4c24a87d7 (patch)
tree59478adff11dc8cd1aa0654dc5475a8216b29e80 /drivers/input
parent4f3a1d592e8dc6d7327fc7ca915b9b764883d5b7 (diff)
parent24a2d11aa804699923077b0e13d1b65e36217db0 (diff)
Merge bk://kernel.bkbits.net/gregkh/linux/linus-2.6
into home.osdl.org:/home/torvalds/v2.5/linux
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/evdev.c12
-rw-r--r--drivers/input/input.c6
-rw-r--r--drivers/input/joystick/db9.c313
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c5
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c6
-rw-r--r--drivers/input/keyboard/Kconfig3
-rw-r--r--drivers/input/keyboard/atkbd.c173
-rw-r--r--drivers/input/mouse/Kconfig20
-rw-r--r--drivers/input/mouse/psmouse-base.c103
-rw-r--r--drivers/input/mouse/psmouse.h22
-rw-r--r--drivers/input/mouse/synaptics.c363
-rw-r--r--drivers/input/mouse/synaptics.h27
-rw-r--r--drivers/input/serio/serio.c31
13 files changed, 835 insertions, 249 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 10a13ac90c48..ca56ac39e2b8 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -208,7 +208,7 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
- int i, t, u;
+ int i, t, u, v;
if (!evdev->exist) return -ENODEV;
@@ -239,14 +239,12 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case EVIOCSKEYCODE:
if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+ if (get_user(v, ((int *) arg) + 1)) return -EFAULT;
u = INPUT_KEYCODE(dev, t);
- if (get_user(INPUT_KEYCODE(dev, t), ((int *) arg) + 1)) return -EFAULT;
-
- for (i = 0; i < dev->keycodemax; i++)
- if(INPUT_KEYCODE(dev, t) == u) break;
+ INPUT_KEYCODE(dev, t) = v;
+ for (i = 0; i < dev->keycodemax; i++) if (v == u) break;
if (i == dev->keycodemax) clear_bit(u, dev->keybit);
- set_bit(INPUT_KEYCODE(dev, t), dev->keybit);
-
+ set_bit(v, dev->keybit);
return 0;
case EVIOCSFF:
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 843c342864f5..45d9bdffdbe4 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -426,8 +426,10 @@ void input_register_device(struct input_dev *dev)
init_timer(&dev->timer);
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
- dev->rep[REP_DELAY] = HZ/4;
- dev->rep[REP_PERIOD] = HZ/33;
+ if (!dev->rep[REP_DELAY])
+ dev->rep[REP_DELAY] = HZ/4;
+ if (!dev->rep[REP_PERIOD])
+ dev->rep[REP_PERIOD] = HZ/33;
INIT_LIST_HEAD(&dev->h_list);
list_add_tail(&dev->node, &input_dev_list);
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 091fe2e887fa..9d757ce3f8ec 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -55,7 +55,9 @@ MODULE_PARM(db9_3, "2i");
#define DB9_MULTI_0802 0x08
#define DB9_MULTI_0802_2 0x09
#define DB9_CD32_PAD 0x0A
-#define DB9_MAX_PAD 0x0B
+#define DB9_SATURN_DPP 0x0B
+#define DB9_SATURN_DPP_2 0x0C
+#define DB9_MAX_PAD 0x0D
#define DB9_UP 0x01
#define DB9_DOWN 0x02
@@ -69,10 +71,7 @@ MODULE_PARM(db9_3, "2i");
#define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08
-#define DB9_SATURN0 0x00
-#define DB9_SATURN1 0x02
-#define DB9_SATURN2 0x04
-#define DB9_SATURN3 0x06
+#define DB9_MAX_DEVICES 2
#define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100
@@ -82,7 +81,7 @@ static int db9_2[] __initdata = { -1, 0 };
static int db9_3[] __initdata = { -1, 0 };
struct db9 {
- struct input_dev dev[2];
+ struct input_dev dev[DB9_MAX_DEVICES];
struct timer_list timer;
struct pardevice *pd;
int mode;
@@ -96,12 +95,247 @@ static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
-static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
+static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 9, 1, 1, 7, 9, 9 };
static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
- db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
+ db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn,
+ db9_cd32_btn, db9_cd32_btn };
static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
- "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" };
+ "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad", "Saturn dpp", "Saturn dpp dual" };
+
+static const int db9_max_pads[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 6, 1, 2, 1, 6, 12 };
+static const int db9_num_axis[DB9_MAX_PAD] = { 0, 2, 2, 2, 0, 2, 2, 7, 2, 2, 2 ,7, 7 };
+static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
+static const int db9_bidirectional[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 };
+static const int db9_reverse[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 };
+
+/*
+ * Saturn controllers
+ */
+#define DB9_SATURN_DELAY 300
+static const int db9_saturn_byte[] = { 1, 1, 1, 2, 2, 2, 2, 2, 1 };
+static const unsigned char db9_saturn_mask[] = { 0x04, 0x01, 0x02, 0x40, 0x20, 0x10, 0x08, 0x80, 0x08 };
+
+/*
+ * db9_saturn_write_sub() writes 2 bit data.
+ */
+static void db9_saturn_write_sub(struct parport *port, int type, unsigned char data, int powered, int pwr_sub)
+{
+ unsigned char c;
+
+ switch (type) {
+ case 1: /* DPP1 */
+ c = 0x80 | 0x30 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | data;
+ parport_write_data(port, c);
+ break;
+ case 2: /* DPP2 */
+ c = 0x40 | data << 4 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | 0x03;
+ parport_write_data(port, c);
+ break;
+ case 0: /* DB9 */
+ c = ((((data & 2) ? 2 : 0) | ((data & 1) ? 4 : 0)) ^ 0x02) | !powered;
+ parport_write_control(port, c);
+ break;
+ }
+}
+
+/*
+ * gc_saturn_read_sub() reads 4 bit data.
+ */
+static unsigned char db9_saturn_read_sub(struct parport *port, int type)
+{
+ unsigned char data;
+
+ if (type) {
+ /* DPP */
+ data = parport_read_status(port) ^ 0x80;
+ return (data & 0x80 ? 1 : 0) | (data & 0x40 ? 2 : 0)
+ | (data & 0x20 ? 4 : 0) | (data & 0x10 ? 8 : 0);
+ } else {
+ /* DB9 */
+ data = parport_read_data(port) & 0x0f;
+ return (data & 0x8 ? 1 : 0) | (data & 0x4 ? 2 : 0)
+ | (data & 0x2 ? 4 : 0) | (data & 0x1 ? 8 : 0);
+ }
+}
+
+/*
+ * db9_saturn_read_analog() sends clock and reads 8 bit data.
+ */
+static unsigned char db9_saturn_read_analog(struct parport *port, int type, int powered)
+{
+ unsigned char data;
+
+ db9_saturn_write_sub(port, type, 0, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ data = db9_saturn_read_sub(port, type) << 4;
+ db9_saturn_write_sub(port, type, 2, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ data |= db9_saturn_read_sub(port, type);
+ return data;
+}
+
+/*
+ * db9_saturn_read_packet() reads whole saturn packet at connector
+ * and returns device identifier code.
+ */
+static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered)
+{
+ int i, j;
+ unsigned char tmp;
+
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ data[0] = db9_saturn_read_sub(port, type);
+ switch (data[0] & 0x0f) {
+ case 0xf:
+ /* 1111 no pad */
+ return data[0] = 0xff;
+ case 0x4: case 0x4 | 0x8:
+ /* ?100 : digital controller */
+ db9_saturn_write_sub(port, type, 0, powered, 1);
+ data[2] = db9_saturn_read_sub(port, type) << 4;
+ db9_saturn_write_sub(port, type, 2, powered, 1);
+ data[1] = db9_saturn_read_sub(port, type) << 4;
+ db9_saturn_write_sub(port, type, 1, powered, 1);
+ data[1] |= db9_saturn_read_sub(port, type);
+ db9_saturn_write_sub(port, type, 3, powered, 1);
+ /* data[2] |= db9_saturn_read_sub(port, type); */
+ data[2] |= data[0];
+ return data[0] = 0x02;
+ case 0x1:
+ /* 0001 : analog controller or multitap */
+ db9_saturn_write_sub(port, type, 2, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ data[0] = db9_saturn_read_analog(port, type, powered);
+ if (data[0] != 0x41) {
+ /* read analog controller */
+ for (i = 0; i < (data[0] & 0x0f); i++)
+ data[i + 1] = db9_saturn_read_analog(port, type, powered);
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ return data[0];
+ } else {
+ /* read multitap */
+ if (db9_saturn_read_analog(port, type, powered) != 0x60)
+ return data[0] = 0xff;
+ for (i = 0; i < 60; i += 10) {
+ data[i] = db9_saturn_read_analog(port, type, powered);
+ if (data[i] != 0xff)
+ /* read each pad */
+ for (j = 0; j < (data[i] & 0x0f); j++)
+ data[i + j + 1] = db9_saturn_read_analog(port, type, powered);
+ }
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ return 0x41;
+ }
+ case 0x0:
+ /* 0000 : mouse */
+ db9_saturn_write_sub(port, type, 2, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ tmp = db9_saturn_read_analog(port, type, powered);
+ if (tmp == 0xff) {
+ for (i = 0; i < 3; i++)
+ data[i + 1] = db9_saturn_read_analog(port, type, powered);
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ return data[0] = 0xe3;
+ }
+ default:
+ return data[0];
+ }
+}
+
+/*
+ * db9_saturn_report() analyzes packet and reports.
+ */
+static int db9_saturn_report(unsigned char id, unsigned char data[60], struct input_dev *dev, int n, int max_pads)
+{
+ int tmp, i, j;
+
+ tmp = (id == 0x41) ? 60 : 10;
+ for (j = 0; (j < tmp) && (n < max_pads); j += 10, n++) {
+ switch (data[j]) {
+ case 0x16: /* multi controller (analog 4 axis) */
+ input_report_abs(dev + n, db9_abs[5], data[j + 6]);
+ case 0x15: /* mission stick (analog 3 axis) */
+ input_report_abs(dev + n, db9_abs[3], data[j + 4]);
+ input_report_abs(dev + n, db9_abs[4], data[j + 5]);
+ case 0x13: /* racing controller (analog 1 axis) */
+ input_report_abs(dev + n, db9_abs[2], data[j + 3]);
+ case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
+ case 0x02: /* digital pad (digital 2 axis + buttons) */
+ input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
+ input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
+ for (i = 0; i < 9; i++)
+ input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
+ break;
+ case 0x19: /* mission stick x2 (analog 6 axis + buttons) */
+ input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
+ input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
+ for (i = 0; i < 9; i++)
+ input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
+ input_report_abs(dev + n, db9_abs[2], data[j + 3]);
+ input_report_abs(dev + n, db9_abs[3], data[j + 4]);
+ input_report_abs(dev + n, db9_abs[4], data[j + 5]);
+ /*
+ input_report_abs(dev + n, db9_abs[8], (data[j + 6] & 128 ? 0 : 1) - (data[j + 6] & 64 ? 0 : 1));
+ input_report_abs(dev + n, db9_abs[9], (data[j + 6] & 32 ? 0 : 1) - (data[j + 6] & 16 ? 0 : 1));
+ */
+ input_report_abs(dev + n, db9_abs[6], data[j + 7]);
+ input_report_abs(dev + n, db9_abs[7], data[j + 8]);
+ input_report_abs(dev + n, db9_abs[5], data[j + 9]);
+ break;
+ case 0xd3: /* sankyo ff (analog 1 axis + stop btn) */
+ input_report_key(dev + n, BTN_A, data[j + 3] & 0x80);
+ input_report_abs(dev + n, db9_abs[2], data[j + 3] & 0x7f);
+ break;
+ case 0xe3: /* shuttle mouse (analog 2 axis + buttons. signed value) */
+ input_report_key(dev + n, BTN_START, data[j + 1] & 0x08);
+ input_report_key(dev + n, BTN_A, data[j + 1] & 0x04);
+ input_report_key(dev + n, BTN_C, data[j + 1] & 0x02);
+ input_report_key(dev + n, BTN_B, data[j + 1] & 0x01);
+ input_report_abs(dev + n, db9_abs[2], data[j + 2] ^ 0x80);
+ input_report_abs(dev + n, db9_abs[3], (0xff-(data[j + 3] ^ 0x80))+1); /* */
+ break;
+ case 0xff:
+ default: /* no pad */
+ input_report_abs(dev + n, db9_abs[0], 0);
+ input_report_abs(dev + n, db9_abs[1], 0);
+ for (i = 0; i < 9; i++)
+ input_report_key(dev + n, db9_cd32_btn[i], 0);
+ break;
+ }
+ }
+ return n;
+}
+
+static int db9_saturn(int mode, struct parport *port, struct input_dev *dev)
+{
+ unsigned char id, data[60];
+ int type, n, max_pads;
+ int tmp, i;
+
+ switch (mode) {
+ case DB9_SATURN_PAD:
+ type = 0;
+ n = 1;
+ break;
+ case DB9_SATURN_DPP:
+ type = 1;
+ n = 1;
+ break;
+ case DB9_SATURN_DPP_2:
+ type = 1;
+ n = 2;
+ break;
+ default:
+ return -1;
+ }
+ max_pads = min(db9_max_pads[mode], DB9_MAX_DEVICES);
+ for (tmp = 0, i = 0; i < n; i++) {
+ id = db9_saturn_read_packet(port, data, type + i, 1);
+ tmp = db9_saturn_report(id, data, dev, tmp, max_pads);
+ }
+ return 0;
+}
static void db9_timer(unsigned long private)
{
@@ -222,28 +456,10 @@ static void db9_timer(unsigned long private)
break;
case DB9_SATURN_PAD:
+ case DB9_SATURN_DPP:
+ case DB9_SATURN_DPP_2:
- parport_write_control(port, DB9_SATURN0);
- data = parport_read_data(port);
-
- input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
- input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
- input_report_key(dev, BTN_TL, ~data & DB9_UP);
- input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
-
- parport_write_control(port, DB9_SATURN2);
- data = parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
-
- parport_write_control(port, DB9_NORMAL);
- data = parport_read_data(port);
-
- input_report_key(dev, BTN_A, ~data & DB9_LEFT);
- input_report_key(dev, BTN_B, ~data & DB9_UP);
- input_report_key(dev, BTN_C, ~data & DB9_DOWN);
- input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
+ db9_saturn(db9->mode, port, dev);
break;
case DB9_CD32_PAD:
@@ -279,8 +495,10 @@ static int db9_open(struct input_dev *dev)
if (!db9->used++) {
parport_claim(db9->pd);
parport_write_data(port, 0xff);
- parport_data_reverse(port);
- parport_write_control(port, DB9_NORMAL);
+ if (db9_reverse[db9->mode]) {
+ parport_data_reverse(port);
+ parport_write_control(port, DB9_NORMAL);
+ }
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
@@ -321,11 +539,13 @@ static struct db9 __init *db9_probe(int *config)
return NULL;
}
- if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
- printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
- return NULL;
+ if (db9_bidirectional[config[1]]) {
+ if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
+ printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
+ return NULL;
+ }
}
-
+
if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
return NULL;
memset(db9, 0, sizeof(struct db9));
@@ -343,7 +563,7 @@ static struct db9 __init *db9_probe(int *config)
return NULL;
}
- for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
+ for (i = 0; i < (min(db9_max_pads[db9->mode], DB9_MAX_DEVICES)); i++) {
sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);
@@ -359,14 +579,19 @@ static struct db9 __init *db9_probe(int *config)
db9->dev[i].id.version = 0x0100;
db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
for (j = 0; j < db9_buttons[db9->mode]; j++)
set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
-
- db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
- db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
-
+ for (j = 0; j < db9_num_axis[db9->mode]; j++) {
+ set_bit(db9_abs[j], db9->dev[i].absbit);
+ if (j < 2) {
+ db9->dev[i].absmin[db9_abs[j]] = -1;
+ db9->dev[i].absmax[db9_abs[j]] = 1;
+ } else {
+ db9->dev[i].absmin[db9_abs[j]] = 1;
+ db9->dev[i].absmax[db9_abs[j]] = 255;
+ db9->dev[i].absflat[db9_abs[j]] = 0;
+ }
+ }
input_register_device(db9->dev + i);
printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name);
}
@@ -419,7 +644,7 @@ void __exit db9_exit(void)
for (i = 0; i < 3; i++)
if (db9_base[i]) {
- for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
+ for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++)
input_unregister_device(db9_base[i]->dev + j);
parport_unregister_device(db9_base[i]->pd);
}
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 176c5e889186..0c37044ef85a 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -166,8 +166,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
iforce->expect_packet = 0;
iforce->ecmd = cmd;
memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
+ wake_up(&iforce->wait);
}
#endif
@@ -264,7 +263,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&iforce->wait, &wait);
- if (usb_submit_urb(iforce->ctrl, GFP_KERNEL)) {
+ if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
return -1;
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 0acb3f9b6c1d..a2cefd078385 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -116,8 +116,7 @@ static void iforce_usb_out(struct urb *urb, struct pt_regs *regs)
iforce_usb_xmit(iforce);
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
+ wake_up(&iforce->wait);
}
static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
@@ -125,8 +124,7 @@ static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
struct iforce *iforce = urb->context;
if (urb->status) return;
iforce->ecmd = 0xff00 | urb->actual_length;
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
+ wake_up(&iforce->wait);
}
static int iforce_usb_probe(struct usb_interface *intf,
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index d210fba2b127..9288a60dff5e 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -13,7 +13,8 @@ config INPUT_KEYBOARD
config KEYBOARD_ATKBD
tristate "AT keyboard support" if EMBEDDED || !X86
- default y
+ default y if INPUT=y && INPUT_KEYBOARD=y && SERIO=y
+ default m
depends on INPUT && INPUT_KEYBOARD && SERIO
help
Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 719def669f8f..9f7726d91402 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -18,6 +18,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/workqueue.h>
+#include <linux/timer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
@@ -40,8 +41,8 @@ static int atkbd_reset = 1;
static unsigned char atkbd_set2_keycode[512] = {
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
0, 56, 42,182, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
- 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
- 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
+ 0, 46, 45, 32, 18, 5, 4, 91, 90, 57, 47, 33, 20, 19, 6, 0,
+ 91, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
85, 86, 90, 91, 92, 93, 14, 94, 95, 79,183, 75, 71,121, 0,123,
@@ -87,10 +88,10 @@ static unsigned char atkbd_set3_keycode[512] = {
#define ATKBD_CMD_GSCANSET 0x11f0
#define ATKBD_CMD_SSCANSET 0x10f0
#define ATKBD_CMD_GETID 0x02f2
+#define ATKBD_CMD_SETREP 0x10f3
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5
#define ATKBD_CMD_RESET_BAT 0x02ff
-#define ATKBD_CMD_SETALL_MB 0x00f8
#define ATKBD_CMD_RESEND 0x00fe
#define ATKBD_CMD_EX_ENABLE 0x10ea
#define ATKBD_CMD_EX_SETLEDS 0x20eb
@@ -114,12 +115,14 @@ struct atkbd {
unsigned char keycode[512];
struct input_dev dev;
struct serio *serio;
+ struct timer_list timer;
char name[64];
char phys[32];
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
unsigned char release;
+ int lastkey;
volatile signed char ack;
unsigned char emul;
unsigned short id;
@@ -142,6 +145,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
#endif
+#if !defined(__i386__) && !defined (__x86_64__)
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
printk("atkbd.c: frame/parity error: %02x\n", flags);
serio_write(serio, ATKBD_CMD_RESEND);
@@ -151,6 +155,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
if (!flags)
atkbd->resend = 0;
+#endif
switch (code) {
case ATKBD_RET_ACK:
@@ -195,6 +200,14 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed");
break;
default:
+
+ if (!atkbd->release) {
+ mod_timer(&atkbd->timer,
+ jiffies + (test_bit(atkbd->keycode[code],
+ atkbd->dev.key) ? HZ/33 : HZ/4) + HZ/100);
+ atkbd->lastkey = atkbd->keycode[code];
+ }
+
input_regs(&atkbd->dev, regs);
input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
input_sync(&atkbd->dev);
@@ -205,6 +218,13 @@ out:
return IRQ_HANDLED;
}
+static void atkbd_force_key_up(unsigned long data)
+{
+ struct atkbd *atkbd = (void *) data;
+ input_report_key(&atkbd->dev, atkbd->lastkey, 0);
+ input_sync(&atkbd->dev);
+}
+
/*
* atkbd_sendbyte() sends a byte to the keyboard, and waits for
* acknowledge. It doesn't handle resends according to the keyboard
@@ -214,7 +234,7 @@ out:
static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
{
- int timeout = 10000; /* 100 msec */
+ int timeout = 20000; /* 200 msec */
atkbd->ack = 0;
#ifdef ATKBD_DEBUG
@@ -322,13 +342,50 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
}
/*
- * Enable keyboard.
+ * atkbd_probe() probes for an AT keyboard on a serio port.
*/
-static void atkbd_enable(struct atkbd *atkbd)
+
+static int atkbd_probe(struct atkbd *atkbd)
{
- if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE))
- printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
- atkbd->serio->phys);
+ unsigned char param[2];
+
+/*
+ * Some systems, where the bit-twiddling when testing the io-lines of the
+ * controller may confuse the keyboard need a full reset of the keyboard. On
+ * these systems the BIOS also usually doesn't do it for us.
+ */
+
+ if (atkbd_reset)
+ if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
+ printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys);
+
+/*
+ * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
+ * Some keyboards report different values, but the first byte is always 0xab or
+ * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
+ * should make sure we don't try to set the LEDs on it.
+ */
+
+ if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
+
+/*
+ * If the get ID command failed, we check if we can at least set the LEDs on
+ * the keyboard. This should work on every keyboard out there. It also turns
+ * the LEDs off, which we want anyway.
+ */
+ param[0] = 0;
+ if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ return -1;
+ atkbd->id = 0xabba;
+ return 0;
+ }
+
+ if (param[0] != 0xab && param[0] != 0xac)
+ return -1;
+ atkbd->id = (param[0] << 8) | param[1];
+
+
+ return 0;
}
/*
@@ -365,103 +422,57 @@ static int atkbd_set_3(struct atkbd *atkbd)
return 4;
}
-/*
- * Try to set the set we want.
- */
+ if (atkbd_set != 3)
+ return 2;
- param[0] = atkbd_set;
+ param[0] = 3;
if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
return 2;
-/*
- * Read set number. Beware here. Some keyboards always send '2'
- * or some other number regardless into what mode they have been
- * attempted to be set. Other keyboards treat the '0' command as
- * 'set to set 0', and not 'report current set' as they should.
- * In that case we time out, and return 2.
- */
-
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET))
return 2;
-/*
- * Here we return the set number the keyboard reports about
- * itself.
- */
+ if (param[0] != 3)
+ return 2;
- return (param[0] == 3) ? 3 : 2;
+ return 3;
}
-/*
- * atkbd_probe() probes for an AT keyboard on a serio port.
- */
-
-static int atkbd_probe(struct atkbd *atkbd)
+static int atkbd_enable(struct atkbd *atkbd)
{
- unsigned char param[2];
-
-/*
- * Some systems, where the bit-twiddling when testing the io-lines of the
- * controller may confuse the keyboard need a full reset of the keyboard. On
- * these systems the BIOS also usually doesn't do it for us.
- */
-
- if (atkbd_reset)
- if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
- printk(KERN_WARNING
- "atkbd.c: keyboard reset failed on %s\n",
- atkbd->serio->phys);
+ unsigned char param[1];
/*
- * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
- * Some keyboards report different values, but the first byte is always 0xab or
- * 0xac. Some old AT keyboards don't report anything.
+ * Set the LEDs to a defined state.
*/
- if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
+ param[0] = 0;
+ if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ return -1;
/*
- * If the get ID command failed, we check if we can at least set the LEDs on
- * the keyboard. This should work on every keyboard out there. It also turns
- * the LEDs off, which we want anyway.
+ * Set autorepeat to fastest possible.
*/
- param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
- return -1;
- atkbd->id = 0xabba;
- return 0;
- }
- if (param[0] != 0xab && param[0] != 0xac)
+ param[0] = 0;
+ if (atkbd_command(atkbd, param, ATKBD_CMD_SETREP))
return -1;
- atkbd->id = (param[0] << 8) | param[1];
/*
- * Set the LEDs to a defined state.
+ * Enable the keyboard to receive keystrokes.
*/
- param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) {
+ printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+ atkbd->serio->phys);
return -1;
+ }
return 0;
}
/*
- * Disable autorepeat. We don't need it, as we do it in software anyway,
- * because that way can get faster repeat, and have less system load (less
- * accesses to the slow ISA hardware). If this fails, we don't care, and will
- * just ignore the repeated keys.
- *
- * This command is for scancode set 3 only.
- */
-static void atkbd_disable_autorepeat(struct atkbd *atkbd)
-{
- atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB);
-}
-
-/*
* atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
* reboot.
*/
@@ -485,7 +496,7 @@ static void atkbd_disconnect(struct serio *serio)
}
/*
- * atkbd_connect() is called when the serio module finds an interface
+ * atkbd_connect() is called when the serio module finds and interface
* that isn't handled yet by an appropriate device driver. We check if
* there is an AT keyboard out there and if yes, we register ourselves
* to the input module.
@@ -513,6 +524,9 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
} else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ atkbd->dev.rep[REP_DELAY] = HZ/4 + HZ/50;
+ atkbd->dev.rep[REP_PERIOD] = HZ/33;
+
atkbd->serio = serio;
init_input_dev(&atkbd->dev);
@@ -525,6 +539,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
serio->private = atkbd;
+ init_timer(&atkbd->timer);
+ atkbd->timer.data = (long) atkbd;
+ atkbd->timer.function = atkbd_force_key_up;
+
if (serio_open(serio, dev)) {
kfree(atkbd);
return;
@@ -539,9 +557,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
}
atkbd->set = atkbd_set_3(atkbd);
- if (atkbd->set == 3)
- atkbd_disable_autorepeat(atkbd);
atkbd_enable(atkbd);
+
} else {
atkbd->set = 2;
atkbd->id = 0xab00;
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index a6b481994163..9105f6c697b3 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -19,9 +19,7 @@ config MOUSE_PS2
Say Y here if you have a PS/2 mouse connected to your system. This
includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
mice with wheels and extra buttons, Microsoft, Logitech or Genius
- compatible. Support for Synaptics TouchPads is also included.
- For Synaptics TouchPad support in XFree86 you'll need this XFree86
- driver: http://w1.894.telia.com/~u89404340/touchpad/index.html
+ compatible.
If unsure, say Y.
@@ -30,6 +28,22 @@ config MOUSE_PS2
The module will be called psmouse. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+config MOUSE_PS2_SYNAPTICS
+ bool "Synaptics TouchPad"
+ default n
+ depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2
+ ---help---
+ Say Y here if you have a Synaptics TouchPad connected to your system.
+ This touchpad is found on many modern laptop computers.
+
+ Note that you also need a user space driver to interpret the data
+ generated by the kernel. A compatible driver for XFree86 is available
+ from http://w1.894.telia.com/~u89404340/touchpad/index.html
+
+ The gpm program is not yet able to interpret the data from this
+ driver, so if you need to use the touchpad in the console, you have to
+ say N for now.
+
config MOUSE_SERIAL
tristate "Serial mouse"
depends on INPUT && INPUT_MOUSE && SERIO
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 030d23149e2e..4ed0da4e7d7e 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -17,6 +17,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
+#include <linux/pm.h>
#include "psmouse.h"
#include "synaptics.h"
#include "logips2pp.h"
@@ -29,6 +30,8 @@ MODULE_PARM(psmouse_resolution, "i");
MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
MODULE_PARM(psmouse_smartscroll, "i");
MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
+MODULE_PARM(psmouse_resetafter, "i");
+MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
MODULE_LICENSE("GPL");
#define PSMOUSE_LOGITECH_SMARTSCROLL 1
@@ -36,11 +39,12 @@ MODULE_LICENSE("GPL");
static int psmouse_noext;
int psmouse_resolution;
int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL;
+unsigned int psmouse_resetafter;
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
/*
- * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
+ * psmouse_process_packet() analyzes the PS/2 mouse packet contents and
* reports relevant events to the input module.
*/
@@ -108,6 +112,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
{
struct psmouse *psmouse = serio->private;
+ if (psmouse->state == PSMOUSE_IGNORE)
+ goto out;
+
if (psmouse->acking) {
switch (data) {
case PSMOUSE_RET_ACK:
@@ -132,20 +139,35 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
}
if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
- printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+ printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
+ psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->pktcnt = 0;
}
psmouse->last = jiffies;
psmouse->packet[psmouse->pktcnt++] = data;
- if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
- psmouse_process_packet(psmouse, regs);
- psmouse->pktcnt = 0;
- goto out;
+ if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
+ if (psmouse->pktcnt == 1)
+ goto out;
+
+ if (psmouse->pktcnt == 2) {
+ if (psmouse->packet[1] == PSMOUSE_RET_ID) {
+ psmouse->state = PSMOUSE_IGNORE;
+ serio_rescan(serio);
+ goto out;
+ }
+ if (psmouse->type == PSMOUSE_SYNAPTICS) {
+ /* neither 0xAA nor 0x00 are valid first bytes
+ * for a packet in absolute mode
+ */
+ psmouse->pktcnt = 0;
+ goto out;
+ }
+ }
}
- if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+ if (psmouse->type == PSMOUSE_SYNAPTICS) {
/*
* The synaptics driver has its own resync logic,
* so it needs to receive all bytes one at a time.
@@ -155,8 +177,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
goto out;
}
- if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
- serio_rescan(serio);
+ if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+ psmouse_process_packet(psmouse, regs);
+ psmouse->pktcnt = 0;
goto out;
}
out:
@@ -200,7 +223,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
psmouse->cmdcnt = receive;
if (command == PSMOUSE_CMD_RESET_BAT)
- timeout = 2000000; /* 2 sec */
+ timeout = 4000000; /* 4 sec */
if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff))
@@ -227,7 +250,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];
- if (psmouse->cmdcnt)
+ if (psmouse->cmdcnt)
return (psmouse->cmdcnt = 0) - 1;
return 0;
@@ -450,14 +473,18 @@ static void psmouse_initialize(struct psmouse *psmouse)
*/
psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+}
/*
- * Last, we enable the mouse so that we get reports from it.
+ * psmouse_activate() enables the mouse so that we get motion reports from it.
*/
+static void psmouse_activate(struct psmouse *psmouse)
+{
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
+ psmouse->state = PSMOUSE_ACTIVATED;
}
/*
@@ -478,13 +505,39 @@ static void psmouse_cleanup(struct serio *serio)
static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
+
+ psmouse->state = PSMOUSE_IGNORE;
+ synaptics_disconnect(psmouse);
input_unregister_device(&psmouse->dev);
serio_close(serio);
- synaptics_disconnect(psmouse);
kfree(psmouse);
}
/*
+ * Reinitialize mouse hardware after software suspend.
+ */
+
+static int psmouse_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
+{
+ struct psmouse *psmouse = dev->data;
+ struct serio_dev *ser_dev = psmouse->serio->dev;
+
+ synaptics_disconnect(psmouse);
+
+ /* We need to reopen the serio port to reinitialize the i8042 controller */
+ serio_close(psmouse->serio);
+ serio_open(psmouse->serio, ser_dev);
+
+ /* Probe and re-initialize the mouse */
+ psmouse_probe(psmouse);
+ psmouse_initialize(psmouse);
+ synaptics_pt_init(psmouse);
+ psmouse_activate(psmouse);
+
+ return 0;
+}
+
+/*
* psmouse_connect() is a callback from the serio module when
* an unhandled serio port is found.
*/
@@ -492,8 +545,10 @@ static void psmouse_disconnect(struct serio *serio)
static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
{
struct psmouse *psmouse;
+ struct pm_dev *pmdev;
- if ((serio->type & SERIO_TYPE) != SERIO_8042)
+ if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
+ (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
return;
if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
@@ -506,6 +561,7 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ psmouse->state = PSMOUSE_NEW_DEVICE;
psmouse->serio = serio;
psmouse->dev.private = psmouse;
@@ -522,6 +578,12 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
return;
}
+ pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
+ if (pmdev) {
+ psmouse->dev.pm_dev = pmdev;
+ pmdev->data = psmouse;
+ }
+
sprintf(psmouse->devname, "%s %s %s",
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
sprintf(psmouse->phys, "%s/input0",
@@ -539,6 +601,10 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
psmouse_initialize(psmouse);
+
+ synaptics_pt_init(psmouse);
+
+ psmouse_activate(psmouse);
}
static struct serio_dev psmouse_dev = {
@@ -567,9 +633,16 @@ static int __init psmouse_smartscroll_setup(char *str)
return 1;
}
+static int __init psmouse_resetafter_setup(char *str)
+{
+ get_option(&str, &psmouse_resetafter);
+ return 1;
+}
+
__setup("psmouse_noext", psmouse_noext_setup);
__setup("psmouse_resolution=", psmouse_resolution_setup);
__setup("psmouse_smartscroll=", psmouse_smartscroll_setup);
+__setup("psmouse_resetafter=", psmouse_resetafter_setup);
#endif
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 05a24de18d7d..a69cb72d8a80 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -13,9 +13,15 @@
#define PSMOUSE_CMD_RESET_BAT 0x02ff
#define PSMOUSE_RET_BAT 0xaa
+#define PSMOUSE_RET_ID 0x00
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
+/* psmouse states */
+#define PSMOUSE_NEW_DEVICE 0
+#define PSMOUSE_ACTIVATED 1
+#define PSMOUSE_IGNORE 2
+
struct psmouse {
void *private;
struct input_dev dev;
@@ -29,6 +35,7 @@ struct psmouse {
unsigned char type;
unsigned char model;
unsigned long last;
+ unsigned char state;
char acking;
volatile char ack;
char error;
@@ -36,16 +43,17 @@ struct psmouse {
char phys[32];
};
-#define PSMOUSE_PS2 1
-#define PSMOUSE_PS2PP 2
-#define PSMOUSE_PS2TPP 3
-#define PSMOUSE_GENPS 4
-#define PSMOUSE_IMPS 5
-#define PSMOUSE_IMEX 6
-#define PSMOUSE_SYNAPTICS 7
+#define PSMOUSE_PS2 1
+#define PSMOUSE_PS2PP 2
+#define PSMOUSE_PS2TPP 3
+#define PSMOUSE_GENPS 4
+#define PSMOUSE_IMPS 5
+#define PSMOUSE_IMEX 6
+#define PSMOUSE_SYNAPTICS 7
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
extern int psmouse_smartscroll;
+extern unsigned int psmouse_resetafter;
#endif /* _PSMOUSE_H */
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 5fa695eb774e..9ba48609d77e 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1,6 +1,9 @@
/*
* Synaptics TouchPad PS/2 mouse driver
*
+ * 2003 Dmitry Torokhov <dtor@mail.ru>
+ * Added support for pass-through port
+ *
* 2003 Peter Osterlund <petero2@telia.com>
* Ported to 2.5 input device infrastructure.
*
@@ -21,6 +24,7 @@
#include <linux/module.h>
#include <linux/input.h>
+#include <linux/serio.h>
#include "psmouse.h"
#include "synaptics.h"
@@ -71,7 +75,7 @@ static int synaptics_set_mode(struct psmouse *psmouse, unsigned char mode)
if (synaptics_special_cmd(psmouse, mode))
return -1;
- param[0] = 0x14;
+ param[0] = SYN_PS_SET_MODE2;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
@@ -83,7 +87,7 @@ static int synaptics_reset(struct psmouse *psmouse)
if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
return -1;
- if (r[0] == 0xAA && r[1] == 0x00)
+ if (r[0] == PSMOUSE_RET_BAT && r[1] == PSMOUSE_RET_ID)
return 0;
return -1;
}
@@ -106,16 +110,25 @@ static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_
* Read the capability-bits from the touchpad
* see also the SYN_CAP_* macros
*/
-static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
+static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability, unsigned long int *ext_cap)
{
unsigned char cap[3];
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1;
*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
- if (SYN_CAP_VALID(*capability))
- return 0;
- return -1;
+ *ext_cap = 0;
+ if (!SYN_CAP_VALID(*capability))
+ return -1;
+
+ if (SYN_EXT_CAP_REQUESTS(*capability)) {
+ if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
+ printk(KERN_ERR "Synaptics claims to have extended capabilities,"
+ " but I'm not able to read them.");
+ } else
+ *ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+ }
+ return 0;
}
/*
@@ -134,19 +147,11 @@ static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident)
return -1;
}
-static int synaptics_enable_device(struct psmouse *psmouse)
-{
- if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
- return -1;
- return 0;
-}
-
static void print_ident(struct synaptics_data *priv)
{
printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
- printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
+ printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
SYN_ID_MINOR(priv->identity));
-
if (SYN_MODEL_ROT180(priv->model_id))
printk(KERN_INFO " 180 degree mounted touchpad\n");
if (SYN_MODEL_PORTRAIT(priv->model_id))
@@ -159,12 +164,17 @@ static void print_ident(struct synaptics_data *priv)
if (SYN_CAP_EXTENDED(priv->capabilities)) {
printk(KERN_INFO " Touchpad has extended capability bits\n");
- if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+ printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
+ (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
+ else if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
printk(KERN_INFO " -> four buttons\n");
if (SYN_CAP_MULTIFINGER(priv->capabilities))
printk(KERN_INFO " -> multifinger detection\n");
if (SYN_CAP_PALMDETECT(priv->capabilities))
printk(KERN_INFO " -> palm detection\n");
+ if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+ printk(KERN_INFO " -> pass-through port\n");
}
}
@@ -172,6 +182,7 @@ static int query_hardware(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
int retries = 0;
+ int mode;
while ((retries++ < 3) && synaptics_reset(psmouse))
printk(KERN_ERR "synaptics reset failed\n");
@@ -180,17 +191,107 @@ static int query_hardware(struct psmouse *psmouse)
return -1;
if (synaptics_model_id(psmouse, &priv->model_id))
return -1;
- if (synaptics_capability(psmouse, &priv->capabilities))
+ if (synaptics_capability(psmouse, &priv->capabilities, &priv->ext_cap))
return -1;
- if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
- SYN_BIT_HIGH_RATE |
- SYN_BIT_DISABLE_GESTURE |
- SYN_BIT_W_MODE)))
+
+ mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
+ if (SYN_ID_MAJOR(priv->identity) >= 4)
+ mode |= SYN_BIT_DISABLE_GESTURE;
+ if (SYN_CAP_EXTENDED(priv->capabilities))
+ mode |= SYN_BIT_W_MODE;
+ if (synaptics_set_mode(psmouse, mode))
return -1;
- synaptics_enable_device(psmouse);
+ return 0;
+}
- print_ident(priv);
+/*****************************************************************************
+ * Synaptics pass-through PS/2 port support
+ ****************************************************************************/
+static int synaptics_pt_open(struct serio *port)
+{
+ return 0;
+}
+
+static void synaptics_pt_close(struct serio *port)
+{
+}
+
+static int synaptics_pt_write(struct serio *port, unsigned char c)
+{
+ struct psmouse *parent = port->driver;
+ char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
+
+ if (synaptics_special_cmd(parent, c))
+ return -1;
+ if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
+ return -1;
+ return 0;
+}
+
+static inline int synaptics_is_pt_packet(unsigned char *buf)
+{
+ return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
+}
+
+static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+{
+ struct psmouse *child = ptport->private;
+
+ if (child) {
+ if (child->state == PSMOUSE_ACTIVATED) {
+ serio_interrupt(ptport, packet[1], 0, NULL);
+ serio_interrupt(ptport, packet[4], 0, NULL);
+ serio_interrupt(ptport, packet[5], 0, NULL);
+ if (child->type >= PSMOUSE_GENPS)
+ serio_interrupt(ptport, packet[2], 0, NULL);
+ } else if (child->state != PSMOUSE_IGNORE) {
+ serio_interrupt(ptport, packet[1], 0, NULL);
+ }
+ }
+}
+
+int synaptics_pt_init(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+ struct serio *port;
+ struct psmouse *child;
+
+ if (psmouse->type != PSMOUSE_SYNAPTICS)
+ return -1;
+ if (!SYN_CAP_EXTENDED(priv->capabilities))
+ return -1;
+ if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
+ return -1;
+
+ priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!port) {
+ printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");
+ return -1;
+ }
+
+ memset(port, 0, sizeof(struct serio));
+ port->type = SERIO_PS_PSTHRU;
+ port->name = "Synaptics pass-through";
+ port->phys = "synaptics-pt/serio0";
+ port->write = synaptics_pt_write;
+ port->open = synaptics_pt_open;
+ port->close = synaptics_pt_close;
+ port->driver = psmouse;
+
+ printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
+ serio_register_slave_port(port);
+
+ /* adjust the touchpad to child's choice of protocol */
+ child = port->private;
+ if (child && child->type >= PSMOUSE_GENPS) {
+ if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+ SYN_BIT_HIGH_RATE |
+ SYN_BIT_DISABLE_GESTURE |
+ SYN_BIT_FOUR_BYTE_CLIENT |
+ SYN_BIT_W_MODE)))
+ printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+ }
return 0;
}
@@ -213,22 +314,27 @@ int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
+#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+ return -1;
+#endif
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));
- priv->inSync = 1;
+ priv->out_of_sync = 0;
if (query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
goto init_fail;
}
+ print_ident(priv);
+
/*
* The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
* which says that they should be valid regardless of the actual size of
- * the senser.
+ * the sensor.
*/
set_bit(EV_ABS, psmouse->dev.evbit);
set_abs_params(&psmouse->dev, ABS_X, 1472, 5472, 0, 0);
@@ -243,7 +349,24 @@ int synaptics_init(struct psmouse *psmouse)
set_bit(BTN_RIGHT, psmouse->dev.keybit);
set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
-
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+ switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+ default:
+ printk(KERN_ERR "This touchpad reports more than 8 multi-buttons, don't know how to handle.\n");
+ case 8:
+ set_bit(BTN_7, psmouse->dev.keybit);
+ set_bit(BTN_6, psmouse->dev.keybit);
+ case 6:
+ set_bit(BTN_5, psmouse->dev.keybit);
+ set_bit(BTN_4, psmouse->dev.keybit);
+ case 4:
+ set_bit(BTN_3, psmouse->dev.keybit);
+ set_bit(BTN_2, psmouse->dev.keybit);
+ case 2:
+ set_bit(BTN_1, psmouse->dev.keybit);
+ set_bit(BTN_0, psmouse->dev.keybit);
+ break;
+ }
clear_bit(EV_REL, psmouse->dev.evbit);
clear_bit(REL_X, psmouse->dev.relbit);
clear_bit(REL_Y, psmouse->dev.relbit);
@@ -259,42 +382,85 @@ void synaptics_disconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
- kfree(priv);
+ if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
+ synaptics_set_mode(psmouse, 0);
+ if (priv->ptport) {
+ serio_unregister_slave_port(priv->ptport);
+ kfree(priv->ptport);
+ }
+ kfree(priv);
+ }
}
/*****************************************************************************
* Functions to interpret the absolute mode packets
****************************************************************************/
-static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
+static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
{
- unsigned char *buf = priv->proto_buf;
-
- hw->x = (((buf[3] & 0x10) << 8) |
- ((buf[1] & 0x0f) << 8) |
- buf[4]);
- hw->y = (((buf[3] & 0x20) << 7) |
- ((buf[1] & 0xf0) << 4) |
- buf[5]);
-
- hw->z = buf[2];
- hw->w = (((buf[0] & 0x30) >> 2) |
- ((buf[0] & 0x04) >> 1) |
- ((buf[3] & 0x04) >> 2));
-
- hw->left = (buf[0] & 0x01) ? 1 : 0;
- hw->right = (buf[0] & 0x2) ? 1 : 0;
hw->up = 0;
hw->down = 0;
+ hw->b0 = 0;
+ hw->b1 = 0;
+ hw->b2 = 0;
+ hw->b3 = 0;
+ hw->b4 = 0;
+ hw->b5 = 0;
+ hw->b6 = 0;
+ hw->b7 = 0;
+
+ if (SYN_MODEL_NEWABS(priv->model_id)) {
+ hw->x = (((buf[3] & 0x10) << 8) |
+ ((buf[1] & 0x0f) << 8) |
+ buf[4]);
+ hw->y = (((buf[3] & 0x20) << 7) |
+ ((buf[1] & 0xf0) << 4) |
+ buf[5]);
+
+ hw->z = buf[2];
+ hw->w = (((buf[0] & 0x30) >> 2) |
+ ((buf[0] & 0x04) >> 1) |
+ ((buf[3] & 0x04) >> 2));
+
+ hw->left = (buf[0] & 0x01) ? 1 : 0;
+ hw->right = (buf[0] & 0x02) ? 1 : 0;
+ if (SYN_CAP_EXTENDED(priv->capabilities) &&
+ (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
+ hw->up = ((buf[3] & 0x01)) ? 1 : 0;
+ if (hw->left)
+ hw->up = !hw->up;
+ hw->down = ((buf[3] & 0x02)) ? 1 : 0;
+ if (hw->right)
+ hw->down = !hw->down;
+ }
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
+ ((buf[3] & 2) ? !hw->right : hw->right)) {
+ switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+ default:
+ ; /* we did comment while initialising... */
+ case 8:
+ hw->b7 = ((buf[5] & 0x08)) ? 1 : 0;
+ hw->b6 = ((buf[4] & 0x08)) ? 1 : 0;
+ case 6:
+ hw->b5 = ((buf[5] & 0x04)) ? 1 : 0;
+ hw->b4 = ((buf[4] & 0x04)) ? 1 : 0;
+ case 4:
+ hw->b3 = ((buf[5] & 0x02)) ? 1 : 0;
+ hw->b2 = ((buf[4] & 0x02)) ? 1 : 0;
+ case 2:
+ hw->b1 = ((buf[5] & 0x01)) ? 1 : 0;
+ hw->b0 = ((buf[4] & 0x01)) ? 1 : 0;
+ }
+ }
+ } else {
+ hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
+ hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);
+
+ hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
+ hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
- if (SYN_CAP_EXTENDED(priv->capabilities) &&
- (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
- hw->up = ((buf[3] & 0x01)) ? 1 : 0;
- if (hw->left)
- hw->up = !hw->up;
- hw->down = ((buf[3] & 0x02)) ? 1 : 0;
- if (hw->right)
- hw->down = !hw->down;
+ hw->left = (buf[0] & 0x01) ? 1 : 0;
+ hw->right = (buf[0] & 0x02) ? 1 : 0;
}
}
@@ -307,7 +473,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
struct synaptics_data *priv = psmouse->private;
struct synaptics_hw_state hw;
- synaptics_parse_hw_state(priv, &hw);
+ synaptics_parse_hw_state(psmouse->packet, priv, &hw);
if (hw.z > 0) {
int w_ok = 0;
@@ -347,7 +513,24 @@ static void synaptics_process_packet(struct psmouse *psmouse)
input_report_key(dev, BTN_RIGHT, hw.right);
input_report_key(dev, BTN_FORWARD, hw.up);
input_report_key(dev, BTN_BACK, hw.down);
-
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+ switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+ default:
+ ; /* we did comment while initialising... */
+ case 8:
+ input_report_key(dev, BTN_7, hw.b7);
+ input_report_key(dev, BTN_6, hw.b6);
+ case 6:
+ input_report_key(dev, BTN_5, hw.b5);
+ input_report_key(dev, BTN_4, hw.b4);
+ case 4:
+ input_report_key(dev, BTN_3, hw.b3);
+ input_report_key(dev, BTN_2, hw.b2);
+ case 2:
+ input_report_key(dev, BTN_1, hw.b1);
+ input_report_key(dev, BTN_0, hw.b0);
+ break;
+ }
input_sync(dev);
}
@@ -355,35 +538,59 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{
struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private;
- unsigned char *pBuf = priv->proto_buf;
- unsigned char u = psmouse->packet[0];
+ unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
+ int newabs = SYN_MODEL_NEWABS(priv->model_id);
input_regs(dev, regs);
- pBuf[priv->proto_buf_tail++] = u;
-
- /* check first byte */
- if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
- priv->inSync = 0;
- priv->proto_buf_tail = 0;
- printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
- return;
- }
+ switch (psmouse->pktcnt) {
+ case 1:
+ if (newabs ? ((data & 0xC8) != 0x80) : ((data & 0xC0) != 0xC0)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+ goto bad_sync;
+ }
+ break;
+ case 2:
+ if (!newabs && ((data & 0x60) != 0x00)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 2nd byte\n");
+ goto bad_sync;
+ }
+ break;
+ case 4:
+ if (newabs ? ((data & 0xC8) != 0xC0) : ((data & 0xC0) != 0x80)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+ goto bad_sync;
+ }
+ break;
+ case 5:
+ if (!newabs && ((data & 0x60) != 0x00)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 5th byte\n");
+ goto bad_sync;
+ }
+ break;
+ default:
+ if (psmouse->pktcnt >= 6) { /* Full packet received */
+ if (priv->out_of_sync) {
+ priv->out_of_sync = 0;
+ printk(KERN_NOTICE "Synaptics driver resynced.\n");
+ }
- /* check 4th byte */
- if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
- priv->inSync = 0;
- priv->proto_buf_tail = 0;
- printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
- return;
- }
+ if (priv->ptport && synaptics_is_pt_packet(psmouse->packet))
+ synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
+ else
+ synaptics_process_packet(psmouse);
- if (priv->proto_buf_tail >= 6) { /* Full packet received */
- if (!priv->inSync) {
- priv->inSync = 1;
- printk(KERN_NOTICE "Synaptics driver resynced.\n");
+ psmouse->pktcnt = 0;
}
- synaptics_process_packet(psmouse);
- priv->proto_buf_tail = 0;
+ break;
+ }
+ return;
+
+ bad_sync:
+ priv->out_of_sync++;
+ psmouse->pktcnt = 0;
+ if (psmouse_resetafter > 0 && priv->out_of_sync == psmouse_resetafter) {
+ psmouse->state = PSMOUSE_IGNORE;
+ serio_rescan(psmouse->serio);
}
}
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 6e3e029a3bdd..4dad98abd54e 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -12,6 +12,7 @@
extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_init(struct psmouse *psmouse);
+extern int synaptics_pt_init(struct psmouse *psmouse);
extern void synaptics_disconnect(struct psmouse *psmouse);
/* synaptics queries */
@@ -22,12 +23,14 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
#define SYN_QUE_RESOLUTION 0x08
+#define SYN_QUE_EXT_CAPAB 0x09
/* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
#define SYN_BIT_HIGH_RATE (1 << 6)
#define SYN_BIT_SLEEP_MODE (1 << 3)
#define SYN_BIT_DISABLE_GESTURE (1 << 2)
+#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1)
#define SYN_BIT_W_MODE (1 << 0)
/* synaptics model ID bits */
@@ -42,11 +45,14 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
/* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
+#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
+#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1)
+#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -62,6 +68,10 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
+/* synaptics special commands */
+#define SYN_PS_SET_MODE2 0x14
+#define SYN_PS_CLIENT_CMD 0x28
+
/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
@@ -75,21 +85,28 @@ struct synaptics_hw_state {
int right;
int up;
int down;
+ int b0;
+ int b1;
+ int b2;
+ int b3;
+ int b4;
+ int b5;
+ int b6;
+ int b7;
};
struct synaptics_data {
/* Data read from the touchpad */
unsigned long int model_id; /* Model-ID */
unsigned long int capabilities; /* Capabilities */
+ unsigned long int ext_cap; /* Extended Capabilities */
unsigned long int identity; /* Identification */
/* Data for normal processing */
- unsigned char proto_buf[6]; /* Buffer for Packet */
- unsigned char last_byte; /* last received byte */
- int inSync; /* Packets in sync */
- int proto_buf_tail;
-
+ unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */
+
+ struct serio *ptport; /* pass-through port */
};
#endif /* _SYNAPTICS_H */
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 78c51d96dea6..7c818a32628a 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -49,7 +49,9 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_register_slave_port);
EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_slave_port);
EXPORT_SYMBOL(serio_register_device);
EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open);
@@ -166,6 +168,17 @@ void serio_register_port(struct serio *serio)
up(&serio_sem);
}
+/*
+ * Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when registering a serio from other input device's
+ * connect() function.
+ */
+void serio_register_slave_port(struct serio *serio)
+{
+ list_add_tail(&serio->node, &serio_list);
+ serio_find_dev(serio);
+}
+
void serio_unregister_port(struct serio *serio)
{
down(&serio_sem);
@@ -175,6 +188,18 @@ void serio_unregister_port(struct serio *serio)
up(&serio_sem);
}
+/*
+ * Same as serio_unregister_port but does not try to acquire serio_sem.
+ * Should be used when unregistering a serio from other input device's
+ * disconnect() function.
+ */
+void serio_unregister_slave_port(struct serio *serio)
+{
+ list_del_init(&serio->node);
+ if (serio->dev && serio->dev->disconnect)
+ serio->dev->disconnect(serio);
+}
+
void serio_register_device(struct serio_dev *dev)
{
struct serio *serio;
@@ -204,9 +229,11 @@ void serio_unregister_device(struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_dev *dev)
{
- if (serio->open(serio))
- return -1;
serio->dev = dev;
+ if (serio->open(serio)) {
+ serio->dev = NULL;
+ return -1;
+ }
return 0;
}