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