public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dtor_core@ameritech.net>
To: linux-kernel@vger.kernel.org
Subject: KVMs & psmouse losing sync
Date: Sat, 30 Oct 2004 00:38:02 -0500	[thread overview]
Message-ID: <200410300038.04193.dtor_core@ameritech.net> (raw)

Hi,

Here is my next attempt at resolving the problem with psmouse losing sync
when used with KVMs that suppress psmouse announcements when switching back
to linux box.

The new parameter psmouse.poll is used to have the driver periodically send
"enable" command to the mouse if there was no data from the device in last
<poll> msec. If the command errors or times out the driver assumes that the
mouse was disconnected and next time there is data on the same serio port
the driver will attempt to reconnect.

The advantages of this approach is that it should work well regardless of
the protocol (normally it is very hard to differentiate between bare PS/2
and PS2++) and driver will not pass any bad packets to userpace. The main
cpms is that we're toast if KVM ACKs the command even when mouse/kbd are
connected to another box. 

The patch is against vanilla 2.6.9, boot with psmouse.poll=500. I would
appreciate comments/testing. Thanks!

-- 
Dmitry

diff -urN --exclude-from=/usr/src/exclude 2.6.9/drivers/input/mouse/psmouse-base.c linux-2.6.9/drivers/input/mouse/psmouse-base.c
--- 2.6.9/drivers/input/mouse/psmouse-base.c	2004-10-18 16:53:43.000000000 -0500
+++ linux-2.6.9/drivers/input/mouse/psmouse-base.c	2004-10-29 22:06:34.000000000 -0500
@@ -49,6 +49,10 @@
 module_param_named(resetafter, psmouse_resetafter, uint, 0);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
+static unsigned int psmouse_poll;
+module_param_named(poll, psmouse_poll, uint, 0);
+MODULE_PARM_DESC(poll, "Poll interval to verify presence of the device (0 to disable).");
+
 __obsolete_setup("psmouse_noext");
 __obsolete_setup("psmouse_resolution=");
 __obsolete_setup("psmouse_smartscroll=");
@@ -139,6 +143,24 @@
 	if (psmouse->state == PSMOUSE_IGNORE)
 		goto out;
 
+	if (unlikely(psmouse->state == PSMOUSE_LOST_HEARTBIT)) {
+		printk(KERN_INFO "psmouse: new data after losing heartbit, reconnecting...\n");
+		psmouse->state = PSMOUSE_IGNORE;
+		serio_reconnect(psmouse->serio);
+		goto out;
+	}
+
+	if (unlikely(psmouse->state == PSMOUSE_WAIT_HEARTBIT)) {
+		if ((flags & (SERIO_PARITY|SERIO_TIMEOUT)) ||
+		    data != PSMOUSE_RET_ACK) {
+			printk(KERN_INFO "psmouse.c: %s at %s lost heartbit\n",
+				psmouse->name, psmouse->phys);
+			psmouse->state = PSMOUSE_LOST_HEARTBIT;
+		} else
+			psmouse->state = PSMOUSE_ACTIVATED;
+		goto out;
+	}
+
 	if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) {
 		if (psmouse->state == PSMOUSE_ACTIVATED)
 			printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
@@ -266,6 +288,31 @@
 	return IRQ_HANDLED;
 }
 
+static void psmouse_heartbit(unsigned long p)
+{
+	struct psmouse *psmouse = (struct psmouse *)p;
+
+	if (!psmouse_poll || psmouse->state != PSMOUSE_ACTIVATED)
+		return;
+
+	if (time_before(jiffies, psmouse->last + msecs_to_jiffies(psmouse_poll))) {
+		/* we recently had some data, just reschedule timer */
+		mod_timer(&psmouse->heartbit, psmouse->last + msecs_to_jiffies(psmouse_poll));
+	} else {
+		/* last data was long ago, ping the mouse */
+		serio_pause_rx(psmouse->serio);
+		if (serio_write(psmouse->serio, PSMOUSE_CMD_ENABLE) < 0) {
+			psmouse->state = PSMOUSE_IGNORE;
+			serio_continue_rx(psmouse->serio);
+			serio_reconnect(psmouse->serio);
+			return;
+		}
+		psmouse->state = PSMOUSE_WAIT_HEARTBIT;
+		serio_continue_rx(psmouse->serio);
+		mod_timer(&psmouse->heartbit, jiffies + msecs_to_jiffies(psmouse_poll));
+	}
+}
+
 /*
  * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
  * It doesn't handle retransmission, though it could - because when there would
@@ -674,6 +721,9 @@
 		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
 
 	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+
+	if (psmouse_poll)
+		mod_timer(&psmouse->heartbit, jiffies + msecs_to_jiffies(psmouse_poll));
 }
 
 
@@ -711,7 +761,9 @@
 	struct psmouse *psmouse, *parent;
 
 	psmouse = serio->private;
+
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+	del_timer_sync(&psmouse->heartbit);
 
 	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
 		parent = serio->parent->private;
@@ -756,6 +808,9 @@
 	memset(psmouse, 0, sizeof(struct psmouse));
 
 	init_waitqueue_head(&psmouse->wait);
+	init_timer(&psmouse->heartbit);
+	psmouse->heartbit.data = (unsigned long)psmouse;
+	psmouse->heartbit.function = psmouse_heartbit;
 	init_input_dev(&psmouse->dev);
 	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
diff -urN --exclude-from=/usr/src/exclude 2.6.9/drivers/input/mouse/psmouse.h linux-2.6.9/drivers/input/mouse/psmouse.h
--- 2.6.9/drivers/input/mouse/psmouse.h	2004-10-18 16:55:06.000000000 -0500
+++ linux-2.6.9/drivers/input/mouse/psmouse.h	2004-10-29 21:31:06.000000000 -0500
@@ -28,6 +28,8 @@
 	PSMOUSE_INITIALIZING,
 	PSMOUSE_CMD_MODE,
 	PSMOUSE_ACTIVATED,
+	PSMOUSE_WAIT_HEARTBIT,
+	PSMOUSE_LOST_HEARTBIT,
 };
 
 /* psmouse protocol handler return codes */
@@ -61,6 +63,8 @@
 	/* Used to signal completion from interrupt handler */
 	wait_queue_head_t wait;
 
+	struct timer_list heartbit;
+
 	psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
 	int (*reconnect)(struct psmouse *psmouse);
 	void (*disconnect)(struct psmouse *psmouse);

             reply	other threads:[~2004-10-30  5:38 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-10-30  5:38 Dmitry Torokhov [this message]
2004-10-31 17:05 ` KVMs & psmouse losing sync Thomas Svedberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200410300038.04193.dtor_core@ameritech.net \
    --to=dtor_core@ameritech.net \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox