boot2 keyboard probing problem (with patch)

Jung-uk Kim jkim at niksun.com
Mon May 12 13:20:44 PDT 2003


Is there anybody tried this yet? Probably it's my fault posting it on 
Friday. :-(

Any (positive or negative) comments are welcome.

Thanks,

Jung-uk Kim

On Friday 09 May 2003 02:56 pm, Jung-uk Kim wrote:
> Recently I tried '-P' option in /boot.config for my desktop. boot2
> always said 'Keyboard: yes' even if I don't have a keyboard
> attached. I realized the keyboard probing is somewhat broken for
> many others, e. g., IBM x335. boot(8) says:
>
> 	Due to space constraints, the keyboard probe initiated by the -P
> option is simply a test that the BIOS has detected an ``extended''
> keyboard.  If an ``XT/AT'' keyboard (with no F11 and F12 keys,
> etc.) is attached, the probe will fail.
>
> When I read src/sys/boot/i386/boot2/boot2.c, I found
>
>             if (opts & 1 << RBX_PROBEKBD) {
>                 i = *(uint8_t *)PTOV(0x496) & 0x10;
>                 printf("Keyboard: %s\n", i ? "yes" : "no");
>                 if (!i)
>                     opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
>                 opts &= ~(1 << RBX_PROBEKBD);
>             }
>
> This confirmed what the manpage said. The problem is 0x496 is set
> by BIOS but recent BIOSes don't seem to set the flag after actual
> probing (or they don't care?). I tried to resurrect KEYBOARD_PROBE
> option (src/sys/boot/i386/libi386/vidconsole.c) but it didn't work
> at all. Then I started writing my own and used some code from
> keyboard_init() for Bochs BIOS, which is written by Adam Sulmicki
> <adam at cfar.umd.edu>.
>
> http://www.eax.com/patches/BOCHS/bochs-bios-keyboard-2.1-diff
>
> My patch is simple: send echo command (0xee) to keyboard controller
> and read it back from keyboard. If keyboard controller doesn't get
> an echo back for some tries, it fails probing.
>
> BTW, I send 0 to port 0x80 (POST return value) to delay because I
> couldn't find better way. A side effect is POST code will be reset
> even if your BIOS reported a problem. However, if you got this far,
> it shouldn't be a critical problem. ;-) Is there any better way to
> delay? KEYBOARD_PROBE used port 0x84 but it was more tasteless
> because we cannot know what it might be used for. (In fact, Compaq
> used it for POST diagnostic.)
>
> This patch worked on my two desktops and an IBM 1U server. AT and
> PS/2 keyboards should work. I think it would work with KVM, too.
> The patch is against 4-STABLE but it could be okay with 5-CURRENT
> if there is enough space left in boot2. ;-)
>
> Please try this patch and let me know if you find any issues or
> have suggestions.
>
> Thanks,
>
> Jung-uk Kim

--- src/sys/boot/i386/boot2/boot2.c.old	Thu Oct 10 11:53:24 2002
+++ src/sys/boot/i386/boot2/boot2.c	Fri May  9 03:45:46 2003
@@ -414,7 +414,64 @@
 		opts ^= 1 << flags[i];
 	    }
 	    if (opts & 1 << RBX_PROBEKBD) {
-		i = *(uint8_t *)PTOV(0x496) & 0x10;
+		__asm __volatile (
+		    "\n\tmovb $2, %%ah\n\t" /* Wait for empty input buffer */
+		    "call wait\n\t"	    /* if %ah is 2 */
+		    "jmp flush\n"
+		    "wait:\n\t"		    /* Wait for a buffer status */
+		    "xorw %%cx, %%cx\n"	    /* Initialize retry */
+		    "loop1:\n\t"
+		    "decw %%cx\n\t"	    /* retry = 0xffff and retry-- */
+		    "jz exit1\n\t"	    /* Exit if retry is 0 */
+		    "inb $0x64, %%al\n\t"   /* Check controller status */
+		    "testb $1, %%ah\n\t"    /* Check output buffer status */
+		    "jnz output\n\t"	    /* if %ah is 1 */
+		    "testb %%ah, %%al\n\t"  /* Input buffer empty? */
+		    "jz exit1\n\t"	    /* Exit if input buffer empty */
+		    "jmp delay\n"	    /* else delay */
+		    "output:\n\t"
+		    "testb %%ah, %%al\n\t"  /* Output buffer full? */
+		    "jnz exit1\n"	    /* Exit if output buffer full */
+		    "delay:\n\t"
+		    "xorb %%al, %%al\n\t"   /* XXX delay hack */
+		    "outb %%al, $0x80\n\t"  /* Send 0 to port 0x80 (POST) */
+		    "jmp loop1\n"	    /* Retry */
+		    "exit1:\n\t"
+		    "ret\n"
+		    "flush:\n\t"
+		    "movw $2001, %%cx\n"    /* Initialize retry */
+		    "loop2:\n\t"
+		    "decw %%cx\n\t"	    /* retry = 2000 and retry-- */
+		    "jz exit2\n\t"	    /* Exit if retry is 0 */
+		    "xorb %%al, %%al\n\t"   /* XXX delay hack */
+		    "outb %%al, $0x80\n\t"  /* Send 0 to port 0x80 (POST) */
+		    "inb $0x64, %%al\n\t"   /* Check controller status */
+		    "testb $1, %%al\n\t"    /* Any character to flush? */
+		    "jz loop2\n\t"	    /* Retry if buffer is empty */
+		    "inb $0x60, %%al\n\t"   /* Flush a character from buffer */
+		    "movw $2001, %%cx\n\t"  /* Reinitialize retry */
+		    "jmp loop2\n"	    /* Retry */
+		    "exit2:\n\t"
+		    "movb $0xee, %%al\n\t"  /* Set echo command */
+		    "outb %%al, $0x60\n\t"  /* Send it! */
+		    "movb $2, %%ah\n\t"	    /* Wait for echo to be sent */
+		    "call wait\n\t"
+		    "andw %%cx, %%cx\n\t"   /* Is retry 0? */
+		    "jz fail\n\t"	    /* Echo not sent */
+		    "movb $1, %%ah\n\t"	    /* Wait for a character */
+		    "call wait\n\t"
+		    "andw %%cx, %%cx\n\t"   /* Is retry 0? */
+		    "jz fail\n\t"	    /* A character not received */
+		    "inb $0x60, %%al\n\t"   /* Receive a character */
+		    "cmpb $0xee, %%al\n\t"  /* Is this an echo? */
+		    "jne fail\n\t"	    /* Fail if echo not received */
+		    "movl $1, %0\n\t"	    /* Set return code = 1 */
+		    "jmp fine\n"	    /* and exit */
+		    "fail:\n\t"
+		    "movl $0, %0\n"	    /* Set return code = 0 */
+		    "fine:\n"		    /* and exit */
+		    : "=r" (i) : : "ah", "al", "cx"
+		);
 		printf("Keyboard: %s\n", i ? "yes" : "no");
 		if (!i)
 		    opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;



More information about the freebsd-hackers mailing list