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*65080Smckusick * @(#)cons.c 8.2 (Berkeley) 12/10/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*65080Smckusick extern char char_type[]; 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; 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 */ 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 */ 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 */ 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 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 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 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 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 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 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! */ 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 */ 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) { 37755104Storek /* XXX this should be done elsewhere, if at all */ 37855104Storek if (tp->t_cflag & PARENB) 37955104Storek if (tp->t_cflag & PARODD ? 380*65080Smckusick (char_type[c & 0177] & 0200) == (c & 0200) : 381*65080Smckusick (char_type[c & 0177] & 0200) != (c & 0200)) 38255104Storek c |= TTY_PE; 38355104Storek c &= ~0200; 38455104Storek } 38555104Storek (*linesw[tp->t_line].l_rint)(c, tp); 38655104Storek } 38755104Storek 38855104Storek cngetc() 38955104Storek { 39055104Storek register int s, c; 39155104Storek 39255104Storek s = splhigh(); 39355104Storek c = (*promvec->pv_getchar)(); 39455104Storek splx(s); 39555104Storek if (c == '\r') 39655104Storek c = '\n'; 39755104Storek return (c); 39855104Storek } 39955104Storek 40055104Storek cnputc(c) 40155104Storek register int c; 40255104Storek { 40355104Storek register int s = splhigh(); 40455104Storek 40555104Storek if (c == '\n') 40655104Storek (*promvec->pv_putchar)('\r'); 40755104Storek (*promvec->pv_putchar)(c); 40855104Storek splx(s); 40955104Storek } 410