NetBSD/sys/arch/arm32/shark/pccons.c

3795 lines
108 KiB
C

/* $NetBSD: pccons.c,v 1.8 1999/03/19 04:58:45 cgd 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 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