/*      $NetBSD: pccons.c,v 1.7 1998/11/19 15:38:21 mrg 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 <sys/param.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/select.h>
#include <sys/tty.h>
#include <sys/fcntl.h>
#include <sys/uio.h>
#include <sys/callout.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <machine/kerndebug.h>
#include <vm/vm.h>

#include <dev/cons.h>

#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/pio.h>

#include <machine/pccons.h>
#ifdef i386
#include <machine/pc/display.h>
#include <machine/conf.h>
#else
#include <arm32/shark/display.h>
#include <sys/conf.h>
#endif

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <arm32/shark/i8042reg.h>
#include <arm32/shark/ns87307reg.h>

#ifdef arm32
#include <arm32/isa/isa_machdep.h>
#else
#include <i386/isa/isa_machdep.h>
#endif

#ifdef	OFW
#include <dev/ofw/openfirm.h>
#endif

#ifdef SHARK
#include <arm32/shark/sequoia.h>
#include <sys/malloc.h>
#include <sys/reboot.h>
#include <machine/devmap.h>
#include <sys/msgbuf.h>
#include <machine/ofw.h>
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;
};


/*
** 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)
        {
            untimeout(do_async_update, NULL);
        }
        do_async_update(sc);
    } 
    else if ((sc->sc_flags & SC_ASYNC_SCHEDULED) == 0)
    {
        /* Schedule an update 
        */
        sc->sc_flags |= SC_ASYNC_SCHEDULED;
        timeout(do_async_update, sc, 1);
    }

    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;
            timeout(ttrstrt, tp, 1);
        }
        /* 
        ** 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
**
**--
*/
int
pcmmap(dev_t   dev, 
       int     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
