1 /* $NetBSD: kd.c,v 1.24 2002/10/23 09:12:13 jdolecek 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/openfirm.h> 58 #include <machine/eeprom.h> 59 #include <machine/psl.h> 60 #include <machine/cpu.h> 61 #include <machine/kbd.h> 62 #include <machine/autoconf.h> 63 64 #ifdef RASTERCONSOLE 65 #include <dev/sun/fbio.h> 66 #include <machine/fbvar.h> 67 #endif 68 69 70 #include <dev/cons.h> 71 #include <dev/sun/event_var.h> 72 #include <dev/sun/kbd_xlate.h> 73 #include <dev/sun/kbdvar.h> 74 #include <sparc64/dev/cons.h> 75 76 dev_type_open(kdopen); 77 dev_type_close(kdclose); 78 dev_type_read(kdread); 79 dev_type_write(kdwrite); 80 dev_type_ioctl(kdioctl); 81 dev_type_tty(kdtty); 82 dev_type_poll(kdpoll); 83 84 const struct cdevsw kd_cdevsw = { 85 kdopen, kdclose, kdread, kdwrite, kdioctl, 86 nostop, kdtty, kdpoll, nommap, ttykqfilter, D_TTY 87 }; 88 89 struct tty *fbconstty = 0; /* tty structure for frame buffer console */ 90 91 #define PUT_WSIZE 64 92 93 struct kd_softc { 94 struct device kd_dev; /* required first: base device */ 95 struct tty *kd_tty; 96 int rows, cols; 97 98 /* Console input hook */ 99 struct cons_channel *kd_in; 100 }; 101 102 /* 103 * There is no point in pretending there might be 104 * more than one keyboard/display device. 105 */ 106 static struct kd_softc kd_softc; 107 static int kd_is_console; 108 109 static int kdparam(struct tty *, struct termios *); 110 static void kdstart(struct tty *); 111 static void kd_init __P((struct kd_softc *)); 112 static void kd_cons_input __P((int)); 113 static int kdcngetc __P((dev_t)); 114 115 int cons_ocount; /* output byte count */ 116 117 /* 118 * This is called by kbd_attach() 119 * XXX - Make this a proper child of kbd? 120 */ 121 void 122 kd_init(kd) 123 struct kd_softc *kd; 124 { 125 struct tty *tp; 126 int i; 127 char *prop; 128 129 kd = &kd_softc; /* XXX */ 130 131 tp = ttymalloc(); 132 tp->t_oproc = kdstart; 133 tp->t_param = kdparam; 134 tp->t_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 135 136 tty_attach(tp); 137 kd->kd_tty = tp; 138 139 /* 140 * get the console struct winsize. 141 */ 142 if (kd_is_console) { 143 fbconstty = tp; 144 #ifdef RASTERCONSOLE 145 kd->rows = fbrcons_rows(); 146 kd->cols = fbrcons_cols(); 147 rcons_ttyinit(tp); 148 #endif 149 } 150 151 if (kd->rows == 0 && 152 (prop = PROM_getpropstring(optionsnode, "screen-#rows"))) { 153 i = 0; 154 while (*prop != '\0') 155 i = i * 10 + *prop++ - '0'; 156 kd->rows = (unsigned short)i; 157 } 158 if (kd->cols == 0 && 159 (prop = PROM_getpropstring(optionsnode, "screen-#columns"))) { 160 i = 0; 161 while (*prop != '\0') 162 i = i * 10 + *prop++ - '0'; 163 kd->cols = (unsigned short)i; 164 } 165 return; 166 } 167 168 struct tty * 169 kdtty(dev) 170 dev_t dev; 171 { 172 struct kd_softc *kd; 173 174 kd = &kd_softc; /* XXX */ 175 return (kd->kd_tty); 176 } 177 178 int 179 kdopen(dev, flag, mode, p) 180 dev_t dev; 181 int flag, mode; 182 struct proc *p; 183 { 184 struct kd_softc *kd; 185 int error, s, unit; 186 struct tty *tp; 187 static int firstopen = 1; 188 189 unit = minor(dev); 190 if (unit != 0) 191 return ENXIO; 192 kd = &kd_softc; /* XXX */ 193 194 if (firstopen) { 195 kd_init(kd); 196 firstopen = 0; 197 } 198 tp = kd->kd_tty; 199 200 /* It's simpler to do this up here. */ 201 if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) 202 == (TS_ISOPEN | TS_XCLUDE)) 203 && (p->p_ucred->cr_uid != 0) ) 204 { 205 return (EBUSY); 206 } 207 208 s = spltty(); 209 210 if ((tp->t_state & TS_ISOPEN) == 0) { 211 /* First open. */ 212 213 /* Notify the input device that serves us */ 214 struct cons_channel *cc = kd->kd_in; 215 if (cc != NULL && 216 (error = (*cc->cc_iopen)(cc)) != 0) { 217 splx(s); 218 return (error); 219 } 220 221 ttychars(tp); 222 tp->t_iflag = TTYDEF_IFLAG; 223 tp->t_oflag = TTYDEF_OFLAG; 224 tp->t_cflag = TTYDEF_CFLAG; 225 tp->t_lflag = TTYDEF_LFLAG; 226 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 227 (void) kdparam(tp, &tp->t_termios); 228 ttsetwater(tp); 229 tp->t_winsize.ws_row = kd->rows; 230 tp->t_winsize.ws_col = kd->cols; 231 /* Flush pending input? Clear translator? */ 232 /* This (pseudo)device always has SOFTCAR */ 233 tp->t_state |= TS_CARR_ON; 234 } 235 236 splx(s); 237 238 return ((*tp->t_linesw->l_open)(dev, tp)); 239 } 240 241 int 242 kdclose(dev, flag, mode, p) 243 dev_t dev; 244 int flag, mode; 245 struct proc *p; 246 { 247 struct kd_softc *kd; 248 struct tty *tp; 249 struct cons_channel *cc; 250 251 kd = &kd_softc; /* XXX */ 252 tp = kd->kd_tty; 253 254 /* XXX This is for cons.c. */ 255 if ((tp->t_state & TS_ISOPEN) == 0) 256 return 0; 257 258 (*tp->t_linesw->l_close)(tp, flag); 259 ttyclose(tp); 260 261 if ((cc = kd->kd_in) != NULL) 262 (void)(*cc->cc_iclose)(cc); 263 264 return (0); 265 } 266 267 int 268 kdread(dev, uio, flag) 269 dev_t dev; 270 struct uio *uio; 271 int flag; 272 { 273 struct kd_softc *kd; 274 struct tty *tp; 275 276 kd = &kd_softc; /* XXX */ 277 tp = kd->kd_tty; 278 279 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 280 } 281 282 int 283 kdwrite(dev, uio, flag) 284 dev_t dev; 285 struct uio *uio; 286 int flag; 287 { 288 struct kd_softc *kd; 289 struct tty *tp; 290 291 kd = &kd_softc; /* XXX */ 292 tp = kd->kd_tty; 293 294 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 295 } 296 297 int 298 kdpoll(dev, events, p) 299 dev_t dev; 300 int events; 301 struct proc *p; 302 { 303 struct kd_softc *kd; 304 struct tty *tp; 305 306 kd = &kd_softc; /* XXX */ 307 tp = kd->kd_tty; 308 309 return ((*tp->t_linesw->l_poll)(tp, events, p)); 310 } 311 312 int 313 kdioctl(dev, cmd, data, flag, p) 314 dev_t dev; 315 u_long cmd; 316 caddr_t data; 317 int flag; 318 struct proc *p; 319 { 320 struct kd_softc *kd; 321 struct tty *tp; 322 int error; 323 324 kd = &kd_softc; /* XXX */ 325 tp = kd->kd_tty; 326 327 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 328 if (error != EPASSTHROUGH) 329 return error; 330 331 error = ttioctl(tp, cmd, data, flag, p); 332 if (error != EPASSTHROUGH) 333 return error; 334 335 /* Handle any ioctl commands specific to kbd/display. */ 336 /* XXX - Send KB* ioctls to kbd module? */ 337 /* XXX - Send FB* ioctls to fb module? */ 338 339 return EPASSTHROUGH; 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 == 0) { 374 /* called at level zero - update screen now. */ 375 (void) spllowersoftclock(); 376 kd_putfb(tp); 377 (void) spltty(); 378 tp->t_state &= ~TS_BUSY; 379 } else { 380 /* called at interrupt level - do it later */ 381 callout_reset(&tp->t_rstrt_ch, 0, 382 kd_later, tp); 383 } 384 } else { 385 /* 386 * This driver uses the PROM for writing the screen, 387 * and that only works if this is the console device. 388 * If this is not the console, just flush the output. 389 * Sorry. (In that case, use xdm instead of getty.) 390 */ 391 ndflush(cl, cl->c_cc); 392 } 393 } 394 if (cl->c_cc <= tp->t_lowat) { 395 if (tp->t_state & TS_ASLEEP) { 396 tp->t_state &= ~TS_ASLEEP; 397 wakeup((caddr_t)cl); 398 } 399 selwakeup(&tp->t_wsel); 400 } 401 out: 402 splx(s); 403 } 404 405 /* 406 * Timeout function to do delayed writes to the screen. 407 * Called at splsoftclock when requested by kdstart. 408 */ 409 static void 410 kd_later(tpaddr) 411 void *tpaddr; 412 { 413 struct tty *tp = tpaddr; 414 register int s; 415 416 kd_putfb(tp); 417 418 s = spltty(); 419 tp->t_state &= ~TS_BUSY; 420 (*tp->t_linesw->l_start)(tp); 421 splx(s); 422 } 423 424 /* 425 * Put text on the screen using the PROM monitor. 426 * This can take a while, so to avoid missing 427 * interrupts, this is called at splsoftclock. 428 */ 429 static void 430 kd_putfb(tp) 431 struct tty *tp; 432 { 433 char buf[PUT_WSIZE]; 434 struct clist *cl = &tp->t_outq; 435 char *p, *end; 436 int len; 437 438 while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) { 439 /* PROM will barf if high bits are set. */ 440 p = buf; 441 end = buf + len; 442 while (p < end) 443 *p++ &= 0x7f; 444 /* Now let the PROM print it. */ 445 OF_write(OF_stdout(), buf, len); 446 } 447 } 448 449 /* 450 * Default PROM-based console input stream 451 */ 452 static int kd_rom_iopen __P((struct cons_channel *)); 453 static int kd_rom_iclose __P((struct cons_channel *)); 454 455 static struct cons_channel prom_cons_channel; 456 457 int 458 kd_rom_iopen(cc) 459 struct cons_channel *cc; 460 { 461 return (0); 462 } 463 464 int 465 kd_rom_iclose(cc) 466 struct cons_channel *cc; 467 { 468 return (0); 469 } 470 471 /* 472 * Our "interrupt" routine for input. This is called by 473 * the keyboard driver (dev/sun/kbd.c) at spltty. 474 */ 475 void 476 kd_cons_input(c) 477 int c; 478 { 479 struct kd_softc *kd = &kd_softc; 480 struct tty *tp; 481 482 /* XXX: Make sure the device is open. */ 483 tp = kd->kd_tty; 484 if (tp == NULL) 485 return; 486 if ((tp->t_state & TS_ISOPEN) == 0) 487 return; 488 489 (*tp->t_linesw->l_rint)(c, tp); 490 } 491 492 493 /**************************************************************** 494 * kd console support 495 ****************************************************************/ 496 497 /* The debugger gets its own key translation state. */ 498 static struct kbd_state *kdcn_state; 499 500 static void kdcnprobe __P((struct consdev *)); 501 static void kdcninit __P((struct consdev *)); 502 static void kdcnputc __P((dev_t, int)); 503 static void kdcnpollc __P((dev_t, int)); 504 505 /* The keyboard driver uses cn_hw to access the real console driver */ 506 extern struct consdev consdev_prom; 507 struct consdev consdev_kd = { 508 kdcnprobe, 509 kdcninit, 510 kdcngetc, 511 kdcnputc, 512 kdcnpollc, 513 NULL, 514 }; 515 struct consdev *cn_hw = &consdev_kd; 516 517 void 518 cons_attach_input(cc, cn) 519 struct cons_channel *cc; 520 struct consdev *cn; 521 { 522 struct kd_softc *kd = &kd_softc; 523 struct kbd_softc *kds = cc->cc_dev; 524 struct kbd_state *ks; 525 526 /* Share the keyboard state */ 527 kdcn_state = ks = &kds->k_state; 528 529 kd->kd_in = cc; 530 cc->cc_upstream = kd_cons_input; 531 532 /* Attach lower level. */ 533 cn_hw->cn_dev = cn->cn_dev; 534 cn_hw->cn_pollc = cn->cn_pollc; 535 cn_hw->cn_getc = cn->cn_getc; 536 537 /* Attach us as console. */ 538 cn_tab->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 539 cn_tab->cn_probe = kdcnprobe; 540 cn_tab->cn_init = kdcninit; 541 cn_tab->cn_getc = kdcngetc; 542 cn_tab->cn_pollc = kdcnpollc; 543 cn_tab->cn_pri = CN_INTERNAL; 544 545 /* Set up initial PROM input channel for /dev/console */ 546 prom_cons_channel.cc_dev = NULL; 547 prom_cons_channel.cc_iopen = kd_rom_iopen; 548 prom_cons_channel.cc_iclose = kd_rom_iclose; 549 550 /* Indicate that it is OK to use the PROM fbwrite */ 551 kd_is_console = 1; 552 } 553 554 555 void kd_attach_input(struct cons_channel *); 556 void 557 kd_attach_input(cc) 558 struct cons_channel *cc; 559 { 560 struct kd_softc *kd = &kd_softc; 561 562 kd->kd_in = cc; 563 cc->cc_upstream = kd_cons_input; 564 } 565 566 567 /* We never call this. */ 568 static void 569 kdcnprobe(cn) 570 struct consdev *cn; 571 { 572 } 573 574 static void 575 kdcninit(cn) 576 struct consdev *cn; 577 { 578 #if 0 579 struct kbd_state *ks = kdcn_state; 580 581 cn->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 582 cn->cn_pri = CN_INTERNAL; 583 584 /* This prepares kbd_translate() */ 585 ks->kbd_id = KBD_MIN_TYPE; 586 kbd_xlate_init(ks); 587 588 /* Set up initial PROM input channel for /dev/console */ 589 prom_cons_channel.cc_dev = NULL; 590 prom_cons_channel.cc_iopen = kd_rom_iopen; 591 prom_cons_channel.cc_iclose = kd_rom_iclose; 592 cons_attach_input(&prom_cons_channel); 593 594 /* Indicate that it is OK to use the PROM fbwrite */ 595 kd_is_console = 1; 596 #endif 597 } 598 599 static int 600 kdcngetc(dev) 601 dev_t dev; 602 { 603 struct kbd_state *ks = kdcn_state; 604 int code, class, data, keysym; 605 extern int prom_cngetc __P((dev_t)); 606 607 608 if (cn_hw->cn_getc == prom_cngetc) return (*cn_hw->cn_getc)(dev); 609 for (;;) { 610 code = (*cn_hw->cn_getc)(dev); 611 keysym = kbd_code_to_keysym(ks, code); 612 class = KEYSYM_CLASS(keysym); 613 614 switch (class) { 615 case KEYSYM_ASCII: 616 goto out; 617 618 case KEYSYM_CLRMOD: 619 case KEYSYM_SETMOD: 620 data = (keysym & 0x1F); 621 /* Only allow ctrl or shift. */ 622 if (data > KBMOD_SHIFT_R) 623 break; 624 data = 1 << data; 625 if (class == KEYSYM_SETMOD) 626 ks->kbd_modbits |= data; 627 else 628 ks->kbd_modbits &= ~data; 629 break; 630 631 case KEYSYM_ALL_UP: 632 /* No toggle keys here. */ 633 ks->kbd_modbits = 0; 634 break; 635 636 default: /* ignore all other keysyms */ 637 break; 638 } 639 } 640 out: 641 return (keysym); 642 } 643 644 static void 645 kdcnputc(dev, c) 646 dev_t dev; 647 int c; 648 { 649 int s; 650 char c0 = (c & 0x7f); 651 652 s = splhigh(); 653 OF_write(OF_stdout(), &c0, 1); 654 splx(s); 655 } 656 657 static void 658 kdcnpollc(dev, on) 659 dev_t dev; 660 int on; 661 { 662 struct kbd_state *ks = kdcn_state; 663 664 if (on) { 665 /* Entering debugger. */ 666 #if NFB > 0 667 fb_unblank(); 668 #endif 669 /* Clear shift keys too. */ 670 ks->kbd_modbits = 0; 671 } else { 672 /* Resuming kernel. */ 673 } 674 (*cn_hw->cn_pollc)(dev, on); 675 } 676