155104Storek /*
263927Sbostic * Copyright (c) 1992, 1993
363927Sbostic * The Regents of the University of California. All rights reserved.
455104Storek *
555104Storek * This software was developed by the Computer Systems Engineering group
655104Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
755104Storek * contributed to Berkeley.
855104Storek *
955499Sbostic * All advertising materials mentioning features or use of this software
1055499Sbostic * must display the following acknowledgement:
1155499Sbostic * This product includes software developed by the University of
1259185Storek * California, Lawrence Berkeley Laboratory.
1355499Sbostic *
1455104Storek * %sccs.include.redist.c%
1555104Storek *
16*65143Storek * @(#)cons.c 8.3 (Berkeley) 12/14/93
1755104Storek *
1863921Storek * from: $Header: cons.c,v 1.12 93/07/20 00:49:45 torek Exp $
1955104Storek */
2055104Storek
2155104Storek /*
2255104Storek * Console (indirect) driver.
2355104Storek */
2455104Storek
2556536Sbostic #include <sys/param.h>
2656536Sbostic #include <sys/proc.h>
2756536Sbostic #include <sys/systm.h>
2856536Sbostic #include <sys/ioctl.h>
2956536Sbostic #include <sys/tty.h>
3056536Sbostic #include <sys/file.h>
3156536Sbostic #include <sys/conf.h>
3255104Storek
3356536Sbostic #include <machine/bsd_openprom.h>
3456536Sbostic #include <machine/psl.h>
3555104Storek
3655104Storek #include "zs.h"
3755104Storek
3855104Storek struct tty *constty = 0; /* virtual console output device */
3955104Storek struct tty *fbconstty = 0; /* tty structure for frame buffer console */
4055104Storek int rom_console_input; /* when set, hardclock calls cnrom() */
4155104Storek
4255104Storek int cons_ocount; /* output byte count */
4355104Storek
4455104Storek extern struct promvec *promvec;
4555104Storek
4655104Storek /*
4755104Storek * The output driver may munge the minor number in cons.t_dev.
4855104Storek */
4955104Storek struct tty cons; /* rom console tty device */
5055104Storek static void cnstart __P((struct tty *));
5155104Storek static void cnfbstart __P((struct tty *));
5255104Storek static void cnfbstop __P((struct tty *, int));
5355104Storek static void cnfbdma __P((void *));
5455104Storek
55*65143Storek extern const char char_type[];
5655104Storek
consinit()5755104Storek consinit()
5855104Storek {
5955104Storek register struct tty *tp = &cons;
6055104Storek register int in, out;
6155104Storek void zsconsole(), bwtwoconsole();
6255104Storek
6355104Storek tp->t_dev = makedev(0, 0); /* /dev/console */
6455104Storek tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
6555104Storek tp->t_param = (int (*)(struct tty *, struct termios *))nullop;
6655104Storek in = *promvec->pv_stdin;
6755104Storek out = *promvec->pv_stdout;
6855104Storek switch (in) {
6955104Storek
7055104Storek #if NZS > 0
7155104Storek case PROMDEV_TTYA:
7255104Storek zsconsole(tp, 0, 0);
7355104Storek break;
7455104Storek
7555104Storek case PROMDEV_TTYB:
7655104Storek zsconsole(tp, 1, 0);
7755104Storek break;
7855104Storek #endif
7955104Storek
8055104Storek case PROMDEV_KBD:
8155104Storek /*
8255104Storek * Tell the keyboard driver to direct ASCII input here.
8355104Storek */
8455104Storek kbd_ascii(tp);
8555104Storek break;
8655104Storek
8755104Storek default:
8855104Storek rom_console_input = 1;
8955104Storek printf("unknown console input source %d; using rom\n", in);
9055104Storek break;
9155104Storek }
9255104Storek switch (out) {
9355104Storek
9455104Storek #if NZS > 0
9555104Storek case PROMDEV_TTYA:
9655104Storek zsconsole(tp, 0, 1);
9755104Storek break;
9855104Storek
9955104Storek case PROMDEV_TTYB:
10055104Storek zsconsole(tp, 1, 1);
10155104Storek break;
10255104Storek #endif
10355104Storek
10455104Storek case PROMDEV_SCREEN:
10555104Storek fbconstty = tp;
10655104Storek tp->t_oproc = cnfbstart;
10755104Storek tp->t_stop = cnfbstop;
10855104Storek break;
10955104Storek
11055104Storek default:
11155104Storek printf("unknown console output sink %d; using rom\n", out);
11255104Storek tp->t_oproc = cnstart;
11355104Storek tp->t_stop = (void (*)(struct tty *, int))nullop;
11455104Storek break;
11555104Storek }
11655104Storek }
11755104Storek
11855104Storek /* ARGSUSED */
cnopen(dev,flag,mode,p)11955104Storek cnopen(dev, flag, mode, p)
12055104Storek dev_t dev;
12155104Storek int flag, mode;
12255104Storek struct proc *p;
12355104Storek {
12455104Storek register struct tty *tp = &cons;
12555104Storek
12655104Storek if ((tp->t_state & TS_ISOPEN) == 0) {
12755104Storek /*
12855104Storek * Leave baud rate alone!
12955104Storek */
13055104Storek ttychars(tp);
13155104Storek tp->t_iflag = TTYDEF_IFLAG;
13255104Storek tp->t_oflag = TTYDEF_OFLAG;
13355104Storek tp->t_lflag = TTYDEF_LFLAG;
13455104Storek tp->t_cflag = TTYDEF_CFLAG;
13555104Storek tp->t_state = TS_ISOPEN | TS_CARR_ON;
13663921Storek (void)(*tp->t_param)(tp, &tp->t_termios);
13755104Storek ttsetwater(tp);
13855104Storek } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
13955104Storek return (EBUSY);
14055104Storek return ((*linesw[tp->t_line].l_open)(dev, tp));
14155104Storek }
14255104Storek
14355104Storek /* ARGSUSED */
cnclose(dev,flag,mode,p)14455104Storek cnclose(dev, flag, mode, p)
14555104Storek dev_t dev;
14655104Storek int flag, mode;
14755104Storek struct proc *p;
14855104Storek {
14955104Storek register struct tty *tp = &cons;
15055104Storek
15155104Storek (*linesw[tp->t_line].l_close)(tp, flag);
15255104Storek ttyclose(tp);
15355104Storek return (0);
15455104Storek }
15555104Storek
15655104Storek /* ARGSUSED */
cnread(dev,uio,flag)15755104Storek cnread(dev, uio, flag)
15855104Storek dev_t dev;
15955104Storek struct uio *uio;
16055104Storek int flag;
16155104Storek {
16255104Storek register struct tty *tp = &cons;
16355104Storek
16455104Storek return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
16555104Storek }
16655104Storek
16755104Storek /* ARGSUSED */
cnwrite(dev,uio,flag)16855104Storek cnwrite(dev, uio, flag)
16955104Storek dev_t dev;
17055104Storek struct uio *uio;
17155104Storek int flag;
17255104Storek {
17355104Storek register struct tty *tp;
17455104Storek
17555104Storek if ((tp = constty) == NULL ||
17655104Storek (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN))
17755104Storek tp = &cons;
17855104Storek return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
17955104Storek }
18055104Storek
cnioctl(dev,cmd,data,flag,p)18155104Storek cnioctl(dev, cmd, data, flag, p)
18255104Storek dev_t dev;
18355104Storek int cmd;
18455104Storek caddr_t data;
18555104Storek int flag;
18655104Storek struct proc *p;
18755104Storek {
18855104Storek register struct tty *tp;
18955104Storek int error;
19055104Storek
19155104Storek /*
19255104Storek * Superuser can always use this to wrest control of console
19355104Storek * output from the "virtual" console.
19455104Storek */
19555104Storek if (cmd == TIOCCONS && constty) {
19655104Storek error = suser(p->p_ucred, (u_short *)NULL);
19755104Storek if (error)
19855104Storek return (error);
19955104Storek constty = NULL;
20055104Storek return (0);
20155104Storek }
20255104Storek tp = &cons;
20355104Storek if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0)
20455104Storek return (error);
20555104Storek if ((error = ttioctl(tp, cmd, data, flag)) >= 0)
20655104Storek return (error);
20755104Storek return (ENOTTY);
20855104Storek }
20955104Storek
cnselect(dev,which,p)21055104Storek cnselect(dev, which, p)
21155104Storek dev_t dev;
21255104Storek int which;
21355104Storek struct proc *p;
21455104Storek {
21555104Storek
21655104Storek return (ttselect(makedev(major(dev), 0), which, p));
21755104Storek }
21855104Storek
21955104Storek /*
22055104Storek * The rest of this code is run only when we are using the ROM vectors.
22155104Storek */
22255104Storek
22355104Storek /*
22455104Storek * Generic output. We just call putchar. (Very bad for performance.)
22555104Storek */
22655104Storek static void
cnstart(tp)22755104Storek cnstart(tp)
22855104Storek register struct tty *tp;
22955104Storek {
23055104Storek register int c, s;
23155104Storek register void (*putc)(int);
23255104Storek
23355104Storek s = spltty();
23455104Storek if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
23555104Storek splx(s);
23655104Storek return;
23755104Storek }
23855104Storek putc = promvec->pv_putchar;
23955104Storek while (tp->t_outq.c_cc) {
24055104Storek c = getc(&tp->t_outq);
24155104Storek /*
24255104Storek * *%&!*& ROM monitor console putchar is not reentrant!
24355104Storek * splhigh/tty around it so as not to run so long with
24455104Storek * clock interrupts blocked.
24555104Storek */
24655104Storek (void) splhigh();
24755104Storek (*putc)(c & 0177);
24855104Storek (void) spltty();
24955104Storek }
25055104Storek if (tp->t_state & TS_ASLEEP) { /* can't happen? */
25155104Storek tp->t_state &= ~TS_ASLEEP;
25255104Storek wakeup((caddr_t)&tp->t_outq);
25355104Storek }
25455104Storek selwakeup(&tp->t_wsel);
25555104Storek splx(s);
25655104Storek }
25755104Storek
25855104Storek /*
25955104Storek * Frame buffer output.
26055104Storek * We use pseudo-DMA, via the ROM `write string' function, called from
26155104Storek * software clock interrupts.
26255104Storek */
26355104Storek static void
cnfbstart(tp)26455104Storek cnfbstart(tp)
26555104Storek register struct tty *tp;
26655104Storek {
26755104Storek register int s;
26855104Storek
26955104Storek s = spltty(); /* paranoid: splsoftclock should suffice */
27055104Storek if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
27155104Storek splx(s);
27255104Storek return;
27355104Storek }
27455104Storek /*
27555104Storek * If there are sleepers, and output has drained below low
27655104Storek * water mark, awaken.
27755104Storek */
27855104Storek if (tp->t_outq.c_cc <= tp->t_lowat) {
27955104Storek if (tp->t_state & TS_ASLEEP) {
28055104Storek tp->t_state &= ~TS_ASLEEP;
28155104Storek wakeup((caddr_t)&tp->t_outq);
28255104Storek }
28355104Storek selwakeup(&tp->t_wsel);
28455104Storek }
28555104Storek if (tp->t_outq.c_cc) {
28655104Storek tp->t_state |= TS_BUSY;
28755104Storek if (s == 0) {
28855104Storek (void) splsoftclock();
28955104Storek cnfbdma((void *)tp);
29055104Storek } else
29155104Storek timeout(cnfbdma, tp, 1);
29255104Storek }
29355104Storek splx(s);
29455104Storek }
29555104Storek
29655104Storek /*
29755104Storek * Stop frame buffer output: just assert TS_FLUSH if necessary.
29855104Storek */
29955104Storek static void
cnfbstop(tp,flag)30055104Storek cnfbstop(tp, flag)
30155104Storek register struct tty *tp;
30255104Storek int flag;
30355104Storek {
30455104Storek register int s = spltty(); /* paranoid */
30555104Storek
30655104Storek if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
30755104Storek tp->t_state |= TS_FLUSH;
30855104Storek splx(s);
30955104Storek }
31055104Storek
31155104Storek /*
31255104Storek * Do pseudo-dma (called from software interrupt).
31355104Storek */
31455104Storek static void
cnfbdma(tpaddr)31555104Storek cnfbdma(tpaddr)
31655104Storek void *tpaddr;
31755104Storek {
31855104Storek register struct tty *tp = tpaddr;
31955104Storek register char *p, *q;
32055104Storek register int n, c, s;
32155104Storek
32255104Storek s = spltty(); /* paranoid */
32355104Storek if (tp->t_state & TS_FLUSH) {
32455104Storek tp->t_state &= ~(TS_BUSY | TS_FLUSH);
32555104Storek splx(s);
32655104Storek } else {
32755104Storek tp->t_state &= ~TS_BUSY;
32855104Storek splx(s);
32955104Storek p = tp->t_outq.c_cf;
33055104Storek n = ndqb(&tp->t_outq, 0);
33155104Storek for (q = p, c = n; --c >= 0; q++)
33255104Storek if (*q & 0200) /* high bits seem to be bad */
33355104Storek *q &= ~0200;
33455104Storek (*promvec->pv_putstr)(p, n);
33555104Storek ndflush(&tp->t_outq, n);
33655104Storek }
33755104Storek if (tp->t_line)
33855104Storek (*linesw[tp->t_line].l_start)(tp);
33955104Storek else
34055104Storek cnfbstart(tp);
34155104Storek }
34255104Storek
34355104Storek /*
34455104Storek * The following is for rom console input. The rom will not call
34555104Storek * an `interrupt' routine on console input ready, so we must poll.
34655104Storek * This is all rather sad.
34755104Storek */
34855104Storek volatile int cn_rxc; /* XXX receive `silo' */
34955104Storek
35055104Storek /* called from hardclock, which is above spltty, so no tty calls! */
cnrom()35155104Storek cnrom()
35255104Storek {
35355104Storek register int c;
35455104Storek
35555104Storek if (cn_rxc >= 0)
35655104Storek return (1);
35755104Storek if ((c = (*promvec->pv_nbgetchar)()) < 0)
35855104Storek return (0);
35955104Storek cn_rxc = c;
36055104Storek return (1);
36155104Storek }
36255104Storek
36355104Storek /* pseudo console software interrupt scheduled when cnrom() returns 1 */
cnrint()36455104Storek cnrint()
36555104Storek {
36655104Storek register struct tty *tp;
36755104Storek register int c, s;
36855104Storek
36955104Storek s = splclock();
37055104Storek c = cn_rxc;
37155104Storek cn_rxc = -1;
37255104Storek splx(s);
37355104Storek if (c < 0)
37455104Storek return;
37555104Storek tp = &cons;
37655104Storek if ((tp->t_cflag & CSIZE) == CS7) {
377*65143Storek #if 0
37855104Storek /* XXX this should be done elsewhere, if at all */
37955104Storek if (tp->t_cflag & PARENB)
38055104Storek if (tp->t_cflag & PARODD ?
38165080Smckusick (char_type[c & 0177] & 0200) == (c & 0200) :
38265080Smckusick (char_type[c & 0177] & 0200) != (c & 0200))
38355104Storek c |= TTY_PE;
384*65143Storek #endif
38555104Storek c &= ~0200;
38655104Storek }
38755104Storek (*linesw[tp->t_line].l_rint)(c, tp);
38855104Storek }
38955104Storek
cngetc()39055104Storek cngetc()
39155104Storek {
39255104Storek register int s, c;
39355104Storek
39455104Storek s = splhigh();
39555104Storek c = (*promvec->pv_getchar)();
39655104Storek splx(s);
39755104Storek if (c == '\r')
39855104Storek c = '\n';
39955104Storek return (c);
40055104Storek }
40155104Storek
cnputc(c)40255104Storek cnputc(c)
40355104Storek register int c;
40455104Storek {
40555104Storek register int s = splhigh();
40655104Storek
40755104Storek if (c == '\n')
40855104Storek (*promvec->pv_putchar)('\r');
40955104Storek (*promvec->pv_putchar)(c);
41055104Storek splx(s);
41155104Storek }
412