* [PATCH 0/7] Additional ALPS touchpad protocol support
@ 2011-10-26 21:14 Seth Forshee
2011-10-26 21:14 ` [PATCH 1/7] Input: ALPS - Move protocol information to Documentation Seth Forshee
` (7 more replies)
0 siblings, 8 replies; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
This patch series adds support for two ALPS touchpad protocol versions
currently unsupported by the driver, which I've arbitrarily called
versions 3 and 4 (with the two currently supported protocol versions
changed to be called versions 1 and 2). The v3 touchpads are commonly
found on Dell laptops, and the v4 touchpads are found on machines from a
variety of other manufacturers.
Both the v3 and v4 touchpads are capable of low-resolution semi-MT
support, but this series only includes support for semi-MT on v3. The v4
protocol has a quirky format, with each data packet containing a full
set of high-resolution ST coordinates and 1/3 of a set of MT data. Thus
we receive 3 ST coordinates for every set of MT coordinates, and we can
only determine the number of contacts every third packet as well. I
haven't spent much time trying to work out the best way to handle this
yet; suggestions are appreciated.
Patches 1-4 are preparatory patches. Patch 5 adds ST support for the v3
and v4 protocols, and patch 6 adds semi-MT support for the v3 protocol.
Patch 7 documents both protocols.
These patches have been through numerous rounds of user testing with
various laptop models and are working well at this point.
Special thanks to Andy Skalski, who made my job much easier by doing
much of the grunt work to reverse-engineer the v3 protocol.
Thanks,
Seth
Seth Forshee (7):
Input: ALPS - Move protocol information to Documentation
Input: psmouse - Add PSMOUSE_CMD_RESET_WRAP
Input: ALPS - Add protocol version field in alps_model_info
Input: ALPS - Remove assumptions about packet size
Input: ALPS - Add support for protocol versions 3 and 4
Input: ALPS - Add semi-MT support for v3 protocol
Input: ALPS - Add documentation for protocol versions 3 and 4
Documentation/input/alps.txt | 188 ++++++++
drivers/input/mouse/alps.c | 1047 +++++++++++++++++++++++++++++++++++++----
drivers/input/mouse/alps.h | 19 +
drivers/input/mouse/psmouse.h | 1 +
4 files changed, 1170 insertions(+), 85 deletions(-)
create mode 100644 Documentation/input/alps.txt
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/7] Input: ALPS - Move protocol information to Documentation
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
@ 2011-10-26 21:14 ` Seth Forshee
2011-10-30 15:33 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 2/7] Input: psmouse - Add PSMOUSE_CMD_RESET_WRAP Seth Forshee
` (6 subsequent siblings)
7 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
In preparation for new protocol support, move the protocol
information currently documented in alps.c to
Documentation/input/alps.txt, where it can be expanded without
cluttering up the driver.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
Documentation/input/alps.txt | 75 ++++++++++++++++++++++++++++++++++++++++++
drivers/input/mouse/alps.c | 37 +--------------------
2 files changed, 76 insertions(+), 36 deletions(-)
create mode 100644 Documentation/input/alps.txt
diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt
new file mode 100644
index 0000000..ab5478f
--- /dev/null
+++ b/Documentation/input/alps.txt
@@ -0,0 +1,75 @@
+ALPS Touchpad Protocol
+----------------------
+
+Introduction
+------------
+
+Currently the ALPS touchpad driver supports two protocol versions in use by
+ALPS touchpads, the "old" and "new" protocol versions. Fundamentally these
+differ only in the format of their event packets (in reality many features may
+be found on new protocol devices that aren't found on the old protocol
+devices, but these are handled transparently as feature differences rather
+than protocol differences).
+
+Detection
+---------
+
+All ALPS touchpads should respond to the "E6 report" command sequence:
+E8-E6-E6-E6-E9. An ALPS touchpad should respond with either 00-00-0A or
+00-00-64.
+
+If the E6 report is successful, the touchpad model is identified using the "E7
+report" sequence: E8-E7-E7-E7-E9. The response is the model signature and is
+matched against known models in the alps_model_data_array.
+
+Packet Format
+-------------
+
+In the following tables, the following notation us used.
+
+ CAPITALS = stick, miniscules = touchpad
+
+?'s can have different meanings on different models, such as wheel rotation,
+extra buttons, stick buttons on a dualpoint, etc.
+
+PS/2 packet format
+------------------
+
+ byte 0: 0 0 YSGN XSGN 1 M R L
+ byte 1: X7 X6 X5 X4 X3 X2 X1 X0
+ byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+
+Note that the device never signals overflow condition.
+
+ALPS Absolute Mode - Old Format
+-------------------------------
+
+ byte 0: 1 0 0 0 1 x9 x8 x7
+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0
+ byte 2: 0 ? ? l r ? fin ges
+ byte 3: 0 ? ? ? ? y9 y8 y7
+ byte 4: 0 y6 y5 y4 y3 y2 y1 y0
+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+
+ALPS Absolute Mode - New Format
+-------------------------------
+
+ byte 0: 1 ? ? ? 1 ? ? ?
+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0
+ byte 2: 0 x10 x9 x8 x7 ? fin ges
+ byte 3: 0 y9 y8 y7 1 M R L
+ byte 4: 0 y6 y5 y4 y3 y2 y1 y0
+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+
+Dualpoint device -- interleaved packet format
+---------------------------------------------
+
+ byte 0: 1 1 0 0 1 1 1 1
+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0
+ byte 2: 0 x10 x9 x8 x7 0 fin ges
+ byte 3: 0 0 YSGN XSGN 1 1 1 1
+ byte 4: X7 X6 X5 X4 X3 X2 X1 X0
+ byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+ byte 6: 0 y9 y8 y7 1 m r l
+ byte 7: 0 y6 y5 y4 y3 y2 y1 y0
+ byte 8: 0 z6 z5 z4 z3 z2 z1 z0
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 99d5876..ad15e7c 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -74,42 +74,7 @@ static const struct alps_model_info alps_model_data[] = {
* isn't valid per PS/2 spec.
*/
-/*
- * PS/2 packet format
- *
- * byte 0: 0 0 YSGN XSGN 1 M R L
- * byte 1: X7 X6 X5 X4 X3 X2 X1 X0
- * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
- *
- * Note that the device never signals overflow condition.
- *
- * ALPS absolute Mode - new format
- *
- * byte 0: 1 ? ? ? 1 ? ? ?
- * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
- * byte 2: 0 x10 x9 x8 x7 ? fin ges
- * byte 3: 0 y9 y8 y7 1 M R L
- * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
- * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
- *
- * Dualpoint device -- interleaved packet format
- *
- * byte 0: 1 1 0 0 1 1 1 1
- * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
- * byte 2: 0 x10 x9 x8 x7 0 fin ges
- * byte 3: 0 0 YSGN XSGN 1 1 1 1
- * byte 4: X7 X6 X5 X4 X3 X2 X1 X0
- * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
- * byte 6: 0 y9 y8 y7 1 m r l
- * byte 7: 0 y6 y5 y4 y3 y2 y1 y0
- * byte 8: 0 z6 z5 z4 z3 z2 z1 z0
- *
- * CAPITALS = stick, miniscules = touchpad
- *
- * ?'s can have different meanings on different models,
- * such as wheel rotation, extra buttons, stick buttons
- * on a dualpoint, etc.
- */
+/* Packet formats are described in Documentation/input/alps.txt */
static bool alps_is_valid_first_byte(const struct alps_model_info *model,
unsigned char data)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 2/7] Input: psmouse - Add PSMOUSE_CMD_RESET_WRAP
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
2011-10-26 21:14 ` [PATCH 1/7] Input: ALPS - Move protocol information to Documentation Seth Forshee
@ 2011-10-26 21:14 ` Seth Forshee
2011-10-30 15:33 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 3/7] Input: ALPS - Add protocol version field in alps_model_info Seth Forshee
` (5 subsequent siblings)
7 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
Add this command in preparation for new ALPS protocol support.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
drivers/input/mouse/psmouse.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 593e910..c2b5aa6 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -8,6 +8,7 @@
#define PSMOUSE_CMD_SETSTREAM 0x00ea
#define PSMOUSE_CMD_SETPOLL 0x00f0
#define PSMOUSE_CMD_POLL 0x00eb /* caller sets number of bytes to receive */
+#define PSMOUSE_CMD_RESET_WRAP 0x00ec
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
--
1.7.5.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 3/7] Input: ALPS - Add protocol version field in alps_model_info
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
2011-10-26 21:14 ` [PATCH 1/7] Input: ALPS - Move protocol information to Documentation Seth Forshee
2011-10-26 21:14 ` [PATCH 2/7] Input: psmouse - Add PSMOUSE_CMD_RESET_WRAP Seth Forshee
@ 2011-10-26 21:14 ` Seth Forshee
2011-10-30 15:34 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 4/7] Input: ALPS - Remove assumptions about packet size Seth Forshee
` (4 subsequent siblings)
7 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
In preparation for adding support for more ALPS protocol versions,
add a field for the protocol version to the model info instead of
using a field in the flags. OLDPROTO and !OLDPROTO are now called
version 1 and version 2, repsectively.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
drivers/input/mouse/alps.c | 47 +++++++++++++++++++++----------------------
drivers/input/mouse/alps.h | 4 +++
2 files changed, 27 insertions(+), 24 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index ad15e7c..572cb21 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -30,7 +30,6 @@
#define dbg(format, arg...) do {} while (0)
#endif
-#define ALPS_OLDPROTO 0x01 /* old style input */
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
#define ALPS_PASS 0x04 /* device has a pass-through port */
@@ -42,30 +41,30 @@
6-byte ALPS packet */
static const struct alps_model_info alps_model_data[] = {
- { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
- { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
- { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
- { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
- { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */
- { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
- { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
- { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
- { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
- { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
- { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
- { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
- { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
- { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
- { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
- { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
+ { { 0x32, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
+ { { 0x33, 0x02, 0x0a }, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
+ { { 0x53, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x53, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x60, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
+ { { 0x63, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x63, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x63, 0x02, 0x28 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
+ { { 0x63, 0x02, 0x3c }, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
+ { { 0x63, 0x02, 0x50 }, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
+ { { 0x63, 0x02, 0x64 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x63, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
+ { { 0x73, 0x00, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
+ { { 0x73, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x73, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
+ { { 0x20, 0x02, 0x0e }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
+ { { 0x22, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
+ { { 0x22, 0x02, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
- { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
+ { { 0x62, 0x02, 0x14 }, ALPS_PROTO_V2, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
- { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
- { { 0x52, 0x01, 0x14 }, 0xff, 0xff,
- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
+ { { 0x73, 0x02, 0x50 }, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
+ { { 0x52, 0x01, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
};
/*
@@ -119,7 +118,7 @@ static void alps_process_packet(struct psmouse *psmouse)
int x, y, z, ges, fin, left, right, middle;
int back = 0, forward = 0;
- if (model->flags & ALPS_OLDPROTO) {
+ if (model->proto_version == ALPS_PROTO_V1) {
left = packet[2] & 0x10;
right = packet[2] & 0x08;
middle = 0;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 904ed8b..4ce9bba 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -12,8 +12,12 @@
#ifndef _ALPS_H
#define _ALPS_H
+#define ALPS_PROTO_V1 0
+#define ALPS_PROTO_V2 1
+
struct alps_model_info {
unsigned char signature[3];
+ unsigned char proto_version;
unsigned char byte0, mask0;
unsigned char flags;
};
--
1.7.5.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 4/7] Input: ALPS - Remove assumptions about packet size
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
` (2 preceding siblings ...)
2011-10-26 21:14 ` [PATCH 3/7] Input: ALPS - Add protocol version field in alps_model_info Seth Forshee
@ 2011-10-26 21:14 ` Seth Forshee
2011-10-30 15:36 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 5/7] Input: ALPS - Add support for protocol versions 3 and 4 Seth Forshee
` (3 subsequent siblings)
7 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
In preparation for version 4 protocol support, which has 8-byte
data packets, remove all hard-coded assumptions about packet size
and use psmouse->pktsize instead.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
drivers/input/mouse/alps.c | 27 ++++++++++++++++++---------
1 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 572cb21..14d1f64 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -315,7 +315,7 @@ static void alps_flush_packet(unsigned long data)
serio_pause_rx(psmouse->ps2dev.serio);
- if (psmouse->pktcnt == 6) {
+ if (psmouse->pktcnt == psmouse->pktsize) {
/*
* We did not any more data in reasonable amount of time.
@@ -365,15 +365,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
return PSMOUSE_BAD_DATA;
}
- /* Bytes 2 - 6 should have 0 in the highest bit */
- if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
+ /* Bytes 2 - pktsize should have 0 in the highest bit */
+ if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
(psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
dbg("refusing packet[%i] = %x\n",
psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
return PSMOUSE_BAD_DATA;
}
- if (psmouse->pktcnt == 6) {
+ if (psmouse->pktcnt == psmouse->pktsize) {
alps_process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
@@ -531,8 +531,13 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable)
static int alps_poll(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- unsigned char buf[6];
+ unsigned char *buf;
bool poll_failed;
+ int ret = -1;
+
+ buf = kmalloc(psmouse->pktsize, GFP_KERNEL);
+ if (!buf)
+ return -1;
if (priv->i->flags & ALPS_PASS)
alps_passthrough_mode(psmouse, true);
@@ -544,18 +549,22 @@ static int alps_poll(struct psmouse *psmouse)
alps_passthrough_mode(psmouse, false);
if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
- return -1;
+ goto out;
if ((psmouse->badbyte & 0xc8) == 0x08) {
/*
* Poll the track stick ...
*/
if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8)))
- return -1;
+ goto out;
}
- memcpy(psmouse->packet, buf, sizeof(buf));
- return 0;
+ memcpy(psmouse->packet, buf, psmouse->pktsize);
+ ret = 0;
+
+out:
+ kfree(buf);
+ return ret;
}
static int alps_hw_init(struct psmouse *psmouse)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 5/7] Input: ALPS - Add support for protocol versions 3 and 4
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
` (3 preceding siblings ...)
2011-10-26 21:14 ` [PATCH 4/7] Input: ALPS - Remove assumptions about packet size Seth Forshee
@ 2011-10-26 21:14 ` Seth Forshee
2011-10-30 15:37 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 6/7] Input: ALPS - Add semi-MT support for v3 protocol Seth Forshee
` (2 subsequent siblings)
7 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
This patch adds support for two ALPS touchpad protocols not
supported currently by the driver, which I am arbitrarily naming
version 3 and version 4. Support is single-touch only at this time,
although both protocols are capable of limited multitouch support.
Thanks to Andrew Skalski, who did the initial reverse-engineering
of the v3 protocol.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
drivers/input/mouse/alps.c | 785 +++++++++++++++++++++++++++++++++++++++++---
drivers/input/mouse/alps.h | 14 +
2 files changed, 761 insertions(+), 38 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 14d1f64..5400fb4 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -30,6 +30,50 @@
#define dbg(format, arg...) do {} while (0)
#endif
+/*
+ * Definitions for ALPS version 3 and 4 command mode protocol
+ */
+#define ALPS_CMD_NIBBLE_10 0x01f2
+
+static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
+ { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
+ { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
+ { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
+ { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
+ { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
+ { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
+ { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
+ { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
+ { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
+ { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
+ { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
+ { PSMOUSE_CMD_SETRES, 0x00 }, /* b */
+ { PSMOUSE_CMD_SETRES, 0x01 }, /* c */
+ { PSMOUSE_CMD_SETRES, 0x02 }, /* d */
+ { PSMOUSE_CMD_SETRES, 0x03 }, /* e */
+ { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
+};
+
+static const struct alps_nibble_commands alps_v4_nibble_commands[] = {
+ { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */
+ { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
+ { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
+ { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
+ { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
+ { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
+ { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
+ { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
+ { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
+ { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
+ { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
+ { PSMOUSE_CMD_SETRES, 0x00 }, /* b */
+ { PSMOUSE_CMD_SETRES, 0x01 }, /* c */
+ { PSMOUSE_CMD_SETRES, 0x02 }, /* d */
+ { PSMOUSE_CMD_SETRES, 0x03 }, /* e */
+ { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
+};
+
+
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
#define ALPS_PASS 0x04 /* device has a pass-through port */
@@ -41,30 +85,33 @@
6-byte ALPS packet */
static const struct alps_model_info alps_model_data[] = {
- { { 0x32, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
- { { 0x33, 0x02, 0x0a }, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
- { { 0x53, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x53, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x60, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
- { { 0x63, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x28 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
- { { 0x63, 0x02, 0x3c }, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
- { { 0x63, 0x02, 0x50 }, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
- { { 0x63, 0x02, 0x64 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
- { { 0x73, 0x00, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
- { { 0x73, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x73, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
- { { 0x20, 0x02, 0x0e }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
- { { 0x22, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
- { { 0x22, 0x02, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
+ { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
+ { { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
+ { { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
+ { { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
+ { { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
+ { { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
+ { { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
+ { { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
+ { { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
+ { { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
+ { { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
+ { { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
+ { { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
- { { 0x62, 0x02, 0x14 }, ALPS_PROTO_V2, 0xcf, 0xcf,
+ { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
- { { 0x73, 0x02, 0x50 }, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
- { { 0x52, 0x01, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff,
- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
+ { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
+ { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
+ { { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
+ { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
+ { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
};
/*
@@ -108,7 +155,7 @@ static void alps_report_buttons(struct psmouse *psmouse,
input_sync(dev2);
}
-static void alps_process_packet(struct psmouse *psmouse)
+static void alps_process_packet_v1_v2(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
@@ -210,6 +257,224 @@ static void alps_process_packet(struct psmouse *psmouse)
input_sync(dev);
}
+static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = priv->dev2;
+ int x, y, z, left, right, middle;
+
+ /* Sanity check packet */
+ if (!(packet[0] & 0x40)) {
+ pr_debug("alps.c: Bad trackstick packet, discarding\n");
+ return;
+ }
+
+ /*
+ * There's a special packet that seems to indicate the end
+ * of a stream of trackstick data. Filter these out.
+ */
+ if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f)
+ return;
+
+ x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f));
+ y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f));
+ z = (packet[4] & 0x7c) >> 2;
+
+ /*
+ * The x and y values tend to be quite large, and when used
+ * alone the trackstick is difficult to use. Scale them down
+ * to compensate.
+ */
+ x /= 8;
+ y /= 8;
+
+ input_report_rel(dev, REL_X, x);
+ input_report_rel(dev, REL_Y, -y);
+
+ /*
+ * Most ALPS models report the trackstick buttons in the touchpad
+ * packets, but a few report them here. No reliable way has been
+ * found to differentiate between the models upfront, so we enable
+ * the quirk in response to seeing a button press in the trackstick
+ * packet.
+ */
+ left = packet[3] & 0x01;
+ right = packet[3] & 0x02;
+ middle = packet[3] & 0x04;
+
+ if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) &&
+ (left || right || middle))
+ priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS;
+
+ if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) {
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev, BTN_MIDDLE, middle);
+ }
+
+ input_sync(dev);
+ return;
+}
+
+static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ struct input_dev *dev2 = priv->dev2;
+ int x, y, z;
+ int left, right, middle;
+
+ /*
+ * There's no single feature of touchpad position and bitmap
+ * packets that can be used to distinguish between them. We
+ * rely on the fact that a bitmap packet should always follow
+ * a position packet with bit 6 of packet[4] set.
+ */
+ if (priv->multi_packet) {
+ priv->multi_packet = 0;
+
+ /*
+ * Sometimes a position packet will indicate a multi-packet
+ * sequence, but then what follows is another position
+ * packet. Check for this, and when it happens process the
+ * position packet as usual.
+ */
+ if (packet[0] & 0x40) {
+ /*
+ * Bitmap packets are not yet supported, so for now
+ * just ignore them.
+ */
+ return;
+ }
+ }
+
+ if (!priv->multi_packet && (packet[4] & 0x40))
+ priv->multi_packet = 1;
+ else
+ priv->multi_packet = 0;
+
+ left = packet[3] & 0x01;
+ right = packet[3] & 0x02;
+ middle = packet[3] & 0x04;
+
+ x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) |
+ ((packet[0] & 0x30) >> 4);
+ y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f);
+ z = packet[5] & 0x7f;
+
+ /*
+ * Sometimes the hardware sends a single packet with z = 0
+ * in the middle of a stream. Real releases generate packets
+ * with x, y, and z all zero, so these seem to be flukes.
+ * Ignore them.
+ */
+ if (x && y && !z)
+ return;
+
+ if (z >= 64)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ if (z > 0) {
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ }
+ input_report_abs(dev, ABS_PRESSURE, z);
+
+ input_report_key(dev, BTN_TOOL_FINGER, z > 0);
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev, BTN_MIDDLE, middle);
+
+ input_sync(dev);
+
+ if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
+ left = packet[3] & 0x10;
+ right = packet[3] & 0x20;
+ middle = packet[3] & 0x40;
+
+ input_report_key(dev2, BTN_LEFT, left);
+ input_report_key(dev2, BTN_RIGHT, right);
+ input_report_key(dev2, BTN_MIDDLE, middle);
+ input_sync(dev2);
+ }
+}
+
+static void alps_process_packet_v3(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+
+ /*
+ * v3 protocol packets come in three types, two representing
+ * touchpad data and one representing trackstick data.
+ * Trackstick packets seem to be distinguished by always
+ * having 0x3f in the last byte. This value has never been
+ * observed in the last byte of either of the other types
+ * of packets.
+ */
+ if (packet[5] == 0x3f) {
+ alps_process_trackstick_packet_v3(psmouse);
+ return;
+ }
+
+ alps_process_touchpad_packet_v3(psmouse);
+}
+
+static void alps_process_packet_v4(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ int x, y, z;
+ int left, right;
+
+ left = packet[4] & 0x01;
+ right = packet[4] & 0x02;
+
+ x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
+ ((packet[0] & 0x30) >> 4);
+ y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
+ z = packet[5] & 0x7f;
+
+ if (z >= 64)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ if (z > 0) {
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ }
+ input_report_abs(dev, ABS_PRESSURE, z);
+
+ input_report_key(dev, BTN_TOOL_FINGER, z > 0);
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+
+ input_sync(dev);
+}
+
+static void alps_process_packet(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ const struct alps_model_info *model = priv->i;
+
+ switch (model->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+ alps_process_packet_v1_v2(psmouse);
+ break;
+ case ALPS_PROTO_V3:
+ alps_process_packet_v3(psmouse);
+ break;
+ case ALPS_PROTO_V4:
+ alps_process_packet_v4(psmouse);
+ break;
+ }
+}
+
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
@@ -381,11 +646,126 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
return PSMOUSE_GOOD_DATA;
}
+static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ struct alps_data *priv = psmouse->private;
+ int command;
+ unsigned char *param;
+ unsigned char dummy[4];
+
+ BUG_ON(nibble > 0xf);
+
+ command = priv->nibble_commands[nibble].command;
+ param = (command & 0x0f00) ?
+ dummy : (unsigned char *)&priv->nibble_commands[nibble].data;
+
+ if (ps2_command(ps2dev, param, command))
+ return -1;
+
+ return 0;
+}
+
+static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ struct alps_data *priv = psmouse->private;
+ int i, nibble;
+
+ if (ps2_command(ps2dev, NULL, priv->addr_command))
+ return -1;
+
+ for (i = 12; i >= 0; i -= 4) {
+ nibble = (addr >> i) & 0xf;
+ if (alps_command_mode_send_nibble(psmouse, nibble))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+ return -1;
+
+ /*
+ * The address being read is returned in the first two bytes
+ * of the result. Check that this address matches the expected
+ * address.
+ */
+ if (addr != ((param[0] << 8) | param[1]))
+ return -1;
+
+ return param[2];
+}
+
+static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
+{
+ if (alps_command_mode_set_addr(psmouse, addr))
+ return -1;
+ return __alps_command_mode_read_reg(psmouse, addr);
+}
+
+static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value)
+{
+ if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf))
+ return -1;
+ if (alps_command_mode_send_nibble(psmouse, value & 0xf))
+ return -1;
+ return 0;
+}
+
+static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr,
+ u8 value)
+{
+ if (alps_command_mode_set_addr(psmouse, addr))
+ return -1;
+ return __alps_command_mode_write_reg(psmouse, value);
+}
+
+static int alps_enter_command_mode(struct psmouse *psmouse,
+ unsigned char *resp)
+{
+ unsigned char param[4];
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
+ pr_err("alps.c: failed to enter command mode\n");
+ return -1;
+ }
+
+ if (param[0] != 0x88 && param[1] != 0x07) {
+ pr_debug("alps.c: unknown response while entering command mode: %2.2x %2.2x %2.2x\n",
+ param[0], param[1], param[2]);
+ return -1;
+ }
+
+ if (resp)
+ *resp = param[2];
+ return 0;
+}
+
+static inline int alps_exit_command_mode(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM))
+ return -1;
+ return 0;
+}
+
static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
unsigned char param[4];
+ const struct alps_model_info *model = NULL;
int i;
/*
@@ -431,12 +811,38 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
*version = (param[0] << 8) | (param[1] << 4) | i;
}
- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
+ 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;
+ sizeof(alps_model_data[i].signature))) {
+ model = alps_model_data + i;
+ break;
+ }
+ }
+
+ if (model && model->proto_version > ALPS_PROTO_V2) {
+ /*
+ * Need to check command mode response to identify
+ * model
+ */
+ model = NULL;
+ if (alps_enter_command_mode(psmouse, param)) {
+ pr_warn("alps.c: touchpad failed to enter command mode\n");
+ } else {
+ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
+ if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
+ alps_model_data[i].command_mode_resp == param[0]) {
+ model = alps_model_data + i;
+ break;
+ }
+ }
+ alps_exit_command_mode(psmouse);
+
+ if (!model)
+ pr_debug("alps.c: Unknown command mode response %2.2x\n", param[0]);
+ }
+ }
- return NULL;
+ return model;
}
/*
@@ -444,7 +850,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
* 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, bool enable)
+static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
@@ -461,7 +867,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
return 0;
}
-static int alps_absolute_mode(struct psmouse *psmouse)
+static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
@@ -540,13 +946,13 @@ static int alps_poll(struct psmouse *psmouse)
return -1;
if (priv->i->flags & ALPS_PASS)
- alps_passthrough_mode(psmouse, true);
+ alps_passthrough_mode_v2(psmouse, true);
poll_failed = ps2_command(&psmouse->ps2dev, buf,
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
if (priv->i->flags & ALPS_PASS)
- alps_passthrough_mode(psmouse, false);
+ alps_passthrough_mode_v2(psmouse, false);
if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
goto out;
@@ -567,13 +973,13 @@ out:
return ret;
}
-static int alps_hw_init(struct psmouse *psmouse)
+static int alps_hw_init_v1_v2(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
const struct alps_model_info *model = priv->i;
if ((model->flags & ALPS_PASS) &&
- alps_passthrough_mode(psmouse, true)) {
+ alps_passthrough_mode_v2(psmouse, true)) {
return -1;
}
@@ -582,13 +988,13 @@ static int alps_hw_init(struct psmouse *psmouse)
return -1;
}
- if (alps_absolute_mode(psmouse)) {
+ if (alps_absolute_mode_v1_v2(psmouse)) {
printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
return -1;
}
if ((model->flags & ALPS_PASS) &&
- alps_passthrough_mode(psmouse, false)) {
+ alps_passthrough_mode_v2(psmouse, false)) {
return -1;
}
@@ -601,6 +1007,295 @@ static int alps_hw_init(struct psmouse *psmouse)
return 0;
}
+/*
+ * Enable or disable passthrough mode to the trackstick. Must be in
+ * command mode when calling this function.
+ */
+static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable)
+{
+ int reg_val;
+
+ reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
+ if (reg_val == -1)
+ return -1;
+
+ if (enable)
+ reg_val |= 0x01;
+ else
+ reg_val &= ~0x01;
+
+ if (__alps_command_mode_write_reg(psmouse, reg_val))
+ return -1;
+
+ return 0;
+}
+
+/* Must be in command mode when calling this function */
+static int alps_absolute_mode_v3(struct psmouse *psmouse)
+{
+ int reg_val;
+
+ reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
+ if (reg_val == -1)
+ return -1;
+
+ reg_val |= 0x06;
+ if (__alps_command_mode_write_reg(psmouse, reg_val))
+ return -1;
+
+ return 0;
+}
+
+static int alps_hw_init_v3(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int reg_val;
+ unsigned char param[4];
+
+ priv->nibble_commands = alps_v3_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+
+ if (alps_enter_command_mode(psmouse, NULL))
+ goto error;
+
+ /* Check for trackstick */
+ reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
+ if (reg_val == -1)
+ goto error;
+ if (reg_val & 0x80) {
+ if (alps_passthrough_mode_v3(psmouse, true))
+ goto error;
+ if (alps_exit_command_mode(psmouse))
+ goto error;
+
+ /*
+ * E7 report for the trackstick
+ *
+ * There have been reports of failures to seem to trace back
+ * to the above trackstick check failing. When these occur
+ * this E7 report fails, so when that happens we continue
+ * with the assumption that there isn't a trackstick after
+ * all.
+ */
+ param[0] = 0x64;
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
+ pr_warn("alps.c: trackstick E7 report failed\n");
+ } else {
+ pr_debug("alps.c: trackstick E7 report: %2.2x %2.2x %2.2x\n",
+ param[0], param[1], param[2]);
+
+ /*
+ * Not sure what this does, but it is absolutely
+ * essential. Without it, the touchpad does not
+ * work at all and the trackstick just emits normal
+ * PS/2 packets.
+ */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ alps_command_mode_send_nibble(psmouse, 0x9) ||
+ alps_command_mode_send_nibble(psmouse, 0x4)) {
+ pr_err("alps.c: Error sending magic E6 sequence\n");
+ goto error_passthrough;
+ }
+ }
+
+ if (alps_enter_command_mode(psmouse, NULL))
+ goto error_passthrough;
+ if (alps_passthrough_mode_v3(psmouse, false))
+ goto error;
+ }
+
+ if (alps_absolute_mode_v3(psmouse)) {
+ pr_err("alps.c: Failed to enter absolute mode\n");
+ goto error;
+ }
+
+ reg_val = alps_command_mode_read_reg(psmouse, 0x0006);
+ if (reg_val == -1)
+ goto error;
+ if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
+ goto error;
+
+ reg_val = alps_command_mode_read_reg(psmouse, 0x0007);
+ if (reg_val == -1)
+ goto error;
+ if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
+ goto error;
+
+ if (alps_command_mode_read_reg(psmouse, 0x0144) == -1)
+ goto error;
+ if (__alps_command_mode_write_reg(psmouse, 0x04))
+ goto error;
+
+ if (alps_command_mode_read_reg(psmouse, 0x0159) == -1)
+ goto error;
+ if (__alps_command_mode_write_reg(psmouse, 0x03))
+ goto error;
+
+ if (alps_command_mode_read_reg(psmouse, 0x0163) == -1)
+ goto error;
+ if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03))
+ goto error;
+
+ if (alps_command_mode_read_reg(psmouse, 0x0162) == -1)
+ goto error;
+ if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
+ goto error;
+
+ /*
+ * This ensures the trackstick packets are in the format
+ * supported by this driver. If bit 1 isn't set the packet
+ * format is different.
+ */
+ if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82))
+ goto error;
+
+ alps_exit_command_mode(psmouse);
+
+ /* Set rate and enable data reporting */
+ param[0] = 0x64;
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
+ pr_err("alps.c: Failed to enable data reporting\n");
+ return -1;
+ }
+
+ return 0;
+
+error_passthrough:
+ /* Something failed while in passthrough mode, so try to get out */
+ if (!alps_enter_command_mode(psmouse, NULL))
+ alps_passthrough_mode_v3(psmouse, false);
+error:
+ /*
+ * Leaving the touchpad in command mode will essentially render
+ * it unusable until the machine reboots, so exit it here just
+ * to be safe
+ */
+ alps_exit_command_mode(psmouse);
+ return -1;
+}
+
+/* Must be in command mode when calling this function */
+static int alps_absolute_mode_v4(struct psmouse *psmouse)
+{
+ int reg_val;
+
+ reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
+ if (reg_val == -1)
+ return -1;
+
+ reg_val |= 0x02;
+ if (__alps_command_mode_write_reg(psmouse, reg_val))
+ return -1;
+
+ return 0;
+}
+
+static int alps_hw_init_v4(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+
+ priv->nibble_commands = alps_v4_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_DISABLE;
+
+ if (alps_enter_command_mode(psmouse, NULL))
+ goto error;
+
+ if (alps_absolute_mode_v4(psmouse)) {
+ pr_err("alps.c: Failed to enter absolute mode\n");
+ goto error;
+ }
+
+ if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03))
+ goto error;
+
+ alps_exit_command_mode(psmouse);
+
+ /*
+ * This sequence changes the output from a 9-byte to an
+ * 8-byte format. All the same data seems to be present,
+ * just in a more compact format.
+ */
+ param[0] = 0xc8;
+ param[1] = 0x64;
+ param[2] = 0x50;
+ if (ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, ¶m[2], PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
+ return -1;
+
+ /* Set rate and enable data reporting */
+ param[0] = 0x64;
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
+ pr_err("alps.c: Failed to enable data reporting\n");
+ return -1;
+ }
+
+ return 0;
+
+error:
+ /*
+ * Leaving the touchpad in command mode will essentially render
+ * it unusable until the machine reboots, so exit it here just
+ * to be safe
+ */
+ alps_exit_command_mode(psmouse);
+ return -1;
+}
+
+static int alps_hw_init(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ const struct alps_model_info *model = priv->i;
+ int ret = -1;
+
+ switch (model->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+ ret = alps_hw_init_v1_v2(psmouse);
+ break;
+ case ALPS_PROTO_V3:
+ ret = alps_hw_init_v3(psmouse);
+ break;
+ case ALPS_PROTO_V4:
+ ret = alps_hw_init_v4(psmouse);
+ break;
+ }
+
+ return ret;
+}
+
static int alps_reconnect(struct psmouse *psmouse)
{
const struct alps_model_info *model;
@@ -641,6 +1336,8 @@ int alps_init(struct psmouse *psmouse)
psmouse->private = priv;
+ psmouse_reset(psmouse);
+
model = alps_get_model(psmouse, &version);
if (!model)
goto init_fail;
@@ -668,8 +1365,20 @@ int alps_init(struct psmouse *psmouse)
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
- input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
- input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
+
+ switch (model->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+ input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
+ break;
+ case ALPS_PROTO_V3:
+ case ALPS_PROTO_V4:
+ input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0);
+ break;
+ }
+
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
if (model->flags & ALPS_WHEEL) {
@@ -712,7 +1421,7 @@ int alps_init(struct psmouse *psmouse)
psmouse->poll = alps_poll;
psmouse->disconnect = alps_disconnect;
psmouse->reconnect = alps_reconnect;
- psmouse->pktsize = 6;
+ psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6;
/* We are having trouble resyncing ALPS touchpads so disable it for now */
psmouse->resync_time = 0;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 4ce9bba..62db7f4 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -14,22 +14,36 @@
#define ALPS_PROTO_V1 0
#define ALPS_PROTO_V2 1
+#define ALPS_PROTO_V3 2
+#define ALPS_PROTO_V4 3
struct alps_model_info {
unsigned char signature[3];
+ unsigned char command_mode_resp; /* v3/v4 only */
unsigned char proto_version;
unsigned char byte0, mask0;
unsigned char flags;
};
+struct alps_nibble_commands {
+ int command;
+ unsigned char data;
+};
+
struct alps_data {
struct input_dev *dev2; /* Relative device */
char phys[32]; /* Phys */
const struct alps_model_info *i;/* Info */
+ const struct alps_nibble_commands *nibble_commands;
+ int addr_command; /* Command to set register address */
int prev_fin; /* Finger bit from previous packet */
+ int multi_packet; /* Multi-packet data in progress */
+ u8 quirks;
struct timer_list timer;
};
+#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
+
#ifdef CONFIG_MOUSE_PS2_ALPS
int alps_detect(struct psmouse *psmouse, bool set_properties);
int alps_init(struct psmouse *psmouse);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 6/7] Input: ALPS - Add semi-MT support for v3 protocol
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
` (4 preceding siblings ...)
2011-10-26 21:14 ` [PATCH 5/7] Input: ALPS - Add support for protocol versions 3 and 4 Seth Forshee
@ 2011-10-26 21:14 ` Seth Forshee
2011-10-30 15:44 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 7/7] Input: ALPS - Add documentation for protocol versions 3 and 4 Seth Forshee
2011-10-26 21:22 ` [PATCH 0/7] Additional ALPS touchpad protocol support Chris Friesen
7 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
drivers/input/mouse/alps.c | 233 ++++++++++++++++++++++++++++++++++++++++----
drivers/input/mouse/alps.h | 1 +
2 files changed, 215 insertions(+), 19 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 5400fb4..60061a0 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
@@ -33,6 +34,12 @@
/*
* Definitions for ALPS version 3 and 4 command mode protocol
*/
+#define ALPS_V3_X_MAX 2000
+#define ALPS_V3_Y_MAX 1400
+
+#define ALPS_BITMAP_X_BITS 15
+#define ALPS_BITMAP_Y_BITS 11
+
#define ALPS_CMD_NIBBLE_10 0x01f2
static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
@@ -257,6 +264,137 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
input_sync(dev);
}
+/*
+ * Process bitmap data from v3 and v4 protocols. Returns the number of
+ * fingers detected. A return value of 0 means at least one of the
+ * bitmaps was empty.
+ *
+ * The bitmaps don't have enough data to track fingers, so this function
+ * only generates points representing a bounding box of all contacts.
+ * These points are returned in x1, y1, x2, and y2 when the return value
+ * is greater than 0.
+ */
+static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
+ int *x1, int *y1, int *x2, int *y2)
+{
+ struct alps_bitmap_point {
+ int start_bit;
+ int num_bits;
+ };
+
+ int fingers_x = 0, fingers_y = 0, fingers;
+ int i, bit, prev_bit;
+ struct alps_bitmap_point x_low = {0,}, x_high = {0,};
+ struct alps_bitmap_point y_low = {0,}, y_high = {0,};
+ struct alps_bitmap_point *point;
+
+ if (!x_map || !y_map)
+ return 0;
+
+ *x1 = *y1 = *x2 = *y2 = 0;
+
+ prev_bit = 0;
+ point = &x_low;
+ for (i = 0; x_map != 0; i++, x_map >>= 1) {
+ bit = x_map & 1;
+ if (bit) {
+ if (!prev_bit) {
+ point->start_bit = i;
+ fingers_x++;
+ }
+ point->num_bits++;
+ } else {
+ if (prev_bit)
+ point = &x_high;
+ else
+ point->num_bits = 0;
+ }
+ prev_bit = bit;
+ }
+
+ /*
+ * y bitmap is reversed for what we need (lower positions are in
+ * higher bits), so we process from the top end.
+ */
+ y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS);
+ prev_bit = 0;
+ point = &y_low;
+ for (i = 0; y_map != 0; i++, y_map <<= 1) {
+ bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
+ if (bit) {
+ if (!prev_bit) {
+ point->start_bit = i;
+ fingers_y++;
+ }
+ point->num_bits++;
+ } else {
+ if (prev_bit)
+ point = &y_high;
+ else
+ point->num_bits = 0;
+ }
+ prev_bit = bit;
+ }
+
+ /*
+ * Fingers can overlap, so we use the maximum count of fingers
+ * on either axis as the finger count.
+ */
+ fingers = max(fingers_x, fingers_y);
+
+ /*
+ * If total fingers is > 1 but either axis reports only a single
+ * contact, we have overlapping or adjacent fingers. For the
+ * purposes of creating a bounding box, divide the single contact
+ * (roughly) equally between the two points.
+ */
+ if (fingers > 1) {
+ if (fingers_x == 1) {
+ i = x_low.num_bits / 2;
+ x_low.num_bits = x_low.num_bits - i;
+ x_high.start_bit = x_low.start_bit + i;
+ x_high.num_bits = max(i, 1);
+ } else if (fingers_y == 1) {
+ i = y_low.num_bits / 2;
+ y_low.num_bits = y_low.num_bits - i;
+ y_high.start_bit = y_low.start_bit + i;
+ y_high.num_bits = max(i, 1);
+ }
+ }
+
+ *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+ (2 * (ALPS_BITMAP_X_BITS - 1));
+ *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+ (2 * (ALPS_BITMAP_Y_BITS - 1));
+
+ if (fingers > 1) {
+ *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) /
+ (2 * (ALPS_BITMAP_X_BITS - 1));
+ *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) /
+ (2 * (ALPS_BITMAP_Y_BITS - 1));
+ }
+
+ return fingers;
+}
+
+static void alps_set_slot(struct input_dev *dev, int slot, bool active,
+ int x, int y)
+{
+ input_mt_slot(dev, slot);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+ if (active) {
+ input_report_abs(dev, ABS_MT_POSITION_X, x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ }
+}
+
+static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
+ int x1, int y1, int x2, int y2)
+{
+ alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
+ alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
+}
+
static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
@@ -325,16 +463,17 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
struct input_dev *dev2 = priv->dev2;
int x, y, z;
int left, right, middle;
+ int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+ int fingers = 0, bmap_fingers;
+ unsigned int x_bitmap, y_bitmap;
/*
- * There's no single feature of touchpad position and bitmap
- * packets that can be used to distinguish between them. We
- * rely on the fact that a bitmap packet should always follow
- * a position packet with bit 6 of packet[4] set.
+ * There's no single feature of touchpad position and bitmap packets
+ * that can be used to distinguish between them. We rely on the fact
+ * that a bitmap packet should always follow a position packet with
+ * bit 6 of packet[4] set.
*/
if (priv->multi_packet) {
- priv->multi_packet = 0;
-
/*
* Sometimes a position packet will indicate a multi-packet
* sequence, but then what follows is another position
@@ -342,18 +481,49 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
* position packet as usual.
*/
if (packet[0] & 0x40) {
+ fingers = (packet[5] & 0x3) + 1;
+ x_bitmap = ((packet[4] & 0x7e) << 8) |
+ ((packet[1] & 0x7f) << 2) |
+ ((packet[0] & 0x30) >> 4);
+ y_bitmap = ((packet[3] & 0x70) << 4) |
+ ((packet[2] & 0x7f) << 1) |
+ (packet[4] & 0x01);
+
+ bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+ &x1, &y1, &x2, &y2);
+
/*
- * Bitmap packets are not yet supported, so for now
- * just ignore them.
+ * We shouldn't report more than one finger if
+ * we don't have two coordinates.
*/
- return;
+ if (fingers > 1 && bmap_fingers < 2)
+ fingers = bmap_fingers;
+
+ /* Now process position packet */
+ packet = priv->multi_data;
+ } else {
+ priv->multi_packet = 0;
}
}
- if (!priv->multi_packet && (packet[4] & 0x40))
+ /*
+ * Bit 6 of byte 0 is not usually set in position packets. The only
+ * times it seems to be set is in situations where the data is
+ * suspect anyway, e.g. a palm resting flat on the touchpad. Given
+ * this combined with the fact that this bit is useful for filtering
+ * out misidentified bitmap packets, we reject anything with this
+ * bit set.
+ */
+ if (packet[0] & 0x40)
+ return;
+
+ if (!priv->multi_packet && (packet[4] & 0x40)) {
priv->multi_packet = 1;
- else
- priv->multi_packet = 0;
+ memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
+ return;
+ }
+
+ priv->multi_packet = 0;
left = packet[3] & 0x01;
right = packet[3] & 0x02;
@@ -373,22 +543,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
if (x && y && !z)
return;
+ /*
+ * If we don't have MT data or the bitmaps were empty, we have
+ * to rely on ST data.
+ */
+ if (!fingers) {
+ x1 = x;
+ y1 = y;
+ fingers = z > 0 ? 1 : 0;
+ }
+
if (z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
+ alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
+ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
+ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
+ input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
+
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev, BTN_MIDDLE, middle);
+
if (z > 0) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
input_report_abs(dev, ABS_PRESSURE, z);
- input_report_key(dev, BTN_TOOL_FINGER, z > 0);
- input_report_key(dev, BTN_LEFT, left);
- input_report_key(dev, BTN_RIGHT, right);
- input_report_key(dev, BTN_MIDDLE, middle);
-
input_sync(dev);
if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
@@ -1373,9 +1559,18 @@ int alps_init(struct psmouse *psmouse)
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
break;
case ALPS_PROTO_V3:
+ set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+ input_mt_init_slots(dev1, 2);
+ input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
+ input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
+
+ set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
+ set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
+ set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
+ /* fall through */
case ALPS_PROTO_V4:
- input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0);
- input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0);
+ input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
break;
}
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 62db7f4..a00a4ab 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -38,6 +38,7 @@ struct alps_data {
int addr_command; /* Command to set register address */
int prev_fin; /* Finger bit from previous packet */
int multi_packet; /* Multi-packet data in progress */
+ unsigned char multi_data[6]; /* Saved multi-packet data */
u8 quirks;
struct timer_list timer;
};
--
1.7.5.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 7/7] Input: ALPS - Add documentation for protocol versions 3 and 4
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
` (5 preceding siblings ...)
2011-10-26 21:14 ` [PATCH 6/7] Input: ALPS - Add semi-MT support for v3 protocol Seth Forshee
@ 2011-10-26 21:14 ` Seth Forshee
2011-10-30 15:46 ` Chase Douglas
2011-10-26 21:22 ` [PATCH 0/7] Additional ALPS touchpad protocol support Chris Friesen
7 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-26 21:14 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Alessandro Rubini, Henrik Rydberg, Chase Douglas, Andrew Skalski,
linux-input, linux-kernel
Also converts from using "old" and "new" to describe the already-known
protocols to using "version 1" and "version 2" to match the code.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
Documentation/input/alps.txt | 135 ++++++++++++++++++++++++++++++++++++++----
1 files changed, 124 insertions(+), 11 deletions(-)
diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt
index ab5478f..f274c28 100644
--- a/Documentation/input/alps.txt
+++ b/Documentation/input/alps.txt
@@ -4,12 +4,9 @@ ALPS Touchpad Protocol
Introduction
------------
-Currently the ALPS touchpad driver supports two protocol versions in use by
-ALPS touchpads, the "old" and "new" protocol versions. Fundamentally these
-differ only in the format of their event packets (in reality many features may
-be found on new protocol devices that aren't found on the old protocol
-devices, but these are handled transparently as feature differences rather
-than protocol differences).
+Currently the ALPS touchpad driver supports four protocol versions in use by
+ALPS touchpads, called versions 1, 2, 3, and 4. Information about the various
+protocol versions is contained in the following sections.
Detection
---------
@@ -22,10 +19,37 @@ If the E6 report is successful, the touchpad model is identified using the "E7
report" sequence: E8-E7-E7-E7-E9. The response is the model signature and is
matched against known models in the alps_model_data_array.
+With protocol versions 3 and 4, the E7 report model signature is always
+73-02-64. To differentiate between these versions, the response from the
+"Enter Command Mode" sequence must be inspected as described below.
+
+Command Mode
+------------
+
+Protocol versions 3 and 4 have a command mode that is used to read and write
+one-byte device registers in a 16-bit address space. The command sequence
+EC-EC-EC-E9 places the device in command mode, and the device will respond
+with 88-07 followed by a third byte. This third byte can be used to determine
+whether the devices uses the version 3 or 4 protocol.
+
+To exit command mode, PSMOUSE_CMD_SETSTREAM (EA) is sent to the touchpad.
+
+While in command mode, register addresses can be set by first sending a
+specific command, either EC for v3 devices or F5 for v4 devices. Then the
+address is sent one nibble at a time, where each nibble is encoded as a
+command with optional data. This enoding differs slightly between the v3 and
+v4 protocols.
+
+Once an address has been set, the addressed register can be read by sending
+PSMOUSE_CMD_GETINFO (E9). The first two bytes of the response contains the
+address of the register being read, and the third contains the value of the
+register. Registers are written by writing the value one nibble at a time
+using the same encoding used for addresses.
+
Packet Format
-------------
-In the following tables, the following notation us used.
+In the following tables, the following notation is used.
CAPITALS = stick, miniscules = touchpad
@@ -41,8 +65,8 @@ PS/2 packet format
Note that the device never signals overflow condition.
-ALPS Absolute Mode - Old Format
--------------------------------
+ALPS Absolute Mode - Protocol Verion 1
+--------------------------------------
byte 0: 1 0 0 0 1 x9 x8 x7
byte 1: 0 x6 x5 x4 x3 x2 x1 x0
@@ -51,8 +75,8 @@ ALPS Absolute Mode - Old Format
byte 4: 0 y6 y5 y4 y3 y2 y1 y0
byte 5: 0 z6 z5 z4 z3 z2 z1 z0
-ALPS Absolute Mode - New Format
--------------------------------
+ALPS Absolute Mode - Protocol Version 2
+---------------------------------------
byte 0: 1 ? ? ? 1 ? ? ?
byte 1: 0 x6 x5 x4 x3 x2 x1 x0
@@ -73,3 +97,92 @@ Dualpoint device -- interleaved packet format
byte 6: 0 y9 y8 y7 1 m r l
byte 7: 0 y6 y5 y4 y3 y2 y1 y0
byte 8: 0 z6 z5 z4 z3 z2 z1 z0
+
+ALPS Absolute Mode - Protocol Version 3
+---------------------------------------
+
+ALPS protocol version 3 has three different packet formats. The first two are
+associated with touchpad events, and the third is associatd with trackstick
+events.
+
+The first type is the touchpad position packet.
+
+ byte 0: 1 ? x1 x0 1 1 1 1
+ byte 1: 0 x10 x9 x8 x7 x6 x5 x4
+ byte 2: 0 y10 y9 y8 y7 y6 y5 y4
+ byte 3: 0 M R L 1 m r l
+ byte 4: 0 mt x3 x2 y3 y2 y1 y0
+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+
+Note that for some devices the trackstick buttons are reported in this packet,
+and on others it is reported in the trackstick packets.
+
+The second packet type contains bitmaps representing the x and y axes. In the
+bitmaps a given bit is set if there is a finger covering that position on the
+given axis. Thus the bitmap packet can be used for low-resolution multi-touch
+data, although finger tracking is not possible. This packet also encodes the
+number of contacts (f1 and f0 in the table below).
+
+ byte 0: 1 1 x1 x0 1 1 1 1
+ byte 1: 0 x8 x7 x6 x5 x4 x3 x2
+ byte 2: 0 y7 y6 y5 y4 y3 y2 y1
+ byte 3: 0 y10 y9 y8 1 1 1 1
+ byte 4: 0 x14 x13 x12 x11 x10 x9 y0
+ byte 5: 0 1 ? ? ? ? f1 f0
+
+This packet only appears after a position packet with the mt bit set, and
+ususally only appears when there are two or more contacts (although
+ocassionally it's seen with only a single contact).
+
+The final v3 packet type is the trackstick packet.
+
+ byte 0: 1 1 x7 y7 1 1 1 1
+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0
+ byte 2: 0 y6 y5 y4 y3 y2 y1 y0
+ byte 3: 0 1 0 0 1 0 0 0
+ byte 4: 0 z4 z3 z2 z1 z0 ? ?
+ byte 5: 0 0 1 1 1 1 1 1
+
+ALPS Absolute Mode - Protocol Version 4
+---------------------------------------
+
+Protocol version 4 has an 8-byte packet format.
+
+ byte 0: 1 ? x1 x0 1 1 1 1
+ byte 1: 0 x10 x9 x8 x7 x6 x5 x4
+ byte 2: 0 y10 y9 y8 y7 y6 y5 y4
+ byte 3: 0 1 x3 x2 y3 y2 y1 y0
+ byte 4: 0 ? ? ? 1 ? r l
+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+ byte 6: bitmap data (described below)
+ byte 7: bitmap data (described below)
+
+The last two bytes represent a partial bitmap packet, with 3 full packets
+required to construct a complete bitmap packet. Once assembled, the 6-byte
+bitmap packet has the following format:
+
+ byte 0: 0 1 x7 x6 x5 x4 x3 x2
+ byte 1: 0 x1 x0 y4 y3 y2 y1 y0
+ byte 2: 0 0 ? x14 x13 x12 x11 x10
+ byte 3: 0 x9 x8 y9 y8 y7 y6 y5
+ byte 4: 0 0 0 0 0 0 0 0
+ byte 5: 0 0 0 0 0 0 0 y10
+
+There are several things worth noting here.
+
+ 1) In the bitmap data, bit 6 of byte 0 serves as a sync byte to
+ identify the first fragment of a bitmap packet.
+
+ 2) The bitmaps represent the same data as in the v3 bitmap packets, although
+ the packet layout is different.
+
+ 3) There doesn't seem to be a count of the contact points anywhere in the v4
+ protocol packets. Deriving a count of contact points must be done by
+ analyzing the bitmaps.
+
+ 4) There is a 3 to 1 ratio of position packets to bitmap packets. Therefore
+ MT position can only be updated for every third ST position update, and
+ the count of contact points can only be updated every third packet as
+ well.
+
+So far no v4 devices with tracksticks have been encountered.
--
1.7.5.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 0/7] Additional ALPS touchpad protocol support
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
` (6 preceding siblings ...)
2011-10-26 21:14 ` [PATCH 7/7] Input: ALPS - Add documentation for protocol versions 3 and 4 Seth Forshee
@ 2011-10-26 21:22 ` Chris Friesen
7 siblings, 0 replies; 20+ messages in thread
From: Chris Friesen @ 2011-10-26 21:22 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg, Chase Douglas,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 03:14 PM, Seth Forshee wrote:
> This patch series adds support for two ALPS touchpad protocol versions
> currently unsupported by the driver, which I've arbitrarily called
> versions 3 and 4 (with the two currently supported protocol versions
> changed to be called versions 1 and 2). The v3 touchpads are commonly
> found on Dell laptops, and the v4 touchpads are found on machines from a
> variety of other manufacturers.
Thanks for doing this! Here's hoping it fixes my Dell.
Chris
--
Chris Friesen
Software Developer
GENBAND
chris.friesen@genband.com
www.genband.com
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/7] Input: ALPS - Move protocol information to Documentation
2011-10-26 21:14 ` [PATCH 1/7] Input: ALPS - Move protocol information to Documentation Seth Forshee
@ 2011-10-30 15:33 ` Chase Douglas
2011-10-31 18:15 ` Seth Forshee
0 siblings, 1 reply; 20+ messages in thread
From: Chase Douglas @ 2011-10-30 15:33 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 05:14 PM, Seth Forshee wrote:
> In preparation for new protocol support, move the protocol
> information currently documented in alps.c to
> Documentation/input/alps.txt, where it can be expanded without
> cluttering up the driver.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Makes sense. Only question is whether we should create a subdir for
device protocols (Documentation/input/devices/alps.txt)?
Acked-by: Chase Douglas <chase.douglas@canonical.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/7] Input: psmouse - Add PSMOUSE_CMD_RESET_WRAP
2011-10-26 21:14 ` [PATCH 2/7] Input: psmouse - Add PSMOUSE_CMD_RESET_WRAP Seth Forshee
@ 2011-10-30 15:33 ` Chase Douglas
0 siblings, 0 replies; 20+ messages in thread
From: Chase Douglas @ 2011-10-30 15:33 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 05:14 PM, Seth Forshee wrote:
> Add this command in preparation for new ALPS protocol support.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Trivial and obvious.
Acked-by: Chase Douglas <chase.douglas@canonical.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/7] Input: ALPS - Add protocol version field in alps_model_info
2011-10-26 21:14 ` [PATCH 3/7] Input: ALPS - Add protocol version field in alps_model_info Seth Forshee
@ 2011-10-30 15:34 ` Chase Douglas
0 siblings, 0 replies; 20+ messages in thread
From: Chase Douglas @ 2011-10-30 15:34 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 05:14 PM, Seth Forshee wrote:
> In preparation for adding support for more ALPS protocol versions,
> add a field for the protocol version to the model info instead of
> using a field in the flags. OLDPROTO and !OLDPROTO are now called
> version 1 and version 2, repsectively.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Makes sense, and the old solution obviously was not going to work going
forward.
Acked-by: Chase Douglas <chase.douglas@canonical.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/7] Input: ALPS - Remove assumptions about packet size
2011-10-26 21:14 ` [PATCH 4/7] Input: ALPS - Remove assumptions about packet size Seth Forshee
@ 2011-10-30 15:36 ` Chase Douglas
2011-10-31 18:17 ` Seth Forshee
0 siblings, 1 reply; 20+ messages in thread
From: Chase Douglas @ 2011-10-30 15:36 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 05:14 PM, Seth Forshee wrote:
> In preparation for version 4 protocol support, which has 8-byte
> data packets, remove all hard-coded assumptions about packet size
> and use psmouse->pktsize instead.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
> ---
> drivers/input/mouse/alps.c | 27 ++++++++++++++++++---------
> 1 files changed, 18 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index 572cb21..14d1f64 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -315,7 +315,7 @@ static void alps_flush_packet(unsigned long data)
>
> serio_pause_rx(psmouse->ps2dev.serio);
>
> - if (psmouse->pktcnt == 6) {
> + if (psmouse->pktcnt == psmouse->pktsize) {
>
> /*
> * We did not any more data in reasonable amount of time.
> @@ -365,15 +365,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> return PSMOUSE_BAD_DATA;
> }
>
> - /* Bytes 2 - 6 should have 0 in the highest bit */
> - if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
> + /* Bytes 2 - pktsize should have 0 in the highest bit */
> + if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
> (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
> dbg("refusing packet[%i] = %x\n",
> psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
> return PSMOUSE_BAD_DATA;
> }
>
> - if (psmouse->pktcnt == 6) {
> + if (psmouse->pktcnt == psmouse->pktsize) {
> alps_process_packet(psmouse);
> return PSMOUSE_FULL_PACKET;
> }
> @@ -531,8 +531,13 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable)
> static int alps_poll(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> - unsigned char buf[6];
> + unsigned char *buf;
> bool poll_failed;
> + int ret = -1;
> +
> + buf = kmalloc(psmouse->pktsize, GFP_KERNEL);
> + if (!buf)
> + return -1;
Can we preallocate a buffer somewhere instead of allocating every time
we enter the function? If we know the maximum packet size we could
allocate on the stack instead.
-- Chase
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 5/7] Input: ALPS - Add support for protocol versions 3 and 4
2011-10-26 21:14 ` [PATCH 5/7] Input: ALPS - Add support for protocol versions 3 and 4 Seth Forshee
@ 2011-10-30 15:37 ` Chase Douglas
0 siblings, 0 replies; 20+ messages in thread
From: Chase Douglas @ 2011-10-30 15:37 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 05:14 PM, Seth Forshee wrote:
> This patch adds support for two ALPS touchpad protocols not
> supported currently by the driver, which I am arbitrarily naming
> version 3 and version 4. Support is single-touch only at this time,
> although both protocols are capable of limited multitouch support.
>
> Thanks to Andrew Skalski, who did the initial reverse-engineering
> of the v3 protocol.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
The general architecture of the code looks good to me, and it has been
tested on many devices.
Acked-by: Chase Douglas <chase.douglas@canonical.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 6/7] Input: ALPS - Add semi-MT support for v3 protocol
2011-10-26 21:14 ` [PATCH 6/7] Input: ALPS - Add semi-MT support for v3 protocol Seth Forshee
@ 2011-10-30 15:44 ` Chase Douglas
0 siblings, 0 replies; 20+ messages in thread
From: Chase Douglas @ 2011-10-30 15:44 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 05:14 PM, Seth Forshee wrote:
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Looks like it does the right thing to me. I believe Seth has tested it
with our uTouch stack, which has some basic support for multitouch
gestures for semi-mt devices.
Acked-by: Chase Douglas <chase.douglas@canonical.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 7/7] Input: ALPS - Add documentation for protocol versions 3 and 4
2011-10-26 21:14 ` [PATCH 7/7] Input: ALPS - Add documentation for protocol versions 3 and 4 Seth Forshee
@ 2011-10-30 15:46 ` Chase Douglas
0 siblings, 0 replies; 20+ messages in thread
From: Chase Douglas @ 2011-10-30 15:46 UTC (permalink / raw)
To: Seth Forshee
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On 10/26/2011 05:14 PM, Seth Forshee wrote:
> Also converts from using "old" and "new" to describe the already-known
> protocols to using "version 1" and "version 2" to match the code.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Documentation is tasty...
Acked-by: Chase Douglas <chase.douglas@canonical.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/7] Input: ALPS - Move protocol information to Documentation
2011-10-30 15:33 ` Chase Douglas
@ 2011-10-31 18:15 ` Seth Forshee
0 siblings, 0 replies; 20+ messages in thread
From: Seth Forshee @ 2011-10-31 18:15 UTC (permalink / raw)
To: Chase Douglas
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On Sun, Oct 30, 2011 at 11:33:10AM -0400, Chase Douglas wrote:
> On 10/26/2011 05:14 PM, Seth Forshee wrote:
> > In preparation for new protocol support, move the protocol
> > information currently documented in alps.c to
> > Documentation/input/alps.txt, where it can be expanded without
> > cluttering up the driver.
> >
> > Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
>
> Makes sense. Only question is whether we should create a subdir for
> device protocols (Documentation/input/devices/alps.txt)?
That's probably a good idea if protocol documentation is going to
proliferate, but currently these docs are in Documentation/input. If we
want to move them it's a subject for a separate patch.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/7] Input: ALPS - Remove assumptions about packet size
2011-10-30 15:36 ` Chase Douglas
@ 2011-10-31 18:17 ` Seth Forshee
2011-10-31 18:24 ` Dmitry Torokhov
0 siblings, 1 reply; 20+ messages in thread
From: Seth Forshee @ 2011-10-31 18:17 UTC (permalink / raw)
To: Chase Douglas
Cc: Dmitry Torokhov, Alessandro Rubini, Henrik Rydberg,
Andrew Skalski, linux-input, linux-kernel
On Sun, Oct 30, 2011 at 11:36:19AM -0400, Chase Douglas wrote:
> On 10/26/2011 05:14 PM, Seth Forshee wrote:
> > In preparation for version 4 protocol support, which has 8-byte
> > data packets, remove all hard-coded assumptions about packet size
> > and use psmouse->pktsize instead.
> >
> > Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
> > ---
> > drivers/input/mouse/alps.c | 27 ++++++++++++++++++---------
> > 1 files changed, 18 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> > index 572cb21..14d1f64 100644
> > --- a/drivers/input/mouse/alps.c
> > +++ b/drivers/input/mouse/alps.c
> > @@ -315,7 +315,7 @@ static void alps_flush_packet(unsigned long data)
> >
> > serio_pause_rx(psmouse->ps2dev.serio);
> >
> > - if (psmouse->pktcnt == 6) {
> > + if (psmouse->pktcnt == psmouse->pktsize) {
> >
> > /*
> > * We did not any more data in reasonable amount of time.
> > @@ -365,15 +365,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> > return PSMOUSE_BAD_DATA;
> > }
> >
> > - /* Bytes 2 - 6 should have 0 in the highest bit */
> > - if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
> > + /* Bytes 2 - pktsize should have 0 in the highest bit */
> > + if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
> > (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
> > dbg("refusing packet[%i] = %x\n",
> > psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
> > return PSMOUSE_BAD_DATA;
> > }
> >
> > - if (psmouse->pktcnt == 6) {
> > + if (psmouse->pktcnt == psmouse->pktsize) {
> > alps_process_packet(psmouse);
> > return PSMOUSE_FULL_PACKET;
> > }
> > @@ -531,8 +531,13 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable)
> > static int alps_poll(struct psmouse *psmouse)
> > {
> > struct alps_data *priv = psmouse->private;
> > - unsigned char buf[6];
> > + unsigned char *buf;
> > bool poll_failed;
> > + int ret = -1;
> > +
> > + buf = kmalloc(psmouse->pktsize, GFP_KERNEL);
> > + if (!buf)
> > + return -1;
>
> Can we preallocate a buffer somewhere instead of allocating every time
> we enter the function? If we know the maximum packet size we could
> allocate on the stack instead.
Thanks for pointing that out; I had meant to come back and do something
about this but forgot. I was hoping to avoid having to hard-code an
assumed maximum packet size. I'll take a look at it.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/7] Input: ALPS - Remove assumptions about packet size
2011-10-31 18:17 ` Seth Forshee
@ 2011-10-31 18:24 ` Dmitry Torokhov
2011-10-31 20:01 ` Seth Forshee
0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Torokhov @ 2011-10-31 18:24 UTC (permalink / raw)
To: Chase Douglas, Alessandro Rubini, Henrik Rydberg, Andrew Skalski,
linux-input
On Mon, Oct 31, 2011 at 02:17:02PM -0400, Seth Forshee wrote:
> On Sun, Oct 30, 2011 at 11:36:19AM -0400, Chase Douglas wrote:
> > On 10/26/2011 05:14 PM, Seth Forshee wrote:
> > > In preparation for version 4 protocol support, which has 8-byte
> > > data packets, remove all hard-coded assumptions about packet size
> > > and use psmouse->pktsize instead.
> > >
> > > Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
> > > ---
> > > drivers/input/mouse/alps.c | 27 ++++++++++++++++++---------
> > > 1 files changed, 18 insertions(+), 9 deletions(-)
> > >
> > > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> > > index 572cb21..14d1f64 100644
> > > --- a/drivers/input/mouse/alps.c
> > > +++ b/drivers/input/mouse/alps.c
> > > @@ -315,7 +315,7 @@ static void alps_flush_packet(unsigned long data)
> > >
> > > serio_pause_rx(psmouse->ps2dev.serio);
> > >
> > > - if (psmouse->pktcnt == 6) {
> > > + if (psmouse->pktcnt == psmouse->pktsize) {
> > >
> > > /*
> > > * We did not any more data in reasonable amount of time.
> > > @@ -365,15 +365,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> > > return PSMOUSE_BAD_DATA;
> > > }
> > >
> > > - /* Bytes 2 - 6 should have 0 in the highest bit */
> > > - if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
> > > + /* Bytes 2 - pktsize should have 0 in the highest bit */
> > > + if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
> > > (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
> > > dbg("refusing packet[%i] = %x\n",
> > > psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
> > > return PSMOUSE_BAD_DATA;
> > > }
> > >
> > > - if (psmouse->pktcnt == 6) {
> > > + if (psmouse->pktcnt == psmouse->pktsize) {
> > > alps_process_packet(psmouse);
> > > return PSMOUSE_FULL_PACKET;
> > > }
> > > @@ -531,8 +531,13 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable)
> > > static int alps_poll(struct psmouse *psmouse)
> > > {
> > > struct alps_data *priv = psmouse->private;
> > > - unsigned char buf[6];
> > > + unsigned char *buf;
> > > bool poll_failed;
> > > + int ret = -1;
> > > +
> > > + buf = kmalloc(psmouse->pktsize, GFP_KERNEL);
> > > + if (!buf)
> > > + return -1;
> >
> > Can we preallocate a buffer somewhere instead of allocating every time
> > we enter the function? If we know the maximum packet size we could
> > allocate on the stack instead.
>
> Thanks for pointing that out; I had meant to come back and do something
> about this but forgot. I was hoping to avoid having to hard-code an
> assumed maximum packet size. I'll take a look at it.
probably doing something like
unsigned char buf[sizeof(psmouse->packet)];
will cover it.
--
Dmitry
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/7] Input: ALPS - Remove assumptions about packet size
2011-10-31 18:24 ` Dmitry Torokhov
@ 2011-10-31 20:01 ` Seth Forshee
0 siblings, 0 replies; 20+ messages in thread
From: Seth Forshee @ 2011-10-31 20:01 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Chase Douglas, Alessandro Rubini, Henrik Rydberg, Andrew Skalski,
linux-input, linux-kernel
On Mon, Oct 31, 2011 at 11:24:37AM -0700, Dmitry Torokhov wrote:
> On Mon, Oct 31, 2011 at 02:17:02PM -0400, Seth Forshee wrote:
> > On Sun, Oct 30, 2011 at 11:36:19AM -0400, Chase Douglas wrote:
> > > On 10/26/2011 05:14 PM, Seth Forshee wrote:
> > > > In preparation for version 4 protocol support, which has 8-byte
> > > > data packets, remove all hard-coded assumptions about packet size
> > > > and use psmouse->pktsize instead.
> > > >
> > > > Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
> > > > ---
> > > > drivers/input/mouse/alps.c | 27 ++++++++++++++++++---------
> > > > 1 files changed, 18 insertions(+), 9 deletions(-)
> > > >
> > > > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> > > > index 572cb21..14d1f64 100644
> > > > --- a/drivers/input/mouse/alps.c
> > > > +++ b/drivers/input/mouse/alps.c
> > > > @@ -315,7 +315,7 @@ static void alps_flush_packet(unsigned long data)
> > > >
> > > > serio_pause_rx(psmouse->ps2dev.serio);
> > > >
> > > > - if (psmouse->pktcnt == 6) {
> > > > + if (psmouse->pktcnt == psmouse->pktsize) {
> > > >
> > > > /*
> > > > * We did not any more data in reasonable amount of time.
> > > > @@ -365,15 +365,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> > > > return PSMOUSE_BAD_DATA;
> > > > }
> > > >
> > > > - /* Bytes 2 - 6 should have 0 in the highest bit */
> > > > - if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
> > > > + /* Bytes 2 - pktsize should have 0 in the highest bit */
> > > > + if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
> > > > (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
> > > > dbg("refusing packet[%i] = %x\n",
> > > > psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
> > > > return PSMOUSE_BAD_DATA;
> > > > }
> > > >
> > > > - if (psmouse->pktcnt == 6) {
> > > > + if (psmouse->pktcnt == psmouse->pktsize) {
> > > > alps_process_packet(psmouse);
> > > > return PSMOUSE_FULL_PACKET;
> > > > }
> > > > @@ -531,8 +531,13 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable)
> > > > static int alps_poll(struct psmouse *psmouse)
> > > > {
> > > > struct alps_data *priv = psmouse->private;
> > > > - unsigned char buf[6];
> > > > + unsigned char *buf;
> > > > bool poll_failed;
> > > > + int ret = -1;
> > > > +
> > > > + buf = kmalloc(psmouse->pktsize, GFP_KERNEL);
> > > > + if (!buf)
> > > > + return -1;
> > >
> > > Can we preallocate a buffer somewhere instead of allocating every time
> > > we enter the function? If we know the maximum packet size we could
> > > allocate on the stack instead.
> >
> > Thanks for pointing that out; I had meant to come back and do something
> > about this but forgot. I was hoping to avoid having to hard-code an
> > assumed maximum packet size. I'll take a look at it.
>
> probably doing something like
>
> unsigned char buf[sizeof(psmouse->packet)];
>
> will cover it.
Yes, that will work great. I'll incorporate that into the next version
of the patches. Thanks.
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2011-10-31 20:01 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-26 21:14 [PATCH 0/7] Additional ALPS touchpad protocol support Seth Forshee
2011-10-26 21:14 ` [PATCH 1/7] Input: ALPS - Move protocol information to Documentation Seth Forshee
2011-10-30 15:33 ` Chase Douglas
2011-10-31 18:15 ` Seth Forshee
2011-10-26 21:14 ` [PATCH 2/7] Input: psmouse - Add PSMOUSE_CMD_RESET_WRAP Seth Forshee
2011-10-30 15:33 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 3/7] Input: ALPS - Add protocol version field in alps_model_info Seth Forshee
2011-10-30 15:34 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 4/7] Input: ALPS - Remove assumptions about packet size Seth Forshee
2011-10-30 15:36 ` Chase Douglas
2011-10-31 18:17 ` Seth Forshee
2011-10-31 18:24 ` Dmitry Torokhov
2011-10-31 20:01 ` Seth Forshee
2011-10-26 21:14 ` [PATCH 5/7] Input: ALPS - Add support for protocol versions 3 and 4 Seth Forshee
2011-10-30 15:37 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 6/7] Input: ALPS - Add semi-MT support for v3 protocol Seth Forshee
2011-10-30 15:44 ` Chase Douglas
2011-10-26 21:14 ` [PATCH 7/7] Input: ALPS - Add documentation for protocol versions 3 and 4 Seth Forshee
2011-10-30 15:46 ` Chase Douglas
2011-10-26 21:22 ` [PATCH 0/7] Additional ALPS touchpad protocol support Chris Friesen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).