1 /* $NetBSD: kd.c,v 1.41 2003/07/15 03:36:15 lukem 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/cdefs.h> 49 __KERNEL_RCSID(0, "$NetBSD: kd.c,v 1.41 2003/07/15 03:36:15 lukem Exp $"); 50 51 #include <sys/param.h> 52 #include <sys/proc.h> 53 #include <sys/systm.h> 54 #include <sys/ioctl.h> 55 #include <sys/tty.h> 56 #include <sys/file.h> 57 #include <sys/conf.h> 58 #include <sys/device.h> 59 60 #include <machine/autoconf.h> 61 #include <machine/mon.h> 62 #include <machine/psl.h> 63 64 #include <dev/cons.h> 65 #include <dev/sun/event_var.h> 66 #include <dev/sun/kbd_xlate.h> 67 #include <dev/sun/kbdvar.h> 68 #include <sun3/dev/zs_cons.h> 69 70 #include "fb.h" 71 72 extern void fb_unblank __P((void)); /* XXX */ 73 74 #define PUT_WSIZE 64 75 76 struct kd_softc { 77 struct device kd_dev; /* required first: base device */ 78 struct tty *kd_tty; 79 80 /* Console input hook */ 81 struct cons_channel *kd_in; 82 }; 83 84 /* 85 * There is no point in pretending there might be 86 * more than one keyboard/display device. 87 */ 88 static struct kd_softc kd_softc; 89 static int kd_is_console; 90 91 static int kdparam(struct tty *, struct termios *); 92 static void kdstart(struct tty *); 93 static void kd_init __P((struct kd_softc *)); 94 static void kd_cons_input __P((int)); 95 96 dev_type_open(kdopen); 97 dev_type_close(kdclose); 98 dev_type_read(kdread); 99 dev_type_write(kdwrite); 100 dev_type_ioctl(kdioctl); 101 dev_type_tty(kdtty); 102 dev_type_poll(kdpoll); 103 104 const struct cdevsw kd_cdevsw = { 105 kdopen, kdclose, kdread, kdwrite, kdioctl, 106 nostop, kdtty, kdpoll, nommap, ttykqfilter, D_TTY 107 }; 108 109 /* 110 * Prepare the console tty; called on first open of /dev/console 111 */ 112 void 113 kd_init(kd) 114 struct kd_softc *kd; 115 { 116 struct tty *tp; 117 118 tp = ttymalloc(); 119 tp->t_oproc = kdstart; 120 tp->t_param = kdparam; 121 tp->t_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 122 123 tty_attach(tp); 124 kd->kd_tty = tp; 125 126 return; 127 } 128 129 struct tty * 130 kdtty(dev) 131 dev_t dev; 132 { 133 struct kd_softc *kd; 134 135 kd = &kd_softc; /* XXX */ 136 return (kd->kd_tty); 137 } 138 139 int 140 kdopen(dev, flag, mode, p) 141 dev_t dev; 142 int flag, mode; 143 struct proc *p; 144 { 145 struct kd_softc *kd; 146 int error, s, unit; 147 struct tty *tp; 148 static int firstopen = 1; 149 150 unit = minor(dev); 151 if (unit != 0) 152 return ENXIO; 153 kd = &kd_softc; /* XXX */ 154 if (firstopen) { 155 kd_init(kd); 156 firstopen = 0; 157 } 158 tp = kd->kd_tty; 159 160 /* It's simpler to do this up here. */ 161 if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) 162 == (TS_ISOPEN | TS_XCLUDE)) 163 && (p->p_ucred->cr_uid != 0) ) 164 { 165 return (EBUSY); 166 } 167 168 s = spltty(); 169 170 if ((tp->t_state & TS_ISOPEN) == 0) { 171 /* First open. */ 172 173 /* Notify the input device that serves us */ 174 struct cons_channel *cc = kd->kd_in; 175 if (cc != NULL && 176 (error = (*cc->cc_iopen)(cc)) != 0) { 177 return (error); 178 } 179 180 ttychars(tp); 181 tp->t_iflag = TTYDEF_IFLAG; 182 tp->t_oflag = TTYDEF_OFLAG; 183 tp->t_cflag = TTYDEF_CFLAG; 184 tp->t_lflag = TTYDEF_LFLAG; 185 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 186 (void) kdparam(tp, &tp->t_termios); 187 ttsetwater(tp); 188 /* Flush pending input? Clear translator? */ 189 /* This (pseudo)device always has SOFTCAR */ 190 tp->t_state |= TS_CARR_ON; 191 } 192 193 splx(s); 194 195 return ((*tp->t_linesw->l_open)(dev, tp)); 196 } 197 198 int 199 kdclose(dev, flag, mode, p) 200 dev_t dev; 201 int flag, mode; 202 struct proc *p; 203 { 204 struct kd_softc *kd; 205 struct tty *tp; 206 struct cons_channel *cc; 207 208 kd = &kd_softc; /* XXX */ 209 tp = kd->kd_tty; 210 211 /* XXX This is for cons.c. */ 212 if ((tp->t_state & TS_ISOPEN) == 0) 213 return 0; 214 215 (*tp->t_linesw->l_close)(tp, flag); 216 ttyclose(tp); 217 if ((cc = kd->kd_in) != NULL) 218 (void)(*cc->cc_iclose)(cc); 219 return (0); 220 } 221 222 int 223 kdread(dev, uio, flag) 224 dev_t dev; 225 struct uio *uio; 226 int flag; 227 { 228 struct kd_softc *kd; 229 struct tty *tp; 230 231 kd = &kd_softc; /* XXX */ 232 tp = kd->kd_tty; 233 234 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 235 } 236 237 int 238 kdwrite(dev, uio, flag) 239 dev_t dev; 240 struct uio *uio; 241 int flag; 242 { 243 struct kd_softc *kd; 244 struct tty *tp; 245 246 kd = &kd_softc; /* XXX */ 247 tp = kd->kd_tty; 248 249 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 250 } 251 252 int 253 kdpoll(dev, events, p) 254 dev_t dev; 255 int events; 256 struct proc *p; 257 { 258 struct kd_softc *kd; 259 struct tty *tp; 260 261 kd = &kd_softc; /* XXX */ 262 tp = kd->kd_tty; 263 264 return ((*tp->t_linesw->l_poll)(tp, events, p)); 265 } 266 267 int 268 kdioctl(dev, cmd, data, flag, p) 269 dev_t dev; 270 u_long cmd; 271 caddr_t data; 272 int flag; 273 struct proc *p; 274 { 275 struct kd_softc *kd; 276 struct tty *tp; 277 int error; 278 279 kd = &kd_softc; /* XXX */ 280 tp = kd->kd_tty; 281 282 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 283 if (error != EPASSTHROUGH) 284 return error; 285 286 error = ttioctl(tp, cmd, data, flag, p); 287 if (error != EPASSTHROUGH) 288 return error; 289 290 /* Handle any ioctl commands specific to kbd/display. */ 291 /* XXX - Send KB* ioctls to kbd module? */ 292 /* XXX - Send FB* ioctls to fb module? */ 293 294 return EPASSTHROUGH; 295 } 296 297 static int 298 kdparam(tp, t) 299 struct tty *tp; 300 struct termios *t; 301 { 302 /* XXX - These are ignored... */ 303 tp->t_ispeed = t->c_ispeed; 304 tp->t_ospeed = t->c_ospeed; 305 tp->t_cflag = t->c_cflag; 306 return 0; 307 } 308 309 310 static void kd_later(void*); 311 static void kd_putfb(struct tty *); 312 313 static void 314 kdstart(tp) 315 struct tty *tp; 316 { 317 struct clist *cl; 318 int s; 319 320 s = spltty(); 321 if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 322 goto out; 323 324 cl = &tp->t_outq; 325 if (cl->c_cc) { 326 if (kd_is_console) { 327 tp->t_state |= TS_BUSY; 328 if ((s & PSL_IPL) == 0) { 329 /* called at level zero - update screen now. */ 330 (void) spllowersoftclock(); 331 kd_putfb(tp); 332 (void) spltty(); 333 tp->t_state &= ~TS_BUSY; 334 } else { 335 /* called at interrupt level - do it later */ 336 callout_reset(&tp->t_rstrt_ch, 0, 337 kd_later, tp); 338 } 339 } else { 340 /* 341 * This driver uses the PROM for writing the screen, 342 * and that only works if this is the console device. 343 * If this is not the console, just flush the output. 344 * Sorry. (In that case, use xdm instead of getty.) 345 */ 346 ndflush(cl, cl->c_cc); 347 } 348 } 349 if (cl->c_cc <= tp->t_lowat) { 350 if (tp->t_state & TS_ASLEEP) { 351 tp->t_state &= ~TS_ASLEEP; 352 wakeup((caddr_t)cl); 353 } 354 selwakeup(&tp->t_wsel); 355 } 356 out: 357 splx(s); 358 } 359 360 /* 361 * Timeout function to do delayed writes to the screen. 362 * Called at splsoftclock when requested by kdstart. 363 */ 364 static void 365 kd_later(tpaddr) 366 void *tpaddr; 367 { 368 struct tty *tp = tpaddr; 369 int s; 370 371 kd_putfb(tp); 372 373 s = spltty(); 374 tp->t_state &= ~TS_BUSY; 375 (*tp->t_linesw->l_start)(tp); 376 splx(s); 377 } 378 379 /* 380 * Put text on the screen using the PROM monitor. 381 * This can take a while, so to avoid missing 382 * interrupts, this is called at splsoftclock. 383 */ 384 static void 385 kd_putfb(tp) 386 struct tty *tp; 387 { 388 char buf[PUT_WSIZE]; 389 struct clist *cl = &tp->t_outq; 390 char *p, *end; 391 int len; 392 393 while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) { 394 /* PROM will barf if high bits are set. */ 395 p = buf; 396 end = buf + len; 397 while (p < end) 398 *p++ &= 0x7f; 399 (romVectorPtr->fbWriteStr)(buf, len); 400 } 401 } 402 403 void 404 cons_attach_input(cc, cn) 405 struct cons_channel *cc; 406 struct consdev *cn; 407 { 408 struct kd_softc *kd = &kd_softc; 409 410 kd->kd_in = cc; 411 cc->cc_upstream = kd_cons_input; 412 } 413 414 /* 415 * Default PROM-based console input stream 416 */ 417 static int kd_rom_iopen __P((struct cons_channel *)); 418 static int kd_rom_iclose __P((struct cons_channel *)); 419 420 static struct cons_channel prom_cons_channel; 421 422 int 423 kd_rom_iopen(cc) 424 struct cons_channel *cc; 425 { 426 /* No-op */ 427 return (0); 428 } 429 430 int 431 kd_rom_iclose(cc) 432 struct cons_channel *cc; 433 { 434 /* No-op */ 435 return (0); 436 } 437 438 /* 439 * Our "interrupt" routine for input. This is called by 440 * the keyboard driver (dev/sun/kbd.c) at spltty. 441 */ 442 void 443 kd_cons_input(c) 444 int c; 445 { 446 struct kd_softc *kd = &kd_softc; 447 struct tty *tp; 448 449 /* XXX: Make sure the device is open. */ 450 tp = kd->kd_tty; 451 if (tp == NULL) 452 return; 453 if ((tp->t_state & TS_ISOPEN) == 0) 454 return; 455 456 (*tp->t_linesw->l_rint)(c, tp); 457 } 458 459 460 /**************************************************************** 461 * kd console support 462 ****************************************************************/ 463 464 /* The debugger gets its own key translation state. */ 465 static struct kbd_state kdcn_state; 466 467 static void kdcnprobe __P((struct consdev *)); 468 static void kdcninit __P((struct consdev *)); 469 static int kdcngetc __P((dev_t)); 470 static void kdcnputc __P((dev_t, int)); 471 static void kdcnpollc __P((dev_t, int)); 472 473 struct consdev consdev_kd = { 474 kdcnprobe, 475 kdcninit, 476 kdcngetc, 477 kdcnputc, 478 kdcnpollc, 479 NULL, 480 }; 481 482 /* We never call this. */ 483 static void 484 kdcnprobe(cn) 485 struct consdev *cn; 486 { 487 } 488 489 static void 490 kdcninit(cn) 491 struct consdev *cn; 492 { 493 struct kbd_state *ks = &kdcn_state; 494 495 cn->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 496 cn->cn_pri = CN_INTERNAL; 497 498 /* This prepares kbd_translate() */ 499 ks->kbd_id = KBD_MIN_TYPE; 500 kbd_xlate_init(ks); 501 502 /* Set up initial PROM input channel for /dev/console */ 503 prom_cons_channel.cc_dev = NULL; 504 prom_cons_channel.cc_iopen = kd_rom_iopen; 505 prom_cons_channel.cc_iclose = kd_rom_iclose; 506 cons_attach_input(&prom_cons_channel, cn); 507 508 /* Indicate that it is OK to use the PROM fbwrite */ 509 kd_is_console = 1; 510 } 511 512 static int 513 kdcngetc(dev) 514 dev_t dev; 515 { 516 struct kbd_state *ks = &kdcn_state; 517 int code, class, data, keysym; 518 519 for (;;) { 520 code = zs_getc(zs_conschan); 521 keysym = kbd_code_to_keysym(ks, code); 522 class = KEYSYM_CLASS(keysym); 523 524 switch (class) { 525 case KEYSYM_ASCII: 526 goto out; 527 528 case KEYSYM_CLRMOD: 529 case KEYSYM_SETMOD: 530 data = (keysym & 0x1F); 531 /* Only allow ctrl or shift. */ 532 if (data > KBMOD_SHIFT_R) 533 break; 534 data = 1 << data; 535 if (class == KEYSYM_SETMOD) 536 ks->kbd_modbits |= data; 537 else 538 ks->kbd_modbits &= ~data; 539 break; 540 541 case KEYSYM_ALL_UP: 542 /* No toggle keys here. */ 543 ks->kbd_modbits = 0; 544 break; 545 546 default: /* ignore all other keysyms */ 547 break; 548 } 549 } 550 out: 551 return (keysym); 552 } 553 554 static void 555 kdcnputc(dev, c) 556 dev_t dev; 557 int c; 558 { 559 (romVectorPtr->fbWriteChar)(c & 0x7f); 560 } 561 562 static void 563 kdcnpollc(dev, on) 564 dev_t dev; 565 int on; 566 { 567 struct kbd_state *ks = &kdcn_state; 568 569 if (on) { 570 /* Entering debugger. */ 571 #if NFB > 0 572 fb_unblank(); 573 #endif 574 /* Clear shift keys too. */ 575 ks->kbd_modbits = 0; 576 } else { 577 /* Resuming kernel. */ 578 } 579 } 580 581