This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sys / i386 / isa / pccons.c
/*-
* 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.
*
* from: @(#)pccons.c 5.11 (Berkeley) 5/21/91
* $Id$
*/
/*
* code to work keyboard & display for PC-style console
*/
#include "param.h"
#include "conf.h"
#include "ioctl.h"
#include "proc.h"
#include "user.h"
#include "tty.h"
#include "uio.h"
#include "i386/isa/isa_device.h"
#include "callout.h"
#include "systm.h"
#include "kernel.h"
#include "syslog.h"
#include "i386/isa/icu.h"
#include "i386/i386/cons.h"
#include "i386/isa/isa.h"
#include "i386/isa/ic/i8042.h"
#include "i386/isa/kbd.h"
#include "machine/pc/display.h"
#ifdef XSERVER /* 15 Aug 92*/
int pc_xmode;
#endif /* XSERVER */
struct tty pccons;
struct pcconsoftc {
char cs_flags;
#define CSF_ACTIVE 0x1 /* timeout active */
#define CSF_POLLING 0x2 /* polling for input */
char cs_lastc; /* last char sent */
int cs_timo; /* timeouts since interrupt */
u_long cs_wedgecnt; /* times restarted */
} pcconsoftc;
struct kbdsoftc {
char kbd_flags;
#define KBDF_ACTIVE 0x1 /* timeout active */
#define KBDF_POLLING 0x2 /* polling for input */
#define KBDF_RAW 0x4 /* pass thru scan codes for input */
char kbd_lastc; /* last char sent */
} kbdsoftc;
static struct video_state {
char esc; /* seen escape */
char ebrac; /* seen escape bracket */
char eparm; /* seen escape and parameters */
char so; /* in standout mode? */
int cx; /* "x" parameter */
int cy; /* "y" parameter */
int row, col; /* current cursor position */
int nrow, ncol; /* current screen geometry */
char fg_at, bg_at; /* normal attributes */
char so_at; /* standout attribute */
char kern_fg_at, kern_bg_at;
char color; /* color or mono display */
} vs;
int pcprobe(), pcattach();
struct isa_driver pcdriver = {
pcprobe, pcattach, "pc",
};
/* block cursor so wfj does not go blind on laptop hunting for
the verdamnt cursor -wfj */
#define FAT_CURSOR
#define COL 80
#define ROW 25
#define CHR 2
#define MONO_BASE 0x3B4
#define MONO_BUF (KERNBASE + 0xB0000)
#define CGA_BASE 0x3D4
#define CGA_BUF (KERNBASE + 0xB8000)
#define IOPHYSMEM 0xA0000
static unsigned int addr_6845 = MONO_BASE;
u_short *Crtat = (u_short *)MONO_BUF;
static openf;
char *sgetc(int);
static char *more_chars;
static int char_count;
/*
* We check the console periodically to make sure
* that it hasn't wedged. Unfortunately, if an XOFF
* is typed on the console, that can't be distinguished
* from more catastrophic failure.
*/
#define CN_TIMERVAL (hz) /* frequency at which to check cons */
#define CN_TIMO (2*60) /* intervals to allow for output char */
int pcstart();
int pcparam();
int ttrstrt();
char partab[];
extern pcopen(dev_t, int, int, struct proc *);
/*
* Wait for CP to accept last CP command sent
* before setting up next command.
*/
#define waitforlast(timo) { \
if (pclast) { \
(timo) = 10000; \
do \
uncache((char *)&pclast->cp_unit); \
while ((pclast->cp_unit&CPTAKE) == 0 && --(timo)); \
} \
}
/*
* Pass command to keyboard controller (8042)
*/
static int kbc_8042cmd(val)
int val;
{
unsigned timeo;
timeo = 100000; /* > 100 msec */
while (inb(KBSTATP) & KBS_IBF)
if (--timeo == 0)
return (-1);
outb(KBCMDP, val);
return (0);
}
/*
* Pass command to keyboard itself
*/
int kbd_cmd(val)
int val;
{
unsigned timeo;
timeo = 100000; /* > 100 msec */
while (inb(KBSTATP) & KBS_IBF)
if (--timeo == 0)
return (-1);
outb(KBOUTP, val);
return (0);
}
/*
* Read response from keyboard
*/
int kbd_response()
{
unsigned timeo;
timeo = 500000; /* > 500 msec (KBR_RSTDONE requires 87) */
while (!(inb(KBSTATP) & KBS_DIB))
if (--timeo == 0)
return (-1);
return ((u_char) inb(KBDATAP));
}
/*
* these are both bad jokes
*/
pcprobe(dev)
struct isa_device *dev;
{
int again = 0;
int response;
/* Enable interrupts and keyboard, etc. */
if (kbc_8042cmd(K_LDCMDBYTE) != 0)
printf("Timeout specifying load of keyboard command byte\n");
if (kbd_cmd(CMDBYTE) != 0)
printf("Timeout writing keyboard command byte\n");
/*
* Discard any stale keyboard activity. The 0.1 boot code isn't
* very careful and sometimes leaves a KBR_RESEND.
*/
while (inb(KBSTATP) & KBS_DIB)
kbd_response();
/* Start keyboard reset */
if (kbd_cmd(KBC_RESET) != 0)
printf("Timeout for keyboard reset command\n");
/* Wait for the first response to reset and handle retries */
while ((response = kbd_response()) != KBR_ACK) {
if (response < 0) {
printf("Timeout for keyboard reset ack byte #1\n");
response = KBR_RESEND;
}
if (response == KBR_RESEND) {
if (!again) {
printf("KEYBOARD disconnected: RECONNECT\n");
again = 1;
}
if (kbd_cmd(KBC_RESET) != 0)
printf("Timeout for keyboard reset command\n");
}
/*
* Other responses are harmless. They may occur for new
* keystrokes.
*/
}
/* Wait for the second response to reset */
while ((response = kbd_response()) != KBR_RSTDONE) {
if (response < 0) {
printf("Timeout for keyboard reset ack byte #2\n");
/*
* If KBR_RSTDONE never arrives, the loop will
* finish here unless the keyboard babbles or
* KBS_DIB gets stuck.
*/
break;
}
}
return (IO_KBDSIZE);
}
pcattach(dev)
struct isa_device *dev;
{
u_short *cp = Crtat + (CGA_BUF-MONO_BUF)/CHR;
u_short was;
if (vs.color == 0)
printf("pc%d: type monochrome\n",dev->id_unit);
else printf("pc%d: type color\n",dev->id_unit);
cursor(0);
}
/* ARGSUSED */
#ifdef __STDC__
pcopen(dev_t dev, int flag, int mode, struct proc *p)
#else
pcopen(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
#endif
{
register struct tty *tp;
if (minor(dev) != 0)
return (ENXIO);
tp = &pccons;
tp->t_oproc = pcstart;
tp->t_param = pcparam;
tp->t_dev = dev;
openf++;
if ((tp->t_state & TS_ISOPEN) == 0) {
tp->t_state |= TS_WOPEN;
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)
return (EBUSY);
tp->t_state |= TS_CARR_ON;
return ((*linesw[tp->t_line].l_open)(dev, tp));
}
pcclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
(*linesw[pccons.t_line].l_close)(&pccons, flag);
ttyclose(&pccons);
return(0);
}
/*ARGSUSED*/
pcread(dev, uio, flag)
dev_t dev;
struct uio *uio;
{
return ((*linesw[pccons.t_line].l_read)(&pccons, uio, flag));
}
/*ARGSUSED*/
pcwrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
{
return ((*linesw[pccons.t_line].l_write)(&pccons, uio, flag));
}
/*
* Got a console receive interrupt -
* the console processor wants to give us a character.
* Catch the character, and see who it goes to.
*/
pcrint(dev, irq, cpl)
dev_t dev;
{
int c;
char *cp;
cp = sgetc(1);
if (cp == 0)
return;
if (pcconsoftc.cs_flags & CSF_POLLING)
return;
#ifdef KDB
if (kdbrintr(c, &pccons))
return;
#endif
if (!openf)
return;
#ifdef XSERVER /* 15 Aug 92*/
/* send at least one character, because cntl-space is a null */
(*linesw[pccons.t_line].l_rint)(*cp++ & 0xff, &pccons);
#endif /* XSERVER */
while (*cp)
(*linesw[pccons.t_line].l_rint)(*cp++ & 0xff, &pccons);
}
#ifdef XSERVER /* 15 Aug 92*/
#define CONSOLE_X_MODE_ON _IO('t',121)
#define CONSOLE_X_MODE_OFF _IO('t',122)
#define CONSOLE_X_BELL _IOW('t',123,int[2])
#endif /* XSERVER */
pcioctl(dev, cmd, data, flag)
dev_t dev;
caddr_t data;
{
register struct tty *tp = &pccons;
register error;
#ifdef XSERVER /* 15 Aug 92*/
if (cmd == CONSOLE_X_MODE_ON) {
pc_xmode_on ();
return (0);
} else if (cmd == CONSOLE_X_MODE_OFF) {
pc_xmode_off ();
return (0);
} else if (cmd == 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(1187500/ ((int*)data)[0],
((int*)data)[1] * hz/ 3000);
} else {
sysbeep(0x31b, hz/4);
}
return (0);
}
#endif /* XSERVER */
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
if (error >= 0)
return (error);
error = ttioctl(tp, cmd, data, flag);
if (error >= 0)
return (error);
return (ENOTTY);
}
int pcconsintr = 1;
/*
* Got a console transmission interrupt -
* the console processor wants another character.
*/
pcxint(dev)
dev_t dev;
{
register struct tty *tp;
register int unit;
if (!pcconsintr)
return;
pccons.t_state &= ~TS_BUSY;
pcconsoftc.cs_timo = 0;
if (pccons.t_line)
(*linesw[pccons.t_line].l_start)(&pccons);
else
pcstart(&pccons);
}
pcstart(tp)
register struct tty *tp;
{
int c, s;
s = spltty();
if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
goto out;
do {
if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
if (tp->t_state&TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup((caddr_t)&tp->t_out);
}
if (tp->t_wsel) {
selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
tp->t_wsel = 0;
tp->t_state &= ~TS_WCOLL;
}
}
if (RB_LEN(&tp->t_out) == 0)
goto out;
c = getc(&tp->t_out);
tp->t_state |= TS_BUSY; /* 21 Aug 92*/
splx(s);
sput(c, 0);
(void)spltty();
tp->t_state &= ~TS_BUSY; /* 21 Aug 92*/
} while(1);
out:
splx(s);
}
pccnprobe(cp)
struct consdev *cp;
{
int maj;
/* 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_tp = &pccons;
cp->cn_pri = CN_INTERNAL;
}
/* ARGSUSED */
pccninit(cp)
struct consdev *cp;
{
/*
* For now, don't screw with it.
*/
/* crtat = 0; */
}
static __color;
/* ARGSUSED */
pccnputc(dev, c)
dev_t dev;
char c;
{
if (c == '\n')
sput('\r', 1);
sput(c, 1);
}
/*
* Print a character on console.
*/
pcputchar(c, tp)
char c;
register struct tty *tp;
{
sput(c, 1);
/*if (c=='\n') getchar();*/
}
/* ARGSUSED */
pccngetc(dev)
dev_t dev;
{
register int s;
register char *cp;
#ifdef XSERVER /* 15 Aug 92*/
if (pc_xmode)
return (0);
#endif /* XSERVER */
s = spltty(); /* block pcrint while we poll */
cp = sgetc(0);
splx(s);
if (*cp == '\r') return('\n');
return (*cp);
}
pcgetchar(tp)
register struct tty *tp;
{
char *cp;
#ifdef XSERVER /* 15 Aug 92*/
if (pc_xmode)
return (0);
#endif /* XSERVER */
cp = sgetc(0);
return (*cp&0xff);
}
/*
* Set line parameters
*/
pcparam(tp, t)
register struct tty *tp;
register struct termios *t;
{
register int cflag = t->c_cflag;
/* and copy to tty */
tp->t_ispeed = t->c_ispeed;
tp->t_ospeed = t->c_ospeed;
tp->t_cflag = cflag;
return(0);
}
#ifdef KDB
/*
* Turn input polling on/off (used by debugger).
*/
pcpoll(onoff)
int onoff;
{
}
#endif
/*
* cursor():
* reassigns cursor position, updated by the rescheduling clock
* which is a index (0-1999) into the text area. Note that the
* cursor is a "foreground" character, it's color determined by
* the fg_at attribute. Thus if fg_at is left as 0, (FG_BLACK),
* as when a portion of screen memory is 0, the cursor may dissappear.
*/
static u_short *crtat = 0;
cursor(int a)
{ int pos = crtat - Crtat;
#ifdef XSERVER /* 15 Aug 92*/
if (!pc_xmode) {
#endif /* XSERVER */
outb(addr_6845, 14);
outb(addr_6845+1, pos>> 8);
outb(addr_6845, 15);
outb(addr_6845+1, pos);
#ifdef FAT_CURSOR
outb(addr_6845, 10);
outb(addr_6845+1, 0);
outb(addr_6845, 11);
outb(addr_6845+1, 18);
#endif FAT_CURSOR
if (a == 0)
timeout(cursor, 0, hz/10);
#ifdef XSERVER /* 15 Aug 92*/
}
#endif /* XSERVER */
}
static u_char shift_down, ctrl_down, alt_down, caps, num, scroll;
#define wrtchar(c, at) \
{ char *cp = (char *)crtat; *cp++ = (c); *cp = (at); crtat++; vs.col++; }
/* 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};
/*
* sput has support for emulation of the 'pc3' termcap entry.
* if ka, use kernel attributes.
*/
sput(c, ka)
u_char c;
u_char ka;
{
int sc = 1; /* do scroll check */
char fg_at, bg_at, at;
#ifdef XSERVER /* 15 Aug 92*/
if (pc_xmode)
return;
#endif /* XSERVER */
if (crtat == 0)
{
u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/CHR;
u_short was;
unsigned cursorat;
/*
* Crtat initialized to point to MONO buffer if not present
* change to CGA_BUF offset ONLY ADD the difference since
* locore.s adds in the remapped offset at the right time
*/
was = *cp;
*cp = (u_short) 0xA55A;
if (*cp != 0xA55A) {
addr_6845 = MONO_BASE;
vs.color=0;
} else {
*cp = was;
addr_6845 = CGA_BASE;
Crtat = Crtat + (CGA_BUF-MONO_BUF)/CHR;
vs.color=1;
}
/* Extract cursor location */
outb(addr_6845,14);
cursorat = inb(addr_6845+1)<<8 ;
outb(addr_6845,15);
cursorat |= inb(addr_6845+1);
crtat = Crtat + cursorat;
vs.ncol = COL;
vs.nrow = ROW;
vs.fg_at = FG_LIGHTGREY;
vs.bg_at = BG_BLACK;
if (vs.color == 0) {
vs.kern_fg_at = FG_UNDERLINE;
vs.so_at = FG_BLACK | BG_LIGHTGREY;
} else {
vs.kern_fg_at = FG_LIGHTGREY;
vs.so_at = FG_YELLOW | BG_BLACK;
}
vs.kern_bg_at = BG_BLACK;
fillw(((vs.bg_at|vs.fg_at)<<8)|' ', crtat, COL*ROW-cursorat);
}
/* which attributes do we use? */
if (ka) {
fg_at = vs.kern_fg_at;
bg_at = vs.kern_bg_at;
} else {
fg_at = vs.fg_at;
bg_at = vs.bg_at;
}
at = fg_at|bg_at;
switch(c) {
int inccol;
case 0x1B:
if(vs.esc)
wrtchar(c, vs.so_at);
vs.esc = 1; vs.ebrac = 0; vs.eparm = 0;
break;
case '\t':
inccol = (8 - vs.col % 8); /* non-destructive tab */
crtat += inccol;
vs.col += inccol;
break;
case '\010':
crtat--; vs.col--;
if (vs.col < 0) vs.col += vs.ncol; /* non-destructive backspace */
break;
case '\r':
crtat -= (crtat - Crtat) % vs.ncol; vs.col = 0;
break;
case '\n':
crtat += vs.ncol ;
break;
default:
bypass:
if (vs.esc) {
if (vs.ebrac) {
switch(c) {
int pos;
case 'm':
if (!vs.cx) vs.so = 0;
else vs.so = 1;
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
case 'A': /* back cx rows */
if (vs.cx <= 0) vs.cx = 1;
pos = crtat - Crtat;
pos -= vs.ncol * vs.cx;
if (pos < 0)
pos += vs.nrow * vs.ncol;
crtat = Crtat + pos;
sc = vs.esc = vs.ebrac = vs.eparm = 0;
break;
case 'B': /* down cx rows */
if (vs.cx <= 0) vs.cx = 1;
pos = crtat - Crtat;
pos += vs.ncol * vs.cx;
if (pos >= vs.nrow * vs.ncol)
pos -= vs.nrow * vs.ncol;
crtat = Crtat + pos;
sc = vs.esc = vs.ebrac = vs.eparm = 0;
break;
case 'C': /* right cursor */
if (vs.cx <= 0)
vs.cx = 1;
pos = crtat - Crtat;
pos += vs.cx; vs.col += vs.cx;
if (vs.col >= vs.ncol) {
vs.col -= vs.ncol;
pos -= vs.ncol; /* cursor stays on same line */
}
crtat = Crtat + pos;
sc = vs.esc = vs.ebrac = vs.eparm = 0;
break;
case 'D': /* left cursor */
if (vs.cx <= 0)
vs.cx = 1;
pos = crtat - Crtat;
pos -= vs.cx; vs.col -= vs.cx;
if (vs.col < 0) {
vs.col += vs.ncol;
pos += vs.ncol; /* cursor stays on same line */
}
crtat = Crtat + pos;
sc = vs.esc = vs.ebrac = vs.eparm = 0;
break;
case 'J': /* Clear ... */
if (vs.cx == 0)
/* ... to end of display */
fillw((at << 8) + ' ',
crtat,
Crtat + vs.ncol * vs.nrow - crtat);
else if (vs.cx == 1)
/* ... to next location */
fillw((at << 8) + ' ',
Crtat,
crtat - Crtat + 1);
else if (vs.cx == 2)
/* ... whole display */
fillw((at << 8) + ' ',
Crtat,
vs.ncol * vs.nrow);
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
case 'K': /* Clear line ... */
if (vs.cx == 0)
/* ... current to EOL */
fillw((at << 8) + ' ',
crtat,
vs.ncol - (crtat - Crtat) % vs.ncol);
else if (vs.cx == 1)
/* ... beginning to next */
fillw((at << 8) + ' ',
crtat - (crtat - Crtat) % vs.ncol,
((crtat - Crtat) % vs.ncol) + 1);
else if (vs.cx == 2)
/* ... entire line */
fillw((at << 8) + ' ',
crtat - (crtat - Crtat) % vs.ncol,
vs.ncol);
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
case 'f': /* in system V consoles */
case 'H': /* Cursor move */
if ((!vs.cx)||(!vs.cy)) {
crtat = Crtat;
vs.col = 0;
} else {
crtat = Crtat + (vs.cx - 1) * vs.ncol + vs.cy - 1;
vs.col = vs.cy - 1;
}
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
case 'S': /* scroll up cx lines */
if (vs.cx <= 0) vs.cx = 1;
bcopy(Crtat+vs.ncol*vs.cx, Crtat, vs.ncol*(vs.nrow-vs.cx)*CHR);
fillw((at <<8)+' ', Crtat+vs.ncol*(vs.nrow-vs.cx), vs.ncol*vs.cx);
/* crtat -= vs.ncol*vs.cx; /* XXX */
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
case 'T': /* scroll down cx lines */
if (vs.cx <= 0) vs.cx = 1;
bcopy(Crtat, Crtat+vs.ncol*vs.cx, vs.ncol*(vs.nrow-vs.cx)*CHR);
fillw((at <<8)+' ', Crtat, vs.ncol*vs.cx);
/* crtat += vs.ncol*vs.cx; /* XXX */
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
case ';': /* Switch params in cursor def */
vs.eparm = 1;
break;
case 'r':
vs.so_at = (vs.cx & 0x0f) | ((vs.cy & 0x0f) << 4);
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
case 'x': /* set attributes */
switch (vs.cx) {
case 0:
/* reset to normal attributes */
bg_at = BG_BLACK;
if (ka)
fg_at = vs.color? FG_LIGHTGREY: FG_UNDERLINE;
else
fg_at = FG_LIGHTGREY;
break;
case 1:
/* ansi background */
if (vs.color)
bg_at = bgansitopc[vs.cy & 7];
break;
case 2:
/* ansi foreground */
if (vs.color)
fg_at = fgansitopc[vs.cy & 7];
break;
case 3:
/* pc text attribute */
if (vs.eparm) {
fg_at = vs.cy & 0x8f;
bg_at = vs.cy & 0x70;
}
break;
}
if (ka) {
vs.kern_fg_at = fg_at;
vs.kern_bg_at = bg_at;
} else {
vs.fg_at = fg_at;
vs.bg_at = bg_at;
}
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
break;
default: /* Only numbers valid here */
if ((c >= '0')&&(c <= '9')) {
if (vs.eparm) {
vs.cy *= 10;
vs.cy += c - '0';
} else {
vs.cx *= 10;
vs.cx += c - '0';
}
} else {
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
}
break;
}
break;
} else if (c == 'c') { /* Clear screen & home */
fillw((at << 8) + ' ', Crtat, vs.ncol*vs.nrow);
crtat = Crtat; vs.col = 0;
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
} else if (c == '[') { /* Start ESC [ sequence */
vs.ebrac = 1; vs.cx = 0; vs.cy = 0; vs.eparm = 0;
} else { /* Invalid, clear state */
vs.esc = 0; vs.ebrac = 0; vs.eparm = 0;
wrtchar(c, vs.so_at);
}
} else {
if (c == 7)
sysbeep(0x31b, hz/4);
else {
if (vs.so) {
wrtchar(c, vs.so_at);
} else
wrtchar(c, at);
if (vs.col >= vs.ncol) vs.col = 0;
break ;
}
}
}
if (sc && crtat >= Crtat+vs.ncol*vs.nrow) { /* scroll check */
if (openf) do (void)sgetc(1); while (scroll);
bcopy(Crtat+vs.ncol, Crtat, vs.ncol*(vs.nrow-1)*CHR);
fillw ((at << 8) + ' ', Crtat + vs.ncol*(vs.nrow-1),
vs.ncol);
crtat -= vs.ncol;
}
if (ka)
cursor(1);
}
unsigned __debug = 0; /*0xffe */
static char scantokey[] = {
0,
120, /* F9 */
0,
116, /* F5 */
114, /* F3 */
112, /* F1 */
113, /* F2 */
123, /* F12 */
0,
121, /* F10 */
119, /* F8 */
117, /* F6 */
115, /* F4 */
16, /* TAB */
1, /* ` */
0,
0,
60, /* ALT (left) */
44, /* SHIFT (left) */
0,
58, /* CTRL (left) */
17, /* Q */
2, /* 1 */
0,
0,
0,
46, /* Z */
32, /* S */
31, /* A */
18, /* W */
3, /* 2 */
0,
0,
48, /* C */
47, /* X */
33, /* D */
19, /* E */
5, /* 4 */
4, /* 3 */
0,
0,
61, /* SPACE */
49, /* V */
34, /* F */
21, /* T */
20, /* R */
6, /* 5 */
0,
0,
51, /* N */
50, /* B */
36, /* H */
35, /* G */
22, /* Y */
7, /* 6 */
0,
0,
0,
52, /* M */
37, /* J */
23, /* U */
8, /* 7 */
9, /* 8 */
0,
0,
53, /* , */
38, /* K */
24, /* I */
25, /* O */
11, /* 0 */
10, /* 9 */
0,
0,
54, /* . */
55, /* / */
39, /* L */
40, /* ; */
26, /* P */
12, /* - */
0,
0,
0,
41, /* " */
0,
27, /* [ */
13, /* + */
0,
0,
0,
57, /* SHIFT (right) */
43, /* ENTER */
28, /* ] */
0,
29, /* \ */
0,
0,
0,
45, /* na*/
0,
0,
0,
0,
15, /* backspace */
0,
0, /* keypad */
93, /* 1 */
0,
92, /* 4 */
91, /* 7 */
0,
0,
0,
99, /* 0 */
104, /* . */
98, /* 2 */
97, /* 5 */
102, /* 6 */
96, /* 8 */
110, /* ESC */
90, /* Num Lock */
122, /* F11 */
106, /* + */
103, /* 3 */
105, /* - */
100, /* * */
101, /* 9 */
0,
0,
0,
0,
0,
118, /* F7 */
};
static char extscantokey[] = {
0,
120, /* F9 */
0,
116, /* F5 */
114, /* F3 */
112, /* F1 */
113, /* F2 */
123, /* F12 */
0,
121, /* F10 */
119, /* F8 */
117, /* F6 */
115, /* F4 */
16, /* TAB */
1, /* ` */
0,
0,
62, /* ALT (right) */
124, /* Print Screen */
0,
64, /* CTRL (right) */
17, /* Q */
2, /* 1 */
0,
0,
0,
46, /* Z */
32, /* S */
31, /* A */
18, /* W */
3, /* 2 */
0,
0,
48, /* C */
47, /* X */
33, /* D */
19, /* E */
5, /* 4 */
4, /* 3 */
0,
0,
61, /* SPACE */
49, /* V */
34, /* F */
21, /* T */
20, /* R */
6, /* 5 */
0,
0,
51, /* N */
50, /* B */
36, /* H */
35, /* G */
22, /* Y */
7, /* 6 */
0,
0,
0,
52, /* M */
37, /* J */
23, /* U */
8, /* 7 */
9, /* 8 */
0,
0,
53, /* , */
38, /* K */
24, /* I */
25, /* O */
11, /* 0 */
10, /* 9 */
0,
0,
54, /* . */
95, /* / */
39, /* L */
40, /* ; */
26, /* P */
12, /* - */
0,
0,
0,
41, /* " */
0,
27, /* [ */
13, /* + */
0,
0,
0,
57, /* SHIFT (right) */
108, /* ENTER */
28, /* ] */
0,
29, /* \ */
0,
0,
0,
45, /* na*/
0,
0,
0,
0,
15, /* backspace */
0,
0, /* keypad */
81, /* end */
0,
79, /* left arrow */
80, /* home */
0,
0,
0,
75, /* ins */
76, /* del */
84, /* down arrow */
97, /* 5 */
89, /* right arrow */
83, /* up arrow */
110, /* ESC */
90, /* Num Lock */
122, /* F11 */
106, /* + */
86, /* page down */
105, /* - */
124, /* print screen */
85, /* page up */
0,
0,
0,
0,
0,
118, /* F7 */
};
#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 ctrl[CODE_SIZE];
} Scan_def;
#define SHIFT 0x0002 /* keyboard shift */
#define ALT 0x0004 /* alternate shift -- alternate chars */
#define NUM 0x0008 /* numeric shift cursors vs. numeric */
#define CTL 0x0010 /* control shift -- allows ctl function */
#define CAPS 0x0020 /* caps shift -- swaps case of letter */
#define ASCII 0x0040 /* ascii code for this key */
#define SCROLL 0x0080 /* stop output */
#define FUNC 0x0100 /* function key */
#define KP 0x0200 /* Keypad keys */
#define NONE 0x0400 /* no function */
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 */
CTL, "", "", "", /* 29 control */
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, "/", "?", "\177", /* 53 / */
SHIFT, "", "", "", /* 54 shift */
KP, "*", "*", "*", /* 55 kp * */
ALT, "", "", "", /* 56 alt */
ASCII, " ", " ", " ", /* 57 space */
CAPS, "", "", "", /* 58 caps */
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 */
};
update_led()
{
int response;
if (kbd_cmd(KBC_STSIND) != 0) {
printf("Timeout for keyboard LED command\n");
} else {
/*
* XXX This is quite questionable, but seems to fix
* the problem reported.
* some keyboard controllers need some time after they
* get a command. Without this the keyboard 'hangs'.
* This seems to be the only place where two commands
* are just one behind another.
*/
DELAY (10000);
if (kbd_cmd(scroll | (num << 1) | (caps << 2)) != 0)
printf("Timeout for keyboard LED data\n");
}
#if 0
else if ((response = kbd_response()) < 0)
printf("Timeout for keyboard LED ack\n");
else if (response != KBR_ACK)
printf("Unexpected keyboard LED ack %d\n", response);
#else
/*
* Skip waiting for and checking the response. The waiting
* would be too long (about 3 msec) and the checking might eat
* fresh keystrokes. The waiting should be done using timeout()
* and the checking should be done in the interrupt handler.
*/
#endif
}
/*
* sgetc(noblock): get characters from the keyboard. If
* noblock == 0 wait until a key is gotten. Otherwise return a
* if no characters are present 0.
*/
char *sgetc(noblock)
{
u_char dt;
unsigned key;
static u_char extended = 0;
static char capchar[2];
/*
* First see if there is something in the keyboard port
*/
loop:
#ifdef XSERVER /* 15 Aug 92*/
if (inb(KBSTATP) & KBS_DIB) {
dt = inb(KBDATAP);
#ifdef REVERSE_CAPS_CTRL
/* switch the caps lock and control keys */
if ((dt & 0x7f) == 29)
dt = (dt & 0x80) | 58;
else
if ((dt & 0x7f) == 58)
dt = (dt & 0x80) | 29;
#endif
if (pc_xmode) {
capchar[0] = dt;
/*
* Check for locking keys
*/
if (!(dt & 0x80))
{
dt = dt & 0x7f;
switch (scan_codes[dt].type)
{
case NUM:
num ^= 1;
update_led();
break;
case CAPS:
caps ^= 1;
update_led();
break;
case SCROLL:
scroll ^= 1;
update_led();
break;
}
}
return (&capchar[0]);
}
}
#else /* !XSERVER*/
if (inb(KBSTATP) & KBS_DIB) {
dt = inb(KBDATAP);
#ifdef REVERSE_CAPS_CTRL
/* switch the caps lock and control keys */
if ((dt & 0x7f) == 29)
dt = (dt & 0x80) | 58;
else
if ((dt & 0x7f) == 58)
dt = (dt & 0x80) | 29;
#endif
}
#endif /* !XSERVER*/
else
{
if (noblock)
return 0;
else
goto loop;
}
if (dt == 0xe0)
{
extended = 1;
#ifdef XSERVER /* 15 Aug 92*/
goto loop;
#else /* !XSERVER*/
if (noblock)
return 0;
else
goto loop;
#endif /* !XSERVER*/
}
#include "ddb.h"
#if NDDB > 0
/*
* Check for cntl-alt-esc
*/
if ((dt == 1) && ctrl_down && alt_down) {
Debugger();
dt |= 0x80; /* discard esc (ddb discarded ctrl-alt) */
}
#endif
/*
* Check for make/break
*/
if (dt & 0x80)
{
/*
* break
*/
dt = dt & 0x7f;
switch (scan_codes[dt].type)
{
case SHIFT:
shift_down = 0;
break;
case ALT:
alt_down = 0;
break;
case CTL:
ctrl_down = 0;
break;
}
}
else
{
/*
* Make
*/
dt = dt & 0x7f;
switch (scan_codes[dt].type)
{
/*
* Locking keys
*/
case NUM:
num ^= 1;
update_led();
break;
case CAPS:
caps ^= 1;
update_led();
break;
case SCROLL:
scroll ^= 1;
update_led();
break;
/*
* Non-locking keys
*/
case SHIFT:
shift_down = 1;
break;
case ALT:
alt_down = 0x80;
break;
case CTL:
ctrl_down = 1;
break;
case ASCII:
#ifdef XSERVER /* 15 Aug 92*/
/*
* 18 Sep 92 Terry Lambert I find that this behaviour is questionable --
* I believe that this should be conditional on
* the value of pc_xmode rather than always
* done. In particular, "case NONE" seems to
* not cause a scancode return. This may
* invalidate alt-"=" and alt-"-" as well as the
* F11 and F12 keys, and some keys on lap-tops,
* Especially Toshibal T1100 and Epson Equity 1
* and Equity 1+ when not in pc_xmode.
*/
/* control has highest priority */
if (ctrl_down)
capchar[0] = scan_codes[dt].ctrl[0];
else if (shift_down)
capchar[0] = scan_codes[dt].shift[0];
else
capchar[0] = scan_codes[dt].unshift[0];
if (caps && (capchar[0] >= 'a'
&& capchar[0] <= 'z')) {
capchar[0] = capchar[0] - ('a' - 'A');
}
capchar[0] |= alt_down;
extended = 0;
return(&capchar[0]);
#else /* !XSERVER*/
case NONE:
#endif /* !XSERVER*/
case FUNC:
if (shift_down)
more_chars = scan_codes[dt].shift;
else if (ctrl_down)
more_chars = scan_codes[dt].ctrl;
else
more_chars = scan_codes[dt].unshift;
#ifndef XSERVER /* 15 Aug 92*/
/* XXX */
if (caps && more_chars[1] == 0
&& (more_chars[0] >= 'a'
&& more_chars[0] <= 'z')) {
capchar[0] = *more_chars - ('a' - 'A');
more_chars = capchar;
}
#endif /* !XSERVER*/
extended = 0;
return(more_chars);
case KP:
if (shift_down || ctrl_down || !num || extended)
more_chars = scan_codes[dt].shift;
else
more_chars = scan_codes[dt].unshift;
extended = 0;
return(more_chars);
#ifdef XSERVER /* 15 Aug 92*/
case NONE:
break;
#endif /* XSERVER*/
}
}
extended = 0;
#ifdef XSERVER /* 15 Aug 92*/
goto loop;
#else /* !XSERVER*/
if (noblock)
return 0;
else
goto loop;
#endif /* !XSERVER*/
}
/* special characters */
#define bs 8
#define lf 10
#define cr 13
#define cntlc 3
#define del 0177
#define cntld 4
getchar()
{
char thechar;
register delay;
int x;
pcconsoftc.cs_flags |= CSF_POLLING;
x = splhigh();
sput('>', 1);
/*while (1) {*/
thechar = *(sgetc(0));
pcconsoftc.cs_flags &= ~CSF_POLLING;
splx(x);
switch (thechar) {
default: if (thechar >= ' ')
sput(thechar, 1);
return(thechar);
case cr:
case lf: sput('\r', 1);
sput('\n', 1);
return(lf);
case bs:
case del:
sput('\b', 1);
sput(' ', 1);
sput('\b', 1);
return(thechar);
case cntlc:
sput('^', 1) ; sput('C', 1) ; sput('\r', 1) ; sput('\n', 1) ;
cpu_reset();
case cntld:
sput('^', 1) ; sput('D', 1) ; sput('\r', 1) ; sput('\n', 1) ;
return(0);
}
/*}*/
}
#include "machine/stdarg.h"
static nrow;
#define DPAUSE 1
void
#ifdef __STDC__
dprintf(unsigned flgs, const char *fmt, ...)
#else
dprintf(flgs, fmt /*, va_alist */)
char *fmt;
unsigned flgs;
#endif
{ extern unsigned __debug;
va_list ap;
if((flgs&__debug) > DPAUSE) {
__color = ffs(flgs&__debug)+1;
va_start(ap,fmt);
kprintf(fmt, 1, (struct tty *)0, ap);
va_end(ap);
if (flgs&DPAUSE || nrow%24 == 23) {
int x;
x = splhigh();
if (nrow%24 == 23) nrow = 0;
(void)sgetc(0);
splx(x);
}
}
__color = 0;
}
consinit() {}
/* -hv- 22-Apr-93: to make init_main more portable */
void cons_highlight()
{
/* pc text attribute */
vs.kern_fg_at = 0x0f;
vs.kern_bg_at = 0x00;
}
void cons_normal()
{
/* reset to normal attributes */
vs.bg_at = BG_BLACK;
/* we are in kernel mode */
vs.fg_at = vs.color? FG_LIGHTGREY: FG_UNDERLINE;
}
int pcmmap(dev_t dev, int offset, int nprot)
{
if (offset > 0x20000)
return -1;
return i386_btop((0xa0000 + offset));
}
#ifdef XSERVER /* 15 Aug 92*/
#include "machine/psl.h"
#include "machine/frame.h"
pc_xmode_on ()
{
struct syscframe *fp;
if (pc_xmode)
return;
pc_xmode = 1;
fp = (struct syscframe *)curproc->p_regs;
fp->sf_eflags |= PSL_IOPL;
}
pc_xmode_off ()
{
struct syscframe *fp;
if (pc_xmode == 0)
return;
pc_xmode = 0;
cursor(0);
fp = (struct syscframe *)curproc->p_regs;
fp->sf_eflags &= ~PSL_IOPL;
}
#endif /* XSERVER*/
/*
* EOF -- File has not been truncated
*/