* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Added support for ibmpc term type and improved keyboard support. -Don Ahn
* @(#)pccons.c 5.3 (Berkeley) %G%
* code to work keyboard & display for console
#include "machine/isa/device.h"
#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 */
int cnprobe(), cnattach();
struct isa_driver cndriver
= {
#define IOPHYSMEM 0xA0000
static unsigned int addr_6845
= MONO_BASE
;
u_short
*Crtat
= (u_short
*)MONO_BUF
;
* 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 */
* Wait for CP to accept last CP command sent
* before setting up next command.
#define waitforlast(timo) { \
uncache((char *)&cnlast->cp_unit); \
while ((cnlast->cp_unit&CPTAKE) == 0 && --(timo)); \
/* Enable interrupts and keyboard controller */
while (inb(0x64)&2); outb(0x64,0x60);
while (inb(0x64)&2); outb(0x60,0x4D);
/* Start keyboard stuff RESET */
while (inb(0x64)&2); /* wait input ready */
outb(0x60,0xFF); /* RESET */
while((c
=inb(0x60))!=0xFA) {
if ((c
== 0xFE) || (c
== 0xFF)) {
if(!again
)printf("KEYBOARD disconnected: RECONNECT \n");
while (inb(0x64)&2); /* wait input ready */
outb(0x60,0xFF); /* RESET */
/* pick up keyboard reset return code */
while((c
=inb(0x60))!=0xAA)nulldev();
u_short
*cp
= Crtat
+ (CGA_BUF
-MONO_BUF
)/CHR
;
/* 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 */
*Crtat
= (u_short
) 0xA55A;
if (tp
->t_state
&TS_XCLUDE
&& u
.u_uid
!= 0)
if ((tp
->t_state
&TS_ISOPEN
) == 0) {
tp
->t_state
= TS_ISOPEN
|TS_CARR_ON
;
tp
->t_flags
= EVENP
|ECHO
|XTABS
|CRMOD
;
return ((*linesw
[tp
->t_line
].l_open
)(dev
, tp
));
(*linesw
[cons
.t_line
].l_close
)(&cons
);
return ((*linesw
[cons
.t_line
].l_read
)(&cons
, uio
));
return ((*linesw
[cons
.t_line
].l_write
)(&cons
, uio
));
* Got a console receive interrupt -
* the console processor wants to give us a character.
* Catch the character, and see who it goes to.
if (consoftc
.cs_flags
&CSF_POLLING
)
(*linesw
[cons
.t_line
].l_rint
)(c
&0xff, &cons
);
cnioctl(dev
, cmd
, addr
, flag
)
register struct tty
*tp
= &cons
;
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, addr
);
if ((error
= ttioctl(tp
, cmd
, addr
, flag
)) < 0)
else if (cmd
== TIOCSETP
|| cmd
== TIOCSETN
)
* Got a console transmission interrupt -
* the console processor wants another character.
cons
.t_state
&= ~TS_BUSY
;
(*linesw
[cons
.t_line
].l_start
)(&cons
);
if (tp
->t_state
& (TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
if (tp
->t_outq
.c_cc
<= TTLOWAT(tp
)) {
if (tp
->t_state
&TS_ASLEEP
) {
tp
->t_state
&= ~TS_ASLEEP
;
wakeup((caddr_t
)&tp
->t_outq
);
selwakeup(tp
->t_wsel
, tp
->t_state
& TS_WCOLL
);
tp
->t_state
&= ~TS_WCOLL
;
while (tp
->t_outq
.c_cc
!= 0) {
c
= getc(&tp
->t_outq
) & 0xff;
if ((tp
->t_flags
& (RAW
|LITOUT
)) == 0) {
timeout(ttrstrt
, (caddr_t
)tp
, (c
&0177));
tp
->t_state
|= TS_TIMEOUT
;
* Print a character on console.
s
= spltty(); /* block cnrint while we poll */
* Turn input polling on/off (used by debugger).
outb(0x61,inb(0x61)&0xFC);
/* set command for counter 2, 2 byte write */
/* send 0x637 for 750 HZ */
timeout(sysbeepstop
,0,hz
/4);
/* cursor() sets an offset (0-1999) into the 80x25 text area */
static u_short
*crtat
= 0;
{ int pos
= crtat
- Crtat
;
outb(addr_6845
+1,pos
>> 8);
outb(addr_6845
+1,pos
&0xff);
/* sput has support for emulation of the 'ibmpc' termcap entry. */
/* This is a bare-bones implementation of a bare-bones entry */
/* One modification: Change li#24 to li#25 to reflect 25 lines */
static int esc
,ebrac
,eparm
,cx
,cy
,row
,so
;
u_short
*cp
= Crtat
+ (CGA_BUF
-MONO_BUF
)/CHR
, was
;
/* 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 */
Crtat
= Crtat
+ (CGA_BUF
-MONO_BUF
)/CHR
;
/* Extract cursor location */
cursorat
= inb(addr_6845
+1)<<8 ;
cursorat
|= inb(addr_6845
+1);
crtat
= Crtat
+ cursorat
;
fillw((bg_at
<<8)|' ', crtat
, COL
*ROW
-cursorat
);
esc
= 1; ebrac
= 0; eparm
= 0;
*crtat
++ = (ca
<<8)| ' '; row
++ ;
if (row
< 0) row
+= COL
; /* non-destructive backspace */
case 'm': /* no support for standout */
esc
= 0; ebrac
= 0; eparm
= 0;
case 'A': /* back one row */
esc
= 0; ebrac
= 0; eparm
= 0;
case 'B': /* down one row */
esc
= 0; ebrac
= 0; eparm
= 0;
case 'C': /* right cursor */
esc
= 0; ebrac
= 0; eparm
= 0;
case 'J': /* Clear to end of display */
fillw((bg_at
<<8)+' ', crtat
,
esc
= 0; ebrac
= 0; eparm
= 0;
case 'K': /* Clear to EOL */
fillw((bg_at
<<8)+' ', crtat
, COL
-row
);
esc
= 0; ebrac
= 0; eparm
= 0;
case 'H': /* Cursor move */
crtat
= Crtat
+(cx
-1)*COL
+cy
-1;
esc
= 0; ebrac
= 0; eparm
= 0;
case ';': /* Switch params in cursor def */
default: /* Only numbers valid here */
if ((c
>= '0')&&(c
<= '9')) {
esc
= 0; ebrac
= 0; eparm
= 0;
} else if (c
== 'c') { /* Clear screen & home */
fillw((bg_at
<<8)+' ', Crtat
,COL
*ROW
);
esc
= 0; ebrac
= 0; eparm
= 0;
} else if (c
== '[') { /* Start ESC [ sequence */
ebrac
= 1; cx
= 0; cy
= 0; eparm
= 0;
} else { /* Invalid, clear state */
esc
= 0; ebrac
= 0; eparm
= 0;
/* Print only printables */
else /*if (c >= ' ') */ {
while(inb(0x3da)&1)nulldev();
*crtat
++ = (so_at
<<8)| c
; row
++ ;
*crtat
++ = (ca
<<8)| c
; row
++ ;
if (crtat
>= Crtat
+COL
*(ROW
)) { /* scroll check */
bcopy(Crtat
+COL
,Crtat
,COL
*(ROW
-1)*CHR
);
fillw ((bg_at
<<8)+' ', Crtat
+COL
*(ROW
-1),COL
) ;
#define L 0x0001 /* locking function */
#define SHF 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 CPS 0x0020 /* caps shift -- swaps case of letter */
#define ASCII 0x0040 /* ascii code for this key */
#define STP 0x0080 /* stop output */
#define FUNC 0x0100 /* function key */
#define SCROLL 0x0200 /* scroll lock key */
0, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, /* scan 0- 7 */
ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, /* scan 8-15 */
ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, /* scan 16-23 */
ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, CTL
, ASCII
, ASCII
, /* scan 24-31 */
ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, /* scan 32-39 */
ASCII
, ASCII
, SHF
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, /* scan 40-47 */
ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, SHF
, ASCII
, /* scan 48-55 */
ALT
, ASCII
, CPS
, FUNC
, FUNC
, FUNC
, FUNC
, FUNC
, /* scan 56-63 */
FUNC
, FUNC
, FUNC
, FUNC
, FUNC
, NUM
, STP
, ASCII
, /* scan 64-71 */
ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, ASCII
, /* scan 72-79 */
ASCII
, ASCII
, ASCII
, ASCII
, 0, 0, 0, 0, /* scan 80-87 */
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
u_char unshift
[] = { /* no shift */
0, 033 , '1' , '2' , '3' , '4' , '5' , '6' , /* scan 0- 7 */
'7' , '8' , '9' , '0' , '-' , '=' , 0177 ,'\t' , /* scan 8-15 */
'q' , 'w' , 'e' , 'r' , 't' , 'y' , 'u' , 'i' , /* scan 16-23 */
'o' , 'p' , '[' , ']' , '\r' , CTL
, 'a' , 's' , /* scan 24-31 */
'd' , 'f' , 'g' , 'h' , 'j' , 'k' , 'l' , ';' , /* scan 32-39 */
'\'' , '`' , SHF
, '\\' , 'z' , 'x' , 'c' , 'v' , /* scan 40-47 */
'b' , 'n' , 'm' , ',' , '.' , '/' , SHF
, '*', /* scan 48-55 */
ALT
, ' ' , CPS
, 1, 2, 3 , 4, 5, /* scan 56-63 */
6, 7, 8, 9, 10, NUM
, STP
, '7', /* scan 64-71 */
'8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */
'2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
u_char shift
[] = { /* shift shift */
0, 033 , '!' , '@' , '#' , '$' , '%' , '^' , /* scan 0- 7 */
'&' , '*' , '(' , ')' , '_' , '+' , 0177 ,'\t' , /* scan 8-15 */
'Q' , 'W' , 'E' , 'R' , 'T' , 'Y' , 'U' , 'I' , /* scan 16-23 */
'O' , 'P' , '{' , '}' , '\r' , CTL
, 'A' , 'S' , /* scan 24-31 */
'D' , 'F' , 'G' , 'H' , 'J' , 'K' , 'L' , ':' , /* scan 32-39 */
'"' , '~' , SHF
, '|' , 'Z' , 'X' , 'C' , 'V' , /* scan 40-47 */
'B' , 'N' , 'M' , '<' , '>' , '?' , SHF
, '*', /* scan 48-55 */
ALT
, ' ' , CPS
, 0, 0, ' ' , 0, 0, /* scan 56-63 */
0, 0, 0, 0, 0, NUM
, STP
, '7', /* scan 64-71 */
'8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */
'2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
u_char ctl
[] = { /* CTL shift */
0, 033 , '!' , 000 , '#' , '$' , '%' , 036 , /* scan 0- 7 */
'&' , '*' , '(' , ')' , 037 , '+' , 034 ,'\177', /* scan 8-15 */
021 , 027 , 005 , 022 , 024 , 031 , 025 , 011 , /* scan 16-23 */
017 , 020 , 033 , 035 , '\r' , CTL
, 001 , 023 , /* scan 24-31 */
004 , 006 , 007 , 010 , 012 , 013 , 014 , ';' , /* scan 32-39 */
'\'' , '`' , SHF
, 034 , 032 , 030 , 003 , 026 , /* scan 40-47 */
002 , 016 , 015 , '<' , '>' , '?' , SHF
, '*', /* scan 48-55 */
ALT
, ' ' , CPS
, 0, 0, ' ' , 0, 0, /* scan 56-63 */
CPS
, 0, 0, 0, 0, 0, 0, 0, /* scan 64-71 */
0, 0, 0, 0, 0, 0, 0, 0, /* scan 72-79 */
0, 0, 0, 0, 0, 0, 0, 0, /* scan 80-87 */
0, 0, 033, '7' , '4' , '1' , 0, NUM
, /* scan 88-95 */
'8' , '5' , '2' , 0, STP
, '9' , '6' , '3' , /*scan 96-103*/
'.' , 0, '*' , '-' , '+' , 0, 0, 0, /*scan 104-111*/
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
u_short action
; /* how this key functions */
char ascii
[8]; /* ascii result character indexed by shifts */
u_char shfts
, ctls
, alts
, caps
, num
, stp
, scroll
;
#define KBSTAT 0x64 /* kbd status port */
#define KBS_INP_BUF_FUL 0x02 /* kbd char ready */
#define KBDATA 0x60 /* kbd data port */
#define KBSTATUSPORT 0x61 /* kbd status */
while (inb(0x64)&2); /* wait input ready */
outb(0x60,0xED); /* LED Command */
while (inb(0x64)&2); /* wait input ready */
outb(0x60,scroll
| 2*num
| 4*caps
);
while (inb(0x64)&2); /* wait input ready */
outb(0x64,0xFE); /* Reset Command */
while (inb(0x64)&2); /* wait input ready */
outb(0x64,0xFF); /* Keyboard Reset Command */
sgetc(noblock) : get a character from the keyboard. If noblock = 0 wait until
a key is gotten. Otherwise return a 0x100 (256).
/* First see if there is something in the keyboard port */
if (inb(KBSTAT
)&1) dt
= inb(KBDATA
);
else { if (noblock
) return (0x100); else goto loop
; }
/* Check for cntl-alt-del */
if ((dt
== 83)&&ctls
&&alts
) _exit();
/* Check for make/break */
case SHF
: shfts
= 0; break;
case ALT
: alts
= 0; break;
case CTL
: ctls
= 0; break;
if(__debug
& (1<<key
)) __debug
&= ~(1<<key
) ;
else __debug
|= (1<<key
) ;
case NUM
: num
^= 1; update_led(); break;
case CPS
: caps
^= 1; update_led(); break;
case SCROLL
: scroll
^= 1; update_led(); break;
case STP
: stp
^= 1; if(stp
) goto loop
; break;
case SHF
: shfts
= 1; break;
case ALT
: alts
= 1; break;
case CTL
: ctls
= 1; break;
if (shfts
) dt
= shift
[dt
];
else if (ctls
) dt
= ctl
[dt
];
if (caps
&& (dt
>= 'a' && dt
<= 'z')) dt
-= 'a' - 'A';
if (noblock
) return (0x100); else goto loop
;
pg(p
,q
,r
,s
,t
,u
,v
,w
,x
,y
,z
) char *p
; {
printf(p
,q
,r
,s
,t
,u
,v
,w
,x
,y
,z
);
consoftc
.cs_flags
|= CSF_POLLING
;
thechar
= (char) sgetc(0);
consoftc
.cs_flags
&= ~CSF_POLLING
;
default: if (thechar
>= ' ')
sput('^',0xe) ; sput('C',0xe) ; sput('\r',0xe) ; sput('\n',0xe) ;
sput('^',0x6) ; sput('D',0x6) ; sput('\r',0x6) ; sput('\n',0x6) ;