155104Storek /* 255104Storek * Copyright (c) 1992 The Regents of the University of California. 355104Storek * 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 12*59185Storek * California, Lawrence Berkeley Laboratory. 1355499Sbostic * 1455104Storek * %sccs.include.redist.c% 1555104Storek * 16*59185Storek * @(#)cons.c 7.4 (Berkeley) 04/20/93 1755104Storek * 18*59185Storek * from: $Header: cons.c,v 1.11 92/11/26 01:09:28 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 5555104Storek extern char partab[]; 5655104Storek 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 */ 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; 13655104Storek ttsetwater(tp); 13755104Storek } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 13855104Storek return (EBUSY); 13955104Storek return ((*linesw[tp->t_line].l_open)(dev, tp)); 14055104Storek } 14155104Storek 14255104Storek /* ARGSUSED */ 14355104Storek cnclose(dev, flag, mode, p) 14455104Storek dev_t dev; 14555104Storek int flag, mode; 14655104Storek struct proc *p; 14755104Storek { 14855104Storek register struct tty *tp = &cons; 14955104Storek 15055104Storek (*linesw[tp->t_line].l_close)(tp, flag); 15155104Storek ttyclose(tp); 15255104Storek return (0); 15355104Storek } 15455104Storek 15555104Storek /* ARGSUSED */ 15655104Storek cnread(dev, uio, flag) 15755104Storek dev_t dev; 15855104Storek struct uio *uio; 15955104Storek int flag; 16055104Storek { 16155104Storek register struct tty *tp = &cons; 16255104Storek 16355104Storek return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 16455104Storek } 16555104Storek 16655104Storek /* ARGSUSED */ 16755104Storek cnwrite(dev, uio, flag) 16855104Storek dev_t dev; 16955104Storek struct uio *uio; 17055104Storek int flag; 17155104Storek { 17255104Storek register struct tty *tp; 17355104Storek 17455104Storek if ((tp = constty) == NULL || 17555104Storek (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN)) 17655104Storek tp = &cons; 17755104Storek return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 17855104Storek } 17955104Storek 18055104Storek cnioctl(dev, cmd, data, flag, p) 18155104Storek dev_t dev; 18255104Storek int cmd; 18355104Storek caddr_t data; 18455104Storek int flag; 18555104Storek struct proc *p; 18655104Storek { 18755104Storek register struct tty *tp; 18855104Storek int error; 18955104Storek 19055104Storek /* 19155104Storek * Superuser can always use this to wrest control of console 19255104Storek * output from the "virtual" console. 19355104Storek */ 19455104Storek if (cmd == TIOCCONS && constty) { 19555104Storek error = suser(p->p_ucred, (u_short *)NULL); 19655104Storek if (error) 19755104Storek return (error); 19855104Storek constty = NULL; 19955104Storek return (0); 20055104Storek } 20155104Storek tp = &cons; 20255104Storek if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0) 20355104Storek return (error); 20455104Storek if ((error = ttioctl(tp, cmd, data, flag)) >= 0) 20555104Storek return (error); 20655104Storek return (ENOTTY); 20755104Storek } 20855104Storek 20955104Storek cnselect(dev, which, p) 21055104Storek dev_t dev; 21155104Storek int which; 21255104Storek struct proc *p; 21355104Storek { 21455104Storek 21555104Storek return (ttselect(makedev(major(dev), 0), which, p)); 21655104Storek } 21755104Storek 21855104Storek /* 21955104Storek * The rest of this code is run only when we are using the ROM vectors. 22055104Storek */ 22155104Storek 22255104Storek /* 22355104Storek * Generic output. We just call putchar. (Very bad for performance.) 22455104Storek */ 22555104Storek static void 22655104Storek cnstart(tp) 22755104Storek register struct tty *tp; 22855104Storek { 22955104Storek register int c, s; 23055104Storek register void (*putc)(int); 23155104Storek 23255104Storek s = spltty(); 23355104Storek if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 23455104Storek splx(s); 23555104Storek return; 23655104Storek } 23755104Storek putc = promvec->pv_putchar; 23855104Storek while (tp->t_outq.c_cc) { 23955104Storek c = getc(&tp->t_outq); 24055104Storek /* 24155104Storek * *%&!*& ROM monitor console putchar is not reentrant! 24255104Storek * splhigh/tty around it so as not to run so long with 24355104Storek * clock interrupts blocked. 24455104Storek */ 24555104Storek (void) splhigh(); 24655104Storek (*putc)(c & 0177); 24755104Storek (void) spltty(); 24855104Storek } 24955104Storek if (tp->t_state & TS_ASLEEP) { /* can't happen? */ 25055104Storek tp->t_state &= ~TS_ASLEEP; 25155104Storek wakeup((caddr_t)&tp->t_outq); 25255104Storek } 25355104Storek selwakeup(&tp->t_wsel); 25455104Storek splx(s); 25555104Storek } 25655104Storek 25755104Storek /* 25855104Storek * Frame buffer output. 25955104Storek * We use pseudo-DMA, via the ROM `write string' function, called from 26055104Storek * software clock interrupts. 26155104Storek */ 26255104Storek static void 26355104Storek cnfbstart(tp) 26455104Storek register struct tty *tp; 26555104Storek { 26655104Storek register int s; 26755104Storek 26855104Storek s = spltty(); /* paranoid: splsoftclock should suffice */ 26955104Storek if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 27055104Storek splx(s); 27155104Storek return; 27255104Storek } 27355104Storek /* 27455104Storek * If there are sleepers, and output has drained below low 27555104Storek * water mark, awaken. 27655104Storek */ 27755104Storek if (tp->t_outq.c_cc <= tp->t_lowat) { 27855104Storek if (tp->t_state & TS_ASLEEP) { 27955104Storek tp->t_state &= ~TS_ASLEEP; 28055104Storek wakeup((caddr_t)&tp->t_outq); 28155104Storek } 28255104Storek selwakeup(&tp->t_wsel); 28355104Storek } 28455104Storek if (tp->t_outq.c_cc) { 28555104Storek tp->t_state |= TS_BUSY; 28655104Storek if (s == 0) { 28755104Storek (void) splsoftclock(); 28855104Storek cnfbdma((void *)tp); 28955104Storek } else 29055104Storek timeout(cnfbdma, tp, 1); 29155104Storek } 29255104Storek splx(s); 29355104Storek } 29455104Storek 29555104Storek /* 29655104Storek * Stop frame buffer output: just assert TS_FLUSH if necessary. 29755104Storek */ 29855104Storek static void 29955104Storek cnfbstop(tp, flag) 30055104Storek register struct tty *tp; 30155104Storek int flag; 30255104Storek { 30355104Storek register int s = spltty(); /* paranoid */ 30455104Storek 30555104Storek if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY) 30655104Storek tp->t_state |= TS_FLUSH; 30755104Storek splx(s); 30855104Storek } 30955104Storek 31055104Storek /* 31155104Storek * Do pseudo-dma (called from software interrupt). 31255104Storek */ 31355104Storek static void 31455104Storek cnfbdma(tpaddr) 31555104Storek void *tpaddr; 31655104Storek { 31755104Storek register struct tty *tp = tpaddr; 31855104Storek register char *p, *q; 31955104Storek register int n, c, s; 32055104Storek 32155104Storek s = spltty(); /* paranoid */ 32255104Storek if (tp->t_state & TS_FLUSH) { 32355104Storek tp->t_state &= ~(TS_BUSY | TS_FLUSH); 32455104Storek splx(s); 32555104Storek } else { 32655104Storek tp->t_state &= ~TS_BUSY; 32755104Storek splx(s); 32855104Storek p = tp->t_outq.c_cf; 32955104Storek n = ndqb(&tp->t_outq, 0); 33055104Storek for (q = p, c = n; --c >= 0; q++) 33155104Storek if (*q & 0200) /* high bits seem to be bad */ 33255104Storek *q &= ~0200; 33355104Storek (*promvec->pv_putstr)(p, n); 33455104Storek ndflush(&tp->t_outq, n); 33555104Storek } 33655104Storek if (tp->t_line) 33755104Storek (*linesw[tp->t_line].l_start)(tp); 33855104Storek else 33955104Storek cnfbstart(tp); 34055104Storek } 34155104Storek 34255104Storek /* 34355104Storek * The following is for rom console input. The rom will not call 34455104Storek * an `interrupt' routine on console input ready, so we must poll. 34555104Storek * This is all rather sad. 34655104Storek */ 34755104Storek volatile int cn_rxc; /* XXX receive `silo' */ 34855104Storek 34955104Storek /* called from hardclock, which is above spltty, so no tty calls! */ 35055104Storek cnrom() 35155104Storek { 35255104Storek register int c; 35355104Storek 35455104Storek if (cn_rxc >= 0) 35555104Storek return (1); 35655104Storek if ((c = (*promvec->pv_nbgetchar)()) < 0) 35755104Storek return (0); 35855104Storek cn_rxc = c; 35955104Storek return (1); 36055104Storek } 36155104Storek 36255104Storek /* pseudo console software interrupt scheduled when cnrom() returns 1 */ 36355104Storek cnrint() 36455104Storek { 36555104Storek register struct tty *tp; 36655104Storek register int c, s; 36755104Storek 36855104Storek s = splclock(); 36955104Storek c = cn_rxc; 37055104Storek cn_rxc = -1; 37155104Storek splx(s); 37255104Storek if (c < 0) 37355104Storek return; 37455104Storek tp = &cons; 37555104Storek if ((tp->t_cflag & CSIZE) == CS7) { 37655104Storek /* XXX this should be done elsewhere, if at all */ 37755104Storek if (tp->t_cflag & PARENB) 37855104Storek if (tp->t_cflag & PARODD ? 37955104Storek (partab[c & 0177] & 0200) == (c & 0200) : 38055104Storek (partab[c & 0177] & 0200) != (c & 0200)) 38155104Storek c |= TTY_PE; 38255104Storek c &= ~0200; 38355104Storek } 38455104Storek (*linesw[tp->t_line].l_rint)(c, tp); 38555104Storek } 38655104Storek 38755104Storek cngetc() 38855104Storek { 38955104Storek register int s, c; 39055104Storek 39155104Storek s = splhigh(); 39255104Storek c = (*promvec->pv_getchar)(); 39355104Storek splx(s); 39455104Storek if (c == '\r') 39555104Storek c = '\n'; 39655104Storek return (c); 39755104Storek } 39855104Storek 39955104Storek cnputc(c) 40055104Storek register int c; 40155104Storek { 40255104Storek register int s = splhigh(); 40355104Storek 40455104Storek if (c == '\n') 40555104Storek (*promvec->pv_putchar)('\r'); 40655104Storek (*promvec->pv_putchar)(c); 40755104Storek splx(s); 40855104Storek } 409