lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 24 Oct 2007 05:54:10 +0200
From:	Arjan Opmeer <arjan@...eer.net>
To:	Arjan Opmeer <arjan@...eer.net>
Cc:	linux-kernel@...r.kernel.org, linux-input@...ey.karlin.mff.cuni.cz
Subject: [PATCH] Elantech touchpad driver update for kernel 2.6.23-mm1

>From Arjan Opmeer <arjan@...eer.net>

Update to the Elantech touchpad driver. Changes include:

- Absolute mode reporting is now working on my laptop.
- Fixed the use of a wrong constant in the Synaptics Identify query
- Added Synaptics Modes query as newer versions of the Windows Elantech
  driver seem to try that query too.
- Make an educated guess bases on the Synaptics Capabilities query whether
  middle mouse button reporting works and how finger taps are reported.
- Added a debug option.

Signed-off-by: Arjan Opmeer <arjan@...eer.net>

---
diff -purN -X linux-2.6.23-mm1.vanilla/Documentation/dontdiff linux-2.6.23-mm1.vanilla/Documentation/input/elantech.txt linux-2.6.23-mm1.elantech/Documentation/input/elantech.txt
--- linux-2.6.23-mm1.vanilla/Documentation/input/elantech.txt	2007-10-22 05:24:20.000000000 +0200
+++ linux-2.6.23-mm1.elantech/Documentation/input/elantech.txt	2007-10-22 05:24:55.000000000 +0200
@@ -1,68 +1,75 @@
 Elantech Touchpad Driver
 ========================
-	Copyright (C) 2007 Arjan Opmeer <arjan@...eer.net>
+        Copyright (C) 2007 Arjan Opmeer <arjan@...eer.net>
 
+        Extra information found and provided by Steve Havelka
 
-Configuration of the touchpad is performed by writing register values to the
-corresponding sysfs entries found under /sys/bus/serio/drivers/psmouse/serioX
+Configuration of the touchpad is performed by writing values to registers
+found under sysfs entries /sys/bus/serio/drivers/psmouse/serio?/reg_*.
+
+E.g. to disable tapping while leaving the other settings to the default
+Windows driver value one would:
+
+   echo -n 0x32 > reg_10
 
 
 Registers
----------
+~~~~~~~~~
 
-* reg_10	(Windows driver default value 0x12)
+* reg_10        (Windows driver default value 0x12)
 
    bit   7   6   5   4   3   2   1   0
-         0   C   T   D   L   R   S   E
+         B   C   T   D   L   A   S   E
 
          E: 1 = enable smart edges in other cases
          S: 1 = enable smart edges only when dragging
-         R: 1 = raw mode (needs 4 byte packets, see reg_11)
+         A: 1 = absolute mode (needs 4 byte packets, see reg_11)
          L: 1 = enable drag lock (see reg_22)
          D: 1 = disable dynamic resolution
          T: 1 = disable tapping
          C: 1 = enable corner tap
+         B: 1 = swap left and right button
 
-* reg_11	(Windows driver default value 0x8f)
+* reg_11        (Windows driver default value 0x8f)
 
    bit   7   6   5   4   3   2   1   0
-         1   0   0   H   V   1   P   N
+         1   0   0   H   V   1   F   P
 
-         N: 1 = bit 4 or 5 of byte 0 is 1 (non null top nibble ?)
-         P: 1 = enable native 4 byte packet mode (forced on by driver)
+         P: 1 = enable parity checking for relative mode
+         F: 1 = enable native 4 byte packet mode
          V: 1 = enable vertical scroll area
          H: 1 = enable horizonal scroll area
 
 
-* reg_20	(Windows driver default value 0x0a)
+* reg_20        (Windows driver default value 0x0a)
 
          single finger width?
 
-* reg_21	(Windows driver default value 0x60)
+* reg_21        (Windows driver default value 0x60)
 
          scroll area width (small: 0x40 ... wide: 0xff)
 
-* reg_22	(Windows driver default value 0xff)
+* reg_22        (Windows driver default value 0xff)
 
          drag lock time out (short: 0x14 ... long: 0xfe; 0xff =never)
 
-* reg_23	(Windows driver default value 0x10)
+* reg_23        (Windows driver default value 0x10)
 
          tap make timeout?
 
          Note: the Windows driver does not write this register
 
-* reg_24	(Windows driver default value 0x10)
+* reg_24        (Windows driver default value 0x10)
 
          tap release timeout?
 
          Note: the Windows driver does not write this register
 
-* reg_25	(Windows driver default value 0x03)
+* reg_25        (Windows driver default value 0x03)
 
          smart edge cursor speed (0x02 = slow, 0x03 = medium, 0x04 = fast)
 
-* reg_26	(Windows driver default value 0x00 ?? )
+* reg_26        (Windows driver default value 0x00 ?? )
 
          smart edge activation area width?
 
@@ -77,18 +84,22 @@ Registers
 
 Initially the Elantouch Touchpad is in emulation mode and reports 3 byte
 standard PS/2 packets and hence works with a standard mouse driver.
-However, it can be configured to talk its native 4 byte mode and a raw 4
+However, it can be configured to talk its native 4 byte relative mode and 4
 byte absolute mode both for which a dedicated driver is needed.
 
 
 Native 4 byte relative mode packet format
------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 byte 0:
    bit   7   6   5   4   3   2   1   0
-         c   c   ?   ?   1   M   R   L
+         c   c  p2  p1   1   M   R   L
 
          L, R, M = 1 when Left, Right, Middle mouse button pressed
+            some models have M as byte 3 odd parity
+         when parity checking is enabled (P = 1):
+            p1 = byte 1 odd parity
+            p2 = byte 2 odd parity
          c = 1 when corner tap detected
 
 byte 1:
@@ -106,30 +117,39 @@ byte 2:
 
 byte 3:
    bit   7   6   5   4   3   2   1   0
-         w   h   0   0  d3  d2  d1  d0
+         w   h  n1  n0  d3  d2  d1  d0
 
-         normally:
-            d3..d0 = scroll wheel amount and direction
-                     positive = down or left
-                     negative = up or right
-         when corner tap detected:
-            d0 = 1 when top right corner tapped
-            d1 = 1 when bottom right corner tapped
-            d2 = 1 when bottom left corner tapped
-            d3 = 1 when top left corner tapped
-         w = 1 when wide finger touch?
-         h = 1 when horizontal scroll action
+         when parity checking is enabled (P = 1):
+            normally:
+               d3..d0 = scroll wheel amount and direction
+                        positive = down or left
+                        negative = up or right
+            when corner tap detected:
+               d0 = 1 when top right corner tapped
+               d1 = 1 when bottom right corner tapped
+               d2 = 1 when bottom left corner tapped
+               d3 = 1 when top left corner tapped
+            n1..n0 = number of fingers on touchpad
+               not all models report this but map one, two and three
+               finger taps directly to L, M and R mouse buttons
+            w = 1 when wide finger touch?
+            h = 1 when horizontal scroll action
+         otherwise (P = 0):
+            all of byte 3 is vertical scroll amount and direction
+            negative = up
+            positive = down
 
 
-Native 4 byte raw absolute mode packet format
----------------------------------------------
+Native 4 byte absolute mode packet format
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 byte 0:
    bit   7   6   5   4   3   2   1   0
-         0   0  z2  z1   1  z0   R   L
+         D   U  p1  p2   1  p3   R   L
 
          L, R = 1 when Left, Right mouse button pressed
-         z2..z0 = some touch weigth?
+         p1..p3 = parity bit of bytes 1..3
+         D, U = 1 when rocker switch pressed Up, Down
 
 byte 1:
    bit   7   6   5   4   3   2   1   0
diff -purN -X linux-2.6.23-mm1.vanilla/Documentation/dontdiff linux-2.6.23-mm1.vanilla/drivers/input/mouse/elantech.c linux-2.6.23-mm1.elantech/drivers/input/mouse/elantech.c
--- linux-2.6.23-mm1.vanilla/drivers/input/mouse/elantech.c	2007-10-22 05:17:57.000000000 +0200
+++ linux-2.6.23-mm1.elantech/drivers/input/mouse/elantech.c	2007-10-22 05:48:47.000000000 +0200
@@ -18,14 +18,12 @@
 #include "synaptics.h"
 #include "elantech.h"
 
-#define ETP_RAW_MODE 		0x04
-#define ETP_4_BYTE_MODE 	0x02
-
-/* These values work with the touchpad on my laptop. Do they need adjustment? */
-#define ETP_XMIN 		32
-#define ETP_XMAX 		0x240
-#define ETP_YMIN 		32
-#define ETP_YMAX 		0x160
+/*
+ * Native absolute mode reporting has odd parity check on the last 3 bytes.
+ * Native relative mode can have odd parity checking on second and third byte,
+ * or last 3 bytes depending on model.
+ */
+static unsigned char parity[256];
 
 /*
  * Send a synaptics style special commands
@@ -49,7 +47,7 @@ static int elantech_write_reg(struct psm
 	if ((reg > 0x11) && (reg < 0x20))
 		return -1;
 
-	if (psmouse_sliced_command(psmouse, ELANTECH_COMMAND) ||
+	if (psmouse_sliced_command(psmouse, ELANTECH_COMMAND_START) ||
 	    psmouse_sliced_command(psmouse, reg) ||
 	    psmouse_sliced_command(psmouse, val) ||
 	    ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) {
@@ -59,67 +57,153 @@ static int elantech_write_reg(struct psm
 	return 0;
 }
 
+static void elantech_packet_dump(unsigned char *packet, int size)
+{
+	int	i;
+
+	printk(KERN_DEBUG "elantech.c: PS/2 packet [");
+	for (i = 0; i < size; i++)
+		printk("%s0x%02x ", (i) ? ", " : " ", packet[i]);
+	printk("]\n");
+}
+
 /*
- * Process byte stream from mouse and interpret complete data packages
+ * Report absolute mode input events
  */
-static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
+static void elantech_report_absolute(struct psmouse *psmouse)
 {
 	struct elantech_data 	*etd = psmouse->private;
 	struct input_dev 	*dev = psmouse->dev;
 	unsigned char 		*packet = psmouse->packet;
-	unsigned int 		z;
+	int			fingers;
 
-	if (psmouse->pktcnt < 4)
-		return PSMOUSE_GOOD_DATA;
+	/* byte 0:  D   U  p1  p2   1  p3   R   L
+	 * byte 1:  f   0  th  tw  x9  x8  y9  y8
+	 * byte 2: x7  x6  x5  x4  x3  x2  x1  x0
+	 * byte 3: y7  y6  y5  y4  y3  y2  y1  y0 */
+	fingers = ((packet[1] & 0x80) >> 7) + ((packet[1] & 0x30) >> 4);
+	input_report_key(dev, BTN_TOUCH, fingers != 0);
+	if (fingers == 1) {
+		input_report_abs(dev, ABS_X,
+			((packet[1] & 0x0c) << 6) | packet[2]);
+		input_report_abs(dev, ABS_Y, ETP_YMAX -
+			(((packet[1] & 0x03) << 8) | packet[3]));
+	}
+	input_report_abs(dev, ABS_PRESSURE, (fingers) ? ETP_DEF_PRESSURE : 0);
+	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_LEFT, packet[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+	if (etd->capabilities & ETP_CAP_HAS_ROCKER) {
+		input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); /* rocker up */
+		input_report_key(dev, BTN_BACK, packet[0] & 0x80); /* rocker down */
+	}
+}
 
-	if (etd->reg_10 & ETP_RAW_MODE) {
-		/*
-		 * What to do with this value? It varies too wildly to work
-		 * as a useful z distance
-		 */
-		z = ((packet[0] & 0x30) >> 3) | ((packet[0] & 0x04) >> 2);
-		input_report_key(dev, BTN_TOUCH, packet[1] & 0x80);
-		if ((packet[1] & 0x30) == 0) {
-			input_report_abs(dev, ABS_X,
-				((packet[1] & 0x0c) << 6) | packet[2]);
-			input_report_abs(dev, ABS_Y,
-				ETP_YMIN + ETP_YMAX -
-				(((packet[1] & 0x03) << 8) | packet[3]));
-		}
-		input_report_key(dev, BTN_TOOL_FINGER,    packet[1] & 0x80);
-		input_report_key(dev, BTN_TOOL_DOUBLETAP, packet[1] & 0x10);
-		input_report_key(dev, BTN_TOOL_TRIPLETAP, packet[1] & 0x20);
-		input_report_key(dev, BTN_LEFT,  packet[0] & 0x01);
-		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
-	} else {
-		input_report_key(dev, BTN_LEFT,   packet[0] & 0x01);
+/*
+ * Report relative mode input events
+ */
+static void elantech_report_relative(struct psmouse *psmouse)
+{
+	struct elantech_data 	*etd = psmouse->private;
+	struct input_dev 	*dev = psmouse->dev;
+	unsigned char 		*packet = psmouse->packet;
+	int 			fingers, cornertap;
+
+	/* byte 0:  c   c  p2  p1   1   M   R   L
+	 * byte 1: dx7 dx6 dx5 dx4 dx3 dx2 dx1 dx0
+	 * byte 2: dy7 dy6 dy5 dy4 dy3 dy2 dy1 dy0
+	 * byte 3:  w   h  n1  n0  d3  d2  d1  d0 */
+	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+
+	if (etd->capabilities & ETP_CAP_REPORTS_MIDDLE_BUTTON)
 		input_report_key(dev, BTN_MIDDLE, packet[0] & 0x04);
-		input_report_key(dev, BTN_RIGHT,  packet[0] & 0x02);
 
-		if ((packet[0] & 0xc0) && (packet[1] & 0xf0)) {
-			input_report_key(dev, BTN_0, packet[3] & 0x01);	/* top right */
-			input_report_key(dev, BTN_1, packet[3] & 0x02);	/* bottom right */
-			input_report_key(dev, BTN_2, packet[3] & 0x04);	/* bottom left */
-			input_report_key(dev, BTN_3, packet[3] & 0x08);	/* top left */
-		} else if (packet[3] & 0x0f) {
-			if (packet[3] & 0x40)
+	if (etd->capabilities & ETP_CAP_ALTERNATE_TAP_BITS) {
+		fingers = (packet[3] & 0x30) >> 4;
+		input_report_key(dev, BTN_LEFT, fingers == 1);
+		input_report_key(dev, BTN_MIDDLE, fingers == 2);
+		input_report_key(dev, BTN_RIGHT, fingers == 3);
+	}
+
+	cornertap = (((packet[0] & 0xc0) == 0xc0) && ((packet[1] & 0xf0) == 0xf0));
+	if (!cornertap) {
+		input_report_rel(dev, REL_X, (int) (packet[1] & 0x7f) -
+					     (int) (packet[1] & 0x80));
+		input_report_rel(dev, REL_Y, (int) (packet[2] & 0x80) -
+					     (int) (packet[2] & 0x7f));
+	}
+
+	/* No more information in 3 bytes */
+	if (!(etd->reg_11 & ETP_R11_4_BYTE_MODE))
+		return;
+
+	if (cornertap) {
+		input_report_key(dev, BTN_0, packet[3] & 0x01);	/* top right */
+		input_report_key(dev, BTN_1, packet[3] & 0x02);	/* bottom right */
+		input_report_key(dev, BTN_2, packet[3] & 0x04);	/* bottom left */
+		input_report_key(dev, BTN_3, packet[3] & 0x08);	/* top left */
+	}
+
+	if (etd->reg_11 & ETP_R11_PARITY_CHECKING) {
+		if (packet[3] & 0x0f) {
+			if (packet[3] & 0x40) {
 				input_report_rel(dev, REL_HWHEEL,
 					(int) (packet[3] & 0x08) -
 					(int) (packet[3] & 0x07));
-			else
+			} else {
 				input_report_rel(dev, REL_WHEEL,
 					(int) (packet[3] & 0x08) -
 					(int) (packet[3] & 0x07));
+			}
 		}
+	} else {
+		if (packet[3])
+			input_report_rel(dev, REL_WHEEL,
+				(int) (packet[3] & 0x80) -
+				(int) (packet[3] & 0x7f));
+	}
+}
 
-		if (packet[1])
-			input_report_rel(dev, REL_X,
-				(int) (packet[1] & 0x7f) -
-				(int) (packet[1] & 0x80));
-		if (packet[2])
-			input_report_rel(dev, REL_Y,
-				(int) (packet[2] & 0x80) -
-				(int) (packet[2] & 0x7f));
+/*
+ * Process byte stream from mouse and interpret complete data packets
+ */
+static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
+{
+	struct elantech_data 	*etd = psmouse->private;
+	struct input_dev 	*dev = psmouse->dev;
+	unsigned char 		*packet = psmouse->packet;
+
+	if (psmouse->pktcnt < psmouse->pktsize)
+		return PSMOUSE_GOOD_DATA;
+
+	if (etd->debug)
+		elantech_packet_dump(packet, psmouse->pktsize);
+
+	if (etd->reg_10 & ETP_R10_ABSOLUTE_MODE) {
+		/* byte 0:  D   U  p1  p2   1  p3   R   L */
+		if ((parity[packet[1]] != ((packet[0] & 0x20) >> 5)) ||
+		    (parity[packet[2]] != ((packet[0] & 0x10) >> 4)) ||
+		    (parity[packet[3]] != ((packet[0] & 0x04) >> 2)))
+			return PSMOUSE_BAD_DATA;
+	} else if (etd->reg_11 & ETP_R11_PARITY_CHECKING) {
+		/* byte 0:  c   c  p2  p1   1   M   R   L */
+		if ((parity[packet[1]] != ((packet[0] & 0x10) >> 4)) ||
+		    (parity[packet[2]] != ((packet[0] & 0x20) >> 5)))
+			return PSMOUSE_BAD_DATA;
+		/* Parity bit has not been sacrificed as middle mouse button bit */
+		if (!(etd->capabilities & ETP_CAP_REPORTS_MIDDLE_BUTTON)) {
+			if (parity[packet[3]] != ((packet[0] & 0x04) >> 2))
+				return PSMOUSE_BAD_DATA;
+		}
+	}
+
+	if (etd->reg_10 & ETP_R10_ABSOLUTE_MODE) {
+		elantech_report_absolute(psmouse);
+	} else {
+		elantech_report_relative(psmouse);
 	}
 
 	input_sync(dev);
@@ -183,6 +267,12 @@ static void elantech_set_defaults(struct
 	set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
 	set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
 
+	/* Rocker button */
+	if (etd->capabilities & ETP_CAP_HAS_ROCKER) {
+		set_bit(BTN_FORWARD, dev->keybit);
+		set_bit(BTN_BACK, dev->keybit);
+	}
+
 	/* Corner taps */
 	set_bit(BTN_0, dev->keybit);
 	set_bit(BTN_1, dev->keybit);
@@ -198,6 +288,7 @@ static void elantech_set_defaults(struct
 	set_bit(EV_ABS, dev->evbit);
 	input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0);
 	input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0);
+	input_set_abs_params(dev, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
 }
 
 struct elantech_attr_data {
@@ -235,9 +326,26 @@ static ssize_t elantech_set_int_attr(str
 	if (*rest || value > 255)
 		return -EINVAL;
 
-	/* Force 4 byte packet mode because driver expects this */
-	if (attr->reg == 0x11)
-		value |= ETP_4_BYTE_MODE;
+	if (attr->reg == 0x10) {
+		/* Force on 4 byte mode when absolute mode gets selected */
+		if ((value & ETP_R10_ABSOLUTE_MODE) &&
+		   !(etd->reg_11 & ETP_R11_4_BYTE_MODE)) {
+			etd->reg_11 |= ETP_R11_4_BYTE_MODE;
+			elantech_write_reg(psmouse, 0x11, etd->reg_11);
+			psmouse->pktsize = 4;
+		}
+	} else if (attr->reg == 0x11) {
+		if (value & ETP_R11_4_BYTE_MODE)
+			psmouse->pktsize = 4;
+		else {
+			/* Force off absolute mode when 4 byte mode is no longer selected */
+			if (etd->reg_10 & ETP_R10_ABSOLUTE_MODE) {
+				etd->reg_10 ^= ETP_R10_ABSOLUTE_MODE;
+				elantech_write_reg(psmouse, 0x10, etd->reg_10);
+			}
+			psmouse->pktsize = 3;
+		}
+	}
 
 	*reg = value;
 	elantech_write_reg(psmouse, attr->reg, value);
@@ -264,6 +372,7 @@ ELANTECH_INT_ATTR(reg_23, 0x23);
 ELANTECH_INT_ATTR(reg_24, 0x24);
 ELANTECH_INT_ATTR(reg_25, 0x25);
 ELANTECH_INT_ATTR(reg_26, 0x26);
+ELANTECH_INT_ATTR(debug, 0);
 
 static struct attribute *elantech_attrs[] = {
 	&psmouse_attr_reg_10.dattr.attr,
@@ -275,6 +384,7 @@ static struct attribute *elantech_attrs[
 	&psmouse_attr_reg_24.dattr.attr,
 	&psmouse_attr_reg_25.dattr.attr,
 	&psmouse_attr_reg_26.dattr.attr,
+	&psmouse_attr_debug.dattr.attr,
 	NULL
 };
 
@@ -312,16 +422,6 @@ int elantech_detect(struct psmouse *psmo
 			param[0], param[1], param[2]);
 		return -1;
 	}
-	/* Why does the Elantech Windows driver try this?
-	 * For now just report it and see if it makes sense
-	 * when more people use this driver
-	 */
-	if (!synaptics_send_cmd(psmouse, SYN_QUE_MODEL, param))
-		pr_info("elantech.c: Synaptics identify query result 0x%02x, 0x%02x, 0x%02x.\n",
-			param[0], param[1], param[2]);
-	if (!synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, param))
-		pr_info("elantech.c: Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
-			param[0], param[1], param[2]);
 
 	if (set_properties) {
 		psmouse->vendor = "Elantech";
@@ -336,14 +436,36 @@ int elantech_detect(struct psmouse *psmo
  */
 int elantech_init(struct psmouse *psmouse)
 {
-	struct elantech_data 	*priv;
-	int			error;
-
-	priv = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
-	psmouse->private = priv;
-	if (!priv)
+	struct elantech_data 	*etd;
+	int			i, error;
+	unsigned char		param[3];
+
+	etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
+	psmouse->private = etd;
+	if (!etd)
 		return -1;
 
+	parity[0] = 1;
+	for (i = 1; i < 256; i++)
+		parity[i] = (parity[i & (i - 1)] ^ 1);
+
+	/*
+	 * Why does the Elantech Windows driver try this?
+	 * For now just report it and see if it makes sense
+	 * when more people use this driver
+	 */
+	if (!synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, param))
+		pr_info("elantech.c: Synaptics identify query result 0x%02x, 0x%02x, 0x%02x.\n",
+			param[0], param[1], param[2]);
+	if (!synaptics_send_cmd(psmouse, SYN_QUE_MODES, param))
+		pr_info("elantech.c: Synaptics modes query result 0x%02x, 0x%02x, 0x%02x.\n",
+			param[0], param[1], param[2]);
+	if (!synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, param)) {
+		pr_info("elantech.c: Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
+			param[0], param[1], param[2]);
+		etd->capabilities = param[0];
+	}
+
 	elantech_set_defaults(psmouse);
 
 	psmouse->protocol_handler = elantech_process_byte;
@@ -355,7 +477,7 @@ int elantech_init(struct psmouse *psmous
 	if (error) {
 		printk(KERN_ERR "elantech.c: failed to create sysfs attributes, error: %d\n",
 			error);
-		kfree(priv);
+		kfree(etd);
 		return -1;
 	}
 
diff -purN -X linux-2.6.23-mm1.vanilla/Documentation/dontdiff linux-2.6.23-mm1.vanilla/drivers/input/mouse/elantech.h linux-2.6.23-mm1.elantech/drivers/input/mouse/elantech.h
--- linux-2.6.23-mm1.vanilla/drivers/input/mouse/elantech.h	2007-10-22 05:17:57.000000000 +0200
+++ linux-2.6.23-mm1.elantech/drivers/input/mouse/elantech.h	2007-10-22 05:25:23.000000000 +0200
@@ -13,7 +13,43 @@
 #ifndef _ELANTECH_H
 #define _ELANTECH_H
 
-#define ELANTECH_COMMAND	0x11	/* Commands start with this value */
+/*
+ * Commands start with this value
+ */
+#define ELANTECH_COMMAND_START		0x11
+
+/*
+ * Register bitmasks
+ */
+#define ETP_R10_ABSOLUTE_MODE		0x04
+#define ETP_R11_PARITY_CHECKING		0x01
+#define ETP_R11_4_BYTE_MODE 		0x02
+
+/*
+ * Capability bitmasks
+ */
+#define ETP_CAP_REPORTS_MIDDLE_BUTTON	0x02
+#define ETP_CAP_HAS_ROCKER		0x04
+#define ETP_CAP_ALTERNATE_TAP_BITS	0x10
+
+/*
+ * One hard to find application note states that X axis range is 0 to 576
+ * and Y axis range is 0 to 384.
+ * Edge fuzz might be necessary because of bezel around the touchpad.
+ */
+#define ETP_EDGE_FUZZ			32
+
+#define ETP_XMIN 			(  0 + ETP_EDGE_FUZZ)
+#define ETP_XMAX 			(576 - ETP_EDGE_FUZZ)
+#define ETP_YMIN 			(  0 + ETP_EDGE_FUZZ)
+#define ETP_YMAX 			(384 - ETP_EDGE_FUZZ)
+
+/*
+ * It seems the touchpad does not report pressure.
+ * Just choose some values for compatibility with X Synaptics driver
+ */
+#define ETP_MAX_PRESSURE		127
+#define ETP_DEF_PRESSURE		64
 
 struct elantech_data {
 	unsigned char reg_10;
@@ -25,6 +61,8 @@ struct elantech_data {
 	unsigned char reg_24;
 	unsigned char reg_25;
 	unsigned char reg_26;
+	unsigned char debug;
+	unsigned char capabilities;
 };
 
 #ifdef CONFIG_MOUSE_PS2_ELANTECH
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ