The following patch fixes the problem cleanly, and is robust against
misbehaving mice. As the current kernel breaks backwards-compatability on
the /dev/psaux device, I would recommend this patch for the 2.2.x kernel
series.
--Scott
@ @
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-oOO-(_)-OOo-=-=-=-=-=
C. Scott Ananian: cananian@lcs.mit.edu / Declare the Truth boldly and
Laboratory for Computer Science/Crypto / without hindrance.
Massachusetts Institute of Technology /META-PARRESIAS AKOLUTOS:Acts 28:31
-.-. .-.. .. ..-. ..-. --- .-. -.. ... -.-. --- - - .- -. .- -. .. .- -.
PGP key available via finger and from http://www.pdos.lcs.mit.edu/~cananian
diff -ruHp -X badboys linux/drivers/char-orig/pc_keyb.c linux/drivers/char/pc_keyb.c
--- linux/drivers/char-orig/pc_keyb.c Fri Jan 29 20:26:03 1999
+++ linux/drivers/char/pc_keyb.c Fri Jan 29 22:46:17 1999
@@ -10,6 +10,9 @@
* because they share the same hardware.
* Johan Myreen <jem@iki.fi> 1998-10-08.
*
+ * Code fixes to handle mouse ACKs properly.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
+ *
*/
#include <linux/config.h>
@@ -74,6 +77,8 @@ static int __init psaux_init(void);
static struct aux_queue *queue; /* Mouse data buffer. */
static int aux_count = 0;
+/* used when we send commands to the mouse that expect an ACK. */
+static volatile unsigned char mouse_reply_expected = 0;
#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
@@ -419,7 +424,10 @@ static unsigned char handle_kbd_event(vo
if (status & KBD_STAT_MOUSE_OBF) {
#ifdef CONFIG_PSMOUSE
/* Mouse data. */
- if (aux_count) {
+ /* Add data to queue unless it's an ACK we were
+ * expecting. */
+ if (aux_count &&
+ (!mouse_reply_expected || scancode!=AUX_ACK)) {
int head = queue->head;
queue->buf[head] = scancode;
add_mouse_randomness(scancode);
@@ -430,7 +438,12 @@ static unsigned char handle_kbd_event(vo
kill_fasync(queue->fasync, SIGIO);
wake_up_interruptible(&queue->proc_list);
}
- }
+ /* if we were expecting an ACK but found
+ * something else, forget about the ACK. */
+ mouse_reply_expected=0;
+ } else if (mouse_reply_expected)
+ /* we found the ACK we were expecting. */
+ mouse_reply_expected--;
#endif
} else {
if (do_acknowledge(scancode))
@@ -770,6 +783,24 @@ static void aux_write_dev(int val)
spin_unlock_irqrestore(&kbd_controller_lock, flags);
}
+/*
+ * Send a byte to the mouse & handle returned ack
+ */
+static void aux_write_ack(int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
+ outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
+ kb_wait();
+ outb(val, KBD_DATA_REG);
+ /* we expect an ACK in response. */
+ mouse_reply_expected++;
+ kb_wait();
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+}
+
static unsigned int get_from_queue(void)
{
unsigned int result;
@@ -834,7 +865,7 @@ static int open_aux(struct inode * inode
kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable the
auxiliary port on
controller. */
- aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
+ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
return 0;
@@ -951,11 +982,11 @@ static int __init psaux_init(void)
#ifdef INITIALIZE_MOUSE
kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
- aux_write_dev(AUX_SET_SAMPLE);
- aux_write_dev(100); /* 100 samples/sec */
- aux_write_dev(AUX_SET_RES);
- aux_write_dev(3); /* 8 counts per mm */
- aux_write_dev(AUX_SET_SCALE21); /* 2:1 scaling */
+ aux_write_ack(AUX_SET_SAMPLE);
+ aux_write_ack(100); /* 100 samples/sec */
+ aux_write_ack(AUX_SET_RES);
+ aux_write_ack(3); /* 8 counts per mm */
+ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
#endif /* INITIALIZE_MOUSE */
kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
diff -ruHp -X badboys linux/drivers/char-orig/pc_keyb.h linux/drivers/char/pc_keyb.h
--- linux/drivers/char-orig/pc_keyb.h Fri Jan 29 20:26:03 1999
+++ linux/drivers/char/pc_keyb.h Fri Jan 29 22:42:24 1999
@@ -115,6 +115,8 @@ extern unsigned char aux_device_present;
#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
#define AUX_RESET 0xFF /* Reset aux device */
+#define AUX_ACK 0xFA /* Command byte ACK. */
+
#define AUX_BUF_SIZE 2048
struct aux_queue {
--- linux/CREDITS.orig Fri Jan 29 22:07:15 1999
+++ linux/CREDITS Fri Jan 29 22:08:20 1999
@@ -46,6 +46,7 @@
P: 1024/85AD9EED AD C0 49 08 91 67 DF D7 FA 04 1A EE 09 E8 44 B0
D: Unix98 pty support.
D: APM update to 1.2 spec.
+D: psaux bug-fixes
N: Erik Andersen
E: andersee@debian.org
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/