1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * 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 Laboratories. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)cons.c 7.3 (Berkeley) 10/11/92 17 * 18 * from: $Header: cons.c,v 1.10 92/07/10 00:02:42 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 char partab[]; 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 ttsetwater(tp); 137 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 138 return (EBUSY); 139 return ((*linesw[tp->t_line].l_open)(dev, tp)); 140 } 141 142 /* ARGSUSED */ 143 cnclose(dev, flag, mode, p) 144 dev_t dev; 145 int flag, mode; 146 struct proc *p; 147 { 148 register struct tty *tp = &cons; 149 150 (*linesw[tp->t_line].l_close)(tp, flag); 151 ttyclose(tp); 152 return (0); 153 } 154 155 /* ARGSUSED */ 156 cnread(dev, uio, flag) 157 dev_t dev; 158 struct uio *uio; 159 int flag; 160 { 161 register struct tty *tp = &cons; 162 163 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 164 } 165 166 /* ARGSUSED */ 167 cnwrite(dev, uio, flag) 168 dev_t dev; 169 struct uio *uio; 170 int flag; 171 { 172 register struct tty *tp; 173 174 if ((tp = constty) == NULL || 175 (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN)) 176 tp = &cons; 177 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 178 } 179 180 cnioctl(dev, cmd, data, flag, p) 181 dev_t dev; 182 int cmd; 183 caddr_t data; 184 int flag; 185 struct proc *p; 186 { 187 register struct tty *tp; 188 int error; 189 190 /* 191 * Superuser can always use this to wrest control of console 192 * output from the "virtual" console. 193 */ 194 if (cmd == TIOCCONS && constty) { 195 error = suser(p->p_ucred, (u_short *)NULL); 196 if (error) 197 return (error); 198 constty = NULL; 199 return (0); 200 } 201 tp = &cons; 202 if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0) 203 return (error); 204 if ((error = ttioctl(tp, cmd, data, flag)) >= 0) 205 return (error); 206 return (ENOTTY); 207 } 208 209 cnselect(dev, which, p) 210 dev_t dev; 211 int which; 212 struct proc *p; 213 { 214 215 return (ttselect(makedev(major(dev), 0), which, p)); 216 } 217 218 /* 219 * The rest of this code is run only when we are using the ROM vectors. 220 */ 221 222 /* 223 * Generic output. We just call putchar. (Very bad for performance.) 224 */ 225 static void 226 cnstart(tp) 227 register struct tty *tp; 228 { 229 register int c, s; 230 register void (*putc)(int); 231 232 s = spltty(); 233 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 234 splx(s); 235 return; 236 } 237 putc = promvec->pv_putchar; 238 while (tp->t_outq.c_cc) { 239 c = getc(&tp->t_outq); 240 /* 241 * *%&!*& ROM monitor console putchar is not reentrant! 242 * splhigh/tty around it so as not to run so long with 243 * clock interrupts blocked. 244 */ 245 (void) splhigh(); 246 (*putc)(c & 0177); 247 (void) spltty(); 248 } 249 if (tp->t_state & TS_ASLEEP) { /* can't happen? */ 250 tp->t_state &= ~TS_ASLEEP; 251 wakeup((caddr_t)&tp->t_outq); 252 } 253 selwakeup(&tp->t_wsel); 254 splx(s); 255 } 256 257 /* 258 * Frame buffer output. 259 * We use pseudo-DMA, via the ROM `write string' function, called from 260 * software clock interrupts. 261 */ 262 static void 263 cnfbstart(tp) 264 register struct tty *tp; 265 { 266 register int s; 267 268 s = spltty(); /* paranoid: splsoftclock should suffice */ 269 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 270 splx(s); 271 return; 272 } 273 /* 274 * If there are sleepers, and output has drained below low 275 * water mark, awaken. 276 */ 277 if (tp->t_outq.c_cc <= tp->t_lowat) { 278 if (tp->t_state & TS_ASLEEP) { 279 tp->t_state &= ~TS_ASLEEP; 280 wakeup((caddr_t)&tp->t_outq); 281 } 282 selwakeup(&tp->t_wsel); 283 } 284 if (tp->t_outq.c_cc) { 285 tp->t_state |= TS_BUSY; 286 if (s == 0) { 287 (void) splsoftclock(); 288 cnfbdma((void *)tp); 289 } else 290 timeout(cnfbdma, tp, 1); 291 } 292 splx(s); 293 } 294 295 /* 296 * Stop frame buffer output: just assert TS_FLUSH if necessary. 297 */ 298 static void 299 cnfbstop(tp, flag) 300 register struct tty *tp; 301 int flag; 302 { 303 register int s = spltty(); /* paranoid */ 304 305 if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY) 306 tp->t_state |= TS_FLUSH; 307 splx(s); 308 } 309 310 /* 311 * Do pseudo-dma (called from software interrupt). 312 */ 313 static void 314 cnfbdma(tpaddr) 315 void *tpaddr; 316 { 317 register struct tty *tp = tpaddr; 318 register char *p, *q; 319 register int n, c, s; 320 321 s = spltty(); /* paranoid */ 322 if (tp->t_state & TS_FLUSH) { 323 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 324 splx(s); 325 } else { 326 tp->t_state &= ~TS_BUSY; 327 splx(s); 328 p = tp->t_outq.c_cf; 329 n = ndqb(&tp->t_outq, 0); 330 for (q = p, c = n; --c >= 0; q++) 331 if (*q & 0200) /* high bits seem to be bad */ 332 *q &= ~0200; 333 (*promvec->pv_putstr)(p, n); 334 ndflush(&tp->t_outq, n); 335 } 336 if (tp->t_line) 337 (*linesw[tp->t_line].l_start)(tp); 338 else 339 cnfbstart(tp); 340 } 341 342 /* 343 * The following is for rom console input. The rom will not call 344 * an `interrupt' routine on console input ready, so we must poll. 345 * This is all rather sad. 346 */ 347 volatile int cn_rxc; /* XXX receive `silo' */ 348 349 /* called from hardclock, which is above spltty, so no tty calls! */ 350 cnrom() 351 { 352 register int c; 353 354 if (cn_rxc >= 0) 355 return (1); 356 if ((c = (*promvec->pv_nbgetchar)()) < 0) 357 return (0); 358 cn_rxc = c; 359 return (1); 360 } 361 362 /* pseudo console software interrupt scheduled when cnrom() returns 1 */ 363 cnrint() 364 { 365 register struct tty *tp; 366 register int c, s; 367 368 s = splclock(); 369 c = cn_rxc; 370 cn_rxc = -1; 371 splx(s); 372 if (c < 0) 373 return; 374 tp = &cons; 375 if ((tp->t_cflag & CSIZE) == CS7) { 376 /* XXX this should be done elsewhere, if at all */ 377 if (tp->t_cflag & PARENB) 378 if (tp->t_cflag & PARODD ? 379 (partab[c & 0177] & 0200) == (c & 0200) : 380 (partab[c & 0177] & 0200) != (c & 0200)) 381 c |= TTY_PE; 382 c &= ~0200; 383 } 384 (*linesw[tp->t_line].l_rint)(c, tp); 385 } 386 387 cngetc() 388 { 389 register int s, c; 390 391 s = splhigh(); 392 c = (*promvec->pv_getchar)(); 393 splx(s); 394 if (c == '\r') 395 c = '\n'; 396 return (c); 397 } 398 399 cnputc(c) 400 register int c; 401 { 402 register int s = splhigh(); 403 404 if (c == '\n') 405 (*promvec->pv_putchar)('\r'); 406 (*promvec->pv_putchar)(c); 407 splx(s); 408 } 409