diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-08-25 19:16:37 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-08-25 19:16:37 +0000 |
commit | dcac4981327d5f2226b4ad42521261acedea253d (patch) | |
tree | 8c150797c17decccaede74d6b2de4b3f21ba25b3 | |
parent | 5f8c06662258b3f3472b38b0a6d4fba9e519c4a0 (diff) |
Legacy-free PC hardware do not have a real PS/2 keyboard controller, but
rather have the USB HCI emulate it during boot, while legacy mode is enabled.
This causes pckbd0 to attach as the console device, but is lost as soon as
the USB HCI driver attaches.
The disappearance of the emulated PS/2 controller can however be detected
in pckbc(4) - which is supposed to attach after [eou]hci(4), with the controller
refusing to ack commands and replying ``please resend'' instead.
In that case, the kernel will now no longer attach pckbd, and will perform a
new console input device selection, allowing the (real) usb keyboard to
become the console.
Thanks to krw@ for countless tests on legacy-free hardware; also tested on
more conventional hardware by naddy@ and I.
Only amd64 and i386 platforms are affected by this change.
-rw-r--r-- | sys/arch/amd64/amd64/wscons_machdep.c | 107 | ||||
-rw-r--r-- | sys/arch/i386/i386/wscons_machdep.c | 106 | ||||
-rw-r--r-- | sys/dev/ic/pckbc.c | 37 | ||||
-rw-r--r-- | sys/dev/pckbc/pckbd.c | 12 |
4 files changed, 189 insertions, 73 deletions
diff --git a/sys/arch/amd64/amd64/wscons_machdep.c b/sys/arch/amd64/amd64/wscons_machdep.c index a5fb88593bc..0ada759ddb5 100644 --- a/sys/arch/amd64/amd64/wscons_machdep.c +++ b/sys/arch/amd64/amd64/wscons_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wscons_machdep.c,v 1.7 2008/07/16 20:03:22 miod Exp $ */ +/* $OpenBSD: wscons_machdep.c,v 1.8 2009/08/25 19:16:34 miod Exp $ */ /* * Copyright (c) 2001 Aaron Campbell @@ -68,12 +68,16 @@ #endif #include "pckbd.h" #include "ukbd.h" -#if (NPCKBD > 0) || (NUKBD > 0) -#include <dev/wscons/wskbdvar.h> -#endif #if (NUKBD > 0) #include <dev/usb/ukbdvar.h> #endif +#include "wskbd.h" +#if NWSKBD > 0 +#include <dev/wscons/wskbdvar.h> +#endif + +void wscn_video_init(void); +void wscn_input_init(int); cons_decl(ws); @@ -100,39 +104,14 @@ wscnprobe(struct consdev *cp) void wscninit(struct consdev *cp) { - static int initted; + static int initted = 0; if (initted) return; - initted = 1; -#if (NVGA > 0) || (NEGA > 0) || (NPCDISPLAY > 0) -#if (NVGA > 0) - if (!vga_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM, -1, 1)) - goto dokbd; -#endif -#if (NEGA > 0) - if (!ega_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM)) - goto dokbd; -#endif -#if (NPCDISPLAY > 0) - if (!pcdisplay_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM)) - goto dokbd; -#endif - if (0) goto dokbd; /* XXX stupid gcc */ -dokbd: -#if (NPCKBC > 0) - if (!pckbc_cnattach(X86_BUS_SPACE_IO, IO_KBD, KBCMDP, PCKBC_KBD_SLOT, - 0)) - return; -#endif -#if (NUKBD > 0) - if (!ukbd_cnattach()) - return; -#endif -#endif /* VGA | EGA | PCDISPLAY */ - return; + wscn_video_init(); + wscn_input_init(0); } void @@ -152,3 +131,67 @@ wscnpollc(dev_t dev, int on) { wskbd_cnpollc(dev, on); } + +/* + * Configure the display part of the console. + */ +void +wscn_video_init() +{ +#if (NVGA > 0) + if (vga_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM, -1, 1) == 0) + return; +#endif +#if (NEGA > 0) + if (ega_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM) == 0) + return; +#endif +#if (NPCDISPLAY > 0) + if (pcdisplay_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM) == 0) + return; +#endif +} + +/* + * Configure the keyboard part of the console. + * This is tricky, because of the games USB controllers play. + * + * On a truly legacy-free design, no PS/2 keyboard controller will be + * found, so we'll settle for the first USB keyboard as the console + * input device. + * + * Otherwise, the PS/2 controller will claim console, even if no PS/2 + * keyboard is plugged into it. This is intentional, so that a PS/2 + * keyboard can be plugged late (even though this is theoretically not + * allowed, most PS/2 controllers survive this). + * + * However, if there isn't any PS/2 keyboard connector, but an USB + * controller in Legacy mode, the kernel will detect a PS/2 keyboard + * connected (while there really isn't any), until the USB controller + * driver attaches. At that point the ghost of the legacy keyboard + * flees away. + * + * The pckbc(4) driver will, however, detect that the keyboard is gone + * missing, and will invoke this function again, allowing a new console + * input device choice. + */ + +void +wscn_input_init(int pass) +{ + if (pass != 0) { +#if NWSKBD > 0 + wskbd_cndetach(); +#endif + } + +#if (NPCKBC > 0) + if (pass == 0 && pckbc_cnattach(X86_BUS_SPACE_IO, IO_KBD, KBCMDP, + PCKBC_KBD_SLOT, 0) == 0) + return; +#endif +#if (NUKBD > 0) + if (ukbd_cnattach() == 0) + return; +#endif +} diff --git a/sys/arch/i386/i386/wscons_machdep.c b/sys/arch/i386/i386/wscons_machdep.c index 79f1c6aef55..31648cbb9b6 100644 --- a/sys/arch/i386/i386/wscons_machdep.c +++ b/sys/arch/i386/i386/wscons_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wscons_machdep.c,v 1.15 2008/07/16 20:03:22 miod Exp $ */ +/* $OpenBSD: wscons_machdep.c,v 1.16 2009/08/25 19:16:36 miod Exp $ */ /* * Copyright (c) 2001 Aaron Campbell @@ -68,12 +68,16 @@ #endif #include "pckbd.h" #include "ukbd.h" -#if (NPCKBD > 0) || (NUKBD > 0) -#include <dev/wscons/wskbdvar.h> -#endif #if (NUKBD > 0) #include <dev/usb/ukbdvar.h> #endif +#include "wskbd.h" +#if NWSKBD > 0 +#include <dev/wscons/wskbdvar.h> +#endif + +void wscn_video_init(void); +void wscn_input_init(int); cons_decl(ws); @@ -100,39 +104,14 @@ wscnprobe(struct consdev *cp) void wscninit(struct consdev *cp) { - static int initted; + static int initted = 0; if (initted) return; - initted = 1; -#if (NVGA > 0) || (NEGA > 0) || (NPCDISPLAY > 0) -#if (NVGA > 0) - if (!vga_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM, -1, 1)) - goto dokbd; -#endif -#if (NEGA > 0) - if (!ega_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM)) - goto dokbd; -#endif -#if (NPCDISPLAY > 0) - if (!pcdisplay_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM)) - goto dokbd; -#endif - if (0) goto dokbd; /* XXX stupid gcc */ -dokbd: -#if (NPCKBC > 0) - if (!pckbc_cnattach(I386_BUS_SPACE_IO, IO_KBD, KBCMDP, PCKBC_KBD_SLOT, - 0)) - return; -#endif -#if (NUKBD > 0) - if (!ukbd_cnattach()) - return; -#endif -#endif /* VGA | EGA | PCDISPLAY */ - return; + wscn_video_init(); + wscn_input_init(0); } void @@ -152,3 +131,66 @@ wscnpollc(dev_t dev, int on) { wskbd_cnpollc(dev, on); } + +/* + * Configure the display part of the console. + */ +void +wscn_video_init() +{ +#if (NVGA > 0) + if (vga_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM, -1, 1) == 0) + return; +#endif +#if (NEGA > 0) + if (ega_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM) == 0) + return; +#endif +#if (NPCDISPLAY > 0) + if (pcdisplay_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM) == 0) + return; +#endif +} + +/* + * Configure the keyboard part of the console. + * This is tricky, because of the games USB controllers play. + * + * On a truly legacy-free design, no PS/2 keyboard controller will be + * found, so we'll settle for the first USB keyboard as the console + * input device. + * + * Otherwise, the PS/2 controller will claim console, even if no PS/2 + * keyboard is plugged into it. This is intentional, so that a PS/2 + * keyboard can be plugged late (even though this is theoretically not + * allowed, most PS/2 controllers survive this). + * + * However, if there isn't any PS/2 keyboard connector, but an USB + * controller in Legacy mode, the kernel will detect a PS/2 keyboard + * connected (while there really isn't any), until the USB controller + * driver attaches. At that point the ghost of the legacy keyboard + * flees away. + * + * The pckbc(4) driver will, however, detect that the keyboard is gone + * missing, and will invoke this function again, allowing a new console + * input device choice. + */ +void +wscn_input_init(int pass) +{ + if (pass != 0) { +#if NWSKBD > 0 + wskbd_cndetach(); +#endif + } + +#if (NPCKBC > 0) + if (pass == 0 && pckbc_cnattach(I386_BUS_SPACE_IO, IO_KBD, KBCMDP, + PCKBC_KBD_SLOT, 0) == 0) + return; +#endif +#if (NUKBD > 0) + if (ukbd_cnattach() == 0) + return; +#endif +} diff --git a/sys/dev/ic/pckbc.c b/sys/dev/ic/pckbc.c index 58ef989ddbc..36c2599570c 100644 --- a/sys/dev/ic/pckbc.c +++ b/sys/dev/ic/pckbc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pckbc.c,v 1.18 2008/09/10 14:01:22 blambert Exp $ */ +/* $OpenBSD: pckbc.c,v 1.19 2009/08/25 19:16:36 miod Exp $ */ /* $NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp $ */ /* @@ -44,7 +44,7 @@ #include "pckbd.h" -#if (NPCKBD > 0) +#if NPCKBD > 0 #include <dev/pckbc/pckbdvar.h> #endif @@ -290,7 +290,7 @@ pckbc_attach(sc) struct pckbc_internal *t; bus_space_tag_t iot; bus_space_handle_t ioh_d, ioh_c; - int res; + int haskbd = 0, res; u_char cmdbits = 0; t = sc->id; @@ -333,16 +333,39 @@ pckbc_attach(sc) if (res != 0) printf("kbc: returned %x on kbd slot test\n", res); #endif - if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) + if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) { cmdbits |= KC8_KENABLE; + haskbd = 1; + } } else { printf("kbc: kbd port test: %x\n", res); return; } #else - if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) + if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) { cmdbits |= KC8_KENABLE; + haskbd = 1; + } #endif /* 0 */ + if (haskbd == 0) { +#if defined(__i386__) || defined(__amd64__) + /* + * If there is no keyboard present, yet we are the console, + * we might be on a legacy-free PC where the PS/2 emulated + * keyboard was elected as console, but went away as soon + * as the USB controller drivers attached. + * + * In that case, we want to release ourselves from console + * duties. + */ + if (pckbc_console != 0) { + extern void wscn_input_init(int); + + pckbc_console = 0; + wscn_input_init(1); + } +#endif + } /* * Check aux port ok. @@ -607,7 +630,7 @@ pckbc_poll_cmd1(t, slot, cmd) #ifdef PCKBCDEBUG printf("pckbc: cmd failed\n"); #endif - cmd->status = EIO; + cmd->status = ENXIO; return; } } @@ -794,7 +817,7 @@ pckbc_cmdresponse(t, slot, data) #ifdef PCKBCDEBUG printf("pckbc: cmd failed\n"); #endif - cmd->status = EIO; + cmd->status = ENXIO; /* dequeue */ } } else { diff --git a/sys/dev/pckbc/pckbd.c b/sys/dev/pckbc/pckbd.c index c2b4c2c176d..207c56de737 100644 --- a/sys/dev/pckbc/pckbd.c +++ b/sys/dev/pckbc/pckbd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pckbd.c,v 1.19 2009/08/13 21:46:23 pirofti Exp $ */ +/* $OpenBSD: pckbd.c,v 1.20 2009/08/25 19:16:36 miod Exp $ */ /* $NetBSD: pckbd.c,v 1.24 2000/06/05 22:20:57 sommerfeld Exp $ */ /*- @@ -330,6 +330,15 @@ pckbdprobe(parent, match, aux) * Let the probe succeed if the keyboard is used * as console input - it can be connected later. */ +#if defined(__i386__) || defined(__amd64__) + /* + * However, on legacy-free PCs, there might really + * be no PS/2 connector at all; in that case, do not + * even try to attach; ukbd will take over as console. + */ + if (res == ENXIO) + return 0; +#endif return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0); } if (resp[0] != KBR_RSTDONE) { @@ -401,7 +410,6 @@ pckbdattach(parent, self, aux) /* * Attach the wskbd, saving a handle to it. - * XXX XXX XXX */ sc->sc_wskbddev = config_found(self, &a, wskbddevprint); } |