[OLPC touchpad] Support PT-only and GS-only operation modes.
David Woodhouse
dwmw2 at infradead.unroutableorg
Wed Nov 15 04:40:31 EST 2006
Commit: bc0b9a38bcd71cef7cb013b8593d80f2f54c924a
Parent: 714e2030f905b0ecf2c3310a042617affdca263c
commit bc0b9a38bcd71cef7cb013b8593d80f2f54c924a
Author: David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Wed Nov 15 17:44:51 2006 +0800
Commit: David Woodhouse <dwmw2 at infradead.org>
CommitDate: Wed Nov 15 17:44:51 2006 +0800
[OLPC touchpad] Support PT-only and GS-only operation modes.
Handle all types of incoming packets, and add 'tpmode' parameter to
initialise as desired. Also add 'tpdebug' parameter.
Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
drivers/input/mouse/olpc.c | 184 ++++++++++++++++++++++++++++++++++++++++----
drivers/input/mouse/olpc.h | 1
2 files changed, 169 insertions(+), 16 deletions(-)
diff --git a/drivers/input/mouse/olpc.c b/drivers/input/mouse/olpc.c
index 1023ea5..9b2a56c 100644
--- a/drivers/input/mouse/olpc.c
+++ b/drivers/input/mouse/olpc.c
@@ -20,7 +20,7 @@
* The touchpad on the OLPC is fairly wide, with the entire area usable
* as a tablet, and the center 1/3rd also usable as a touchpad.
*
- * The device has simultanious reporting, so that both can be used at once.
+ * The device has simultaneous reporting, so that both can be used at once.
*
* The PT+GS protocol is similar to the base ALPS protocol, in that the
* GS data is where the ALPS parser would expect to find it, however
@@ -36,14 +36,23 @@ #include <linux/libps2.h>
#include "psmouse.h"
#include "olpc.h"
+static int tpmode = 0;
+module_param(tpmode, int, 0644);
+
+static int tpdebug;
+module_param(tpdebug, int, 0644);
static const struct olpc_model_info olpc_model_data[] = {
- { { 0x67, 0x00, 0x0a }, 0xeb, 0xff, 0 }, /* OLPC in PT+GS mode. */
- { { 0x67, 0x00, 0x14 }, 0xeb, 0xff, 0 }, /* Newer OLPC in PT+GS mode. */
+ { { 0x67, 0x00, 0x0a }, 0 }, /* OLPC in PT+GS mode. */
+ { { 0x67, 0x00, 0x14 }, 0 }, /* Newer OLPC in PT+GS mode. */
};
+#define OLPC_PKT_SIM 0xeb
+#define OLPC_PKT_PT 0xcf
+#define OLPC_PKT_GS 0xff
+
/*
- * OLPC absolute Mode - simultanious format
+ * OLPC absolute Mode - simultaneous format
*
* byte 0: 1 1 1 0 1 0 1 1
* byte 1: 0 gx6 gx5 gx4 gx3 gx2 gx1 gx0
@@ -110,12 +119,126 @@ static void olpc_process_packet(struct p
input_sync(dev2);
}
-static psmouse_ret_t olpc_process_byte(struct psmouse *psmouse)
+/*
+ * OLPC absolute Mode - single-mode format
+ *
+ * byte 0: 1 1 0 0 1 1 1 1
+ * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
+ * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw gs-dsw
+ * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
+ * byte 3: 0 y9 y8 y7 1 0 swr swl
+ * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
+ * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+ *
+ * ?'s are not defined in the protocol spec, may vary between models.
+ *
+ * swr/swl are the left/right buttons.
+ *
+ * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
+ * pen/finger
+ */
+
+static void olpc_process_pt_packet(struct psmouse *psmouse)
+{
+ struct olpc_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, gs_down, pt_down, left, right;
+
+ left = packet[3] & 1;
+ right = packet[3] & 2;
+ x = packet[1] | ((packet[2] & 0x78) << (7 - 3));
+ y = packet[4] | ((packet[3] & 0x70) << (7 - 4));
+ z = packet[5];
+
+ pt_down = packet[2] & 2;
+ gs_down = packet[2] & 1;
+
+ if (tpdebug) {
+ printk(KERN_DEBUG "%s %02x %02x %02x %02x %02x %02x\n",
+ __func__, psmouse->packet[0], psmouse->packet[1],
+ psmouse->packet[2], psmouse->packet[3], psmouse->packet[4],
+ psmouse->packet[5]);
+ printk(KERN_DEBUG "l=%d r=%d p=%d g=%d x=%d y=%d z=%d\n",
+ left, right, pt_down, gs_down, x, y, z);
+ }
+
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev2, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev2, BTN_RIGHT, right);
+
+ input_report_key(dev, BTN_TOUCH, pt_down);
+ input_report_key(dev, BTN_TOOL_PEN, pt_down);
+ input_report_key(dev2, BTN_TOUCH, gs_down);
+ input_report_key(dev2, BTN_TOOL_FINGER, gs_down);
+
+ input_report_abs(dev2, ABS_PRESSURE, z);
+
+ if (pt_down) {
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ }
+
+ input_sync(dev);
+ input_sync(dev2);
+}
+
+static void olpc_process_gs_packet(struct psmouse *psmouse)
{
struct olpc_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, gs_down, pt_down, left, right;
+
+ left = packet[3] & 1;
+ right = packet[3] & 2;
+ x = packet[1] | ((packet[2] & 0x78) << (7 - 3));
+ y = packet[4] | ((packet[3] & 0x70) << (7 - 4));
+ z = packet[5];
+
+ gs_down = packet[2] & 2;
+ pt_down = packet[2] & 1;
+
+ if (tpdebug) {
+ printk(KERN_DEBUG "%s %02x %02x %02x %02x %02x %02x\n",
+ __func__, psmouse->packet[0], psmouse->packet[1],
+ psmouse->packet[2], psmouse->packet[3], psmouse->packet[4],
+ psmouse->packet[5]);
+ printk(KERN_DEBUG "l=%d r=%d p=%d g=%d x=%d y=%d z=%d\n",
+ left, right, pt_down, gs_down, x, y, z);
+ }
+
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev2, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev2, BTN_RIGHT, right);
+
+ input_report_key(dev, BTN_TOUCH, pt_down);
+ input_report_key(dev, BTN_TOOL_PEN, pt_down);
+ input_report_key(dev2, BTN_TOUCH, gs_down);
+ input_report_key(dev2, BTN_TOOL_FINGER, gs_down);
+
+ input_report_abs(dev2, ABS_PRESSURE, z);
+
+ if (gs_down) {
+ input_report_abs(dev2, ABS_X, x);
+ input_report_abs(dev2, ABS_Y, y);
+ }
+
+ input_sync(dev);
+ input_sync(dev2);
+}
+
+static psmouse_ret_t olpc_process_byte(struct psmouse *psmouse)
+{
psmouse_ret_t ret = PSMOUSE_BAD_DATA;
- if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0)
+ if (psmouse->packet[0] != OLPC_PKT_SIM &&
+ psmouse->packet[0] != OLPC_PKT_PT &&
+ psmouse->packet[0] != OLPC_PKT_GS)
goto out;
/* Bytes 2 - 9 should have 0 in the highest bit */
@@ -124,13 +247,33 @@ static psmouse_ret_t olpc_process_byte(s
goto out;
/*
- * Bytes 4 and 7 should have 1 in the 4th bit, and the high bit unset.
+ * For simultaneous mode, bytes 4 and 7 should have 1 in the 4th bit,
+ * and the high bit unset.
+ */
+ if (psmouse->packet[0] == OLPC_PKT_SIM &&
+ (psmouse->pktcnt == 4 || psmouse->pktcnt == 7) &&
+ ((psmouse->packet[psmouse->pktcnt - 1] & 0x88) != 8))
+ goto out;
+
+ /*
+ * For single mode, byte 4 should have bit 3 set and bit 2 clear
*/
- if ((psmouse->pktcnt == 4 || psmouse->pktcnt == 7) &&
- ((psmouse->packet[psmouse->pktcnt - 1] & 0x88) != 8))
+ if (psmouse->packet[0] != OLPC_PKT_SIM &&
+ psmouse->pktcnt == 4 &&
+ ((psmouse->packet[psmouse->pktcnt - 1] & 0xc) != 0x8))
goto out;
- if (psmouse->pktcnt == 9) {
+ if (psmouse->packet[0] == OLPC_PKT_PT &&
+ psmouse->pktcnt == 6) {
+ olpc_process_pt_packet(psmouse);
+ ret = PSMOUSE_FULL_PACKET;
+ goto out;
+ } else if (psmouse->packet[0] == OLPC_PKT_GS &&
+ psmouse->pktcnt == 6) {
+ olpc_process_gs_packet(psmouse);
+ ret = PSMOUSE_FULL_PACKET;
+ goto out;
+ } else if (psmouse->pktcnt == 9) {
olpc_process_packet(psmouse);
ret = PSMOUSE_FULL_PACKET;
@@ -194,16 +337,27 @@ static int olpc_absolute_mode(struct psm
return -1;
/*
- * Switch to simultanious mode, F2 (GETID) three times with no
+ * Switch to simultaneous mode, F2 (GETID) three times with no
* arguments or reply, followed by SETRES with an argument of 2.
*/
ps2_command(ps2dev, NULL, 0xF2);
ps2_command(ps2dev, NULL, 0xF2);
ps2_command(ps2dev, NULL, 0xF2);
- param = 0x02;
- ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
-
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+ switch(tpmode) {
+ default:
+ printk(KERN_WARNING "Invalid tpmode %d. Default to simultaneous mode\n", tpmode);
+ case 0: /* Dual mode */
+ param = 0x02;
+ ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+ break;
+ case 1: /* GS only */
+ ps2_command(ps2dev, NULL, 0xe6);
+ break;
+ case 2: /* PT only */
+ ps2_command(ps2dev, NULL, 0xe7);
+ break;
+ }
param = 100;
ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
diff --git a/drivers/input/mouse/olpc.h b/drivers/input/mouse/olpc.h
index f61bc90..4e7c76a 100644
--- a/drivers/input/mouse/olpc.h
+++ b/drivers/input/mouse/olpc.h
@@ -20,7 +20,6 @@ int olpc_init(struct psmouse *psmouse);
struct olpc_model_info {
unsigned char signature[3];
- unsigned char byte0, mask0;
unsigned char flags;
};
More information about the Commits-kernel
mailing list