1 /* $NetBSD: kd.c,v 1.1 1997/10/18 00:00:30 gwr Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Gordon W. Ross. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Keyboard/Display device. 41 * 42 * This driver exists simply to provide a tty device that 43 * the indirect console driver can point to. 44 * The kbd driver sends its input here. 45 * Output goes to the screen via PROM printf. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/proc.h> 50 #include <sys/systm.h> 51 #include <sys/ioctl.h> 52 #include <sys/tty.h> 53 #include <sys/file.h> 54 #include <sys/conf.h> 55 #include <sys/device.h> 56 57 #include <machine/bsd_openprom.h> 58 #include <machine/eeprom.h> 59 #include <machine/psl.h> 60 #include <machine/cpu.h> 61 #include <machine/kbd.h> 62 #if defined(SUN4) 63 #include <machine/oldmon.h> 64 #endif 65 #include <machine/autoconf.h> 66 #include <machine/conf.h> 67 68 #ifdef RASTERCONSOLE 69 #include <machine/fbio.h> 70 #include <machine/fbvar.h> 71 #endif 72 73 74 #include <dev/cons.h> 75 #include <dev/sun/kbd_xlate.h> 76 #include <sparc/dev/cons.h> 77 78 extern void fb_unblank __P((void)); /* XXX */ 79 struct tty *fbconstty = 0; /* tty structure for frame buffer console */ 80 81 #define KDMAJOR 1 82 #define PUT_WSIZE 64 83 84 struct kd_softc { 85 struct device kd_dev; /* required first: base device */ 86 struct tty *kd_tty; 87 int rows, cols; 88 }; 89 90 /* 91 * There is no point in pretending there might be 92 * more than one keyboard/display device. 93 */ 94 static struct kd_softc kd_softc; 95 static int kd_is_console; 96 97 static int kdparam(struct tty *, struct termios *); 98 static void kdstart(struct tty *); 99 100 int rom_console_input; /* when set, hardclock calls cnrom() */ 101 int cons_ocount; /* output byte count */ 102 103 /* Now talking directly to the zs, so this is not needed. */ 104 int 105 cnrom() 106 { 107 return (0); 108 } 109 void 110 cnrint() 111 { 112 } 113 114 /* 115 * This is called by kbd_attach() 116 * XXX - Make this a proper child of kbd? 117 */ 118 void 119 kd_init(unit) 120 int unit; 121 { 122 struct kd_softc *kd; 123 struct tty *tp; 124 125 if (unit != 0) 126 return; 127 kd = &kd_softc; /* XXX */ 128 129 tp = ttymalloc(); 130 tp->t_oproc = kdstart; 131 tp->t_param = kdparam; 132 tp->t_dev = makedev(KDMAJOR, unit); 133 134 #if 1 /* XXX - Why? */ 135 clalloc(&tp->t_rawq, 1024, 1); 136 clalloc(&tp->t_canq, 1024, 1); 137 /* output queue doesn't need quoting */ 138 clalloc(&tp->t_outq, 1024, 0); 139 #endif 140 141 tty_attach(tp); 142 kd->kd_tty = tp; 143 144 /* 145 * get the console struct winsize. 146 */ 147 if (kd_is_console) { 148 fbconstty = tp; 149 #ifdef RASTERCONSOLE 150 kd->rows = fbrcons_rows(); 151 kd->cols = fbrcons_cols(); 152 #endif 153 } 154 155 if (CPU_ISSUN4COR4M) { 156 int i; 157 char *prop; 158 159 if (kd->rows == 0 && 160 (prop = getpropstring(optionsnode, "screen-#rows"))) { 161 i = 0; 162 while (*prop != '\0') 163 i = i * 10 + *prop++ - '0'; 164 kd->rows = (unsigned short)i; 165 } 166 if (kd->cols == 0 && 167 (prop = getpropstring(optionsnode, "screen-#columns"))) { 168 i = 0; 169 while (*prop != '\0') 170 i = i * 10 + *prop++ - '0'; 171 kd->cols = (unsigned short)i; 172 } 173 } 174 if (CPU_ISSUN4) { 175 struct eeprom *ep = (struct eeprom *)eeprom_va; 176 177 if (ep) { 178 if (kd->rows == 0) 179 kd->rows = (u_short)ep->eeTtyRows; 180 if (kd->cols == 0) 181 kd->cols = (u_short)ep->eeTtyCols; 182 } 183 } 184 185 return; 186 } 187 188 struct tty * 189 kdtty(dev) 190 dev_t dev; 191 { 192 struct kd_softc *kd; 193 194 kd = &kd_softc; /* XXX */ 195 return (kd->kd_tty); 196 } 197 198 int 199 kdopen(dev, flag, mode, p) 200 dev_t dev; 201 int flag, mode; 202 struct proc *p; 203 { 204 struct kd_softc *kd; 205 int error, s, unit; 206 struct tty *tp; 207 208 unit = minor(dev); 209 if (unit != 0) 210 return ENXIO; 211 kd = &kd_softc; /* XXX */ 212 tp = kd->kd_tty; 213 214 if ((error = kbd_iopen(unit)) != 0) { 215 #ifdef DIAGNOSTIC 216 printf("kd: kbd_iopen, error=%d\n", error); 217 #endif 218 return (error); 219 } 220 221 /* It's simpler to do this up here. */ 222 if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) 223 == (TS_ISOPEN | TS_XCLUDE)) 224 && (p->p_ucred->cr_uid != 0) ) 225 { 226 return (EBUSY); 227 } 228 229 s = spltty(); 230 231 if ((tp->t_state & TS_ISOPEN) == 0) { 232 /* First open. */ 233 ttychars(tp); 234 tp->t_iflag = TTYDEF_IFLAG; 235 tp->t_oflag = TTYDEF_OFLAG; 236 tp->t_cflag = TTYDEF_CFLAG; 237 tp->t_lflag = TTYDEF_LFLAG; 238 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 239 (void) kdparam(tp, &tp->t_termios); 240 ttsetwater(tp); 241 tp->t_winsize.ws_row = kd->rows; 242 tp->t_winsize.ws_col = kd->cols; 243 /* Flush pending input? Clear translator? */ 244 /* This (pseudo)device always has SOFTCAR */ 245 tp->t_state |= TS_CARR_ON; 246 } 247 248 splx(s); 249 250 return ((*linesw[tp->t_line].l_open)(dev, tp)); 251 } 252 253 int 254 kdclose(dev, flag, mode, p) 255 dev_t dev; 256 int flag, mode; 257 struct proc *p; 258 { 259 struct kd_softc *kd; 260 struct tty *tp; 261 262 kd = &kd_softc; /* XXX */ 263 tp = kd->kd_tty; 264 265 /* XXX This is for cons.c. */ 266 if ((tp->t_state & TS_ISOPEN) == 0) 267 return 0; 268 269 (*linesw[tp->t_line].l_close)(tp, flag); 270 ttyclose(tp); 271 return (0); 272 } 273 274 int 275 kdread(dev, uio, flag) 276 dev_t dev; 277 struct uio *uio; 278 int flag; 279 { 280 struct kd_softc *kd; 281 struct tty *tp; 282 283 kd = &kd_softc; /* XXX */ 284 tp = kd->kd_tty; 285 286 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 287 } 288 289 int 290 kdwrite(dev, uio, flag) 291 dev_t dev; 292 struct uio *uio; 293 int flag; 294 { 295 struct kd_softc *kd; 296 struct tty *tp; 297 298 kd = &kd_softc; /* XXX */ 299 tp = kd->kd_tty; 300 301 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 302 } 303 304 int 305 kdioctl(dev, cmd, data, flag, p) 306 dev_t dev; 307 u_long cmd; 308 caddr_t data; 309 int flag; 310 struct proc *p; 311 { 312 struct kd_softc *kd; 313 struct tty *tp; 314 int error; 315 316 kd = &kd_softc; /* XXX */ 317 tp = kd->kd_tty; 318 319 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 320 if (error >= 0) 321 return error; 322 error = ttioctl(tp, cmd, data, flag, p); 323 if (error >= 0) 324 return error; 325 326 /* Handle any ioctl commands specific to kbd/display. */ 327 /* XXX - Send KB* ioctls to kbd module? */ 328 /* XXX - Send FB* ioctls to fb module? */ 329 330 return ENOTTY; 331 } 332 333 void 334 kdstop(tp, flag) 335 struct tty *tp; 336 int flag; 337 { 338 339 } 340 341 342 static int 343 kdparam(tp, t) 344 struct tty *tp; 345 struct termios *t; 346 { 347 /* XXX - These are ignored... */ 348 tp->t_ispeed = t->c_ispeed; 349 tp->t_ospeed = t->c_ospeed; 350 tp->t_cflag = t->c_cflag; 351 return 0; 352 } 353 354 355 static void kd_later(void*); 356 static void kd_putfb(struct tty *); 357 358 static void 359 kdstart(tp) 360 struct tty *tp; 361 { 362 struct clist *cl; 363 register int s; 364 365 s = spltty(); 366 if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 367 goto out; 368 369 cl = &tp->t_outq; 370 if (cl->c_cc) { 371 if (kd_is_console) { 372 tp->t_state |= TS_BUSY; 373 if ((s & PSR_PIL) == 0) { 374 /* called at level zero - update screen now. */ 375 (void) splsoftclock(); 376 kd_putfb(tp); 377 (void) spltty(); 378 tp->t_state &= ~TS_BUSY; 379 } else { 380 /* called at interrupt level - do it later */ 381 timeout(kd_later, (void*)tp, 0); 382 } 383 } else { 384 /* 385 * This driver uses the PROM for writing the screen, 386 * and that only works if this is the console device. 387 * If this is not the console, just flush the output. 388 * Sorry. (In that case, use xdm instead of getty.) 389 */ 390 ndflush(cl, cl->c_cc); 391 } 392 } 393 if (cl->c_cc <= tp->t_lowat) { 394 if (tp->t_state & TS_ASLEEP) { 395 tp->t_state &= ~TS_ASLEEP; 396 wakeup((caddr_t)cl); 397 } 398 selwakeup(&tp->t_wsel); 399 } 400 out: 401 splx(s); 402 } 403 404 /* 405 * Timeout function to do delayed writes to the screen. 406 * Called at splsoftclock when requested by kdstart. 407 */ 408 static void 409 kd_later(tpaddr) 410 void *tpaddr; 411 { 412 struct tty *tp = tpaddr; 413 register int s; 414 415 kd_putfb(tp); 416 417 s = spltty(); 418 tp->t_state &= ~TS_BUSY; 419 (*linesw[tp->t_line].l_start)(tp); 420 splx(s); 421 } 422 423 /* 424 * Put text on the screen using the PROM monitor. 425 * This can take a while, so to avoid missing 426 * interrupts, this is called at splsoftclock. 427 */ 428 static void 429 kd_putfb(tp) 430 struct tty *tp; 431 { 432 char buf[PUT_WSIZE]; 433 struct clist *cl = &tp->t_outq; 434 char *p, *end; 435 int len; 436 437 while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) { 438 /* PROM will barf if high bits are set. */ 439 p = buf; 440 end = buf + len; 441 while (p < end) 442 *p++ &= 0x7f; 443 /* Now let the PROM print it. */ 444 if (promvec->pv_romvec_vers > 2) { 445 (*promvec->pv_v2devops.v2_write) 446 (*promvec->pv_v2bootargs.v2_fd1, buf, len); 447 } else 448 (*promvec->pv_putstr)(buf, len); 449 } 450 } 451 452 /* 453 * Our "interrupt" routine for input. This is called by 454 * the keyboard driver (dev/sun/kbd.c) at spltty. 455 */ 456 void 457 kd_input(c) 458 int c; 459 { 460 struct kd_softc *kd = &kd_softc; 461 struct tty *tp; 462 463 /* XXX: Make sure the device is open. */ 464 tp = kd->kd_tty; 465 if (tp == NULL) 466 return; 467 if ((tp->t_state & TS_ISOPEN) == 0) 468 return; 469 470 (*linesw[tp->t_line].l_rint)(c, tp); 471 } 472 473 474 /**************************************************************** 475 * kd console support 476 ****************************************************************/ 477 478 /* The debugger gets its own key translation state. */ 479 static struct kbd_state kdcn_state; 480 481 static void kdcnprobe __P((struct consdev *)); 482 static void kdcninit __P((struct consdev *)); 483 static int kdcngetc __P((dev_t)); 484 static void kdcnputc __P((dev_t, int)); 485 static void kdcnpollc __P((dev_t, int)); 486 487 struct consdev consdev_kd = { 488 kdcnprobe, 489 kdcninit, 490 kdcngetc, 491 kdcnputc, 492 kdcnpollc, 493 }; 494 495 /* We never call this. */ 496 static void 497 kdcnprobe(cn) 498 struct consdev *cn; 499 { 500 } 501 502 static void 503 kdcninit(cn) 504 struct consdev *cn; 505 { 506 struct kbd_state *ks = &kdcn_state; 507 508 cn->cn_dev = makedev(KDMAJOR, 0); 509 cn->cn_pri = CN_INTERNAL; 510 511 /* This prepares kbd_translate() */ 512 ks->kbd_id = KBD_MIN_TYPE; 513 kbd_xlate_init(ks); 514 515 /* Indicate that it is OK to use the PROM fbwrite */ 516 kd_is_console = 1; 517 } 518 519 static int 520 kdcngetc(dev) 521 dev_t dev; 522 { 523 struct kbd_state *ks = &kdcn_state; 524 int code, class, data, keysym; 525 526 for (;;) { 527 code = zs_getc(zs_conschan); 528 keysym = kbd_code_to_keysym(ks, code); 529 class = KEYSYM_CLASS(keysym); 530 531 switch (class) { 532 case KEYSYM_ASCII: 533 goto out; 534 535 case KEYSYM_CLRMOD: 536 case KEYSYM_SETMOD: 537 data = (keysym & 0x1F); 538 /* Only allow ctrl or shift. */ 539 if (data > KBMOD_SHIFT_R) 540 break; 541 data = 1 << data; 542 if (class == KEYSYM_SETMOD) 543 ks->kbd_modbits |= data; 544 else 545 ks->kbd_modbits &= ~data; 546 break; 547 548 case KEYSYM_ALL_UP: 549 /* No toggle keys here. */ 550 ks->kbd_modbits = 0; 551 break; 552 553 default: /* ignore all other keysyms */ 554 break; 555 } 556 } 557 out: 558 return (keysym); 559 } 560 561 static void 562 kdcnputc(dev, c) 563 dev_t dev; 564 int c; 565 { 566 char c0 = (c & 0x7f); 567 568 if (promvec->pv_romvec_vers > 2) 569 (*promvec->pv_v2devops.v2_write) 570 (*promvec->pv_v2bootargs.v2_fd1, &c0, 1); 571 else 572 (*promvec->pv_putchar)(c); 573 } 574 575 static void 576 kdcnpollc(dev, on) 577 dev_t dev; 578 int on; 579 { 580 struct kbd_state *ks = &kdcn_state; 581 582 if (on) { 583 /* Entering debugger. */ 584 fb_unblank(); 585 /* Clear shift keys too. */ 586 ks->kbd_modbits = 0; 587 } else { 588 /* Resuming kernel. */ 589 } 590 } 591 592