1*55104Storek /* 2*55104Storek * Copyright (c) 1992 The Regents of the University of California. 3*55104Storek * All rights reserved. 4*55104Storek * 5*55104Storek * This software was developed by the Computer Systems Engineering group 6*55104Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7*55104Storek * contributed to Berkeley. 8*55104Storek * 9*55104Storek * %sccs.include.redist.c% 10*55104Storek * 11*55104Storek * @(#)cons.c 7.1 (Berkeley) 07/13/92 12*55104Storek * 13*55104Storek * from: $Header: cons.c,v 1.10 92/07/10 00:02:42 torek Exp $ 14*55104Storek */ 15*55104Storek 16*55104Storek /* 17*55104Storek * Console (indirect) driver. 18*55104Storek */ 19*55104Storek 20*55104Storek #include "sys/param.h" 21*55104Storek #include "sys/proc.h" 22*55104Storek #include "sys/systm.h" 23*55104Storek #include "sys/ioctl.h" 24*55104Storek #include "sys/tty.h" 25*55104Storek #include "sys/file.h" 26*55104Storek #include "sys/conf.h" 27*55104Storek 28*55104Storek #include "machine/bsd_openprom.h" 29*55104Storek #include "machine/psl.h" 30*55104Storek 31*55104Storek #include "zs.h" 32*55104Storek 33*55104Storek struct tty *constty = 0; /* virtual console output device */ 34*55104Storek struct tty *fbconstty = 0; /* tty structure for frame buffer console */ 35*55104Storek int rom_console_input; /* when set, hardclock calls cnrom() */ 36*55104Storek 37*55104Storek int cons_ocount; /* output byte count */ 38*55104Storek 39*55104Storek extern struct promvec *promvec; 40*55104Storek 41*55104Storek /* 42*55104Storek * The output driver may munge the minor number in cons.t_dev. 43*55104Storek */ 44*55104Storek struct tty cons; /* rom console tty device */ 45*55104Storek static void cnstart __P((struct tty *)); 46*55104Storek static void cnfbstart __P((struct tty *)); 47*55104Storek static void cnfbstop __P((struct tty *, int)); 48*55104Storek static void cnfbdma __P((void *)); 49*55104Storek 50*55104Storek extern char partab[]; 51*55104Storek 52*55104Storek consinit() 53*55104Storek { 54*55104Storek register struct tty *tp = &cons; 55*55104Storek register int in, out; 56*55104Storek void zsconsole(), bwtwoconsole(); 57*55104Storek 58*55104Storek tp->t_dev = makedev(0, 0); /* /dev/console */ 59*55104Storek tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 60*55104Storek tp->t_param = (int (*)(struct tty *, struct termios *))nullop; 61*55104Storek in = *promvec->pv_stdin; 62*55104Storek out = *promvec->pv_stdout; 63*55104Storek switch (in) { 64*55104Storek 65*55104Storek #if NZS > 0 66*55104Storek case PROMDEV_TTYA: 67*55104Storek zsconsole(tp, 0, 0); 68*55104Storek break; 69*55104Storek 70*55104Storek case PROMDEV_TTYB: 71*55104Storek zsconsole(tp, 1, 0); 72*55104Storek break; 73*55104Storek #endif 74*55104Storek 75*55104Storek case PROMDEV_KBD: 76*55104Storek /* 77*55104Storek * Tell the keyboard driver to direct ASCII input here. 78*55104Storek */ 79*55104Storek kbd_ascii(tp); 80*55104Storek break; 81*55104Storek 82*55104Storek default: 83*55104Storek rom_console_input = 1; 84*55104Storek printf("unknown console input source %d; using rom\n", in); 85*55104Storek break; 86*55104Storek } 87*55104Storek switch (out) { 88*55104Storek 89*55104Storek #if NZS > 0 90*55104Storek case PROMDEV_TTYA: 91*55104Storek zsconsole(tp, 0, 1); 92*55104Storek break; 93*55104Storek 94*55104Storek case PROMDEV_TTYB: 95*55104Storek zsconsole(tp, 1, 1); 96*55104Storek break; 97*55104Storek #endif 98*55104Storek 99*55104Storek case PROMDEV_SCREEN: 100*55104Storek fbconstty = tp; 101*55104Storek tp->t_oproc = cnfbstart; 102*55104Storek tp->t_stop = cnfbstop; 103*55104Storek break; 104*55104Storek 105*55104Storek default: 106*55104Storek printf("unknown console output sink %d; using rom\n", out); 107*55104Storek tp->t_oproc = cnstart; 108*55104Storek tp->t_stop = (void (*)(struct tty *, int))nullop; 109*55104Storek break; 110*55104Storek } 111*55104Storek } 112*55104Storek 113*55104Storek /* ARGSUSED */ 114*55104Storek cnopen(dev, flag, mode, p) 115*55104Storek dev_t dev; 116*55104Storek int flag, mode; 117*55104Storek struct proc *p; 118*55104Storek { 119*55104Storek register struct tty *tp = &cons; 120*55104Storek 121*55104Storek if ((tp->t_state & TS_ISOPEN) == 0) { 122*55104Storek /* 123*55104Storek * Leave baud rate alone! 124*55104Storek */ 125*55104Storek ttychars(tp); 126*55104Storek tp->t_iflag = TTYDEF_IFLAG; 127*55104Storek tp->t_oflag = TTYDEF_OFLAG; 128*55104Storek tp->t_lflag = TTYDEF_LFLAG; 129*55104Storek tp->t_cflag = TTYDEF_CFLAG; 130*55104Storek tp->t_state = TS_ISOPEN | TS_CARR_ON; 131*55104Storek ttsetwater(tp); 132*55104Storek } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 133*55104Storek return (EBUSY); 134*55104Storek return ((*linesw[tp->t_line].l_open)(dev, tp)); 135*55104Storek } 136*55104Storek 137*55104Storek /* ARGSUSED */ 138*55104Storek cnclose(dev, flag, mode, p) 139*55104Storek dev_t dev; 140*55104Storek int flag, mode; 141*55104Storek struct proc *p; 142*55104Storek { 143*55104Storek register struct tty *tp = &cons; 144*55104Storek 145*55104Storek (*linesw[tp->t_line].l_close)(tp, flag); 146*55104Storek ttyclose(tp); 147*55104Storek return (0); 148*55104Storek } 149*55104Storek 150*55104Storek /* ARGSUSED */ 151*55104Storek cnread(dev, uio, flag) 152*55104Storek dev_t dev; 153*55104Storek struct uio *uio; 154*55104Storek int flag; 155*55104Storek { 156*55104Storek register struct tty *tp = &cons; 157*55104Storek 158*55104Storek return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 159*55104Storek } 160*55104Storek 161*55104Storek /* ARGSUSED */ 162*55104Storek cnwrite(dev, uio, flag) 163*55104Storek dev_t dev; 164*55104Storek struct uio *uio; 165*55104Storek int flag; 166*55104Storek { 167*55104Storek register struct tty *tp; 168*55104Storek 169*55104Storek if ((tp = constty) == NULL || 170*55104Storek (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN)) 171*55104Storek tp = &cons; 172*55104Storek return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 173*55104Storek } 174*55104Storek 175*55104Storek cnioctl(dev, cmd, data, flag, p) 176*55104Storek dev_t dev; 177*55104Storek int cmd; 178*55104Storek caddr_t data; 179*55104Storek int flag; 180*55104Storek struct proc *p; 181*55104Storek { 182*55104Storek register struct tty *tp; 183*55104Storek int error; 184*55104Storek 185*55104Storek /* 186*55104Storek * Superuser can always use this to wrest control of console 187*55104Storek * output from the "virtual" console. 188*55104Storek */ 189*55104Storek if (cmd == TIOCCONS && constty) { 190*55104Storek error = suser(p->p_ucred, (u_short *)NULL); 191*55104Storek if (error) 192*55104Storek return (error); 193*55104Storek constty = NULL; 194*55104Storek return (0); 195*55104Storek } 196*55104Storek tp = &cons; 197*55104Storek if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0) 198*55104Storek return (error); 199*55104Storek if ((error = ttioctl(tp, cmd, data, flag)) >= 0) 200*55104Storek return (error); 201*55104Storek return (ENOTTY); 202*55104Storek } 203*55104Storek 204*55104Storek cnselect(dev, which, p) 205*55104Storek dev_t dev; 206*55104Storek int which; 207*55104Storek struct proc *p; 208*55104Storek { 209*55104Storek 210*55104Storek return (ttselect(makedev(major(dev), 0), which, p)); 211*55104Storek } 212*55104Storek 213*55104Storek /* 214*55104Storek * The rest of this code is run only when we are using the ROM vectors. 215*55104Storek */ 216*55104Storek 217*55104Storek /* 218*55104Storek * Generic output. We just call putchar. (Very bad for performance.) 219*55104Storek */ 220*55104Storek static void 221*55104Storek cnstart(tp) 222*55104Storek register struct tty *tp; 223*55104Storek { 224*55104Storek register int c, s; 225*55104Storek register void (*putc)(int); 226*55104Storek 227*55104Storek s = spltty(); 228*55104Storek if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 229*55104Storek splx(s); 230*55104Storek return; 231*55104Storek } 232*55104Storek putc = promvec->pv_putchar; 233*55104Storek while (tp->t_outq.c_cc) { 234*55104Storek c = getc(&tp->t_outq); 235*55104Storek /* 236*55104Storek * *%&!*& ROM monitor console putchar is not reentrant! 237*55104Storek * splhigh/tty around it so as not to run so long with 238*55104Storek * clock interrupts blocked. 239*55104Storek */ 240*55104Storek (void) splhigh(); 241*55104Storek (*putc)(c & 0177); 242*55104Storek (void) spltty(); 243*55104Storek } 244*55104Storek if (tp->t_state & TS_ASLEEP) { /* can't happen? */ 245*55104Storek tp->t_state &= ~TS_ASLEEP; 246*55104Storek wakeup((caddr_t)&tp->t_outq); 247*55104Storek } 248*55104Storek selwakeup(&tp->t_wsel); 249*55104Storek splx(s); 250*55104Storek } 251*55104Storek 252*55104Storek /* 253*55104Storek * Frame buffer output. 254*55104Storek * We use pseudo-DMA, via the ROM `write string' function, called from 255*55104Storek * software clock interrupts. 256*55104Storek */ 257*55104Storek static void 258*55104Storek cnfbstart(tp) 259*55104Storek register struct tty *tp; 260*55104Storek { 261*55104Storek register int s; 262*55104Storek 263*55104Storek s = spltty(); /* paranoid: splsoftclock should suffice */ 264*55104Storek if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 265*55104Storek splx(s); 266*55104Storek return; 267*55104Storek } 268*55104Storek /* 269*55104Storek * If there are sleepers, and output has drained below low 270*55104Storek * water mark, awaken. 271*55104Storek */ 272*55104Storek if (tp->t_outq.c_cc <= tp->t_lowat) { 273*55104Storek if (tp->t_state & TS_ASLEEP) { 274*55104Storek tp->t_state &= ~TS_ASLEEP; 275*55104Storek wakeup((caddr_t)&tp->t_outq); 276*55104Storek } 277*55104Storek selwakeup(&tp->t_wsel); 278*55104Storek } 279*55104Storek if (tp->t_outq.c_cc) { 280*55104Storek tp->t_state |= TS_BUSY; 281*55104Storek if (s == 0) { 282*55104Storek (void) splsoftclock(); 283*55104Storek cnfbdma((void *)tp); 284*55104Storek } else 285*55104Storek timeout(cnfbdma, tp, 1); 286*55104Storek } 287*55104Storek splx(s); 288*55104Storek } 289*55104Storek 290*55104Storek /* 291*55104Storek * Stop frame buffer output: just assert TS_FLUSH if necessary. 292*55104Storek */ 293*55104Storek static void 294*55104Storek cnfbstop(tp, flag) 295*55104Storek register struct tty *tp; 296*55104Storek int flag; 297*55104Storek { 298*55104Storek register int s = spltty(); /* paranoid */ 299*55104Storek 300*55104Storek if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY) 301*55104Storek tp->t_state |= TS_FLUSH; 302*55104Storek splx(s); 303*55104Storek } 304*55104Storek 305*55104Storek /* 306*55104Storek * Do pseudo-dma (called from software interrupt). 307*55104Storek */ 308*55104Storek static void 309*55104Storek cnfbdma(tpaddr) 310*55104Storek void *tpaddr; 311*55104Storek { 312*55104Storek register struct tty *tp = tpaddr; 313*55104Storek register char *p, *q; 314*55104Storek register int n, c, s; 315*55104Storek 316*55104Storek s = spltty(); /* paranoid */ 317*55104Storek if (tp->t_state & TS_FLUSH) { 318*55104Storek tp->t_state &= ~(TS_BUSY | TS_FLUSH); 319*55104Storek splx(s); 320*55104Storek } else { 321*55104Storek tp->t_state &= ~TS_BUSY; 322*55104Storek splx(s); 323*55104Storek p = tp->t_outq.c_cf; 324*55104Storek n = ndqb(&tp->t_outq, 0); 325*55104Storek for (q = p, c = n; --c >= 0; q++) 326*55104Storek if (*q & 0200) /* high bits seem to be bad */ 327*55104Storek *q &= ~0200; 328*55104Storek (*promvec->pv_putstr)(p, n); 329*55104Storek ndflush(&tp->t_outq, n); 330*55104Storek } 331*55104Storek if (tp->t_line) 332*55104Storek (*linesw[tp->t_line].l_start)(tp); 333*55104Storek else 334*55104Storek cnfbstart(tp); 335*55104Storek } 336*55104Storek 337*55104Storek /* 338*55104Storek * The following is for rom console input. The rom will not call 339*55104Storek * an `interrupt' routine on console input ready, so we must poll. 340*55104Storek * This is all rather sad. 341*55104Storek */ 342*55104Storek volatile int cn_rxc; /* XXX receive `silo' */ 343*55104Storek 344*55104Storek /* called from hardclock, which is above spltty, so no tty calls! */ 345*55104Storek cnrom() 346*55104Storek { 347*55104Storek register int c; 348*55104Storek 349*55104Storek if (cn_rxc >= 0) 350*55104Storek return (1); 351*55104Storek if ((c = (*promvec->pv_nbgetchar)()) < 0) 352*55104Storek return (0); 353*55104Storek cn_rxc = c; 354*55104Storek return (1); 355*55104Storek } 356*55104Storek 357*55104Storek /* pseudo console software interrupt scheduled when cnrom() returns 1 */ 358*55104Storek cnrint() 359*55104Storek { 360*55104Storek register struct tty *tp; 361*55104Storek register int c, s; 362*55104Storek 363*55104Storek s = splclock(); 364*55104Storek c = cn_rxc; 365*55104Storek cn_rxc = -1; 366*55104Storek splx(s); 367*55104Storek if (c < 0) 368*55104Storek return; 369*55104Storek tp = &cons; 370*55104Storek if ((tp->t_cflag & CSIZE) == CS7) { 371*55104Storek /* XXX this should be done elsewhere, if at all */ 372*55104Storek if (tp->t_cflag & PARENB) 373*55104Storek if (tp->t_cflag & PARODD ? 374*55104Storek (partab[c & 0177] & 0200) == (c & 0200) : 375*55104Storek (partab[c & 0177] & 0200) != (c & 0200)) 376*55104Storek c |= TTY_PE; 377*55104Storek c &= ~0200; 378*55104Storek } 379*55104Storek (*linesw[tp->t_line].l_rint)(c, tp); 380*55104Storek } 381*55104Storek 382*55104Storek cngetc() 383*55104Storek { 384*55104Storek register int s, c; 385*55104Storek 386*55104Storek s = splhigh(); 387*55104Storek c = (*promvec->pv_getchar)(); 388*55104Storek splx(s); 389*55104Storek if (c == '\r') 390*55104Storek c = '\n'; 391*55104Storek return (c); 392*55104Storek } 393*55104Storek 394*55104Storek cnputc(c) 395*55104Storek register int c; 396*55104Storek { 397*55104Storek register int s = splhigh(); 398*55104Storek 399*55104Storek if (c == '\n') 400*55104Storek (*promvec->pv_putchar)('\r'); 401*55104Storek (*promvec->pv_putchar)(c); 402*55104Storek splx(s); 403*55104Storek } 404