1 /* $NetBSD: zs.c,v 1.72 2003/07/15 03:36:16 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 * Zilog Z8530 Dual UART driver (machine-dependent part) 41 * 42 * Runs two serial lines per chip using slave drivers. 43 * Plain tty/async lines use the zs_async slave. 44 * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves. 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.72 2003/07/15 03:36:16 lukem Exp $"); 49 50 #include "opt_kgdb.h" 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/conf.h> 55 #include <sys/device.h> 56 #include <sys/file.h> 57 #include <sys/ioctl.h> 58 #include <sys/kernel.h> 59 #include <sys/proc.h> 60 #include <sys/tty.h> 61 #include <sys/time.h> 62 #include <sys/syslog.h> 63 64 #include <machine/autoconf.h> 65 #include <machine/cpu.h> 66 #include <machine/mon.h> 67 #include <machine/z8530var.h> 68 69 #include <sun3/sun3/machdep.h> 70 #ifdef _SUN3X_ 71 #include <sun3/sun3x/obio.h> 72 #else 73 #include <sun3/sun3/obio.h> 74 #endif 75 #include <sun3/dev/zs_cons.h> 76 77 #include <dev/cons.h> 78 #include <dev/ic/z8530reg.h> 79 80 #include "kbd.h" /* NKBD */ 81 #include "zsc.h" /* NZSC */ 82 #define NZS NZSC 83 84 /* Make life easier for the initialized arrays here. */ 85 #if NZS < 2 86 #undef NZS 87 #define NZS 2 88 #endif 89 90 /* 91 * Some warts needed by z8530tty.c - 92 * The default parity REALLY needs to be the same as the PROM uses, 93 * or you can not see messages done with printf during boot-up... 94 */ 95 int zs_def_cflag = (CREAD | CS8 | HUPCL); 96 97 /* 98 * The Sun3 provides a 4.9152 MHz clock to the ZS chips. 99 */ 100 #define PCLK (9600 * 512) /* PCLK pin input clock rate */ 101 102 /* 103 * Define interrupt levels. 104 */ 105 #define ZSHARD_PRI 6 /* Wired on the CPU board... */ 106 #define ZSSOFT_PRI 3 /* Want tty pri (4) but this is OK. */ 107 108 #define ZS_DELAY() delay(2) 109 110 /* The layout of this is hardware-dependent (padding, order). */ 111 struct zschan { 112 volatile u_char zc_csr; /* ctrl,status, and indirect access */ 113 u_char zc_xxx0; 114 volatile u_char zc_data; /* data */ 115 u_char zc_xxx1; 116 }; 117 struct zsdevice { 118 /* Yes, they are backwards. */ 119 struct zschan zs_chan_b; 120 struct zschan zs_chan_a; 121 }; 122 123 124 /* Default OBIO addresses. */ 125 static int zs_physaddr[NZS] = { 126 OBIO_ZS_KBD_MS, 127 OBIO_ZS_TTY_AB }; 128 129 /* Saved PROM mappings */ 130 static struct zsdevice *zsaddr[NZS]; 131 132 /* Flags from cninit() */ 133 static int zs_hwflags[NZS][2]; 134 135 /* Default speed for each channel */ 136 static int zs_defspeed[NZS][2] = { 137 { 1200, /* keyboard */ 138 1200 }, /* mouse */ 139 { 9600, /* ttya */ 140 9600 }, /* ttyb */ 141 }; 142 143 static u_char zs_init_reg[16] = { 144 0, /* 0: CMD (reset, etc.) */ 145 0, /* 1: No interrupts yet. */ 146 0x18 + ZSHARD_PRI, /* IVECT */ 147 ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 148 ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, 149 ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 150 0, /* 6: TXSYNC/SYNCLO */ 151 0, /* 7: RXSYNC/SYNCHI */ 152 0, /* 8: alias for data port */ 153 ZSWR9_MASTER_IE, 154 0, /*10: Misc. TX/RX control bits */ 155 ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 156 ((PCLK/32)/9600)-2, /*12: BAUDLO (default=9600) */ 157 0, /*13: BAUDHI (default=9600) */ 158 ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, 159 ZSWR15_BREAK_IE, 160 }; 161 162 163 /* Find PROM mappings (for console support). */ 164 void 165 zs_init() 166 { 167 int i; 168 169 for (i = 0; i < NZS; i++) { 170 zsaddr[i] = (struct zsdevice *) 171 obio_find_mapping(zs_physaddr[i], sizeof(struct zschan)); 172 } 173 } 174 175 struct zschan * 176 zs_get_chan_addr(zs_unit, channel) 177 int zs_unit, channel; 178 { 179 struct zsdevice *addr; 180 struct zschan *zc; 181 182 if (zs_unit >= NZS) 183 return NULL; 184 addr = zsaddr[zs_unit]; 185 if (addr == NULL) 186 return NULL; 187 if (channel == 0) { 188 zc = &addr->zs_chan_a; 189 } else { 190 zc = &addr->zs_chan_b; 191 } 192 return (zc); 193 } 194 195 196 /**************************************************************** 197 * Autoconfig 198 ****************************************************************/ 199 200 /* Definition of the driver for autoconfig. */ 201 static int zs_match __P((struct device *, struct cfdata *, void *)); 202 static void zs_attach __P((struct device *, struct device *, void *)); 203 static int zs_print __P((void *, const char *name)); 204 205 CFATTACH_DECL(zsc, sizeof(struct zsc_softc), 206 zs_match, zs_attach, NULL, NULL); 207 208 extern struct cfdriver zsc_cd; 209 210 static int zshard __P((void *)); 211 static int zssoft __P((void *)); 212 static int zs_get_speed __P((struct zs_chanstate *)); 213 214 215 /* 216 * Is the zs chip present? 217 */ 218 static int 219 zs_match(parent, cf, aux) 220 struct device *parent; 221 struct cfdata *cf; 222 void *aux; 223 { 224 struct confargs *ca = aux; 225 int unit; 226 void *va; 227 228 /* 229 * This driver only supports its wired-in mappings, 230 * because the console support depends on those. 231 */ 232 if (ca->ca_paddr == zs_physaddr[0]) { 233 unit = 0; 234 } else if (ca->ca_paddr == zs_physaddr[1]) { 235 unit = 1; 236 } else { 237 return (0); 238 } 239 240 /* Make sure zs_init() found mappings. */ 241 va = zsaddr[unit]; 242 if (va == NULL) 243 return (0); 244 245 /* This returns -1 on a fault (bus error). */ 246 if (peek_byte(va) == -1) 247 return (0); 248 249 /* Default interrupt priority (always splbio==2) */ 250 if (ca->ca_intpri == -1) 251 ca->ca_intpri = ZSHARD_PRI; 252 253 return (1); 254 } 255 256 /* 257 * Attach a found zs. 258 * 259 * Match slave number to zs unit number, so that misconfiguration will 260 * not set up the keyboard as ttya, etc. 261 */ 262 static void 263 zs_attach(parent, self, aux) 264 struct device *parent; 265 struct device *self; 266 void *aux; 267 { 268 struct zsc_softc *zsc = (void *) self; 269 struct confargs *ca = aux; 270 struct zsc_attach_args zsc_args; 271 volatile struct zschan *zc; 272 struct zs_chanstate *cs; 273 int s, zs_unit, channel; 274 static int didintr; 275 276 zs_unit = zsc->zsc_dev.dv_unit; 277 278 printf(": (softpri %d)\n", ZSSOFT_PRI); 279 280 /* Use the mapping setup by the Sun PROM. */ 281 if (zsaddr[zs_unit] == NULL) 282 panic("zs_attach: zs%d not mapped", zs_unit); 283 284 /* 285 * Initialize software state for each channel. 286 */ 287 for (channel = 0; channel < 2; channel++) { 288 zsc_args.channel = channel; 289 zsc_args.hwflags = zs_hwflags[zs_unit][channel]; 290 cs = &zsc->zsc_cs_store[channel]; 291 zsc->zsc_cs[channel] = cs; 292 293 simple_lock_init(&cs->cs_lock); 294 cs->cs_channel = channel; 295 cs->cs_private = NULL; 296 cs->cs_ops = &zsops_null; 297 cs->cs_brg_clk = PCLK / 16; 298 299 zc = zs_get_chan_addr(zs_unit, channel); 300 cs->cs_reg_csr = &zc->zc_csr; 301 cs->cs_reg_data = &zc->zc_data; 302 303 memcpy(cs->cs_creg, zs_init_reg, 16); 304 memcpy(cs->cs_preg, zs_init_reg, 16); 305 306 /* XXX: Get these from the EEPROM instead? */ 307 /* XXX: See the mvme167 code. Better. */ 308 if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) 309 cs->cs_defspeed = zs_get_speed(cs); 310 else 311 cs->cs_defspeed = zs_defspeed[zs_unit][channel]; 312 cs->cs_defcflag = zs_def_cflag; 313 314 /* Make these correspond to cs_defcflag (-crtscts) */ 315 cs->cs_rr0_dcd = ZSRR0_DCD; 316 cs->cs_rr0_cts = 0; 317 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 318 cs->cs_wr5_rts = 0; 319 320 /* 321 * Clear the master interrupt enable. 322 * The INTENA is common to both channels, 323 * so just do it on the A channel. 324 */ 325 if (channel == 0) { 326 zs_write_reg(cs, 9, 0); 327 } 328 329 /* 330 * Look for a child driver for this channel. 331 * The child attach will setup the hardware. 332 */ 333 if (!config_found(self, (void *)&zsc_args, zs_print)) { 334 /* No sub-driver. Just reset it. */ 335 u_char reset = (channel == 0) ? 336 ZSWR9_A_RESET : ZSWR9_B_RESET; 337 s = splhigh(); 338 zs_write_reg(cs, 9, reset); 339 splx(s); 340 } 341 } 342 343 /* 344 * Now safe to install interrupt handlers. Note the arguments 345 * to the interrupt handlers aren't used. Note, we only do this 346 * once since both SCCs interrupt at the same level and vector. 347 */ 348 if (!didintr) { 349 didintr = 1; 350 isr_add_autovect(zssoft, NULL, ZSSOFT_PRI); 351 isr_add_autovect(zshard, NULL, ca->ca_intpri); 352 } 353 /* XXX; evcnt_attach() ? */ 354 355 /* 356 * Set the master interrupt enable and interrupt vector. 357 * (common to both channels, do it on A) 358 */ 359 cs = zsc->zsc_cs[0]; 360 s = splhigh(); 361 /* interrupt vector */ 362 zs_write_reg(cs, 2, zs_init_reg[2]); 363 /* master interrupt control (enable) */ 364 zs_write_reg(cs, 9, zs_init_reg[9]); 365 splx(s); 366 367 /* 368 * XXX: L1A hack - We would like to be able to break into 369 * the debugger during the rest of autoconfiguration, so 370 * lower interrupts just enough to let zs interrupts in. 371 * This is done after both zs devices are attached. 372 */ 373 if (zs_unit == 1) { 374 (void)spl5(); /* splzs - 1 */ 375 } 376 } 377 378 static int 379 zs_print(aux, name) 380 void *aux; 381 const char *name; 382 { 383 struct zsc_attach_args *args = aux; 384 385 if (name != NULL) 386 aprint_normal("%s: ", name); 387 388 if (args->channel != -1) 389 aprint_normal(" channel %d", args->channel); 390 391 return UNCONF; 392 } 393 394 static volatile int zssoftpending; 395 396 /* 397 * Our ZS chips all share a common, autovectored interrupt, 398 * so we have to look at all of them on each interrupt. 399 */ 400 static int 401 zshard(arg) 402 void *arg; 403 { 404 struct zsc_softc *zsc; 405 int unit, rval, softreq; 406 407 rval = softreq = 0; 408 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 409 zsc = zsc_cd.cd_devs[unit]; 410 if (zsc == NULL) 411 continue; 412 rval |= zsc_intr_hard(zsc); 413 softreq |= zsc->zsc_cs[0]->cs_softreq; 414 softreq |= zsc->zsc_cs[1]->cs_softreq; 415 } 416 417 /* We are at splzs here, so no need to lock. */ 418 if (softreq && (zssoftpending == 0)) { 419 zssoftpending = ZSSOFT_PRI; 420 isr_soft_request(ZSSOFT_PRI); 421 } 422 return (rval); 423 } 424 425 /* 426 * Similar scheme as for zshard (look at all of them) 427 */ 428 static int 429 zssoft(arg) 430 void *arg; 431 { 432 struct zsc_softc *zsc; 433 int s, unit; 434 435 /* This is not the only ISR on this IPL. */ 436 if (zssoftpending == 0) 437 return (0); 438 439 /* 440 * The soft intr. bit will be set by zshard only if 441 * the variable zssoftpending is zero. The order of 442 * these next two statements prevents our clearing 443 * the soft intr bit just after zshard has set it. 444 */ 445 isr_soft_clear(ZSSOFT_PRI); 446 zssoftpending = 0; 447 448 /* Make sure we call the tty layer at spltty. */ 449 s = spltty(); 450 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 451 zsc = zsc_cd.cd_devs[unit]; 452 if (zsc == NULL) 453 continue; 454 (void) zsc_intr_soft(zsc); 455 } 456 splx(s); 457 return (1); 458 } 459 460 461 /* 462 * Compute the current baud rate given a ZS channel. 463 */ 464 static int 465 zs_get_speed(cs) 466 struct zs_chanstate *cs; 467 { 468 int tconst; 469 470 tconst = zs_read_reg(cs, 12); 471 tconst |= zs_read_reg(cs, 13) << 8; 472 return (TCONST_TO_BPS(cs->cs_brg_clk, tconst)); 473 } 474 475 /* 476 * MD functions for setting the baud rate and control modes. 477 */ 478 int 479 zs_set_speed(cs, bps) 480 struct zs_chanstate *cs; 481 int bps; /* bits per second */ 482 { 483 int tconst, real_bps; 484 485 if (bps == 0) 486 return (0); 487 488 #ifdef DIAGNOSTIC 489 if (cs->cs_brg_clk == 0) 490 panic("zs_set_speed"); 491 #endif 492 493 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 494 if (tconst < 0) 495 return (EINVAL); 496 497 /* Convert back to make sure we can do it. */ 498 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 499 500 /* XXX - Allow some tolerance here? */ 501 if (real_bps != bps) 502 return (EINVAL); 503 504 cs->cs_preg[12] = tconst; 505 cs->cs_preg[13] = tconst >> 8; 506 507 /* Caller will stuff the pending registers. */ 508 return (0); 509 } 510 511 int 512 zs_set_modes(cs, cflag) 513 struct zs_chanstate *cs; 514 int cflag; /* bits per second */ 515 { 516 int s; 517 518 /* 519 * Output hardware flow control on the chip is horrendous: 520 * if carrier detect drops, the receiver is disabled, and if 521 * CTS drops, the transmitter is stoped IN MID CHARACTER! 522 * Therefore, NEVER set the HFC bit, and instead use the 523 * status interrupt to detect CTS changes. 524 */ 525 s = splzs(); 526 cs->cs_rr0_pps = 0; 527 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 528 cs->cs_rr0_dcd = 0; 529 if ((cflag & MDMBUF) == 0) 530 cs->cs_rr0_pps = ZSRR0_DCD; 531 } else 532 cs->cs_rr0_dcd = ZSRR0_DCD; 533 if ((cflag & CRTSCTS) != 0) { 534 cs->cs_wr5_dtr = ZSWR5_DTR; 535 cs->cs_wr5_rts = ZSWR5_RTS; 536 cs->cs_rr0_cts = ZSRR0_CTS; 537 } else if ((cflag & MDMBUF) != 0) { 538 cs->cs_wr5_dtr = 0; 539 cs->cs_wr5_rts = ZSWR5_DTR; 540 cs->cs_rr0_cts = ZSRR0_DCD; 541 } else { 542 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 543 cs->cs_wr5_rts = 0; 544 cs->cs_rr0_cts = 0; 545 } 546 splx(s); 547 548 /* Caller will stuff the pending registers. */ 549 return (0); 550 } 551 552 553 /* 554 * Read or write the chip with suitable delays. 555 */ 556 557 u_char 558 zs_read_reg(cs, reg) 559 struct zs_chanstate *cs; 560 u_char reg; 561 { 562 u_char val; 563 564 *cs->cs_reg_csr = reg; 565 ZS_DELAY(); 566 val = *cs->cs_reg_csr; 567 ZS_DELAY(); 568 return val; 569 } 570 571 void 572 zs_write_reg(cs, reg, val) 573 struct zs_chanstate *cs; 574 u_char reg, val; 575 { 576 *cs->cs_reg_csr = reg; 577 ZS_DELAY(); 578 *cs->cs_reg_csr = val; 579 ZS_DELAY(); 580 } 581 582 u_char zs_read_csr(cs) 583 struct zs_chanstate *cs; 584 { 585 u_char val; 586 587 val = *cs->cs_reg_csr; 588 ZS_DELAY(); 589 return val; 590 } 591 592 void zs_write_csr(cs, val) 593 struct zs_chanstate *cs; 594 u_char val; 595 { 596 *cs->cs_reg_csr = val; 597 ZS_DELAY(); 598 } 599 600 u_char zs_read_data(cs) 601 struct zs_chanstate *cs; 602 { 603 u_char val; 604 605 val = *cs->cs_reg_data; 606 ZS_DELAY(); 607 return val; 608 } 609 610 void zs_write_data(cs, val) 611 struct zs_chanstate *cs; 612 u_char val; 613 { 614 *cs->cs_reg_data = val; 615 ZS_DELAY(); 616 } 617 618 /**************************************************************** 619 * Console support functions (Sun3 specific!) 620 * Note: this code is allowed to know about the layout of 621 * the chip registers, and uses that to keep things simple. 622 * XXX - I think I like the mvme167 code better. -gwr 623 ****************************************************************/ 624 625 void *zs_conschan; 626 627 /* 628 * Handle user request to enter kernel debugger. 629 */ 630 void 631 zs_abort(cs) 632 struct zs_chanstate *cs; 633 { 634 volatile struct zschan *zc = zs_conschan; 635 int rr0; 636 637 /* Wait for end of break to avoid PROM abort. */ 638 /* XXX - Limit the wait? */ 639 do { 640 rr0 = zc->zc_csr; 641 ZS_DELAY(); 642 } while (rr0 & ZSRR0_BREAK); 643 644 /* This is always available on the Sun3. */ 645 Debugger(); 646 } 647 648 /* 649 * Polled input char. 650 */ 651 int 652 zs_getc(arg) 653 void *arg; 654 { 655 volatile struct zschan *zc = arg; 656 int s, c, rr0; 657 658 s = splhigh(); 659 /* Wait for a character to arrive. */ 660 do { 661 rr0 = zc->zc_csr; 662 ZS_DELAY(); 663 } while ((rr0 & ZSRR0_RX_READY) == 0); 664 665 c = zc->zc_data; 666 ZS_DELAY(); 667 splx(s); 668 669 /* 670 * This is used by the kd driver to read scan codes, 671 * so don't translate '\r' ==> '\n' here... 672 */ 673 return (c); 674 } 675 676 /* 677 * Polled output char. 678 */ 679 void 680 zs_putc(arg, c) 681 void *arg; 682 int c; 683 { 684 volatile struct zschan *zc = arg; 685 int s, rr0; 686 687 s = splhigh(); 688 /* Wait for transmitter to become ready. */ 689 do { 690 rr0 = zc->zc_csr; 691 ZS_DELAY(); 692 } while ((rr0 & ZSRR0_TX_READY) == 0); 693 694 zc->zc_data = c; 695 ZS_DELAY(); 696 splx(s); 697 } 698 699 /*****************************************************************/ 700 701 static void zscninit __P((struct consdev *)); 702 static int zscngetc __P((dev_t)); 703 static void zscnputc __P((dev_t, int)); 704 705 /* 706 * Console table shared by ttya, ttyb 707 */ 708 struct consdev consdev_tty = { 709 nullcnprobe, 710 zscninit, 711 zscngetc, 712 zscnputc, 713 nullcnpollc, 714 NULL, 715 }; 716 717 static void 718 zscninit(cn) 719 struct consdev *cn; 720 { 721 } 722 723 /* 724 * Polled console input putchar. 725 */ 726 static int 727 zscngetc(dev) 728 dev_t dev; 729 { 730 return (zs_getc(zs_conschan)); 731 } 732 733 /* 734 * Polled console output putchar. 735 */ 736 static void 737 zscnputc(dev, c) 738 dev_t dev; 739 int c; 740 { 741 zs_putc(zs_conschan, c); 742 } 743 744 /*****************************************************************/ 745 746 static void prom_cninit __P((struct consdev *)); 747 static int prom_cngetc __P((dev_t)); 748 static void prom_cnputc __P((dev_t, int)); 749 750 /* 751 * The console is set to this one initially, 752 * which lets us use the PROM until consinit() 753 * is called to select a real console. 754 */ 755 struct consdev consdev_prom = { 756 nullcnprobe, 757 prom_cninit, 758 prom_cngetc, 759 prom_cnputc, 760 nullcnpollc, 761 }; 762 763 /* 764 * The console table pointer is statically initialized 765 * to point to the PROM (output only) table, so that 766 * early calls to printf will work. 767 */ 768 struct consdev *cn_tab = &consdev_prom; 769 770 void 771 nullcnprobe(cn) 772 struct consdev *cn; 773 { 774 } 775 776 static void 777 prom_cninit(cn) 778 struct consdev *cn; 779 { 780 } 781 782 /* 783 * PROM console input putchar. 784 * (dummy - this is output only) 785 */ 786 static int 787 prom_cngetc(dev) 788 dev_t dev; 789 { 790 return (0); 791 } 792 793 /* 794 * PROM console output putchar. 795 */ 796 static void 797 prom_cnputc(dev, c) 798 dev_t dev; 799 int c; 800 { 801 (*romVectorPtr->putChar)(c & 0x7f); 802 } 803 804 /*****************************************************************/ 805 806 extern struct consdev consdev_kd; 807 808 static struct { 809 int zs_unit, channel; 810 } zstty_conf[NZS*2] = { 811 /* XXX: knowledge from the config file here... */ 812 { 1, 0 }, /* ttya */ 813 { 1, 1 }, /* ttyb */ 814 { 0, 0 }, /* ttyc */ 815 { 0, 1 }, /* ttyd */ 816 }; 817 818 static char *prom_inSrc_name[] = { 819 "keyboard/display", 820 "ttya", "ttyb", 821 "ttyc", "ttyd" }; 822 823 /* 824 * This function replaces sys/dev/cninit.c 825 * Determine which device is the console using 826 * the PROM "input source" and "output sink". 827 */ 828 void 829 cninit() 830 { 831 struct sunromvec *v; 832 struct zschan *zc; 833 struct consdev *cn; 834 int channel, zs_unit, zstty_unit; 835 u_char inSource, outSink; 836 extern const struct cdevsw zstty_cdevsw; 837 838 /* Get the zs driver ready for console duty. */ 839 zs_init(); 840 841 v = romVectorPtr; 842 inSource = *v->inSource; 843 outSink = *v->outSink; 844 if (inSource != outSink) { 845 mon_printf("cninit: mismatched PROM output selector\n"); 846 } 847 848 switch (inSource) { 849 default: 850 mon_printf("cninit: invalid inSource=%d\n", inSource); 851 sunmon_abort(); 852 inSource = 0; 853 /* fall through */ 854 855 case 0: /* keyboard/display */ 856 #if NKBD > 0 857 zs_unit = 0; 858 channel = 0; 859 cn = &consdev_kd; 860 /* Set cn_dev, cn_pri in kd.c */ 861 break; 862 #else /* NKBD */ 863 mon_printf("cninit: kdb/display not configured\n"); 864 sunmon_abort(); 865 inSource = 1; 866 /* fall through */ 867 #endif /* NKBD */ 868 869 case 1: /* ttya */ 870 case 2: /* ttyb */ 871 case 3: /* ttyc (rewired keyboard connector) */ 872 case 4: /* ttyd (rewired mouse connector) */ 873 zstty_unit = inSource - 1; 874 zs_unit = zstty_conf[zstty_unit].zs_unit; 875 channel = zstty_conf[zstty_unit].channel; 876 cn = &consdev_tty; 877 cn->cn_dev = makedev(cdevsw_lookup_major(&zstty_cdevsw), 878 zstty_unit); 879 cn->cn_pri = CN_REMOTE; 880 break; 881 882 } 883 /* Now that inSource has been validated, print it. */ 884 mon_printf("console is %s\n", prom_inSrc_name[inSource]); 885 886 zc = zs_get_chan_addr(zs_unit, channel); 887 if (zc == NULL) { 888 mon_printf("cninit: zs not mapped.\n"); 889 return; 890 } 891 zs_conschan = zc; 892 zs_hwflags[zs_unit][channel] = ZS_HWFLAG_CONSOLE; 893 cn_tab = cn; 894 (*cn->cn_init)(cn); 895 #ifdef KGDB 896 zs_kgdb_init(); 897 #endif 898 } 899