[PATCH] psaux device ACK discrepancy

C. Scott Ananian (cananian@lesser-magoo.lcs.mit.edu)
Fri, 29 Jan 1999 23:10:50 -0500 (EST)


When the psaux device driver was overhauled some months back and made part
of pc_keyb.c, someone forgot that mice send ACK bytes (0xFA) to nearly
every command sent to them. The result is that /dev/psaux spits out 1 or
more 0xFA bytes whenever you open it, without provocation. This screws up
low-level mice configurators (I maintain such for the Synaptics TouchPad)
which don't like ACKs being sent without cause.

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/