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