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