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