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