[PATCH 2/2] Alps Dualpoint, Interleaved packets

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



... and this fixes the double-click issue when flooded with packets.  It
makes sure we never set the same mouse button on both dev and dev2.
When the button is released, it releases on both devices, since we don't
record which of them got the initial button-down.

Greetings,
 Sebastian



Date: Sun, 13 Dec 2009 22:44:10 +0100
Subject: [PATCH 2/2] fix double-click issue


Input: ALPS - add interleaved protocol support (Dell E6x00 series)

From: Sebastian Kapfer <sebastian_kapfer@xxxxxxx>

Fix a race between the button-down and the button-up events which could
lead to a single physical click on an Alps dualpoint unit being reported
as a double-click in X11.

This patch ensures that any click is assigned to only of the two
input_devs associated with the dualpoint unit, and never reported on the
other input_dev.

Signed-off-by: Sebastian Kapfer <sebastian_kapfer@xxxxxxx>


---
 drivers/input/mouse/alps.c |   78 ++++++++++++++++++++++++++------------------
 drivers/input/mouse/alps.h |    3 +-
 2 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 71b40ae..10b591c 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -39,6 +39,7 @@
 #define ALPS_FOUR_BUTTONS	0x40	/* 4 direction button present */
 #define ALPS_PS2_INTERLEAVED	0x80	/* 3-byte PS/2 packet interleaved with
 					   6-byte ALPS packet */
+#define ALPS_SHARED_BTNSTATE	0x100	/* PS/2 and touchpad share button st. */
 
 static const struct alps_model_info alps_model_data[] = {
 	{ { 0x32, 0x02, 0x14 },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
@@ -61,7 +62,7 @@ static const struct alps_model_info alps_model_data[] = {
 	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
 	/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
 	{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
-		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
+		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED | ALPS_SHARED_BTNSTATE },
 	{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS },	  /* Dell Vostro 1400 */
 };
 
@@ -108,18 +109,49 @@ static const struct alps_model_info alps_model_data[] = {
  * on a dualpoint, etc.
  */
 
-static void alps_report_buttons(struct input_dev *dev,
-				int left, int right, int middle,
-				bool release_only)
+static void alps_report_single_button(struct psmouse *psmouse,
+				      int keycode, int mask, int state,
+				      struct input_dev *dev)
 {
-	if (!left || !release_only)
-		input_report_key(dev, BTN_LEFT, left);
+	struct alps_data *priv = psmouse->private;
+	const struct alps_model_info *model = priv->i;
 
-	if (!right || !release_only)
-		input_report_key(dev, BTN_RIGHT, right);
+	/* some Alps units do not report touchpad and trackpoint
+	   buttons separately (e.g. even the trackpoint movement
+	   packets have buttons set while touchpad buttons are down) */
+	if (model->flags & ALPS_SHARED_BTNSTATE) {
+		if (state) {
+			/* need to avoid sending a button-down to both
+			   devices (can cause spurious double-click */
+			if (priv->btn_state & mask)
+				return;
+
+			priv->btn_state |= mask;
+		} else {
+			/* we don't know which device got the button
+			   down event.  just release both to be sure. */
+			struct input_dev *other = psmouse->dev;
+			if (dev == other)
+				other = priv->dev2;
+			input_report_key(other, keycode, state);
+			input_sync(other);
+
+			priv->btn_state &= 7 ^ mask;
+		}
+	}
 
-	if (!middle || !release_only)
-		input_report_key(dev, BTN_MIDDLE, middle);
+	/* input_sync called by our caller */
+	input_report_key(dev, keycode, state);
+}
+
+
+static void alps_report_buttons(struct psmouse *psmouse,
+				struct input_dev *dev,
+				int left, int right, int middle)
+{
+	alps_report_single_button(psmouse, BTN_LEFT,   1, left,   dev);
+	alps_report_single_button(psmouse, BTN_RIGHT,  2, right,  dev);
+	alps_report_single_button(psmouse, BTN_MIDDLE, 4, middle, dev);
 }
 
 static void alps_process_packet(struct psmouse *psmouse)
@@ -167,25 +199,13 @@ static void alps_process_packet(struct psmouse *psmouse)
 		input_report_rel(dev2, REL_X,  (x > 383 ? (x - 768) : x));
 		input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
 
-		alps_report_buttons(dev2, left, right, middle, false);
+		alps_report_buttons(psmouse, dev2, left, right, middle);
 
 		input_sync(dev2);
-		input_sync(dev);
 		return;
 	}
 
-	alps_report_buttons(dev, left, right, middle, false);
-
-	if (model->flags & ALPS_PS2_INTERLEAVED) {
-		/*
-		 * On devices using interleaved packets, when user presses
-		 * the same button on both trackpoint and touchpad, the
-		 * release for the trackpoint is not reported so we have
-		 * send release events to both devices.
-		 */
-		alps_report_buttons(dev2, left, right, middle, true);
-		input_sync(dev2);
-	}
+	alps_report_buttons(psmouse, dev, left, right, middle);
 
 	/* Convert hardware tap to a reasonable Z value */
 	if (ges && !fin)
@@ -248,14 +268,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 		int right = packet[0] & 2;
 		int middle = packet[0] & 4;
 
-
-		if (priv->i->flags & ALPS_PS2_INTERLEAVED) {
-			alps_report_buttons(psmouse->dev,
-					    left, right, middle, true);
-			input_sync(psmouse->dev);
-		}
-
-		alps_report_buttons(dev2, left, right, middle, false);
+		alps_report_buttons(psmouse, dev2, left, right, middle);
 	}
 
 	input_report_rel(dev2, REL_X,
@@ -675,6 +688,7 @@ int alps_init(struct psmouse *psmouse)
 
 	priv->dev2 = dev2;
 	setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
+	priv->btn_state = 0;
 
 	psmouse->private = priv;
 
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 904ed8b..b477063 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -15,7 +15,7 @@
 struct alps_model_info {
         unsigned char signature[3];
         unsigned char byte0, mask0;
-        unsigned char flags;
+        unsigned int flags;
 };
 
 struct alps_data {
@@ -23,6 +23,7 @@ struct alps_data {
 	char phys[32];			/* Phys */
 	const struct alps_model_info *i;/* Info */
 	int prev_fin;			/* Finger bit from previous packet */
+	int btn_state;			/* buttons reported to input_dev */
 	struct timer_list timer;
 };
 
-- 
1.6.3.3



--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux