Subject: YAKF (Yet Another Keyboard Fix)
To: None <port-i386@sun-lamp.cs.berkeley.edu>
From: Mike Long <mike.long@analog.com>
List: port-i386
Date: 04/21/1994 01:39:22
I've been playing around a bit more with pccons.c (still using 1.60)
recently, and I have more precise results to report.

It turns out that on my system (the eternally cursed Phoenix BIOS
Gateway 2000), there MUST be a delay between reading the keyboard
status port (KBSTATP, 0x64) and reading the keyboard data port
(KBDATAP, 0x60) during the probe.  I use calls to delay() to provide
the required delay; I use 6 as an argument because delay() appears to
ignore anything <= 5.  Adding calls to printf() as in the 'flush any
garbage' loop should also do the job.  Note that the old hammer on the
keyboard trick will no longer work, since any such keystrokes are
thrown out by this loop.  Note that the 6us delay isn't really out of
line, since some PS/2 keyboard controllers apparently require a 7us
delay (cf Frank van Gilluwe, _The Undocumented PC_, p. 273).

I also found out that the extra 'just to be sure' KBC_ENABLE command
locks up my keyboard every time, no matter how many calls to delay() I
stick in there and in kbd_cmd.  I also comment out the scan code table
thing, because I just don't want to deal with it. :-)

The following are my current patches to pccons.c 1.60.  My next step
is to upgrade to a 4/16 system and see how well I do with the latest
pccons, and to see if pcvt handles the keyboard any better than pccons
does.  My thanks go to John Hayward, for sending me on the right path;
and to Charles, for not tolerating the previous state of this driver.

P.S.  Why isn't delay() declared in any of the i386 kernel's .h files?

*** pccons.c.orig	Sat Mar 12 06:05:00 1994
--- pccons.c	Tue Apr 19 00:19:55 1994
***************
*** 326,339 ****
  
  #if 1
  	/* Flush any garbage. */
! 	while (inb(KBSTATP) & KBS_DIB)
  		(void) inb(KBDATAP);
  	/* Reset the keyboard. */
  	if (!kbd_cmd(KBC_RESET, 1)) {
  		printf("pcprobe: reset error %d\n", 1);
  		goto lose;
  	}
  	while ((inb(KBSTATP) & KBS_DIB) == 0);
  	if (inb(KBDATAP) != KBR_RSTDONE) {
  		printf("pcprobe: reset error %d\n", 2);
  		goto lose;
--- 326,343 ----
  
  #if 1
  	/* Flush any garbage. */
! 	while (inb(KBSTATP) & KBS_DIB) {
! 		printf("pcprobe: flushing KB before reset\n"); /*mwl*/
  		(void) inb(KBDATAP);
+ 		delay(6); /*mwl*/
+ 	}
  	/* Reset the keyboard. */
  	if (!kbd_cmd(KBC_RESET, 1)) {
  		printf("pcprobe: reset error %d\n", 1);
  		goto lose;
  	}
  	while ((inb(KBSTATP) & KBS_DIB) == 0);
+ 	delay(6);		/* mwl: prevent Phoenix KB lockup XXX */
  	if (inb(KBDATAP) != KBR_RSTDONE) {
  		printf("pcprobe: reset error %d\n", 2);
  		goto lose;
***************
*** 343,350 ****
  	 * This is kind of stupid, but we account for them anyway by just
  	 * flushing the buffer.
  	 */
! 	while (inb(KBSTATP) & KBS_DIB)
  		(void) inb(KBDATAP);
  	/* Just to be sure. */
  	if (!kbd_cmd(KBC_ENABLE, 1)) {
  		printf("pcprobe: reset error %d\n", 3);
--- 347,358 ----
  	 * This is kind of stupid, but we account for them anyway by just
  	 * flushing the buffer.
  	 */
! 	delay(6);		/* mwl */
! 	while (inb(KBSTATP) & KBS_DIB) {
! 		printf("pcprobe: purging ack byte\n"); /* mwl */
  		(void) inb(KBDATAP);
+ 	}
+ #if 0
  	/* Just to be sure. */
  	if (!kbd_cmd(KBC_ENABLE, 1)) {
  		printf("pcprobe: reset error %d\n", 3);
***************
*** 377,383 ****
  			goto lose;
  		}
  	}
! 
  lose:
  	/*
  	 * Technically, we should probably fail the probe.  But we'll be nice
--- 385,391 ----
  			goto lose;
  		}
  	}
! #endif
  lose:
  	/*
  	 * Technically, we should probably fail the probe.  But we'll be nice
-- 
Mike Long                                         Mike.Long@Analog.com
VLSI Design Engineer                              voice: (617)461-4030
Analog Devices, SPD Division                        FAX: (617)461-3010
Norwood, MA 02062 USA                assert(*this!=opinionof(Analog));

------------------------------------------------------------------------------