/* cons.c 7.9 91/05/16 */
* Tahoe console processor driver
* Minor device 0 is the CP itself.
* No real read/writes can be done to him.
* Minor 1 is the console terminal.
* Minor 2 is the remote line trminal.
#include "../include/cpu.h"
#include "../include/mtpr.h"
struct tty
*cntty
[3] = { &CPtty
, &cons
, &RLtty
};
struct tty
*constty
= 0; /* virtual console */
#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 */
struct speedtab cnspeedtab
[] = {
* 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 */
struct cpdcb_o consout
[3] = {
{ CPTAKE
|CPDONE
}, { CPTAKE
|CPDONE
}, { CPTAKE
|CPDONE
}
struct cpdcb_i consin
[3] = {
{ CPTAKE
|CPDONE
}, { CPTAKE
|CPDONE
}, { CPTAKE
|CPDONE
}
* 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)); \
if (tp
->t_state
&TS_XCLUDE
&& u
.u_uid
!= 0)
cnpostread(unit
); /* post request for input */
if ((tp
->t_state
&TS_ISOPEN
) == 0) {
tp
->t_iflag
= TTYDEF_IFLAG
|ICRNL
;
tp
->t_oflag
= TTYDEF_OFLAG
|OPOST
|ONLCR
;
tp
->t_lflag
= TTYDEF_LFLAG
;
tp
->t_ispeed
= tp
->t_ospeed
= TTYDEF_SPEED
;
tp
->t_state
= TS_ISOPEN
|TS_CARR_ON
;
cnparams(tp
, &tp
->t_termios
);
return ((*linesw
[tp
->t_line
].l_open
)(dev
, tp
));
register struct cpdcb_i
*cin
;
cin
->cp_hdr
.cp_unit
= unit
;
cin
->cp_hdr
.cp_comm
= CPREAD
;
cin
->cp_hdr
.cp_count
= 1; /* Get ready for input */
mtpr(CPMDCB
, vtoph((struct proc
*)0, (unsigned)cin
));
cnclose(dev
, flag
, mode
, p
)
register struct tty
*tp
= cntty
[minor(dev
)];
(*linesw
[tp
->t_line
].l_close
)(tp
, flag
);
struct tty
*tp
= cntty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
, flag
));
register struct tty
*tp
= cntty
[minor(dev
)];
if (tp
== &cons
&& constty
&&
(constty
->t_state
& (TS_CARR_ON
| TS_ISOPEN
)) ==
(TS_CARR_ON
| TS_ISOPEN
))
return ((*linesw
[tp
->t_line
].l_write
)(tp
, 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.
if (!intenable
|| consoftc
[unit
].cs_flags
&CSF_POLLING
)
/* make sure we dont take it from cache */
uncache(&consin
[unit
].cpi_buf
[0]);
c
= consin
[unit
].cpi_buf
[0];
/* This resets status bits */
consin
[unit
].cp_hdr
.cp_unit
= unit
;
/* Ready for new character */
mtpr(CPMDCB
, vtoph((struct proc
*)0, (unsigned)&consin
[unit
]));
cnlast
= &consin
[unit
].cp_hdr
;
if ((tp
->t_cflag
&CSIZE
) != CS8
)
if (unit
== CPCONS
&& kdbrintr(c
, tp
))
(*linesw
[tp
->t_line
].l_rint
)(c
& 0377, tp
);
cnioctl(dev
, cmd
, addr
, flag
)
register struct tty
*tp
= cntty
[minor(dev
)];
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, addr
);
if ((error
= ttioctl(tp
, cmd
, addr
, flag
)) < 0)
* Got a console transmission interrupt -
* the console processor wants another character.
if (!intenable
|| !consintr
)
scope_in(unit
== CPCONS
? 1 : 2);
consoftc
[unit
].cs_timo
= 0;
(*linesw
[tp
->t_line
].l_start
)(tp
);
scope_in(minor(tp
->t_dev
) == CPCONS
? 3 : 4);
if (tp
->t_state
& (TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
if (tp
->t_outq
.c_cc
<= tp
->t_lowat
) {
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
;
if (tp
->t_outq
.c_cc
== 0)
c
= getc(&tp
->t_outq
) & 0xff;
if (tp
->t_cflag
&PARENB
&& ((tp
->t_cflag
&CSIZE
)==CS7
)) {
c
|= (tp
->t_cflag
&PARODD
? ~partab
[c
] : partab
[c
]) & 0200;
cnputchar('\r', (struct tty
*)0);
cnputchar(c
, (struct tty
*)0);
* Print a character on console.
register struct cpdcb_o
*current
;
register struct consoftc
*cs
;
/* tp == 0 only in system error messages */
tp
->t_dev
= CPCONS
; /* may not be open */
c
|= partab
[c
&0177]&0200;
current
= &consout
[unit
];
* Try waiting for the console tty to finish previous command
* on this unit, otherwise give up after a reasonable time.
uncache(¤t
->cp_hdr
.cp_unit
);
while ((current
->cp_hdr
.cp_unit
&CPDONE
) == 0 && --timo
);
current
->cp_hdr
.cp_comm
= CPWRITE
;
current
->cp_hdr
.cp_count
= 1;
* Try waiting for the console tty
* to accept previous command.
current
->cp_hdr
.cp_unit
= (char)unit
;
if ((cs
->cs_flags
&CSF_ACTIVE
) == 0 && clk_enable
) {
cs
->cs_flags
|= CSF_ACTIVE
;
timeout(cnrestart
, (caddr_t
)tp
, CN_TIMERVAL
);
mtpr(CPMDCB
, vtoph((struct proc
*)0, (unsigned)current
));
cnlast
= ¤t
->cp_hdr
;
#if defined(KADB) || defined(GENERIC)
s
= spl8(); /* block cnrint while we poll */
register struct cpdcb_i
*current
;
current
->cp_hdr
.cp_unit
= unit
; /* Resets done bit */
current
->cp_hdr
.cp_comm
= CPREAD
;
current
->cp_hdr
.cp_count
= 1;
mtpr(CPMDCB
, vtoph((struct proc
*)0, (unsigned)current
));
while ((current
->cp_hdr
.cp_unit
&CPDONE
) == 0)
uncache(¤t
->cp_hdr
.cp_unit
);
uncache(¤t
->cpi_buf
[0]);
c
= current
->cpi_buf
[0] & 0x7f;
cnlast
= ¤t
->cp_hdr
;
* Restart (if necessary) transfer to CP line.
* This way, lost transmit interrupts don't wedge output.
register struct consoftc
*cs
;
cs
= &consoftc
[minor(tp
->t_dev
)];
cs
->cs_flags
&= ~CSF_ACTIVE
;
if (--cs
->cs_timo
== 0) {
cnputchar(cs
->cs_lastc
, tp
);
cs
->cs_flags
|= CSF_ACTIVE
;
timeout(cnrestart
, (caddr_t
)tp
, CN_TIMERVAL
);
register struct cpdcb_o
*current
;
current
= &consout
[unit
];
current
->cp_hdr
.cp_comm
= CPRESET
;
current
->cp_hdr
.cp_count
= 0;
current
->cp_hdr
.cp_unit
= unit
;
mtpr(CPMDCB
, vtoph((struct proc
*)0, (unsigned)current
));
cnlast
= ¤t
->cp_hdr
;
uncache(¤t
->cp_hdr
.cp_unit
);
while ((current
->cp_hdr
.cp_unit
&CPTAKE
) == 0 && --timo
);
if (current
->cp_hdr
.cp_unit
& CPTAKE
) {
cnparams(tp
, &tp
->t_termios
);
log(LOG_ERR
, "Console wedged, reset failed.\n");
register struct termios
*t
;
int unit
= minor(tp
->t_dev
);
register struct cpdcb_o
*current
= &consout
[unit
];
register cflag
= t
->c_cflag
;
if (((speedcode
== ttspeedtab(t
->c_ospeed
, cnspeedtab
)) < 0) ||
(t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
) ||
((csize
= (cflag
&CSIZE
)) != CS7
&& csize
!= CS8
))
* Try waiting for the console tty to finish any output,
* otherwise give up after a reasonable time.
uncache(¤t
->cp_hdr
.cp_unit
);
while ((current
->cp_hdr
.cp_unit
&CPDONE
) == 0 && --timo
);
current
->cp_hdr
.cp_comm
= CPSTTY
;
current
->cp_hdr
.cp_count
= 4;
current
->cp_buf
[0] = speedcode
;
current
->cp_buf
[1] = (cflag
&PARENB
) ? ((cflag
&PARODD
) ? 2 : 1) : 0;
current
->cp_buf
[2] = (cflag
&CSTOPB
) ? 2 : 0;
current
->cp_buf
[3] = (csize
==CS8
) ? 8 : 7;
current
->cp_buf
[1] = 0; /* no parity */
current
->cp_buf
[2] = 0; /* stop bits */
current
->cp_buf
[3] = 8; /* data bits */
current
->cp_hdr
.cp_unit
= unit
;
mtpr(CPMDCB
, vtoph((struct proc
*)0, (unsigned)current
));
cnlast
= ¤t
->cp_hdr
;
* Turn input polling on/off (used by debugger).
consoftc
[CPCONS
].cs_flags
&= ~CSF_POLLING
;
cnpostread(CPCONS
); /* restart input */
consoftc
[CPCONS
].cs_flags
|= CSF_POLLING
;