/* $NetBSD: pccons.c,v 1.10 2000/06/26 04:55:31 simonb Exp $ */ /* * Copyright 1997 * Digital Equipment Corporation. All rights reserved. * * This software is furnished under license and may be used and * copied only in accordance with the following terms and conditions. * Subject to these conditions, you may download, copy, install, * use, modify and distribute this software in source and/or binary * form. No title or ownership is transferred hereby. * * 1) Any source code used, modified or distributed must reproduce * and retain this copyright notice and list of conditions as * they appear in the source file. * * 2) No right is granted to use any trade name, trademark, or logo of * Digital Equipment Corporation. Neither the "Digital Equipment * Corporation" name nor any trademark or logo of Digital Equipment * Corporation may be used to endorse or promote products derived * from this software without the prior written permission of * Digital Equipment Corporation. * * 3) This software is provided "AS-IS" and any express or implied * warranties, including but not limited to, any implied warranties * of merchantability, fitness for a particular purpose, or * non-infringement are disclaimed. In no event shall DIGITAL be * liable for any damages whatsoever, and in particular, DIGITAL * shall not be liable for special, indirect, consequential, or * incidental damages or damages for lost profits, loss of * revenue or loss of use, whether such damages arise in contract, * negligence, tort, under statute, in equity, at law or otherwise, * even if advised of the possibility of such damage. */ /*- * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz and Don Ahn. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)pccons.c 5.11 (Berkeley) 5/21/91 */ /* **++ ** ** FACILITY: ** ** Driver for keyboard and display for PC-style console device. ** ** ABSTRACT: ** ** The driver has been cleaned up a little as part of the StrongARM ** porting work. The main modifications have been to change the ** driver to use the bus_space_ macros, re-organise the sget and sput ** mechanisms and utilise a more robust set of i8042 keybord controller ** routines which are now external to this module and also used by the ** pms mouse driver. ** ** AUTHORS: ** ** Unknown. Modified by Patrick Crilly & John Court, ** Digital Equipment Corporation. ** ** CREATION DATE: ** ** Unknown ** **-- */ #include "opt_ddb.h" #include "opt_xserver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef i386 #include #include #else #include #include #endif #include #include #include #include #ifdef OFW #include #endif #ifdef SHARK #include #include #include #include #include #include extern int msgbufmapped; #endif /* ** Macro defintions */ /* ** If an address for the keyboard console ** hasn't been defined then supply a default ** one. */ #ifndef CONKBDADDR #define CONKBDADDR 0x60 #endif #define XFREE86_BUG_COMPAT #ifndef BEEP_FREQ #define BEEP_FREQ 1500 #endif #ifndef BEEP_TIME #define BEEP_TIME (hz/5) #endif #define PCBURST 128 /* Macro to extract the minor device number from the device identifier */ #define PCUNIT(x) (minor(x)) #define COL 80 #define ROW 25 #define CHR 2 #ifdef arm32 #define sysbeep(freq, time) /* not yet implemented */ #define fillw(pattern, address, length)\ {\ u_short p;\ u_short *a;\ int i;\ for (p = (pattern), a = (address), i = 0; i < (length); a++, i++)\ *a = p;\ } #endif /* * DANGER WIL ROBINSON -- the values of SCROLL, NUM, CAPS, and ALT are * important. */ #define SCROLL 0x0001 /* stop output */ #define NUM 0x0002 /* numeric shift cursors vs. numeric */ #define CAPS 0x0004 /* caps shift -- swaps case of letter */ #define SHIFT 0x0008 /* keyboard shift */ #define CTL 0x0010 /* control shift -- allows ctl function */ #define ASCII 0x0020 /* ascii code for this key */ #define ALT 0x0080 /* alternate shift -- alternate chars */ #define FUNC 0x0100 /* function key */ #define KP 0x0200 /* Keypad keys */ #define NONE 0x0400 /* no function */ #define BREAKBIT 0x80 /* This bit used in XT scancodes to */ /* indicate the release of key. */ /* ** Softc structure for the pc device */ struct pc_softc { struct device sc_dev; #define SC_ASYNC_SCHEDULED 0x01 /* An update of keyboard and screen is */ /* already scheduled. */ #define SC_XMODE 0x02 /* We are operating with X above us. */ #define SC_POLLING 0x04 /* We are polling instead of using */ /* keyboard interrupts. */ u_char sc_flags; /* Values defined above. */ struct tty *sc_tty; struct { void *sc_ih; u_char sc_shift_state; /* State of shifting keys. */ u_char sc_new_lock_state; u_char sc_old_lock_state; u_char sc_new_typematic_rate; u_char sc_old_typematic_rate; bus_space_tag_t sc_iot; /* Kbd IO ports tag */ bus_space_handle_t sc_ioh; /* Kbd IO ports handle */ } kbd; struct { int cx, cy; /* escape parameters */ int row, col; /* current cursor position */ int nrow, ncol, nchr; /* current screen geometry */ u_char state; /* parser state */ #define VSS_ESCAPE 1 #define VSS_EBRACE 2 #define VSS_EPARAM 3 char so; /* in standout mode? */ char color; /* color or mono display */ char at; /* normal attributes */ char so_at; /* standout attributes */ } vs; }; static struct callout async_update_ch = CALLOUT_INITIALIZER; /* ** Forward routine declarations */ int pcprobe __P((struct device *, struct cfdata *, void *)); void pcattach __P((struct device *, struct device *, void *)); int pcintr __P((void *)); char *sget __P((struct pc_softc *)); void sput __P((struct pc_softc *, u_char *, int, u_char)); void pcstart __P((struct tty *)); int pcparam __P((struct tty *, struct termios *)); void set_cursor_shape __P((struct pc_softc *)); #ifdef XFREE86_BUG_COMPAT void get_cursor_shape __P((struct pc_softc *)); #endif void do_async_update __P((void *)); void async_update __P((struct pc_softc *, u_char)); void pccnprobe __P((struct consdev *)); void pccninit __P((struct consdev *)); void pccnputc __P((dev_t, char)); int pccngetc __P((dev_t)); void pccnpollc __P((dev_t, int)); #ifdef SHARK static void force_vga_mode __P((void)); /* ** Definitions needed by getDisplayInfo */ struct regspec { u_int bustype; u_int addr; u_int size; }; struct display_info { int init; vm_offset_t paddr; int linebytes; int depth; int height; int width; char *charSet; int charSetLen; vm_offset_t ioBase; int ioLen; }; static void getDisplayInfo __P((struct display_info *)); static struct display_info display; #define displayInfo(property) (display.init? display.property: -1) #ifdef X_CGA_BUG static void cga_save_restore __P((int)); /* ** Definitions needed by cga_save_restore */ #define CGA_SAVE 0 #define CGA_RESTORE 1 #define TEXT_LENGTH 16382 #define FONT_LENGTH 8192 #define AR_INDEX 0x3C0 #define AR_READ 0x3C1 #define GR_INDEX 0x3CE #define GR_DATA 0x3CF #define SR_INDEX 0x3C4 #define SR_DATA 0x3C5 #endif #endif /* ** Global variables */ /* ** Data structures required by config */ struct cfattach pc_ca = { sizeof(struct pc_softc), pcprobe, pcattach }; extern struct cfdriver pc_cd; static unsigned int addr_6845 = MONO_BASE; /* Define globals used when acting as console at boot time. */ static struct pc_softc bootSoftc; static u_char attachCompleted = FALSE; static u_char actingConsole = FALSE; /* Our default debug settings, when debug is compiled in via config option ** KERNEL_DEBUG that is. */ int pcdebug = KERN_DEBUG_ERROR | KERN_DEBUG_WARNING; static u_short *Crtat; /* pointer to backing store */ static u_short *crtat; /* pointer to current char */ static u_short cursor_shape = 0xffff; /* don't update until set by user */ static u_short old_cursor_shape = 0xffff; /* **++ ** FUNCTIONAL DESCRIPTION: ** ** kbd_init ** ** This function initialises the keyboard controller and keyboard for use. ** If the keyboard controller hasn't been reset then self-test the ** controller (this gets the controller going) and self-test the keyboard. ** Enable and reset the keyboard and then set the scan table in the ** keyboard controller. ** ** FORMAL PARAMETERS: ** ** iot I/O tag for the mapped register space ** ioh I/O handle for the mapped register space ** ** IMPLICIT INPUTS: ** ** None. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** 1 - Keyboard and controller successfully initialised ** 0 - Failed to initialise keyboard or controller ** **-- */ static int kbd_init(bus_space_tag_t iot, bus_space_handle_t ioh) { int status = 1; u_char value = 0; /* XXX */ /* Perfrom a controller reset if this is a cold reset happening */ if (!I8042_WARM(iot, ioh)) { /* ** Perform an internal 8042 controller test. */ if (I8042_SELFTEST(iot, ioh)) { /* ** Perform a keyboard interface test. This causes the controller ** to test the keyboard clock and data lines. */ if (!I8042_KBDTEST(iot, ioh)) { status = 0; KERN_DEBUG( pcdebug, KERN_DEBUG_ERROR, ("kbd_int: keyboard failed self test\n")); } } else { status = 0; KERN_DEBUG(pcdebug, KERN_DEBUG_ERROR, ("kbd_init: 8042 controller failed self test.\n")); } } /* End if we need to do cold start self tests */ /* Enable keyboard but not the Auxiliary device in the 8042 controller. */ if (status && I8042_WRITECCB(iot, ioh, NOAUX_CMDBYTE)) { /* Flush any garbage. */ i8042_flush(iot, ioh); /* Reset the keyboard. */ I8042_KBDRESET(iot, ioh, status); if (status) { /* ** Some keyboards seem to leave a second ack byte after the reset. ** This is kind of stupid, but we account for them anyway by just ** flushing the buffer. */ i8042_flush(iot, ioh); /* Send the keyboard physical device an enable command. */ if (i8042_cmd(iot, ioh, I8042_KBD_CMD, I8042_CHECK_RESPONSE, KBR_ACK, KBC_ENABLE)) { /* ** Some keyboard/8042 combinations do not seem to work if ** the keyboard is set to table 1; in fact, it would appear ** that some keyboards just ignore the command altogether. ** So by default, we use the AT scan codes and have the ** 8042 translate them. Unfortunately, this is known to not ** work on some PS/2 machines. We try desparately to deal ** with this by checking the (lack of a) translate bit ** in the 8042 and attempting to set the keyboard to XT mode. ** If this all fails, well, tough luck. ** ** XXX It would perhaps be a better choice to just use AT ** scan codes and not bother with this. */ I8042_READCCB(iot, ioh, status, value); if (status && (value & KC8_TRANS)) { /* The 8042 is translating for us; use AT codes. */ if (!i8042_cmd(iot, ioh, I8042_KBD_CMD, I8042_CHECK_RESPONSE, KBR_ACK, KBC_SETTABLE) || !i8042_cmd(iot, ioh, I8042_KBD_CMD, I8042_CHECK_RESPONSE, KBR_ACK, 2)) { status = 0; KERN_DEBUG( pcdebug, KERN_DEBUG_ERROR, ("kbdinit: failed to scan table\n")); } } else { /* Stupid 8042; set keyboard to XT codes. */ if ( !i8042_cmd(iot, ioh, I8042_KBD_CMD, I8042_CHECK_RESPONSE, KBR_ACK, KBC_SETTABLE) || !i8042_cmd(iot, ioh, I8042_KBD_CMD, I8042_CHECK_RESPONSE, KBR_ACK, 1) ) { status = 0; KERN_DEBUG( pcdebug, KERN_DEBUG_ERROR, ("kbdinit: failed to scan table\n")); } } } /* End if able to send keyboard physical device an enable */ else { KERN_DEBUG( pcdebug, KERN_DEBUG_ERROR, ("kbdinit: failed enable of physical keyboard\n")); } } /* End if reset of physical keyboard successful */ else { KERN_DEBUG( pcdebug, KERN_DEBUG_ERROR, ("kdbinit: keyboard failed reset. Status = 0x%x\n", status)); } } /* End if able to write to CCB and cold self tests worked */ else { KERN_DEBUG( pcdebug, KERN_DEBUG_ERROR, ("kdb_init: keyboard failed enable or keyboard self " " tests failed. Status = 0x%x\n", status)); status = 0; } return (status); } /* End kbd_init() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** set_cursor_shape ** ** The function name says it all. ** ** FORMAL PARAMETERS: ** ** None. ** ** IMPLICIT INPUTS: ** ** addr_6845 - Base adddress of the video registers ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none ** ** **-- */ void set_cursor_shape(struct pc_softc *sc) { register int iobase = addr_6845; /* Write to the start of cursor register */ outb(iobase, 10); outb(iobase+1, cursor_shape >> 8); /* Write to the end of cursor register */ outb(iobase, 11); outb(iobase+1, cursor_shape); old_cursor_shape = cursor_shape; } /* End set_cursor_shape() */ #ifdef XSERVER #ifdef XFREE86_BUG_COMPAT /* **++ ** FUNCTIONAL DESCRIPTION: ** ** get_cursor_shape ** ** The function name says it all. ** ** FORMAL PARAMETERS: ** ** None. ** ** IMPLICIT INPUTS: ** ** addr_6845 - Base adddress of the video registers ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none ** **-- */ void get_cursor_shape(struct pc_softc *sc) { register int iobase = addr_6845; /* Read from the start of cursor register */ outb(iobase, 10); cursor_shape = inb(iobase+1) << 8; /* Read from the end of cursor register */ outb(iobase, 11); cursor_shape |= inb(iobase+1); /* * real 6845's, as found on, MDA, Hercules or CGA cards, do * not support reading the cursor shape registers. the 6845 * tri-states it's data bus. This is _normally_ read by the * cpu as either 0x00 or 0xff.. in which case we just use * a line cursor. */ if (cursor_shape == 0x0000 || cursor_shape == 0xffff) { cursor_shape = 0x0b10; } else { cursor_shape &= 0x1f1f; } } /* End get_cursor_shape() */ #endif /* XFREE86_BUG_COMPAT */ #endif /* XSERVER */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** do_aysnc_update ** ** This function is called to update "output" of the console device. ** If either the leds or the typematic rate of the keyboard have ** been modified they are updated. If the cursor has moved ** its position on the screen it is updated. ** ** FORMAL PARAMETERS: ** ** sc - Pointer to the softc structure. ** ** IMPLICIT INPUTS: ** ** none ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none. ** **-- */ void do_async_update(void *arg) { struct pc_softc *sc = arg; u_char poll = (sc->sc_flags & SC_POLLING) ? I8042_CHECK_RESPONSE : I8042_NO_RESPONSE; int pos; static int old_pos = -1; /* Turn off the async scheduled flag as we are it */ sc->sc_flags &= ~SC_ASYNC_SCHEDULED; /* Update the leds on the keyboard if they have changed. */ if (sc->kbd.sc_new_lock_state != sc->kbd.sc_old_lock_state) { sc->kbd.sc_old_lock_state = sc->kbd.sc_new_lock_state; if (!i8042_cmd(sc->kbd.sc_iot, sc->kbd.sc_ioh, I8042_KBD_CMD, poll, KBR_ACK, KBC_MODEIND) || !i8042_cmd(sc->kbd.sc_iot, sc->kbd.sc_ioh, I8042_KBD_CMD, poll, KBR_ACK, sc->kbd.sc_new_lock_state) ) { KERN_DEBUG( pcdebug, KERN_DEBUG_WARNING, ("pc: timeout updating leds\n")); (void) i8042_cmd(sc->kbd.sc_iot, sc->kbd.sc_ioh, I8042_KBD_CMD, poll, KBR_ACK, KBC_ENABLE); } } /* Update the keyboard typematic rate if it has changed. */ if (sc->kbd.sc_new_typematic_rate != sc->kbd.sc_old_typematic_rate) { sc->kbd.sc_old_typematic_rate = sc->kbd.sc_new_typematic_rate; if (!i8042_cmd(sc->kbd.sc_iot, sc->kbd.sc_ioh, I8042_KBD_CMD, poll, KBR_ACK, KBC_TYPEMATIC) || !i8042_cmd(sc->kbd.sc_iot, sc->kbd.sc_ioh, I8042_KBD_CMD, poll, KBR_ACK, sc->kbd.sc_new_typematic_rate) ) { KERN_DEBUG(pcdebug, KERN_DEBUG_WARNING, ("pc: timeout updating typematic rate\n")); (void) i8042_cmd(sc->kbd.sc_iot, sc->kbd.sc_ioh, I8042_KBD_CMD, poll, KBR_ACK, KBC_ENABLE); } } if ( (sc->sc_flags & SC_XMODE) == 0 ) { /* Update position of cursor on screen */ pos = crtat - Crtat; if (pos != old_pos) { register int iobase = addr_6845; outb(iobase, 14); outb(iobase+1, pos >> 8); outb(iobase, 15); outb(iobase+1, pos); old_pos = pos; } if (cursor_shape != old_cursor_shape) { set_cursor_shape(sc); } } return; } /* End do_async_update() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** aysnc_update ** ** This function is called to schedule an update of the "output" of ** the console device. If we've been called by the kernel or ** operating in polling mode, dequeue any scheduled update and ** peform the update by calling do_aysnc_update; otherwise ** if no update is currently queued, schedule a timeout to ** perform one. ** ** FORMAL PARAMETERS: ** ** None. ** ** IMPLICIT INPUTS: ** ** none. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none. **-- */ void async_update(struct pc_softc *sc, u_char nowait) { if (nowait || (sc->sc_flags & SC_POLLING)) { /* Untimeout any update already scheduled and force an update ** right now. */ if (sc->sc_flags & SC_ASYNC_SCHEDULED) { callout_stop(&async_update_ch); } do_async_update(sc); } else if ((sc->sc_flags & SC_ASYNC_SCHEDULED) == 0) { /* Schedule an update */ sc->sc_flags |= SC_ASYNC_SCHEDULED; callout_reset(&async_update_ch, 1, do_async_update, sc); } return; } /* End async_update() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcprobe ** ** This is the probe routine for the console device. If the ** console device hasn't already been set up then the register ** space for the keyboard controller is mapped and the ** controller initialised. The isa_atach_args is filled ** in with the size of keyboard's register space. ** ** FORMAL PARAMETERS: ** ** parent - pointer to the parent device. ** match - not used ** aux - pointer to an isa_attach_args structure. ** ** IMPLICIT INPUTS: ** ** actingConsole - indicates whether the pc device is being used as ** the console device. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** 0 - Probe failed to find the requested device. ** 1 - Probe sucessfully talked to the device. ** ** SIDE EFFECTS: ** ** none. **-- */ int pcprobe(struct device *parent, struct cfdata *match, void *aux) { struct isa_attach_args *ia = aux; int probeOk = 1; /* assume it will succeed */ int iobase; bus_space_tag_t iot; bus_space_handle_t ioh; if (actingConsole == FALSE) { iobase = ia->ia_iobase; iot = ia->ia_iot; /* Map register space */ if ( I8042_MAP(iot, iobase, ioh) == 0 ) { /* ** Initalise keyboard controller. We don't fail the ** probe even if the init failed. This allows the ** console device to be used even if a keyboard ** isn't connected. */ if (!kbd_init(iot, ioh)) { KERN_DEBUG(pcdebug, KERN_DEBUG_ERROR, ("pcprobe: failed to initialise keyboard\n")); probeOk = 0; } I8042_UNMAP(iot, ioh); } else { probeOk = 0; } } /* end-if keyboard not initialised for console */ /* ** Fill in the isa structure with the number of ** ports used and mapped memory size. */ ia->ia_iosize = I8042_NPORTS; ia->ia_msize = 0; return (probeOk); } /* End pcprobe() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcattach ** ** This is the attach routine for the pc device. It updates the ** cursor position, sets up the interrupt routine for the keyboard ** and the configures any child devices. ** ** FORMAL PARAMETERS: ** ** parent - pointer to my parents device structure. ** self - pointer to my softc with device structure at front. ** aux - pointer to the isa_attach_args structure. ** ** IMPLICIT INPUTS: ** ** actingConsole - indicates whether the pc device is being used as ** the console device. ** ** IMPLICIT OUTPUTS: ** ** None ** ** FUNCTION VALUE: ** ** none. ** ** SIDE EFFECTS: ** ** none. **-- */ void pcattach(struct device *parent, struct device *self, void *aux) { struct pc_softc *sc = (void *)self; struct isa_attach_args *ia = aux; int iobase; /* ** If the keyboard isn't being used as a console device, ** map the register space. */ if (actingConsole == FALSE) { KERN_DEBUG( pcdebug, KERN_DEBUG_INFO, ("\npcattach: mapping io space\n")); iobase = ia->ia_iobase; sc->sc_flags = 0x00; sc->kbd.sc_shift_state = 0x00; sc->kbd.sc_new_lock_state = 0x00; sc->kbd.sc_old_lock_state = 0xff; sc->kbd.sc_new_typematic_rate = 0xff; sc->kbd.sc_old_typematic_rate = 0xff; sc->kbd.sc_iot = ia->ia_iot; if (I8042_MAP(sc->kbd.sc_iot,iobase,sc->kbd.sc_ioh) != 0) { panic("pcattach: kbd io mapping failed"); } bootSoftc.vs.cx = bootSoftc.vs.cy = 0; bootSoftc.vs.row = bootSoftc.vs.col = 0; bootSoftc.vs.nrow = 0; bootSoftc.vs.ncol = 0; bootSoftc.vs.nchr = 0; bootSoftc.vs.state = 0; bootSoftc.vs.so = 0; bootSoftc.vs.color = 0; bootSoftc.vs.at = 0; bootSoftc.vs.so_at = 0; #ifdef SHARK /* ** Get display information from ofw before leaving linear mode. */ getDisplayInfo(&display); /* Must force hardware into VGA mode before anything else ** otherwise we may hang trying to do output. */ force_vga_mode(); #endif } else { /* We are the console so better fill in the softc with the values ** we have been using in the console up to this point. */ sc->sc_flags = bootSoftc.sc_flags; sc->kbd.sc_shift_state = bootSoftc.kbd.sc_shift_state; sc->kbd.sc_new_lock_state = bootSoftc.kbd.sc_new_lock_state; sc->kbd.sc_old_lock_state = bootSoftc.kbd.sc_old_lock_state; sc->kbd.sc_new_typematic_rate = bootSoftc.kbd.sc_new_typematic_rate; sc->kbd.sc_old_typematic_rate = bootSoftc.kbd.sc_old_typematic_rate; sc->kbd.sc_iot = bootSoftc.kbd.sc_iot; sc->kbd.sc_ioh = bootSoftc.kbd.sc_ioh; /* Copy across the video state as well. */ sc->vs.cx = bootSoftc.vs.cx; sc->vs.cy = bootSoftc.vs.cy; sc->vs.row = bootSoftc.vs.row; sc->vs.col = bootSoftc.vs.col; sc->vs.nrow = bootSoftc.vs.nrow; sc->vs.ncol = bootSoftc.vs.ncol; sc->vs.nchr = bootSoftc.vs.nchr; sc->vs.state = bootSoftc.vs.state; sc->vs.so = bootSoftc.vs.so; sc->vs.color = bootSoftc.vs.color; sc->vs.at = bootSoftc.vs.at; sc->vs.so_at = bootSoftc.vs.so_at; } /* At this point the softc is set up "enough" and want to swap console ** functionality to use that standard interface. ** ** THIS MUST BE DONE BEFORE ANY MORE OUTPUT IS DONE. */ attachCompleted = TRUE; /* Update screen */ printf(": %s\n", sc->vs.color ? "color" : "mono"); do_async_update(sc); /* Set up keyboard controller interrupt */ sc->kbd.sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_LEVEL, IPL_TTY, pcintr, sc); /* ** Pass child devices our io handle so they can use ** the same io space as the keyboard. */ #if 0 ia->ia_delaybah = sc->kbd.sc_ioh; #else ia->ia_aux = (void *)sc->kbd.sc_ioh; #endif /* ** Search for and configure any child devices. */ while (config_found(self, ia, NULL) != NULL) /* will break when no more children */ ; } /* End pcattach() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcopen ** ** This routine is to open the console device. It first makes ** sure that the device unit specified is valid and not already ** in use. A tty structure is allocated if one hasn't been ** already. It then sets up the tty flags and calls the line ** disciplines open routine. ** ** FORMAL PARAMETERS: ** ** dev - Device identifier consisting of major and minor numbers. ** flag - not used ** mode - not used. ** p - not used. ** ** IMPLICIT INPUTS: ** ** none. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** Returns an errno value on error. This is either the error ** error returned by the line discipline or one of the ** following errnos. ** ** ENXIO - invalid device specified for open. ** EBUSY - The unit is already opened for exclusive use and the ** current requestor is NOT root. ** ** SIDE EFFECTS: ** ** none. **-- */ int pcopen(dev_t dev, int flag, int mode, struct proc *p) { struct pc_softc *sc; int unit = PCUNIT(dev); struct tty *tp; KERN_DEBUG( pcdebug, KERN_DEBUG_INFO, ("pcopen by process %d\n", p->p_pid)); /* ** Sanity check the minor device number we have been instructed ** to open and set up our softc structure pointer. */ if (unit >= pc_cd.cd_ndevs) { return ENXIO; } sc = pc_cd.cd_devs[unit]; if (sc == 0) { return ENXIO; } /* ** Check if we have a tty structure already and create one if not */ if (!sc->sc_tty) { tp = sc->sc_tty = ttymalloc(); tty_attach(tp); } else { tp = sc->sc_tty; } /* ** Initialise the tty structure with a H/W output routine, ** H/W parameter modification routine and device identifier. */ tp->t_oproc = pcstart; tp->t_param = pcparam; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { /* ** Initial open of the device so set up the tty with ** default flag settings */ ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; pcparam(tp, &tp->t_termios); ttsetwater(tp); } else if ( tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0 ) { /* ** Don't allow the open if the tty has been set up ** for exclusive use and this isn't root trying to ** open the device */ return EBUSY; } tp->t_state |= TS_CARR_ON; /* ** Invoke the line discipline open routine */ return ((*linesw[tp->t_line].l_open)(dev, tp)); } /* End pcopen() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcclose ** ** This function is called on the last close for a device unit. ** It calls the line discipline close to clean up any pending ** output and to flush queues. It then close the tty device. ** ** FORMAL PARAMETERS: ** ** dev - Device identifier consisting of major and minor numbers. ** flag - Not used. ** mode - Not used. ** p - Not used. ** ** IMPLICIT INPUTS: ** ** none ** ** IMPLICIT OUTPUTS: ** ** none ** ** FUNCTION VALUE: ** ** 0 - Always returns success. ** ** SIDE EFFECTS: ** ** none. **-- */ int pcclose(dev_t dev, int flag, int mode, struct proc *p) { /* ** Set up our pointers to the softc and tty structures. ** ** Note : This all assumes that the system wont call us with ** an invalid (ie. non-existant), device identifier. */ struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; struct tty *tp = sc->sc_tty; /* ** Let the line discipline clean up any pending output and ** flush queues. */ (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); return(0); } /* End pcclose() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Handles a read operation on the device. We just ** locate the tty device associated with the unit specified ** and pass everything on to the line driver. ** ** FORMAL PARAMETERS: ** ** dev - Device identifier consisting of major and minor numbers. ** uio - Pointer to the user I/O information (ie. read buffer). ** flag - Information on how the I/O should be done (eg. blocking ** or non-blocking). ** ** IMPLICIT INPUTS: ** ** pc_cd - The console driver global anchor structure containing ** pointers to all of the softc structures for each unit ** (amoung other things). ** ** IMPLICIT OUTPUTS: ** ** none ** ** FUNCTION VALUE: ** ** Returns zero on success and an errno on failure. ** ** SIDE EFFECTS: ** ** none **-- */ int pcread(dev_t dev, struct uio *uio, int flag) { struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; struct tty *tp = sc->sc_tty; return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); } /* End pcread() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Handles a write operation on the device. We just ** locate the tty device associated with the unit specified ** and pass everything on to the line driver. ** ** FORMAL PARAMETERS: ** ** dev - Device identifier consisting of major and minor numbers. ** uio - Pointer to the user I/O information (ie. read buffer). ** flag - Information on how the I/O should be done (eg. blocking ** or non-blocking). ** ** IMPLICIT INPUTS: ** ** pc_cd - The console driver global anchor structure containing ** pointers to all of the softc structures for each unit ** (amoung other things). ** ** IMPLICIT OUTPUTS: ** ** none ** ** FUNCTION VALUE: ** ** Returns zero on success and an errno on failure. ** ** SIDE EFFECTS: ** ** none **-- */ int pcwrite(dev_t dev, struct uio *uio, int flag) { struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; struct tty *tp = sc->sc_tty; return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } /* End pcwrite() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Return the tty structure for the given device unit. ** ** FORMAL PARAMETERS: ** ** dev - Device identifier consisting of major and minor numbers. ** ** IMPLICIT INPUTS: ** ** pc_cd - The console driver global anchor structure containing ** pointers to all of the softc structures for each unit ** (amoung other things). ** ** IMPLICIT OUTPUTS: ** ** none ** ** FUNCTION VALUE: ** ** Returns zero on success and an errno on failure. ** ** SIDE EFFECTS: ** ** none **-- */ struct tty * pctty(dev_t dev) { struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; struct tty *tp = sc->sc_tty; return (tp); } /* End pctty() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcintr ** ** This is the interrupt handler routine for the keyboard controller. ** If we're in polling mode then just return. If not then call the ** sget routine to read the and convert the character in the keyboard ** buffer. The convereted character is then passed to the line ** discipline's read interrupt routine. ** ** FORMAL PARAMETERS: ** ** arg - Pointer to our device/softc structure. ** ** IMPLICIT INPUTS: ** ** none. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** 0 - Interrupt not handled by the driver. ** 1 - Interrupt handled by the driver. ** ** SIDE EFFECTS: ** ** none. **-- */ int pcintr(void *arg) { struct pc_softc *sc = arg; register struct tty *tp = sc->sc_tty; u_char *cp; int handledInt; handledInt = 1; if (sc->sc_flags & SC_POLLING) { KERN_DEBUG( pcdebug, KERN_DEBUG_WARNING, ("pcintr: received interrupt in polling mode\n")); } else { /* ** Get the character string for the keyboard event. ** The scanned character string is passed to ** the line discipline's received character routine. */ cp = sget(sc); if (tp && (tp->t_state & TS_ISOPEN) && cp) { do { (*linesw[tp->t_line].l_rint)(*cp++, tp); } while (*cp); } } /* End else we aren't polling at the moment */ return (handledInt); } /* End pcintr() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This routine is responsible for performing I/O controls on the ** console device. We first pass the command to our line discipline to ** see if it is one they are intended to handle. If they "know nothing!!" ** we pass it on to the generic ttioctl() routine. If they also deny ** responsibility, we then check if it's a ioctl we support. ** The ioctls we support are: ** ** CONSOLE_X_MODE_ON - X is using the console device ** CONSOLE_X_MODE_OFF - X is releasing the console device ** CONSOLE_X_BELL - ring the bell ** CONSOLE_SET_TYPEMATIC_RATE - set keyboard typematic rate ** ** FORMAL PARAMETERS: ** ** dev - Device identifier consisting of major and minor numbers. ** cmd - The requested IOCTL command to be performed. This is a ** composite integer with the following structure but ** refer to ttycom.h and ioccom.h for full details : ** ** Bit Position { 3322222222221111111111 ** { 10987654321098765432109876543210 ** Meaning | DDDLLLLLLLLLLLLLGGGGGGGGCCCCCCCC ** ** D - Command direction, in/out/both. ** L - Command arguement length. ** G - Command group, 't' used for tty. ** C - Actual command enumeration. ** ** data - user data ** flag - Not used by us but passed to line discipline and ttioctl ** p - pointer to proc structure of user. ** ** IMPLICIT INPUTS: ** ** none. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** We will return any errors returned by either the line discipline ** routine or the ttioctl() routine. In addition we may directly ** generate the following errors : ** ** EINVAL - Invalid value for typematic rate specified. ** ENOTTY - Unknown ioctl command attempted. ** ** SIDE EFFECTS: ** ** The softc sc_hwflags may be altered which will effect the behaviour of ** several other routines when dealing with the hardware. **-- */ int pcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; struct tty *tp = sc->sc_tty; int error; /* Give the line discipline first crack at doing something with ** the requested operation. ** Error > 0 means that the operation requested was known by ** the line discipline but something went wrong. Error = 0 means the ** request was successfully handled by the line discipline so ** we don't need to to do anything. Error < 0 means the line ** discipline doesn't handle this sort of operation. */ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error < 0) { /* Try the common tty ioctl routine to see if it recognises the ** request. */ error = ttioctl(tp, cmd, data, flag, p); if (error < 0) { /* Ok must be something specific to our device, ** lets start by assuming we will succeed. */ error = 0; switch (cmd) { #ifdef XSERVER case CONSOLE_X_MODE_ON: #ifdef X_CGA_BUG if ((sc->sc_flags & SC_XMODE) == 0 ) { cga_save_restore(CGA_SAVE); } #endif sc->sc_flags |= SC_XMODE; /* * throw away pending data so raw keycodes don't get * mixed with translated characters. */ ttyflush(tp, FREAD); break; case CONSOLE_X_MODE_OFF: #ifdef X_CGA_BUG if (sc->sc_flags & SC_XMODE) { cga_save_restore(CGA_RESTORE); } #endif sc->sc_flags &= ~SC_XMODE; async_update(sc, FALSE); /* * throw away pending data so raw keycodes don't get * mixed with translated characters. */ ttyflush(tp, FREAD); break; case CONSOLE_X_BELL: /* ** If set, data is a pointer to a length 2 array of ** integers. data[0] is the pitch in Hz and data[1] ** is the duration in msec. */ if (data) { sysbeep(((int*)data)[0], (((int*)data)[1] * hz) / 1000); } else { sysbeep(BEEP_FREQ, BEEP_TIME); } break; #ifdef SHARK case CONSOLE_X_TV_ON: /* ** Switch on TV output, data indicates mode, ** but we are currently hardwired to NTSC, so ignore it. */ consXTvOn(); break; case CONSOLE_X_TV_OFF: /* ** Switch off TV output. */ consXTvOff(); break; #endif /* SHARK */ #endif /* XSERVER */ case CONSOLE_SET_TYPEMATIC_RATE: { u_char rate; if (data) { rate = *((u_char *)data); /* ** Check that it isn't too big (which would cause ** it to be confused with a command). */ if (rate & 0x80) { error = EINVAL; } else { /* Update rate in keyboard */ sc->kbd.sc_new_typematic_rate = rate; async_update(sc, FALSE); } } else { error = EINVAL; } } break; #ifdef SHARK case CONSOLE_GET_LINEAR_INFO: if(data) { /* * Warning: Relies on OFW setting up the console in * linear mode */ vm_offset_t linearPhysAddr = displayInfo(paddr); /* Size unknown - X Server will probe chip later. */ ((struct map_info *)data)->method = MAP_MMAP; ((struct map_info *)data)->size = MAP_INFO_UNKNOWN; ((struct map_info *)data)->u.map_info_mmap.map_offset = linearPhysAddr & PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.map_size = MAP_INFO_UNKNOWN; ((struct map_info *)data)->u.map_info_mmap.internal_offset = linearPhysAddr & ~PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.internal_size = MAP_INFO_UNKNOWN; } else { error = EINVAL; } break; case CONSOLE_GET_IO_INFO: if(data) { vm_offset_t ioPhysAddr = displayInfo(ioBase); int ioLength = displayInfo(ioLen); vm_offset_t pam_io_data; ((struct map_info *)data)->method = MAP_MMAP; ((struct map_info *)data)->size = ioLength / sizeof(bus_size_t); pam_io_data = vtophys(isa_io_data_vaddr()); ((struct map_info *)data)->u.map_info_mmap.map_offset = (pam_io_data + ioPhysAddr) & PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.internal_offset = (pam_io_data + ioPhysAddr) & ~PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.map_size = (((struct map_info *)data)->u.map_info_mmap.internal_offset + ioLength + PT_SIZE - 1) & PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.internal_size = ioLength; } else { error = EINVAL; } break; case CONSOLE_GET_MEM_INFO: if(data) { vm_offset_t vam_mem_data = isa_mem_data_vaddr(); /* * Address and size defined in shark.h and * isa_machdep.h */ ((struct map_info *)data)->method = MAP_MMAP; ((struct map_info *)data)->size = VGA_BUF_LEN / sizeof(bus_size_t); ((struct map_info *)data)->u.map_info_mmap.map_offset = (vtophys(vam_mem_data) + VGA_BUF) & PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.internal_offset = (vtophys(vam_mem_data) + VGA_BUF) & ~PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.map_size = (((struct map_info *)data)->u.map_info_mmap.internal_offset + VGA_BUF_LEN + PT_SIZE - 1) & PG_FRAME; ((struct map_info *)data)->u.map_info_mmap.internal_size = VGA_BUF_LEN; } else { error = EINVAL; } break; #endif /* SHARK */ default: error = ENOTTY; break; } /* End switch on ioctl command */ } /* End need to check if this is a device specific command */ } /* End need to check if this is a common tty command */ return (error); } /* End pcioctl() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcstart ** ** This routine is responsible for outputing any data in the tty output ** queue. If the tty is not already in the process of transmitting ** then we remove an amount of data from the output queue and copy it ** to the screen via the sput routine. If data still remains to be ** transmitted we queue a timeout on the tty. If the amount of data ** sent puts the output queue below the low water mark we wake up ** anyone sleeping. ** ** FORMAL PARAMETERS: ** ** tp - pointer to the tty structure wanting to send data. ** ** IMPLICIT INPUTS: ** ** none ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none. ** ** SIDE EFFECTS: ** ** none ** **-- */ void pcstart(struct tty *tp) { struct clist *cl; int s, len; u_char buf[PCBURST]; struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(tp->t_dev)]; s = spltty(); if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) { /* ** Copy data to be output from c-list to output buffer ** and send it to the screen via the sput routine. ** We need to do this outside spl since it could be fairly ** expensive. */ tp->t_state |= TS_BUSY; splx(s); cl = &tp->t_outq; len = q_to_b(cl, buf, PCBURST); sput(sc, buf, len, FALSE); s = spltty(); tp->t_state &= ~TS_BUSY; /* ** If there is still data to be output, queue a timeout ** on the tty. */ if (cl->c_cc) { tp->t_state |= TS_TIMEOUT; callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp); } /* ** Check if we are under the low water mark and ** need to wake any sleepers */ if (cl->c_cc <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup(cl); } selwakeup(&tp->t_wsel); } } /* End if not busy, timeout, or stopped */ /* Restore spl */ splx(s); return; } /* End pcstart() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcstop ** ** This routine does nothing as writes to the output device ** aren't buffered and therefore cannot be stopped. ** ** FORMAL PARAMETERS: ** ** tp - Pointer to our tty structure. ** flag - Ignored. ** ** IMPLICIT INPUTS: ** ** none. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none. ** ** SIDE EFFECTS: ** ** none. **-- */ void pcstop(struct tty *tp, int flag) { return; } /* End pcstop() */ /*****************************************************************************/ /* */ /* The following are the routines that allow the pc device to operate */ /* as the console device. They are prefixed pccn. */ /* */ /*****************************************************************************/ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pccnprobe ** ** Probe for the generic console device. ** ** FORMAL PARAMETERS: ** ** cp - pointer to a console device structure. ** ** IMPLICIT INPUTS: ** ** The isa_io_bs_tag is used to identify which I/O space needs to be ** mapped to talk to the keyboard device. The CONKBDADDR option ** is used to determine the base address of the keyboard controller. ** This file supplies a default value, in case it is not defined ** in the config file ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none - however cn_pri is effectively a return value as this determines ** the priority of this device in being the console. ** ** SIDE EFFECTS: ** ** none. ** **-- */ void pccnprobe(struct consdev *cp) { int maj; int s; /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) { if (cdevsw[maj].d_open == pcopen) { break; } } /* initialize required fields */ cp->cn_dev = makedev(maj, 0); cp->cn_pri = CN_DEAD; /* assume can't configure keyboard */ /* initialise the boot softc to use until we get attached with a ** real softc. */ memset(&bootSoftc, 0, sizeof(bootSoftc)); bootSoftc.kbd.sc_iot = &isa_io_bs_tag; s = splhigh(); /* Setup base address of keyboard device on the SuperIO chip. Then ** map our register space within the bus. */ if (i87307KbdConfig(bootSoftc.kbd.sc_iot, CONKBDADDR, IRQ_KEYBOARD)) { if (I8042_MAP(bootSoftc.kbd.sc_iot,CONKBDADDR,bootSoftc.kbd.sc_ioh) == 0) { /* ** Initalise the keyboard. Look for another device if ** keyboard wont initialise but leave us as a backup display ** unit. */ if (kbd_init(bootSoftc.kbd.sc_iot, bootSoftc.kbd.sc_ioh)) { cp->cn_pri = CN_INTERNAL; } I8042_UNMAP(bootSoftc.kbd.sc_iot, bootSoftc.kbd.sc_ioh); } } splx(s); return; } /* End pccnprobe() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pccninit ** ** This is the intialisation entry point called through the constab ** array. All we do is intialise the keyboard controller. We ignore ** any failure, this allows the generic console device to be used ** even if no keyboard is plugged in. ** ** FORMAL PARAMETERS: ** ** cp - pointer to a console device structure. ** ** IMPLICIT INPUTS: ** ** none ** ** IMPLICIT OUTPUTS: ** ** actingConsole is set to one to indicate that the console device has ** been initialised. ** ** FUNCTION VALUE: ** ** none. ** ** SIDE EFFECTS: ** ** none. ** **-- */ void pccninit(struct consdev *cp) { int s = splhigh(); actingConsole = TRUE; if (I8042_MAP(bootSoftc.kbd.sc_iot, CONKBDADDR, bootSoftc.kbd.sc_ioh)) { panic("pccninit: kbd mapping failed"); } bootSoftc.sc_flags = 0x00; bootSoftc.kbd.sc_shift_state = 0x00; bootSoftc.kbd.sc_new_lock_state = 0x00; bootSoftc.kbd.sc_old_lock_state = 0xff; bootSoftc.kbd.sc_new_typematic_rate = 0xff; bootSoftc.kbd.sc_old_typematic_rate = 0xff; bootSoftc.vs.cx = bootSoftc.vs.cy = 0; bootSoftc.vs.row = bootSoftc.vs.col = 0; bootSoftc.vs.nrow = 0; bootSoftc.vs.ncol = 0; bootSoftc.vs.nchr = 0; bootSoftc.vs.state = 0; bootSoftc.vs.so = 0; bootSoftc.vs.color = 0; bootSoftc.vs.at = 0; bootSoftc.vs.so_at = 0; #ifdef SHARK /* ** Get display information from ofw before leaving linear mode. */ getDisplayInfo(&display); /* Must force hardware into VGA mode before anything else ** otherwise we may hang trying to do console output. */ force_vga_mode(); pccnputc(0, '\n'); #endif splx(s); return; } /* End pccninit() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pccnputc ** ** This is a simple putc routine for the generic console device. ** It simply calls sput to write the character to the screen. ** ** FORMAL PARAMETERS: ** ** dev - our device identification ** c - the character to be transmited. ** ** IMPLICIT INPUTS: ** ** none. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none. ** ** SIDE EFFECTS: ** ** none ** **-- */ void pccnputc(dev_t dev, char c) { struct pc_softc *currentSC; /* Ok so we are a little bit complicated because I insist on using a ** decent approach to softc's. Here we check whether the attach has ** been performed on the console device and if so get the REAL softc. ** otherwise we use the bootSoftc cause we are the console in boot ** sequence. */ if (attachCompleted == TRUE) { currentSC = pc_cd.cd_devs[PCUNIT(dev)]; } else { currentSC = &bootSoftc; } /* write the character to the screen */ if (c == '\n') { sput(currentSC, "\r\n", 2, TRUE); } else { sput(currentSC, &c, 1, TRUE); } return; } /* End pccnputc() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pccngetc ** ** This routine reads a character from the keyboard output buffer. ** It waits until there is a charcater available and then calls ** the sget routine to convert the character, before returning it. ** ** FORMAL PARAMETERS: ** ** dev - The identifier for our device. ** ** IMPLICIT INPUTS: ** ** none. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** Returns the converted character read from the keyboard. ** ** SIDE EFFECTS: ** ** none ** **-- */ int pccngetc(dev_t dev) { register char *cp = NULL; struct pc_softc *currentSC; /* Ok so we are a little bit complicated because I insist on using a ** decent approach to softc's. Here we check whether the attach has ** been performed on the console device and if so get the REAL softc. ** otherwise we use the bootSoftc cause we are the console in boot ** sequence. */ if (attachCompleted == TRUE) { currentSC = pc_cd.cd_devs[PCUNIT(dev)]; } else { currentSC = &bootSoftc; } if ( (currentSC->sc_flags & SC_XMODE) == 0 ) { do { /* wait for a keyboard byte from the 8042 controller. */ for (;;) { if ( !i8042_wait_input(currentSC->kbd.sc_iot, currentSC->kbd.sc_ioh, I8042_KBD_DATA) ) { KERN_DEBUG( pcdebug, KERN_DEBUG_WARNING, ("pccnget: in deep dodo got bad status\n")); } break; } /* End do forever until we get a character */ /* Read and convert character in keyboard buffer */ cp = sget(currentSC); } while (!cp); if (*cp == '\r') { return '\n'; } } /* End if NOT in Xmode */ return *cp; } /* End pccngetc() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcncpollc ** ** This routine is used to activate/deactivate the polling interface ** to the generic console device. If polling is being turned off ** and the console device is in use, the interrupt routine is called ** to pass up any character that may still be in the keyboard output ** buffer. ** ** FORMAL PARAMETERS: ** ** dev - our device identification ** on - 1 - set device to polling ** 0 - turn off polling on the device ** ** IMPLICIT INPUTS: ** ** none ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none. ** ** SIDE EFFECTS: ** ** none **-- */ void pccnpollc(dev_t dev, int on) { struct pc_softc *currentSC; /* Ok so we are a little bit complicated because I insist on using a ** decent approach to softc's. Here we check whether the attach has ** been performed on the console device and if so get the REAL softc. ** otherwise we use the bootSoftc cause we are the console in boot ** sequence. */ if (attachCompleted == TRUE) { currentSC = pc_cd.cd_devs[PCUNIT(dev)]; } else { currentSC = &bootSoftc; } currentSC->sc_flags = on ? currentSC->sc_flags | SC_POLLING : currentSC->sc_flags & ~SC_POLLING; if (!on) { int s; /* Comming out of polling mode. Make sure we try and process any ** character that may be in the buffer at this time that we have ** already ignored the interrupt for. */ s = spltty(); pcintr(currentSC); splx(s); } /* end-if not polling */ return; } /* End pccnpollc() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcparam ** ** This routine is called by the tty to modify hardware settings on ** the device as specified by the termios structured passed to it ** (.e.g. line speed). As there is nothing we can set in the hardware, ** we just update the fields in the tty structure and return success. ** ** FORMAL PARAMETERS: ** ** tp - Pointer to a tty structure for our device. ** t - Pointer to the termios structure containing new configuration ** parameters. ** ** IMPLICIT INPUTS: ** ** none ** ** IMPLICIT OUTPUTS: ** ** none ** ** FUNCTION VALUE: ** ** 0 - Always succeeds. ** ** SIDE EFFECTS: ** ** none. **-- */ int pcparam(struct tty *tp, struct termios *t) { tp->t_ispeed = t->c_ispeed; tp->t_ospeed = t->c_ospeed; tp->t_cflag = t->c_cflag; return 0; } /* End pcparam() */ /* ** wrtchar ** ** Write a character to the screen. ** Load pointer with current cursor address. ** Write character and the character attributes ** to to cursor address. Update cursor address ** and column location. */ #define wrtchar(sc, c, at) \ do { \ char *cp = (char *)crtat; \ \ *cp++ = (c); \ *cp = (at); \ crtat++; sc->vs.col++; \ } while (0) /* translate ANSI color codes to standard pc ones */ static char fgansitopc[] = { FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, FG_MAGENTA, FG_CYAN, FG_LIGHTGREY }; static char bgansitopc[] = { BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, BG_MAGENTA, BG_CYAN, BG_LIGHTGREY }; /* **++ ** FUNCTIONAL DESCRIPTION: ** ** sput ** ** This routine is used to write to the screen using ** pc3 terminal emulation. ** ** FORMAL PARAMETERS: ** ** None. ** ** IMPLICIT INPUTS: ** ** None. ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** none ** **-- */ void sput(struct pc_softc *sc, u_char *cp, int n, u_char nowait) { u_char c, scroll = 0; if (sc->sc_flags & SC_XMODE) return; /* Initialise the display if not done already */ if (crtat == 0) { u_short volatile *cp; #ifdef DOESNT_ALWAYS_DO_THE_RIGHT_THING u_short was; #endif unsigned cursorat; vm_offset_t vam_mem_data = isa_mem_data_vaddr(); /* ** Check to see if we have color support ** by attempting to write and read from ** the colour buffer. If successful then ** we operate in color mode otherwise ** mono. */ cp = (void *)((u_long)(CGA_BUF) + vam_mem_data); #ifdef DOESNT_ALWAYS_DO_THE_RIGHT_THING was = *cp; /* save whatever is at CGA_BUF */ *cp = (u_short) 0xA55A; if (*cp != 0xA55A) { cp = (void *)((u_long)(MONO_BUF) + vam_mem_data); addr_6845 = MONO_BASE; sc->vs.color = 0; } else { *cp = was; /* restore previous contents of CGA_BUF */ addr_6845 = CGA_BASE; sc->vs.color = 1; } #else addr_6845 = CGA_BASE; sc->vs.color = 1; #endif /* Extract cursor location */ outb(addr_6845, 14); cursorat = inb(addr_6845+1) << 8; outb(addr_6845, 15); cursorat |= inb(addr_6845+1); #ifdef FAT_CURSOR cursor_shape = 0x0012; #endif /* Save cursor locations */ Crtat = (u_short *)cp; crtat = (u_short *)(cp + cursorat); /* Set up screen size and colours */ sc->vs.ncol = COL; sc->vs.nrow = ROW; sc->vs.nchr = COL * ROW; sc->vs.at = FG_LIGHTGREY | BG_BLACK; if (sc->vs.color == 0) { sc->vs.so_at = FG_BLACK | BG_LIGHTGREY; } else { sc->vs.so_at = FG_YELLOW | BG_BLACK; } fillw((sc->vs.at << 8) | ' ', crtat, sc->vs.nchr - cursorat); } /* end-if screen unitialised */ /* Process supplied character string */ while (n--) { if (!(c = *cp++)) continue; switch (c) { case 0x1B: if (sc->vs.state >= VSS_ESCAPE) { wrtchar(sc, c, sc->vs.so_at); sc->vs.state = 0; goto maybe_scroll; } else { sc->vs.state = VSS_ESCAPE; } break; case '\t': { int inccol = 8 - (sc->vs.col & 7); crtat += inccol; sc->vs.col += inccol; } maybe_scroll: if (sc->vs.col >= COL) { sc->vs.col -= COL; scroll = 1; } break; case '\010': if (crtat <= Crtat) break; --crtat; if (--sc->vs.col < 0) sc->vs.col += COL; /* non-destructive backspace */ break; case '\r': crtat -= sc->vs.col; sc->vs.col = 0; break; case '\n': crtat += sc->vs.ncol; scroll = 1; break; default: switch (sc->vs.state) { case 0: if (c == '\a') { sysbeep(BEEP_FREQ, BEEP_TIME); } else { /* * If we're outputting multiple printed * characters, just blast them to the * screen until we reach the end of the * buffer or a control character. This * saves time by short-circuiting the * switch. * If we reach the end of the line, we * break to do a scroll check. */ for (;;) { if (sc->vs.so) { wrtchar(sc, c, sc->vs.so_at); } else { wrtchar(sc, c, sc->vs.at); } if (sc->vs.col >= sc->vs.ncol) { sc->vs.col = 0; scroll = 1; break; } if (!n || (c = *cp) < ' ') break; n--, cp++; } } break; case VSS_ESCAPE: if (c == '[') { /* Start ESC [ sequence */ sc->vs.cx = sc->vs.cy = 0; sc->vs.state = VSS_EBRACE; } else if (c == 'c') /* Clear screen & home */ { fillw((sc->vs.at << 8) | ' ', Crtat, sc->vs.nchr); crtat = Crtat; sc->vs.col = 0; sc->vs.state = 0; } else /* Invalid, clear state */ { wrtchar(sc, c, sc->vs.so_at); sc->vs.state = 0; goto maybe_scroll; } break; default: /* VSS_EBRACE or VSS_EPARAM */ switch (c) { int pos; case 'm': if (!sc->vs.cx) sc->vs.so = 0; else sc->vs.so = 1; sc->vs.state = 0; break; case 'A': { /* back cx rows */ int cx = sc->vs.cx; if (cx <= 0) cx = 1; else cx %= sc->vs.nrow; pos = crtat - Crtat; pos -= sc->vs.ncol * cx; if (pos < 0) pos += sc->vs.nchr; crtat = Crtat + pos; sc->vs.state = 0; break; } case 'B': { /* down cx rows */ int cx = sc->vs.cx; if (cx <= 0) cx = 1; else cx %= sc->vs.nrow; pos = crtat - Crtat; pos += sc->vs.ncol * cx; if (pos >= sc->vs.nchr) pos -= sc->vs.nchr; crtat = Crtat + pos; sc->vs.state = 0; break; } case 'C': { /* right cursor */ int cx = sc->vs.cx, col = sc->vs.col; if (cx <= 0) cx = 1; else cx %= sc->vs.ncol; pos = crtat - Crtat; pos += cx; col += cx; if (col >= sc->vs.ncol) { pos -= sc->vs.ncol; col -= sc->vs.ncol; } sc->vs.col = col; crtat = Crtat + pos; sc->vs.state = 0; break; } case 'D': { /* left cursor */ int cx = sc->vs.cx, col = sc->vs.col; if (cx <= 0) cx = 1; else cx %= sc->vs.ncol; pos = crtat - Crtat; pos -= cx; col -= cx; if (col < 0) { pos += sc->vs.ncol; col += sc->vs.ncol; } sc->vs.col = col; crtat = Crtat + pos; sc->vs.state = 0; break; } case 'J': /* Clear ... */ switch (sc->vs.cx) { case 0: /* ... to end of display */ fillw((sc->vs.at << 8) | ' ', crtat, Crtat + sc->vs.nchr - crtat); break; case 1: /* ... to next location */ fillw((sc->vs.at << 8) | ' ', Crtat, crtat - Crtat + 1); break; case 2: /* ... whole display */ fillw((sc->vs.at << 8) | ' ', Crtat, sc->vs.nchr); break; } sc->vs.state = 0; break; case 'K': /* Clear line ... */ switch (sc->vs.cx) { case 0: /* ... current to EOL */ fillw((sc->vs.at << 8) | ' ', crtat, sc->vs.ncol - sc->vs.col); break; case 1: /* ... beginning to next */ fillw((sc->vs.at << 8) | ' ', crtat - sc->vs.col, sc->vs.col + 1); break; case 2: /* ... entire line */ fillw((sc->vs.at << 8) | ' ', crtat - sc->vs.col, sc->vs.ncol); break; } sc->vs.state = 0; break; case 'f': /* in system V consoles */ case 'H': { /* Cursor move */ int cx = sc->vs.cx, cy = sc->vs.cy; if (!cx || !cy) { crtat = Crtat; sc->vs.col = 0; } else { if (cx > sc->vs.nrow) cx = sc->vs.nrow; if (cy > sc->vs.ncol) cy = sc->vs.ncol; crtat = Crtat + (cx - 1) * sc->vs.ncol + cy - 1; sc->vs.col = cy - 1; } sc->vs.state = 0; break; } case 'M': { /* delete cx rows */ u_short *crtAt = crtat - sc->vs.col; int cx = sc->vs.cx, row = (crtAt - Crtat) / sc->vs.ncol, nrow = sc->vs.nrow - row; if (cx <= 0) cx = 1; else if (cx > nrow) cx = nrow; if (cx < nrow) bcopy(crtAt + sc->vs.ncol * cx, crtAt, sc->vs.ncol * (nrow - cx) * CHR); fillw((sc->vs.at << 8) | ' ', crtAt + sc->vs.ncol * (nrow - cx), sc->vs.ncol * cx); sc->vs.state = 0; break; } case 'S': { /* scroll up cx lines */ int cx = sc->vs.cx; if (cx <= 0) cx = 1; else if (cx > sc->vs.nrow) cx = sc->vs.nrow; if (cx < sc->vs.nrow) bcopy(Crtat + sc->vs.ncol * cx, Crtat, sc->vs.ncol * (sc->vs.nrow - cx) * CHR); fillw((sc->vs.at << 8) | ' ', Crtat + sc->vs.ncol * (sc->vs.nrow - cx), sc->vs.ncol * cx); #if 0 crtat -= sc->vs.ncol * cx; /* XXX */ #endif sc->vs.state = 0; break; } case 'L': { /* insert cx rows */ u_short *crtAt = crtat - sc->vs.col; int cx = sc->vs.cx, row = (crtAt - Crtat) / sc->vs.ncol, nrow = sc->vs.nrow - row; if (cx <= 0) cx = 1; else if (cx > nrow) cx = nrow; if (cx < nrow) bcopy(crtAt, crtAt + sc->vs.ncol * cx, sc->vs.ncol * (nrow - cx) * CHR); fillw((sc->vs.at << 8) | ' ', crtAt, sc->vs.ncol * cx); sc->vs.state = 0; break; } case 'T': { /* scroll down cx lines */ int cx = sc->vs.cx; if (cx <= 0) cx = 1; else if (cx > sc->vs.nrow) cx = sc->vs.nrow; if (cx < sc->vs.nrow) bcopy(Crtat, Crtat + sc->vs.ncol * cx, sc->vs.ncol * (sc->vs.nrow - cx) * CHR); fillw((sc->vs.at << 8) | ' ', Crtat, sc->vs.ncol * cx); #if 0 crtat += sc->vs.ncol * cx; /* XXX */ #endif sc->vs.state = 0; break; } case ';': /* Switch params in cursor def */ sc->vs.state = VSS_EPARAM; break; case 'r': sc->vs.so_at = (sc->vs.cx & FG_MASK) | ((sc->vs.cy << 4) & BG_MASK); sc->vs.state = 0; break; case 'x': /* set attributes */ switch (sc->vs.cx) { case 0: sc->vs.at = FG_LIGHTGREY | BG_BLACK; break; case 1: /* ansi background */ if (!sc->vs.color) break; sc->vs.at &= FG_MASK; sc->vs.at |= bgansitopc[sc->vs.cy & 7]; break; case 2: /* ansi foreground */ if (!sc->vs.color) break; sc->vs.at &= BG_MASK; sc->vs.at |= fgansitopc[sc->vs.cy & 7]; break; case 3: /* pc text attribute */ if (sc->vs.state >= VSS_EPARAM) sc->vs.at = sc->vs.cy; break; } sc->vs.state = 0; break; default: /* Only numbers valid here */ if ((c >= '0') && (c <= '9')) { if (sc->vs.state >= VSS_EPARAM) { sc->vs.cy *= 10; sc->vs.cy += c - '0'; } else { sc->vs.cx *= 10; sc->vs.cx += c - '0'; } } else sc->vs.state = 0; break; } break; } } if (scroll) { scroll = 0; /* scroll check */ if (crtat >= Crtat + sc->vs.nchr) { if (nowait == FALSE) { int s = spltty(); if (sc->kbd.sc_new_lock_state & SCROLL) tsleep(&(sc->kbd.sc_new_lock_state), PUSER, "pcputc", 0); splx(s); } bcopy(Crtat + sc->vs.ncol, Crtat, (sc->vs.nchr - sc->vs.ncol) * CHR); fillw((sc->vs.at << 8) | ' ', Crtat + sc->vs.nchr - sc->vs.ncol, sc->vs.ncol); crtat -= sc->vs.ncol; } } } async_update(sc, nowait); } #define CODE_SIZE 4 /* Use a max of 4 for now... */ typedef struct { u_short type; char unshift[CODE_SIZE]; char shift[CODE_SIZE]; char ctl[CODE_SIZE]; } Scan_def; static Scan_def scan_codes[] = { { NONE, "", "", "" }, /* 0 unused */ { ASCII,"\033", "\033", "\033" }, /* 1 ESCape */ { ASCII,"1", "!", "!" }, /* 2 1 */ { ASCII,"2", "@", "\000" }, /* 3 2 */ { ASCII,"3", "#", "#" }, /* 4 3 */ { ASCII,"4", "$", "$" }, /* 5 4 */ { ASCII,"5", "%", "%" }, /* 6 5 */ { ASCII,"6", "^", "\036" }, /* 7 6 */ { ASCII,"7", "&", "&" }, /* 8 7 */ { ASCII,"8", "*", "\010" }, /* 9 8 */ { ASCII,"9", "(", "(" }, /* 10 9 */ { ASCII,"0", ")", ")" }, /* 11 0 */ { ASCII,"-", "_", "\037" }, /* 12 - */ { ASCII,"=", "+", "+" }, /* 13 = */ { ASCII,"\177", "\177", "\010" }, /* 14 backspace */ { ASCII,"\t", "\177\t", "\t" }, /* 15 tab */ { ASCII,"q", "Q", "\021" }, /* 16 q */ { ASCII,"w", "W", "\027" }, /* 17 w */ { ASCII,"e", "E", "\005" }, /* 18 e */ { ASCII,"r", "R", "\022" }, /* 19 r */ { ASCII,"t", "T", "\024" }, /* 20 t */ { ASCII,"y", "Y", "\031" }, /* 21 y */ { ASCII,"u", "U", "\025" }, /* 22 u */ { ASCII,"i", "I", "\011" }, /* 23 i */ { ASCII,"o", "O", "\017" }, /* 24 o */ { ASCII,"p", "P", "\020" }, /* 25 p */ { ASCII,"[", "{", "\033" }, /* 26 [ */ { ASCII,"]", "}", "\035" }, /* 27 ] */ { ASCII,"\r", "\r", "\n" }, /* 28 return */ #if defined (CAPS_IS_CONTROL) { CAPS, "", "", "" }, /* 29 caps */ #else { CTL, "", "", "" }, /* 29 control */ #endif { ASCII,"a", "A", "\001" }, /* 30 a */ { ASCII,"s", "S", "\023" }, /* 31 s */ { ASCII,"d", "D", "\004" }, /* 32 d */ { ASCII,"f", "F", "\006" }, /* 33 f */ { ASCII,"g", "G", "\007" }, /* 34 g */ { ASCII,"h", "H", "\010" }, /* 35 h */ { ASCII,"j", "J", "\n" }, /* 36 j */ { ASCII,"k", "K", "\013" }, /* 37 k */ { ASCII,"l", "L", "\014" }, /* 38 l */ { ASCII,";", ":", ";" }, /* 39 ; */ { ASCII,"'", "\"", "'" }, /* 40 ' */ { ASCII,"`", "~", "`" }, /* 41 ` */ { SHIFT,"", "", "" }, /* 42 shift */ { ASCII,"\\", "|", "\034" }, /* 43 \ */ { ASCII,"z", "Z", "\032" }, /* 44 z */ { ASCII,"x", "X", "\030" }, /* 45 x */ { ASCII,"c", "C", "\003" }, /* 46 c */ { ASCII,"v", "V", "\026" }, /* 47 v */ { ASCII,"b", "B", "\002" }, /* 48 b */ { ASCII,"n", "N", "\016" }, /* 49 n */ { ASCII,"m", "M", "\r" }, /* 50 m */ { ASCII,",", "<", "<" }, /* 51 , */ { ASCII,".", ">", ">" }, /* 52 . */ { ASCII,"/", "?", "\037" }, /* 53 / */ { SHIFT,"", "", "" }, /* 54 shift */ { KP, "*", "*", "*" }, /* 55 kp * */ { ALT, "", "", "" }, /* 56 alt */ { ASCII," ", " ", "\000" }, /* 57 space */ #if defined (CAPS_IS_CONTROL) { CTL, "", "", "" }, /* 58 ctl */ #else { CAPS, "", "", "" }, /* 58 caps */ #endif { FUNC, "\033[M", "\033[Y", "\033[k" }, /* 59 f1 */ { FUNC, "\033[N", "\033[Z", "\033[l" }, /* 60 f2 */ { FUNC, "\033[O", "\033[a", "\033[m" }, /* 61 f3 */ { FUNC, "\033[P", "\033[b", "\033[n" }, /* 62 f4 */ { FUNC, "\033[Q", "\033[c", "\033[o" }, /* 63 f5 */ { FUNC, "\033[R", "\033[d", "\033[p" }, /* 64 f6 */ { FUNC, "\033[S", "\033[e", "\033[q" }, /* 65 f7 */ { FUNC, "\033[T", "\033[f", "\033[r" }, /* 66 f8 */ { FUNC, "\033[U", "\033[g", "\033[s" }, /* 67 f9 */ { FUNC, "\033[V", "\033[h", "\033[t" }, /* 68 f10 */ { NUM, "", "", "" }, /* 69 num lock */ { SCROLL,"", "", "" }, /* 70 scroll lock */ { KP, "7", "\033[H", "7" }, /* 71 kp 7 */ { KP, "8", "\033[A", "8" }, /* 72 kp 8 */ { KP, "9", "\033[I", "9" }, /* 73 kp 9 */ { KP, "-", "-", "-" }, /* 74 kp - */ { KP, "4", "\033[D", "4" }, /* 75 kp 4 */ { KP, "5", "\033[E", "5" }, /* 76 kp 5 */ { KP, "6", "\033[C", "6" }, /* 77 kp 6 */ { KP, "+", "+", "+" }, /* 78 kp + */ { KP, "1", "\033[F", "1" }, /* 79 kp 1 */ { KP, "2", "\033[B", "2" }, /* 80 kp 2 */ { KP, "3", "\033[G", "3" }, /* 81 kp 3 */ { KP, "0", "\033[L", "0" }, /* 82 kp 0 */ { KP, ".", "\177", "." }, /* 83 kp . */ { NONE, "", "", "" }, /* 84 0 */ { NONE, "100", "", "" }, /* 85 0 */ { NONE, "101", "", "" }, /* 86 0 */ { FUNC, "\033[W", "\033[i", "\033[u" }, /* 87 f11 */ { FUNC, "\033[X", "\033[j", "\033[v" }, /* 88 f12 */ { NONE, "102", "", "" }, /* 89 0 */ { NONE, "103", "", "" }, /* 90 0 */ { NONE, "", "", "" }, /* 91 0 */ { NONE, "", "", "" }, /* 92 0 */ { NONE, "", "", "" }, /* 93 0 */ { NONE, "", "", "" }, /* 94 0 */ { NONE, "", "", "" }, /* 95 0 */ { NONE, "", "", "" }, /* 96 0 */ { NONE, "", "", "" }, /* 97 0 */ { NONE, "", "", "" }, /* 98 0 */ { NONE, "", "", "" }, /* 99 0 */ { NONE, "", "", "" }, /* 100 */ { NONE, "", "", "" }, /* 101 */ { NONE, "", "", "" }, /* 102 */ { NONE, "", "", "" }, /* 103 */ { NONE, "", "", "" }, /* 104 */ { NONE, "", "", "" }, /* 105 */ { NONE, "", "", "" }, /* 106 */ { NONE, "", "", "" }, /* 107 */ { NONE, "", "", "" }, /* 108 */ { NONE, "", "", "" }, /* 109 */ { NONE, "", "", "" }, /* 110 */ { NONE, "", "", "" }, /* 111 */ { NONE, "", "", "" }, /* 112 */ { NONE, "", "", "" }, /* 113 */ { NONE, "", "", "" }, /* 114 */ { NONE, "", "", "" }, /* 115 */ { NONE, "", "", "" }, /* 116 */ { NONE, "", "", "" }, /* 117 */ { NONE, "", "", "" }, /* 118 */ { NONE, "", "", "" }, /* 119 */ { NONE, "", "", "" }, /* 120 */ { NONE, "", "", "" }, /* 121 */ { NONE, "", "", "" }, /* 122 */ { NONE, "", "", "" }, /* 123 */ { NONE, "", "", "" }, /* 124 */ { NONE, "", "", "" }, /* 125 */ { NONE, "", "", "" }, /* 126 */ { NONE, "", "", "" }, /* 127 */ }; /* **++ ** FUNCTIONAL DESCRIPTION: ** ** xinterpret ** ** This routine interprets a read scan code according to what ** Xserver requires. ** ** FORMAL PARAMETERS: ** ** sc - Input : The console softc structure. ** dt - Input : The scan code read from the keyboard. ** ** IMPLICIT INPUTS: ** ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** A pointer to the converted characters read from the keyboard ** NULL if no characters read ** ** SIDE EFFECTS: ** ** A sleeper waiting on kbd.sc_new_lock_state may be woken up if the ** SCROLL key has been depressed. **-- */ char * xinterpret(struct pc_softc *sc, u_char dt) { u_char dt_make; static u_char capchar[2]; #if defined(DDB) && defined(XSERVER_DDB) /* F12 enters the debugger while in X mode */ if (dt == 88) { Debugger(); } #endif capchar[0] = dt; capchar[1] = 0; /* ** Check for locking keys. ** ** XXX Setting the LEDs this way is a bit bogus. What if the ** keyboard has been remapped in X? */ dt_make = dt & ~BREAKBIT; switch (scan_codes[dt_make].type) { case NUM: case CAPS: case SCROLL: if (dt & BREAKBIT) { /* This is the break code, reset kbd.sc_shift_state and ** exit. */ sc->kbd.sc_shift_state &= ~(scan_codes[dt_make].type); } else if ( (sc->kbd.sc_shift_state & scan_codes[dt_make].type) == 0 ) { /* This is NOT a repeat of an already recorded ** kbd.sc_shift_state, so record it now and update. */ sc->kbd.sc_shift_state |= scan_codes[dt_make].type; sc->kbd.sc_new_lock_state ^= scan_codes[dt_make].type; if ( (scan_codes[dt_make].type == SCROLL) && ((sc->kbd.sc_new_lock_state & SCROLL) == 0) ) { /* For scroll we also have to wake up sleepers. */ wakeup(&(sc->kbd.sc_new_lock_state)); } async_update(sc, FALSE); } break; } /* End switch on scan code type */ return capchar; } /* End xinterpret */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** sget ** ** This routine reads a character from the keyboard and ** converts it using the above scan code tables. ** ** FORMAL PARAMETERS: ** ** iot I/O tag for the mapped register space ** ioh I/O handle for the mapped register space ** ** IMPLICIT INPUTS: ** ** None. ** ** IMPLICIT OUTPUTS: ** ** ack - received ack from keyboard ** nak - received nak from keyboard ** ** FUNCTION VALUE: ** ** A pointer to the converted characters read from the keyboard ** NULL if no characters read ** ** SIDE EFFECTS: ** **-- */ char * sget(struct pc_softc *sc) { u_char dt = 0; /* XXX */ u_char dt_make; u_char status; static u_char extended = 0; static u_char capchar[2]; bus_space_tag_t iot = sc->kbd.sc_iot; bus_space_handle_t ioh = sc->kbd.sc_ioh; char *returnValue; returnValue = NULL; /* Grab the next byte of keyboard data. There is no point in looping ** here since the controller only puts one byte at a time in the ** output buffer and we are LONG gone before it has time to put the ** next byte in after our initial read (at least on a StrongARM we are). */ I8042_GETKBD_DATA(iot, ioh, status, dt); if (status) { if (sc->sc_flags & SC_XMODE) { returnValue = xinterpret(sc, dt); } else if (dt == KBR_EXTENDED) { extended = TRUE; } else { #ifdef DDB /* ** Check for cntl-alt-esc. */ if ((dt == 1) && (sc->kbd.sc_shift_state & (CTL | ALT)) == (CTL | ALT)) { Debugger(); dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */ } #endif #ifdef SHARK if ((dt == 127) && (sc->kbd.sc_shift_state & (CTL | ALT)) == (CTL | ALT)) { cpu_reboot(0, NULL); } #endif /* ** Record make sequence regardless of what dt is since the make ** code is the key to the scan table. */ dt_make = dt & ~BREAKBIT; switch (scan_codes[dt_make].type) { /* ** locking keys */ case NUM: case CAPS: case SCROLL: if (dt & BREAKBIT) { /* This is the break code, reset kbd.sc_shift_state and ** exit. */ sc->kbd.sc_shift_state &= ~(scan_codes[dt_make].type); } else if ((sc->kbd.sc_shift_state & scan_codes[dt_make].type) == 0) { /* This isn't a repeat of an already registered ** shift function key. So record it now. */ sc->kbd.sc_shift_state |= scan_codes[dt_make].type; sc->kbd.sc_new_lock_state ^= scan_codes[dt_make].type; if ( (scan_codes[dt_make].type == SCROLL) && ((sc->kbd.sc_new_lock_state & SCROLL) == 0) ) { /* For scroll we also have to wake up sleepers. */ wakeup(&(sc->kbd.sc_new_lock_state)); } /* Update external view of what happened. */ async_update(sc, FALSE); } break; /* ** non-locking keys. Just record in our shift_state. */ case SHIFT: case ALT: case CTL: if (dt & BREAKBIT) { /* This is the break code, reset shift_state and ** exit. */ sc->kbd.sc_shift_state &= ~(scan_codes[dt_make].type); } else { sc->kbd.sc_shift_state |= scan_codes[dt_make].type; } break; case ASCII: if ((dt & BREAKBIT) == 0) { /* control has highest priority */ if (sc->kbd.sc_shift_state & CTL) { capchar[0] = scan_codes[dt_make].ctl[0]; } else if (sc->kbd.sc_shift_state & SHIFT) { capchar[0] = scan_codes[dt_make].shift[0]; } else { capchar[0] = scan_codes[dt_make].unshift[0]; } if ((sc->kbd.sc_new_lock_state & CAPS) && capchar[0] >= 'a' && capchar[0] <= 'z') { capchar[0] -= ('a' - 'A'); } capchar[0] |= (sc->kbd.sc_shift_state & ALT); extended = 0; returnValue = capchar; } break; case NONE: break; case FUNC: if ((dt & BREAKBIT) == 0) { if (sc->kbd.sc_shift_state & SHIFT) { returnValue = scan_codes[dt_make].shift; } else if (sc->kbd.sc_shift_state & CTL) { returnValue = scan_codes[dt_make].ctl; } else { returnValue = scan_codes[dt_make].unshift; } extended = 0; } break; case KP: if ((dt & BREAKBIT) == 0) { if (sc->kbd.sc_shift_state & (SHIFT | CTL) || (sc->kbd.sc_new_lock_state & NUM) == 0 || extended) { returnValue = scan_codes[dt_make].shift; } else { returnValue = scan_codes[dt_make].unshift; } extended = 0; } break; } /* End switch on scan code type */ extended = 0; } /* End else not in Xmode and not an extended scan code indication */ } /* End if keyboard data found */ return (returnValue); } /* End sget() */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** pcmmap ** ** This function returns the page where a specified offset into the ** video memory occurs. ** ** FORMAL PARAMETERS: ** ** dev - device identifier consisting of major and minor numbers. ** offset - offset into video memory * nprot - unused ** ** IMPLICIT INPUTS: ** ** 0xa0000 - Base address of screeen buffer ** ** IMPLICIT OUTPUTS: ** ** none. ** ** FUNCTION VALUE: ** ** The page that the offset into video memory is located at ** -1 Couldn't map offset ** **-- */ paddr_t pcmmap(dev_t dev, off_t offset, int nprot) { #ifdef SHARK vm_offset_t pam_io_data, vam_mem_data; if (offset < 0) return (-1); if(offset >> 24 == displayInfo(paddr) >> 24) { /* Display memory - allow any address since we ** don't know the size */ return arm_byte_to_page(offset); } pam_io_data = vtophys(isa_io_data_vaddr()); vam_mem_data = isa_mem_data_vaddr(); if(offset >> 24 == pam_io_data >> 24) { /* IO space - Should not allow addresses outside of the VGA registers */ if(offset >= ((pam_io_data + displayInfo(ioBase)) & PG_FRAME) && offset <= pam_io_data + displayInfo(ioBase) + displayInfo(ioLen)) { return arm_byte_to_page(offset); } } else if(offset >> 24 == vtophys(vam_mem_data) >> 24) { /* Memory - Allow 0xA0000 to 0xBFFFF */ if(offset >= ((vtophys(vam_mem_data) + VGA_BUF) & PG_FRAME) && offset <= vtophys(vam_mem_data) + VGA_BUF + VGA_BUF_LEN) { return arm_byte_to_page(offset); } } return -1; #else /* not SHARK */ if (offset > 0x20000) { return -1; } #ifdef arm32 return arm_byte_to_page(0xa0000 + offset); #endif #ifdef i386 return i386_btop(0xa0000 + offset); #endif #endif } /* End pcmmap() */ #ifdef SHARK static int _shark_screen_ihandle = 0; static int _shark_screen_is_stdout = 0; int get_shark_screen_ihandle() { int chosen_phandle; int stdout_ihandle, stdout_phandle; char buf[128]; if (_shark_screen_ihandle != 0) goto out; /* * Find out whether the firmware's chosen stdout is * a display. If so, use the existing ihandle so the firmware * doesn't become Unhappy. If not, just open it. */ if ((chosen_phandle = OF_finddevice("/chosen")) == -1 || OF_getprop(chosen_phandle, "stdout", &stdout_ihandle, sizeof(stdout_ihandle)) != sizeof(stdout_ihandle)) { goto notstdout; } stdout_ihandle = of_decode_int((unsigned char *)&stdout_ihandle); if ((stdout_phandle = OF_instance_to_package(stdout_ihandle)) == -1 || OF_getprop(stdout_phandle, "device_type", buf, sizeof(buf)) <= 0) { goto notstdout; } if (strcmp(buf, "display") == 0) { /* The display is the standard output device. */ _shark_screen_ihandle = stdout_ihandle; _shark_screen_is_stdout = 1; goto out; } notstdout: if ((_shark_screen_ihandle = OF_open("screen")) == 0) _shark_screen_ihandle = -1; out: return (_shark_screen_ihandle); } #define OFW_PUTC(cp) \ do { \ if (*(cp) != '\n') \ (void)OF_write(_shark_screen_ihandle, (cp), 1); \ else \ (void)OF_write(_shark_screen_ihandle, "\r\n", 2);\ } while (0) void shark_screen_cleanup(redisplay) int redisplay; { char *cp; if (_shark_screen_ihandle != -1 && _shark_screen_ihandle != 0) { /* * reset the screen. If we had to open the screen device, * close it, too. * * If we didn't have to open the screen, that means that * it's the console's stdout. If we're told to (e.g. * when halting), write the contents of the message buffer * to it, so all debugging info isn't lost. */ (void)OF_call_method("install", _shark_screen_ihandle, 0, 0); (void)OF_write(_shark_screen_ihandle, "\f", 1); if (!_shark_screen_is_stdout) { OF_close(_shark_screen_ihandle); } else if (redisplay && msgbufmapped && msgbufp->msg_magic == MSG_MAGIC) { for (cp = &msgbufp->msg_bufc[msgbufp->msg_bufx]; cp < &msgbufp->msg_bufc[msgbufp->msg_bufx]; cp++) { OFW_PUTC(cp); } for (cp = &msgbufp->msg_bufc[0]; cp < &msgbufp->msg_bufc[msgbufp->msg_bufx]; cp++) { OFW_PUTC(cp); } } } } #undef OFW_PUTC /* Throw the CT65550 into VGA mode. */ static void force_vga_mode(void) { int ihandle; if ((ihandle = get_shark_screen_ihandle()) == -1) { printf("pccons: Unable to open PC screen device"); } else { if (OF_call_method("text-mode3", ihandle, 0, 0) != 0) { printf("pccons: Text-mode3 method invocation on PC " "screen device failed\n"); } } return; } /* End force_vga_mode() */ /* Get information from OFW about the display device */ static void getDisplayInfo(struct display_info *displayInfP) { struct regspec *displayRegs; int regSize; u_int nReg, r; u_int ioStart, ioEnd, memStart, memEnd, *startp, *endp; int ihandle, phandle; unsigned long tempval; if ((ihandle = get_shark_screen_ihandle()) != -1 && (phandle = OF_instance_to_package(ihandle)) != -1) { displayInfP->init = TRUE; /* Linear frame buffer virtual and physical address */ if (OF_getprop(phandle, "address", &tempval, sizeof(vm_offset_t)) > 0) { vm_offset_t vaddr; vaddr = (vm_offset_t)of_decode_int((unsigned char *)&tempval); /* translation must be done by OFW, because we have not yet called ofw_configmem and switched over to netBSD memory manager */ displayInfP->paddr = ofw_gettranslation(vaddr); } else { displayInfP->paddr = (vm_offset_t)(-1); } /* Bytes per scan line */ if (OF_getprop(phandle, "linebytes", &tempval, sizeof(int)) > 0) { displayInfP->linebytes = of_decode_int((unsigned char *)&tempval); } else { displayInfP->linebytes = (vm_offset_t)(-1); } /* Colour depth - bits per pixel */ if (OF_getprop(phandle, "depth", &tempval, sizeof(int)) > 0) { displayInfP->depth = of_decode_int((unsigned char *)&tempval); } else { displayInfP->depth = (vm_offset_t)(-1); } /* Display height - pixels */ if (OF_getprop(phandle, "height", &tempval, sizeof(int)) > 0) { displayInfP->height = of_decode_int((unsigned char *)&tempval); } else { displayInfP->height = (vm_offset_t)(-1); } /* Display width - pixels */ if (OF_getprop(phandle, "width", &tempval, sizeof(int)) > 0) { displayInfP->width = of_decode_int((unsigned char *)&tempval); } else { displayInfP->width = (vm_offset_t)(-1); } /* Name of character Set */ if ((displayInfP->charSetLen = OF_getproplen(phandle, "character-set")) > 0) { displayInfP->charSet = (char *)malloc(displayInfP->charSetLen + 1, M_DEVBUF, M_NOWAIT); displayInfP->charSetLen = OF_getprop(phandle, "character-set", displayInfP->charSet, displayInfP->charSetLen); } if (displayInfP->charSetLen <= 0) { displayInfP->charSet = (char *)-1; } /* Register values. * XXX Treated as a contiguous range for memory mapping * XXX this code is still horribly broken, but it's better * now -- cgd (Nov. 14, 1997) */ if ((regSize = OF_getproplen(phandle, "reg")) > 0) { displayRegs = (struct regspec *)malloc(regSize, M_DEVBUF, M_NOWAIT); if ((regSize = OF_getprop(phandle, "reg", displayRegs, regSize)) > 0) { nReg = regSize / sizeof(struct regspec); ioStart = memStart = 0xffffffff; ioEnd = memEnd = 0; for (r = 0; r < nReg; r++) { displayRegs[r].bustype = of_decode_int((void *)&(displayRegs[r]).bustype); displayRegs[r].addr = of_decode_int((void *)&(displayRegs[r]).addr); displayRegs[r].size = of_decode_int((void *)&(displayRegs[r]).size); if (displayRegs[r].bustype & 1) { /* XXX I/O space */ startp = &ioStart; endp = &ioEnd; } else { startp = &memStart; endp = &memEnd; } if (displayRegs[r].addr < *startp) *startp = displayRegs[r].addr; if (displayRegs[r].addr + displayRegs[r].size > *endp) *endp = displayRegs[r].addr + displayRegs[r].size; } if (memStart != 0xffffffff) { displayInfP->paddr = memStart; } else { #if 0 /* XXX leave this alone until 'address' hack dies */ displayInfP->paddr = (vm_offset_t)-1; #endif } if (ioStart != 0xffffffff) { displayInfP->ioBase = ioStart; displayInfP->ioLen = ioEnd - ioStart; } else { displayInfP->ioBase = (vm_offset_t)-1; displayInfP->ioLen = -1; } } } if (regSize <= 0) { displayInfP->ioBase = (vm_offset_t)-1; displayInfP->ioLen = -1; } } else { displayInfP->paddr = (vm_offset_t)-1; displayInfP->linebytes = -1; displayInfP->depth = -1; displayInfP->height = -1; displayInfP->width = -1; displayInfP->charSet = (char *)-1; displayInfP->charSetLen = 0; displayInfP->ioBase = (vm_offset_t)-1; displayInfP->ioLen = 0; } return; } #ifdef X_CGA_BUG static void cga_save_restore(int mode) { int i; char tmp; static char *textInfo, *fontInfo; static char GraphicsReg[9]; static char SequencerReg[5]; static char AttributeReg10; switch (mode) { case CGA_SAVE: /* * Copy text from screen. */ textInfo = (char *)malloc(16384, M_DEVBUF, M_NOWAIT); bcopy(Crtat, textInfo, TEXT_LENGTH); /* ** Save the registers before we change them */ /* reset flip-flop */ tmp = inb(CGA_BASE + 0x0A); /* Read Mode Control register */ outb(AR_INDEX, 0x30); AttributeReg10 = inb(AR_READ); fontInfo = (char *)malloc(8192, M_DEVBUF, M_NOWAIT); for (i = 0; i < 9; i++) { outb(GR_INDEX, i); GraphicsReg[i] = inb(GR_DATA); } for (i = 0; i < 5; i++) { outb(SR_INDEX, i); SequencerReg[i] = inb(SR_DATA); } /* ** Blank the screen */ outb(SR_INDEX, 1); outb(SR_DATA, (inb(SR_DATA) | 0x20)); /* ** Set up frame buffer to point to plane 2 where the ** font information is stored. */ /* reset flip-flop */ tmp = inb(CGA_BASE + 0x0A); /* graphics mode */ outb(AR_INDEX,0x30); outb(AR_INDEX, 0x01); /* write to plane 2 */ outb(SR_INDEX, 0x02); outb(SR_DATA, 0x04); /* enable plane graphics */ outb(SR_INDEX, 0x04); outb(SR_DATA, 0x06); /* read plane 2 */ outb(GR_INDEX, 0x04); outb(GR_DATA, 0x02); /* write mode 0, read mode 0 */ outb(GR_INDEX, 0x05); outb(GR_DATA, 0x00); /* set graphics mode - Warning: CGA specific */ outb(GR_INDEX, 0x06); outb(GR_DATA, 0x0d); /* * Copy font information */ bcopy(Crtat, fontInfo, FONT_LENGTH); /* * Restore registers in case the X Server wants to save * the text too. */ tmp = inb(0x3D0 + 0x0A); /* reset flip-flop */ outb(AR_INDEX,0x30); outb(AR_INDEX, AttributeReg10); for (i = 0; i < 9; i ++) { outb(GR_INDEX, i); outb(GR_DATA, GraphicsReg[i]); } for (i = 0; i < 5; i++) { outb(SR_INDEX, i); outb(SR_DATA, SequencerReg[i]); } break; case CGA_RESTORE: /* ** Set up frame buffer to point to plane 2 where the ** font information is stored. */ /* reset flip-flop */ tmp = inb(CGA_BASE + 0x0A); /* graphics mode */ outb(AR_INDEX,0x30); outb(AR_INDEX, 0x01); /* write to plane 2 */ outb(SR_INDEX, 0x02); outb(SR_DATA, 0x04); /* enable plane graphics */ outb(SR_INDEX, 0x04); outb(SR_DATA, 0x06); /* read plane 2 */ outb(GR_INDEX, 0x04); outb(GR_DATA, 0x02); /* write mode 0, read mode 0 */ outb(GR_INDEX, 0x05); outb(GR_DATA, 0x00); /* set graphics mode - Warning: CGA specific */ outb(GR_INDEX, 0x06); outb(GR_DATA, 0x0d); /* ** Restore font information */ bcopy(fontInfo, Crtat, FONT_LENGTH); /* ** Put registers back the way they were for text. */ tmp = inb(0x3D0 + 0x0A); /* reset flip-flop */ outb(AR_INDEX,0x30); outb(AR_INDEX, AttributeReg10); for (i = 0; i < 9; i ++) { outb(GR_INDEX, i); outb(GR_DATA, GraphicsReg[i]); } for (i = 0; i < 5; i++) { outb(SR_INDEX, i); outb(SR_DATA, SequencerReg[i]); } /* ** Restore text information */ bcopy(textInfo, Crtat, TEXT_LENGTH); break; default: panic("unknown save/restore mode"); break; } } #endif #endif