summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Osterlund <petero2@telia.com>2004-07-23 12:21:11 +0200
committerPeter Osterlund <petero2@telia.com>2006-04-09 04:02:35 +0200
commit7ff083e441ec925ca0d138c5ec2a53e8a6435d99 (patch)
tree0f098f381f5c11ac6c9c048abc5de2900ce76a4f
parentf40f0e40ce01415baff8f86a8038ad8b6d02a118 (diff)
* Better default parameters for alps touchpads.
* Added Dmitry's updated alps patch that can do hardware auto-detection and also disables hardware tapping.
-rw-r--r--README.alps58
-rw-r--r--alps.patch502
2 files changed, 383 insertions, 177 deletions
diff --git a/README.alps b/README.alps
index 99ee0d8..55317e6 100644
--- a/README.alps
+++ b/README.alps
@@ -1,61 +1,41 @@
-It is possible to use the driver with an ALPS Glidepoint device, but
-you probably have to change some parameter values. One user reported
-success with the following settings:
+It is possible to use this driver with an ALPS Glidepoint device. If
+you use a 2.6 linux kernel, you need to apply the ALPS kernel patch
+in the alps.patch file.
- LeftEdge = 60
- RightEdge = 830
- TopEdge = 70
- BottomEdge = 650
- FingerLow = 25
- FingerHigh = 30
- MaxTapTime = 180
- MaxTapMove = 110
- EmulateMidButtonTime = 75
- VertScrollDelta = 50
- HorizScrollDelta = 50
- MinSpeed = 0.2
- MaxSpeed = 0.5
- AccelFactor = 0.01
- EdgeMotionSpeed = 40
- UpDownScrolling = 1
- TouchpadOff = 0
-
-If you use a 2.6 linux kernel, you need to apply the ALPS kernel patch
-in the alps.patch file. Note also that the auto-dev protocol option
-doesn't work for ALPS devices, so you have to use the "event" protocol
-instead and set the device option to the correct event device. (Look
-for a mouse device in /proc/bus/input/devices and see which event
-device it is connected to.) Here is an example InputDevice section for
-the XF86Config file.
+Since ALPS touchpads don't have the same resolution as Synaptics
+touchpads, you probably have to change some parameter values. Here is
+an example InputDevice section for the X configuration file.
Section "InputDevice"
Driver "synaptics"
Identifier "Mouse[1]"
- Option "Device" "/dev/input/event1"
- Option "Protocol" "event"
- Option "LeftEdge" "60"
+ Option "Device" "/dev/psaux"
+ Option "Protocol" "auto-dev"
+ Option "LeftEdge" "120"
Option "RightEdge" "830"
- Option "TopEdge" "70"
+ Option "TopEdge" "120"
Option "BottomEdge" "650"
- Option "FingerLow" "25"
- Option "FingerHigh" "30"
+ Option "FingerLow" "14"
+ Option "FingerHigh" "15"
Option "MaxTapTime" "180"
Option "MaxTapMove" "110"
Option "EmulateMidButtonTime" "75"
- Option "VertScrollDelta" "50"
- Option "HorizScrollDelta" "50"
+ Option "VertScrollDelta" "20"
+ Option "HorizScrollDelta" "20"
Option "MinSpeed" "0.2"
Option "MaxSpeed" "0.5"
Option "AccelFactor" "0.01"
- Option "EdgeMotionSpeed" "40"
+ Option "EdgeMotionMinSpeed" "15"
+ Option "EdgeMotionMaxSpeed" "15"
Option "UpDownScrolling" "1"
- Option "TouchpadOff" "0"
+ Option "CircularScrolling" "1"
+ Option "CircScrollDelta" "0.1"
+ Option "CircScrollTrigger" "2"
EndSection
If you use a 2.4 linux kernel, you don't need to patch the kernel, but
you should instead set "Device" and "Protocol" like this:
- Option "Device" "/dev/psaux"
Option "Protocol" "alps"
diff --git a/alps.patch b/alps.patch
index ce54f25..83934d8 100644
--- a/alps.patch
+++ b/alps.patch
@@ -1,145 +1,117 @@
+Hi,
-Vojtech Pavlik <vojtech@suse.cz> writes:
+I lifted some code off tpconfig and merged it with Peter's/Neil's ALPS driver.
+The driver will try to auto-detect presence of an ALPS touchpad by issuing
+E6/E7 requests and matching responses with known ALPS signatures. It will
+also try disabling hardware tapping so taps could be controlled by either
+userspace drivers (X/GPM) or future version of mousedev (2.6.8 I hope will
+have it).
-> On Sun, Oct 05, 2003 at 06:55:31PM +0200, Peter Osterlund wrote:
->
-> > I have updated your patch for kernel 2.6.0-test6-bk6 and made it
-> > report events compatible with the synaptics touchpad kernel driver.
-> > This should make it possible to use an ALPS device with the XFree86
-> > synaptics driver:
-> >
-> > http://w1.894.telia.com/~u89404340/touchpad/index.html
-> >
-> > Using this driver will give you edge scrolling and similar things.
-> >
-> > I don't have an ALPS GlidePoint so I haven't been able to test this
-> > patch at all. Test reports are appreciated. You probably need to
-> > change a few parameters in the X configuration, like edge parameters
-> > and finger pressure thresholds. Also note that the auto detection will
-> > not work with an ALPS device, so you have to use Protocol="event" and
-> > Device="/dev/input/eventN" for some value of N.
->
-> Very nice. Could you also make it a separate file? I think it's enough
-> code to make that worth it ...
+Please give it a try.
+
+--
+Dmitry
-Here is a new patch that moves the ALPS code to a separate file. The
-logic in ALPS_process_packet() has also gone through a few iterations
-with Johan Braennlund as a tester, so that it actually even works now,
-at least with his touchpad.
-
-Note though that the potential problems mentioned by Neil Brown in his
-initial announcement have not been dealt with:
-
- It appears (but see 1) that it is not possible to reliably detect
- an ALPS device.
- ...
- So the current code always sends the ALPS set-absolute-mode
- sequence (4 disables before the enable) unless a
- non-3-byte-protocol device was detected.
-
- There are two consequences of always assuming an ALPS that may not
- be good.
- 1) The mouse always claims to generate various ABS events even
- when there might not be any ABS-generating device behind the
- mouse.
- 2) The driver could misinterpret a normal mouse event that
- overflowed in the negative direction for both X and Y as part
- of an ALPS absolute event. This is because ALPS absolute
- events are detected by checking if the top 5 bits of the first
- byte are all one. I doubt this is a real problem as double
- overflows are very unlikely (aren't they?)
+---
linux-petero/drivers/input/mouse/Makefile | 2
- linux-petero/drivers/input/mouse/alps.c | 137 ++++++++++++++++++++++++
- linux-petero/drivers/input/mouse/alps.h | 17 ++
- linux-petero/drivers/input/mouse/psmouse-base.c | 8 +
- linux-petero/drivers/input/mouse/psmouse.h | 1
- 5 files changed, 164 insertions(+), 1 deletion(-)
+ linux-petero/drivers/input/mouse/alps.c | 359 ++++++++++++++++++++++++
+ linux-petero/drivers/input/mouse/alps.h | 17 +
+ linux-petero/drivers/input/mouse/psmouse-base.c | 24 +
+ linux-petero/drivers/input/mouse/psmouse.h | 4
+ 5 files changed, 404 insertions(+), 2 deletions(-)
diff -puN drivers/input/mouse/Makefile~alps drivers/input/mouse/Makefile
---- linux/drivers/input/mouse/Makefile~alps 2004-06-08 23:17:59.940957256 +0200
-+++ linux-petero/drivers/input/mouse/Makefile 2004-06-08 23:17:59.963953760 +0200
-@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_PS2) += psmouse.o
+--- linux/drivers/input/mouse/Makefile~alps 2004-07-21 17:24:22.499256904 +0200
++++ linux-petero/drivers/input/mouse/Makefile 2004-07-21 17:24:22.504256144 +0200
+@@ -14,4 +14,4 @@ obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
-psmouse-objs := psmouse-base.o logips2pp.o synaptics.o
-+psmouse-objs := psmouse-base.o logips2pp.o alps.o synaptics.o
++psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o
diff -puN /dev/null drivers/input/mouse/alps.c
--- /dev/null 2004-02-23 22:02:56.000000000 +0100
-+++ linux-petero/drivers/input/mouse/alps.c 2004-06-08 23:17:59.963953760 +0200
-@@ -0,0 +1,137 @@
++++ linux-petero/drivers/input/mouse/alps.c 2004-07-21 17:24:22.504256144 +0200
+@@ -0,0 +1,359 @@
+/*
+ * ALPS touchpad PS/2 mouse driver
+ *
+ * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
++ * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
++ *
++ * ALPS detection, tap switching and status querying info is taken from
++ * tpconfig utility (by C. Scott Ananian and Bruce Kall).
+ *
+ * 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 "alps.h"
+#include <linux/input.h>
+#include <linux/serio.h>
-+#include "psmouse.h"
+
-+static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
-+{
-+ dev->absmin[axis] = min;
-+ dev->absmax[axis] = max;
-+ dev->absfuzz[axis] = fuzz;
-+ dev->absflat[axis] = flat;
++#include "psmouse.h"
++#include "alps.h"
+
-+ set_bit(axis, dev->absbit);
-+}
++#define DEBUG
++#ifdef DEBUG
++#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg)
++#else
++#define dbg(format, arg...) do {} while (0)
++#endif
+
-+/*
-+ * If it is a 3-byte setting and we are allowed to use extensions,
-+ * then it could be an ALPS Glidepoint, so send the init sequence just
-+ * incase. i.e. 4 consecutive "disable"s before the "enable"
-+ */
++#define ALPS_MODEL_GLIDEPOINT 1
++#define ALPS_MODEL_DUALPOINT 2
+
-+void ALPS_initialize(struct psmouse *psmouse)
-+{
-+ if (psmouse->type < PSMOUSE_GENPS) {
-+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE);
-+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE);
-+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE);
-+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE);
-+
-+ set_bit(BTN_TOUCH, psmouse->dev.keybit);
-+ set_bit(BTN_BACK, psmouse->dev.keybit);
-+ set_bit(BTN_FORWARD, psmouse->dev.keybit);
-+ set_bit(BTN_TOOL_FINGER, psmouse->dev.keybit);
-+ set_bit(EV_ABS, psmouse->dev.evbit);
-+ set_abs_params(&psmouse->dev, ABS_X, 0, 0, 0, 0);
-+ set_abs_params(&psmouse->dev, ABS_Y, 0, 0, 0, 0);
-+ set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0);
-+ }
-+}
++struct alps_model_info {
++ unsigned char signature[3];
++ unsigned char model;
++} alps_model_data[] = {
++ { { 0x33, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x53, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x53, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x63, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x63, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x73, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x73, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x63, 0x02, 0x28 }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x63, 0x02, 0x3c }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x63, 0x02, 0x50 }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x63, 0x02, 0x64 }, ALPS_MODEL_GLIDEPOINT },
++ { { 0x20, 0x02, 0x0e }, ALPS_MODEL_DUALPOINT },
++ { { 0x22, 0x02, 0x0a }, ALPS_MODEL_DUALPOINT },
++ { { 0x22, 0x02, 0x14 }, ALPS_MODEL_DUALPOINT },
++};
+
+/*
+ * ALPS abolute Mode
-+ * byte 0: 1 1 1 1 1 mid0 rig0 lef0
-+ * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
-+ * byte 2: 0 x10 x9 x8 x7 up1 fin ges
-+ * byte 3: 0 y9 y8 y7 1 mid1 rig1 lef1
-+ * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
-+ * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
++ * byte 0: 1 1 1 1 1 mid0 rig0 lef0
++ * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
++ * byte 2: 0 x10 x9 x8 x7 up1 fin ges
++ * byte 3: 0 y9 y8 y7 1 mid1 rig1 lef1
++ * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
++ * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+ *
+ * On a dualpoint, {mid,rig,lef}0 are the stick, 1 are the pad.
+ * We just 'or' them together for now.
+ *
++ * We used to send 'ges'tures as BTN_TOUCH but this made it impossible
++ * to disable tap events in the synaptics driver since the driver
++ * was unable to distinguish a gesture tap from an actual button click.
++ * A tap gesture now creates an emulated touch that the synaptics
++ * driver can interpret as a tap event, if MaxTapTime=0 and
++ * MaxTapMove=0 then the driver will ignore taps.
++ *
+ * The touchpad on an 'Acer Aspire' has 4 buttons:
+ * left,right,up,down.
+ * This device always sets {mid,rig,lef}0 to 1 and
+ * reflects left,right,down,up in lef1,rig1,mid1,up1.
+ */
+
-+static void ALPS_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
++static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
+{
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = &psmouse->dev;
@@ -152,6 +124,9 @@ diff -puN /dev/null drivers/input/mouse/alps.c
+ y = (packet[4] & 0x7f) | ((packet[3] & 0x70)<<(7-4));
+ z = packet[5];
+
++ if (z > 30) input_report_key(dev, BTN_TOUCH, 1);
++ if (z < 25) input_report_key(dev, BTN_TOUCH, 0);
++
+ if (z > 0) {
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
@@ -159,9 +134,6 @@ diff -puN /dev/null drivers/input/mouse/alps.c
+ input_report_abs(dev, ABS_PRESSURE, z);
+ input_report_key(dev, BTN_TOOL_FINGER, z > 0);
+
-+ if (z > 30) input_report_key(dev, BTN_TOUCH, 1);
-+ if (z < 25) input_report_key(dev, BTN_TOUCH, 0);
-+
+ left |= (packet[2] ) & 1;
+ left |= (packet[3] ) & 1;
+ right |= (packet[3] >> 1) & 1;
@@ -189,27 +161,242 @@ diff -puN /dev/null drivers/input/mouse/alps.c
+ input_sync(dev);
+}
+
-+int ALPS_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
++static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
++{
++ /* ALPS absolute mode packets start with 0b11111mrl */
++ if ((psmouse->packet[0] & 0xf8) != 0xf8)
++ return PSMOUSE_BAD_DATA;
++
++ /* Bytes 2 - 6 should have 0 in the highest bit */
++ if (psmouse->pktcnt > 1 && psmouse->pktcnt <= 6 &&
++ (psmouse->packet[psmouse->pktcnt] & 0x80))
++ return PSMOUSE_BAD_DATA;
++
++ if (psmouse->pktcnt == 6) {
++ alps_process_packet(psmouse, regs);
++ return PSMOUSE_FULL_PACKET;
++ }
++
++ return PSMOUSE_GOOD_DATA;
++}
++
++int alps_get_model(struct psmouse *psmouse)
+{
-+ if (psmouse->type >= PSMOUSE_GENPS)
++ unsigned char param[4];
++ int i;
++
++ /*
++ * First try "E6 report".
++ * ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64
++ */
++ param[0] = 0;
++ if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
++ return -1;
++
++ param[0] = param[1] = param[2] = 0xff;
++ if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+ return -1;
+
-+ /* ALPS absolute mode packets start with 0b11111mrl
-+ * Normal mouse packets are extremely unlikely to overflow both
-+ * x and y
++ dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
++
++ if (param[0] != 0x00 || param[1] != 0x00 || (param[2] != 0x0a && param[2] != 0x64))
++ return -1;
++
++ /* Now try "E7 report". ALPS should return 0x33 in byte 1 */
++ param[0] = 0;
++ if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21))
++ return -1;
++
++ param[0] = param[1] = param[2] = 0xff;
++ if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
++ return -1;
++
++ dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
++
++ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
++ if (!memcmp(param, alps_model_data[i].signature, sizeof(alps_model_data[i].signature)))
++ return alps_model_data[i].model;
++
++ return -1;
++}
++
++static int alps_absolute_mode(struct psmouse *psmouse)
++{
++ /* Try ALPS magic knock - 4 disable before enable */
++ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
++ return -1;
++
++ /*
++ * Switch mouse to poll (remote) mode so motion data will not
++ * get in our way
+ */
-+ if ((psmouse->packet[0] & 0xf8) != 0xf8)
++ return psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETPOLL);
++}
++
++static int alps_get_status(struct psmouse *psmouse, char *param)
++{
++ /* Get status: 0xF5 0xF5 0xF5 0xE9 */
++ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+ return -1;
+
-+ if (psmouse->pktcnt == 6) {
-+ ALPS_process_packet(psmouse, regs);
-+ psmouse->pktcnt = 0;
++ dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
++
++ return 0;
++}
++
++/*
++ * For DualPint devices select the device that should respond to
++ * subsequent commands. It looks like glidepad is behind stickpointer,
++ * I'd thought it would be other way around...
++ */
++static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
++{
++ unsigned char param[3];
++ int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
++
++ if (psmouse_command(psmouse, NULL, cmd) ||
++ psmouse_command(psmouse, NULL, cmd) ||
++ psmouse_command(psmouse, NULL, cmd) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE))
++ return -1;
++
++ /* we may get 3 more bytes, just ignore them */
++ psmouse_command(psmouse, param, 0x0300);
++
++ return 0;
++}
++
++/*
++ * Turn touchpad tappinig on or off. The sequence are:
++ * 0xE9 0xF5 0xF5 0xF3 0x0A to enable,
++ * 0xE9 0xF5 0xF5 0xE8 0x00 to disable.
++ * My guess that 0xE9 (GetInfo) is here as a sync point.
++ * For models that also have stickpointer (DualPoints) its tapping
++ * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but
++ * we don't fiddle with it.
++ */
++static int alps_tap_mode(struct psmouse *psmouse, int model, int enable)
++{
++ int rc = 0;
++ int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
++ unsigned char tap_arg = enable ? 0x0A : 0x00;
++ unsigned char param[4];
++
++ if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
++ return -1;
++
++ if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
++ psmouse_command(psmouse, &tap_arg, cmd))
++ rc = -1;
++
++ if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
++ return -1;
++
++ if (alps_get_status(psmouse, param))
++ return -1;
++
++
++ return rc;
++}
++
++static int alps_reconnect(struct psmouse *psmouse)
++{
++ int model;
++ unsigned char param[4];
++
++ if ((model = alps_get_model(psmouse)) < 0)
++ return -1;
++
++ if (alps_get_status(psmouse, param))
++ return -1;
++
++ if ((model == ALPS_MODEL_DUALPOINT ? param[2] : param[0]) & 0x04)
++ alps_tap_mode(psmouse, model, 0);
++
++ if (alps_absolute_mode(psmouse)) {
++ printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
++ return -1;
+ }
++
+ return 0;
+}
++
++static void alps_disconnect(struct psmouse *psmouse)
++{
++ psmouse_reset(psmouse);
++}
++
++int alps_init(struct psmouse *psmouse)
++{
++ unsigned char param[4];
++ int model;
++
++ if ((model = alps_get_model(psmouse)) < 0)
++ return -1;
++
++ if (alps_get_status(psmouse, param)) {
++ printk(KERN_ERR "alps.c: touchpad status report request failed\n");
++ return -1;
++ }
++
++ printk(KERN_INFO "ALPS Touchpad (%s) detected\n",
++ model == ALPS_MODEL_GLIDEPOINT ? "Glidepoint" : "Dualpoint");
++
++ if ((model == ALPS_MODEL_DUALPOINT ? param[2] : param[0]) & 0x04) {
++ printk(KERN_INFO " Disabling hardware tapping\n");
++ if (alps_tap_mode(psmouse, model, 0))
++ printk(KERN_WARNING "alps.c: Failed to disable hardware tapping\n");
++ }
++
++ if (alps_absolute_mode(psmouse)) {
++ printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
++ return -1;
++ }
++
++ psmouse->dev.evbit[LONG(EV_REL)] &= ~BIT(EV_REL);
++ psmouse->dev.relbit[LONG(REL_X)] &= ~BIT(REL_X);
++ psmouse->dev.relbit[LONG(REL_X)] &= ~BIT(REL_X);
++
++ psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
++ input_set_abs_params(&psmouse->dev, ABS_X, 0, 0, 0, 0);
++ input_set_abs_params(&psmouse->dev, ABS_Y, 0, 0, 0, 0);
++ input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0);
++
++ psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
++ psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
++ psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
++ psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
++
++ psmouse->protocol_handler = alps_process_byte;
++ psmouse->disconnect = alps_disconnect;
++ psmouse->reconnect = alps_reconnect;
++
++ return 0;
++}
++
++int alps_detect(struct psmouse *psmouse)
++{
++ return alps_get_model(psmouse) < 0 ? 0 : 1;
++}
++
diff -puN /dev/null drivers/input/mouse/alps.h
--- /dev/null 2004-02-23 22:02:56.000000000 +0100
-+++ linux-petero/drivers/input/mouse/alps.h 2004-06-08 23:17:59.963953760 +0200
++++ linux-petero/drivers/input/mouse/alps.h 2004-07-21 17:24:22.504256144 +0200
@@ -0,0 +1,17 @@
+/*
+ * ALPS touchpad PS/2 mouse driver
@@ -223,15 +410,23 @@ diff -puN /dev/null drivers/input/mouse/alps.h
+
+#ifndef _ALPS_H
+#define _ALPS_H
-+struct psmouse;
-+struct pt_regs;
-+void ALPS_initialize(struct psmouse *psmouse);
-+int ALPS_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
++
++int alps_detect(struct psmouse *psmouse);
++int alps_init(struct psmouse *psmouse);
++
+#endif
diff -puN drivers/input/mouse/psmouse-base.c~alps drivers/input/mouse/psmouse-base.c
---- linux/drivers/input/mouse/psmouse-base.c~alps 2004-06-08 23:17:59.943956800 +0200
-+++ linux-petero/drivers/input/mouse/psmouse-base.c 2004-06-08 23:27:27.101735712 +0200
-@@ -21,6 +21,7 @@
+--- linux/drivers/input/mouse/psmouse-base.c~alps 2004-07-21 17:24:22.500256752 +0200
++++ linux-petero/drivers/input/mouse/psmouse-base.c 2004-07-21 17:24:22.505255992 +0200
+@@ -2,6 +2,7 @@
+ * PS/2 mouse driver
+ *
+ * Copyright (c) 1999-2002 Vojtech Pavlik
++ * Copyright (c) 2003-2004 Dmitry Torokhov
+ */
+
+ /*
+@@ -21,6 +22,7 @@
#include "psmouse.h"
#include "synaptics.h"
#include "logips2pp.h"
@@ -239,31 +434,55 @@ diff -puN drivers/input/mouse/psmouse-base.c~alps drivers/input/mouse/psmouse-ba
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("PS/2 mouse driver");
-@@ -203,6 +204,10 @@ static irqreturn_t psmouse_interrupt(str
- }
- }
+@@ -53,7 +55,7 @@ __obsolete_setup("psmouse_smartscroll=")
+ __obsolete_setup("psmouse_resetafter=");
+ __obsolete_setup("psmouse_rate=");
-+ if ((psmouse_max_proto > PSMOUSE_PS2) &&
-+ !ALPS_process_byte(psmouse, regs))
-+ goto out;
-+
- rc = psmouse->protocol_handler(psmouse, regs);
+-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
++static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
- switch (rc) {
-@@ -595,6 +600,9 @@ static void psmouse_initialize(struct ps
- */
+ /*
+ * psmouse_process_byte() analyzes the PS/2 data stream and reports
+@@ -442,6 +444,26 @@ static int psmouse_extensions(struct psm
+ synaptics_reset(psmouse);
+ }
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
++/*
++ * Try ALPS TouchPad
++ */
++ if (max_proto > PSMOUSE_PS2 && alps_detect(psmouse)) {
++
++ if (set_properties) {
++ psmouse->vendor = "ALPS";
++ psmouse->name = "TouchPad";
++ }
++
++ if (max_proto > PSMOUSE_IMEX)
++ if (!set_properties || alps_init(psmouse) == 0)
++ return PSMOUSE_ALPS;
+
-+ if (psmouse_max_proto > PSMOUSE_PS2)
-+ ALPS_initialize(psmouse);
- }
++/*
++ * Don't try anything fancy, just basic Intellimouse/Explorer protocols
++ */
++ max_proto = PSMOUSE_IMEX;
++ }
++
+ if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
- /*
+ if (set_properties) {
diff -puN drivers/input/mouse/psmouse.h~alps drivers/input/mouse/psmouse.h
---- linux/drivers/input/mouse/psmouse.h~alps 2004-06-08 23:17:59.944956648 +0200
-+++ linux-petero/drivers/input/mouse/psmouse.h 2004-06-08 23:17:59.965953456 +0200
-@@ -9,6 +9,7 @@
+--- linux/drivers/input/mouse/psmouse.h~alps 2004-07-21 17:24:22.501256600 +0200
++++ linux-petero/drivers/input/mouse/psmouse.h 2004-07-21 17:24:22.505255992 +0200
+@@ -2,13 +2,16 @@
+ #define _PSMOUSE_H
+
+ #define PSMOUSE_CMD_SETSCALE11 0x00e6
++#define PSMOUSE_CMD_SETSCALE21 0x00e7
+ #define PSMOUSE_CMD_SETRES 0x10e8
+ #define PSMOUSE_CMD_GETINFO 0x03e9
+ #define PSMOUSE_CMD_SETSTREAM 0x00ea
++#define PSMOUSE_CMD_SETPOLL 0x00f0
+ #define PSMOUSE_CMD_POLL 0x03eb
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
@@ -271,5 +490,12 @@ diff -puN drivers/input/mouse/psmouse.h~alps drivers/input/mouse/psmouse.h
#define PSMOUSE_CMD_RESET_DIS 0x00f6
#define PSMOUSE_CMD_RESET_BAT 0x02ff
-
+@@ -72,6 +75,7 @@ struct psmouse {
+ #define PSMOUSE_IMPS 5
+ #define PSMOUSE_IMEX 6
+ #define PSMOUSE_SYNAPTICS 7
++#define PSMOUSE_ALPS 8
+
+ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
_