--- linux-orig/drivers/char/pc_keyb.c Mon Aug 9 12:04:39 1999 +++ linux/drivers/char/pc_keyb.c Tue Apr 11 00:52:19 2000 @@ -13,6 +13,8 @@ * Code fixes to handle mouse ACKs properly. * C. Scott Ananian 1999-01-29. * + * Code fixes to *really* handle mouse ACKs properly. + * Julian Bradfield 1999-04-30. */ #include @@ -75,8 +77,13 @@ 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. */ +/* used when we (as opposed to the user programs using the aux device) + send commands to the mouse that expect an ACK. */ static unsigned char mouse_reply_expected = 0; +/* used to make sure we read acks from the mouse before we + write another byte */ +static unsigned char mouse_ack_pending = 0; +#define MOUSE_ACK_TIMEOUT 5 /* actually, 1 seems to be enough usually */ #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) @@ -386,6 +393,10 @@ static inline void handle_mouse_event(unsigned char scancode) { #ifdef CONFIG_PSMOUSE + if (mouse_ack_pending) + /* it needn't actually be an ack, it could be an echo; + but every byte sent to the mouse results in a byte back */ + mouse_ack_pending = 0; if (mouse_reply_expected) { if (scancode == AUX_ACK) { mouse_reply_expected--; @@ -770,12 +781,23 @@ static void aux_write_dev(int val) { unsigned long flags; + int loop = 0; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); + /* if we haven't yet received the ack from the previous + write, we must wait for it to arrive; otherwise we + lose it. (At least, I think this is what is happening.) */ + while (mouse_ack_pending && loop++ < MOUSE_ACK_TIMEOUT ) { + mdelay(1); + handle_kbd_event(); + } + if ( mouse_ack_pending ) + printk(KERN_WARNING "mouse ack timeout\n") ; kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); kbd_write_output(val); + mouse_ack_pending = 1; spin_unlock_irqrestore(&kbd_controller_lock, flags); } @@ -785,13 +807,21 @@ static void aux_write_ack(int val) { unsigned long flags; + int loop = 0; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); + while (mouse_ack_pending && loop++ < MOUSE_ACK_TIMEOUT) { + mdelay(1); + handle_kbd_event(); + } + if ( mouse_ack_pending ) + printk(KERN_WARNING "mouse ack timeout\n") ; kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); kbd_write_output(val); - /* we expect an ACK in response. */ + mouse_ack_pending = 1; + /* we will deal with the ACK ourselves. */ mouse_reply_expected++; kb_wait(); spin_unlock_irqrestore(&kbd_controller_lock, flags);