1 /* $OpenBSD: zs.c,v 1.35 2024/09/04 07:54:52 mglocker Exp $ */ 2 /* $NetBSD: zs.c,v 1.29 2001/05/30 15:24:24 lukem Exp $ */ 3 4 /*- 5 * Copyright (c) 1996 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Gordon W. Ross. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Zilog Z8530 Dual UART driver (machine-dependent part) 35 * 36 * Runs two serial lines per chip using slave drivers. 37 * Plain tty/async lines use the zstty slave. 38 * Sun keyboard/mouse uses the zskbd/zsms slaves. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/conf.h> 44 #include <sys/device.h> 45 #include <sys/ioctl.h> 46 #include <sys/kernel.h> 47 #include <sys/proc.h> 48 #include <sys/tty.h> 49 #include <sys/time.h> 50 #include <sys/syslog.h> 51 52 #include <machine/autoconf.h> 53 #include <machine/openfirm.h> 54 #include <machine/conf.h> 55 #include <machine/cpu.h> 56 #include <machine/psl.h> 57 #include <machine/z8530var.h> 58 59 #include <dev/cons.h> 60 #include <dev/ic/z8530reg.h> 61 #include <sparc64/dev/fhcvar.h> 62 #include <ddb/db_output.h> 63 64 #include <sparc64/dev/cons.h> 65 66 struct cfdriver zs_cd = { 67 NULL, "zs", DV_TTY 68 }; 69 70 /* 71 * Some warts needed by z8530tty.c - 72 * The default parity REALLY needs to be the same as the PROM uses, 73 * or you can not see messages done with printf during boot-up... 74 */ 75 int zs_def_cflag = (CREAD | CS8 | HUPCL); 76 int zs_major = 12; 77 78 /* 79 * The Sun provides a 4.9152 MHz clock to the ZS chips. 80 */ 81 #define PCLK (9600 * 512) /* PCLK pin input clock rate */ 82 83 #define ZS_DELAY() 84 85 /* The layout of this is hardware-dependent (padding, order). */ 86 struct zschan { 87 volatile u_char zc_csr; /* ctrl,status, and indirect access */ 88 u_char zc_xxx0; 89 volatile u_char zc_data; /* data */ 90 u_char zc_xxx1; 91 }; 92 struct zsdevice { 93 /* Yes, they are backwards. */ 94 struct zschan zs_chan_b; 95 struct zschan zs_chan_a; 96 }; 97 98 /* ZS channel used as the console device (if any) */ 99 void *zs_conschan_get, *zs_conschan_put; 100 101 static u_char zs_init_reg[16] = { 102 0, /* 0: CMD (reset, etc.) */ 103 0, /* 1: No interrupts yet. */ 104 0, /* 2: IVECT */ 105 ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 106 ZSWR4_CLK_X16 | ZSWR4_ONESB, 107 ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 108 0, /* 6: TXSYNC/SYNCLO */ 109 0, /* 7: RXSYNC/SYNCHI */ 110 0, /* 8: alias for data port */ 111 ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR, 112 0, /*10: Misc. TX/RX control bits */ 113 ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 114 ((PCLK/32)/9600)-2, /*12: BAUDLO (default=9600) */ 115 0, /*13: BAUDHI (default=9600) */ 116 ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, 117 ZSWR15_BREAK_IE, 118 }; 119 120 /* Console ops */ 121 static int zscngetc(dev_t); 122 static void zscnputc(dev_t, int); 123 124 struct consdev zs_consdev = { 125 NULL, 126 NULL, 127 zscngetc, 128 zscnputc, 129 nullcnpollc, 130 NULL, 131 }; 132 133 134 /**************************************************************** 135 * Autoconfig 136 ****************************************************************/ 137 138 /* Definition of the driver for autoconfig. */ 139 static int zs_match_sbus(struct device *, void *, void *); 140 static void zs_attach_sbus(struct device *, struct device *, void *); 141 142 static int zs_match_fhc(struct device *, void *, void *); 143 static void zs_attach_fhc(struct device *, struct device *, void *); 144 145 static void zs_attach(struct zsc_softc *, struct zsdevice *, int); 146 static int zs_print(void *, const char *name); 147 148 const struct cfattach zs_sbus_ca = { 149 sizeof(struct zsc_softc), zs_match_sbus, zs_attach_sbus 150 }; 151 152 const struct cfattach zs_fhc_ca = { 153 sizeof(struct zsc_softc), zs_match_fhc, zs_attach_fhc 154 }; 155 156 /* Interrupt handlers. */ 157 static int zshard(void *); 158 static void zssoft(void *); 159 160 static int zs_get_speed(struct zs_chanstate *); 161 162 /* Console device support */ 163 static int zs_console_flags(int, int, int); 164 165 /* 166 * Is the zs chip present? 167 */ 168 static int 169 zs_match_sbus(struct device *parent, void *vcf, void *aux) 170 { 171 struct cfdata *cf = vcf; 172 struct sbus_attach_args *sa = aux; 173 174 if (strcmp(cf->cf_driver->cd_name, sa->sa_name) != 0) 175 return (0); 176 177 return (1); 178 } 179 180 static int 181 zs_match_fhc(struct device *parent, void *vcf, void *aux) 182 { 183 struct cfdata *cf = vcf; 184 struct fhc_attach_args *fa = aux; 185 186 if (strcmp(cf->cf_driver->cd_name, fa->fa_name) != 0) 187 return (0); 188 return (1); 189 } 190 191 static void 192 zs_attach_sbus(struct device *parent, struct device *self, void *aux) 193 { 194 struct zsc_softc *zsc = (void *) self; 195 struct sbus_attach_args *sa = aux; 196 struct zsdevice *zsaddr; 197 bus_space_handle_t kvaddr; 198 199 if (sa->sa_nintr == 0) { 200 printf(" no interrupt lines\n"); 201 return; 202 } 203 204 /* Only map registers once. */ 205 if (sa->sa_npromvaddrs) { 206 /* 207 * We're converting from a 32-bit pointer to a 64-bit 208 * pointer. Since the 32-bit entity is negative, but 209 * the kernel is still mapped into the lower 4GB 210 * range, this needs to be zero-extended. 211 * 212 * XXXXX If we map the kernel and devices into the 213 * high 4GB range, this needs to be changed to 214 * sign-extend the address. 215 */ 216 zsaddr = (struct zsdevice *) 217 (unsigned long int)sa->sa_promvaddrs[0]; 218 } else { 219 if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset, 220 sa->sa_size, BUS_SPACE_MAP_LINEAR, 0, &kvaddr) != 0) { 221 printf("%s @ sbus: cannot map registers\n", 222 self->dv_xname); 223 return; 224 } 225 zsaddr = (struct zsdevice *) 226 bus_space_vaddr(sa->sa_bustag, kvaddr); 227 } 228 229 zsc->zsc_bustag = sa->sa_bustag; 230 zsc->zsc_dmatag = sa->sa_dmatag; 231 zsc->zsc_promunit = getpropint(sa->sa_node, "slave", -2); 232 zsc->zsc_node = sa->sa_node; 233 234 zs_attach(zsc, zsaddr, sa->sa_pri); 235 } 236 237 static void 238 zs_attach_fhc(struct device *parent, struct device *self, void *aux) 239 { 240 struct zsc_softc *zsc = (void *) self; 241 struct fhc_attach_args *fa = aux; 242 struct zsdevice *zsaddr; 243 bus_space_handle_t kvaddr; 244 245 if (fa->fa_nreg < 1 && fa->fa_npromvaddrs < 1) { 246 printf(": no registers\n"); 247 return; 248 } 249 250 if (fa->fa_nintr < 1) { 251 printf(": no interrupts\n"); 252 return; 253 } 254 255 if (fa->fa_npromvaddrs) { 256 /* 257 * We're converting from a 32-bit pointer to a 64-bit 258 * pointer. Since the 32-bit entity is negative, but 259 * the kernel is still mapped into the lower 4GB 260 * range, this needs to be zero-extended. 261 * 262 * XXXXX If we map the kernel and devices into the 263 * high 4GB range, this needs to be changed to 264 * sign-extend the address. 265 */ 266 zsaddr = (struct zsdevice *) 267 (unsigned long int)fa->fa_promvaddrs[0]; 268 } else { 269 if (fhc_bus_map(fa->fa_bustag, fa->fa_reg[0].fbr_slot, 270 fa->fa_reg[0].fbr_offset, fa->fa_reg[0].fbr_size, 271 BUS_SPACE_MAP_LINEAR, &kvaddr) != 0) { 272 printf("%s @ fhc: cannot map registers\n", 273 self->dv_xname); 274 return; 275 } 276 zsaddr = (struct zsdevice *) 277 bus_space_vaddr(fa->fa_bustag, kvaddr); 278 } 279 280 zsc->zsc_bustag = fa->fa_bustag; 281 zsc->zsc_dmatag = NULL; 282 zsc->zsc_promunit = getpropint(fa->fa_node, "slave", -2); 283 zsc->zsc_node = fa->fa_node; 284 285 zs_attach(zsc, zsaddr, fa->fa_intr[0]); 286 } 287 288 /* 289 * Attach a found zs. 290 */ 291 static void 292 zs_attach(struct zsc_softc *zsc, struct zsdevice *zsd, int pri) 293 { 294 struct zsc_attach_args zsc_args; 295 struct zs_chanstate *cs; 296 int s, channel, softpri = PIL_TTY; 297 298 printf(" softpri %d\n", softpri); 299 300 /* 301 * Initialize software state for each channel. 302 */ 303 for (channel = 0; channel < 2; channel++) { 304 struct zschan *zc; 305 struct device *child; 306 307 zsc_args.type = "serial"; 308 if (getproplen(zsc->zsc_node, "keyboard") == 0) { 309 if (channel == 0) 310 zsc_args.type = "keyboard"; 311 if (channel == 1) 312 zsc_args.type = "mouse"; 313 } 314 315 zsc_args.channel = channel; 316 cs = &zsc->zsc_cs_store[channel]; 317 zsc->zsc_cs[channel] = cs; 318 319 cs->cs_channel = channel; 320 cs->cs_private = NULL; 321 cs->cs_ops = &zsops_null; 322 cs->cs_brg_clk = PCLK / 16; 323 324 zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b; 325 326 zsc_args.consdev = NULL; 327 zsc_args.hwflags = zs_console_flags(zsc->zsc_promunit, 328 zsc->zsc_node, 329 channel); 330 331 if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) { 332 zsc_args.hwflags |= ZS_HWFLAG_USE_CONSDEV; 333 zsc_args.consdev = &zs_consdev; 334 } 335 336 if (getproplen(zsc->zsc_node, channel == 0 ? 337 "port-a-ignore-cd" : "port-b-ignore-cd") == 0) { 338 zsc_args.hwflags |= ZS_HWFLAG_NO_DCD; 339 } 340 341 if ((zsc_args.hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) { 342 zs_conschan_get = zc; 343 } 344 if ((zsc_args.hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) { 345 zs_conschan_put = zc; 346 } 347 /* Children need to set cn_dev, etc */ 348 349 cs->cs_reg_csr = &zc->zc_csr; 350 cs->cs_reg_data = &zc->zc_data; 351 352 bcopy(zs_init_reg, cs->cs_creg, 16); 353 bcopy(zs_init_reg, cs->cs_preg, 16); 354 355 /* XXX: Consult PROM properties for this?! */ 356 cs->cs_defspeed = zs_get_speed(cs); 357 cs->cs_defcflag = zs_def_cflag; 358 359 /* Make these correspond to cs_defcflag (-crtscts) */ 360 cs->cs_rr0_dcd = ZSRR0_DCD; 361 cs->cs_rr0_cts = 0; 362 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 363 cs->cs_wr5_rts = 0; 364 365 /* 366 * Clear the master interrupt enable. 367 * The INTENA is common to both channels, 368 * so just do it on the A channel. 369 */ 370 if (channel == 0) { 371 zs_write_reg(cs, 9, 0); 372 } 373 374 /* 375 * Look for a child driver for this channel. 376 * The child attach will setup the hardware. 377 */ 378 if (!(child = 379 config_found(&zsc->zsc_dev, (void *)&zsc_args, zs_print))) { 380 /* No sub-driver. Just reset it. */ 381 u_char reset = (channel == 0) ? 382 ZSWR9_A_RESET : ZSWR9_B_RESET; 383 s = splzs(); 384 zs_write_reg(cs, 9, reset); 385 splx(s); 386 } 387 } 388 389 /* 390 * Now safe to install interrupt handlers. 391 */ 392 if (bus_intr_establish(zsc->zsc_bustag, pri, IPL_SERIAL, 0, zshard, 393 zsc, zsc->zsc_dev.dv_xname) == NULL) 394 panic("zsattach: could not establish interrupt"); 395 if (!(zsc->zsc_softintr = softintr_establish(softpri, zssoft, zsc))) 396 panic("zsattach: could not establish soft interrupt"); 397 398 /* 399 * Set the master interrupt enable and interrupt vector. 400 * (common to both channels, do it on A) 401 */ 402 cs = zsc->zsc_cs[0]; 403 s = splhigh(); 404 /* interrupt vector */ 405 zs_write_reg(cs, 2, zs_init_reg[2]); 406 /* master interrupt control (enable) */ 407 zs_write_reg(cs, 9, zs_init_reg[9]); 408 splx(s); 409 410 } 411 412 static int 413 zs_print(void *aux, const char *name) 414 { 415 struct zsc_attach_args *args = aux; 416 417 if (name != NULL) 418 printf("%s: ", name); 419 420 if (args->channel != -1) 421 printf(" channel %d", args->channel); 422 423 return (UNCONF); 424 } 425 426 static int 427 zshard(void *arg) 428 { 429 struct zsc_softc *zsc = (struct zsc_softc *)arg; 430 int rval = 0; 431 432 while (zsc_intr_hard(zsc)) 433 rval = 1; 434 if ((zsc->zsc_cs[0] && zsc->zsc_cs[0]->cs_softreq) || 435 (zsc->zsc_cs[1] && zsc->zsc_cs[1]->cs_softreq)) 436 softintr_schedule(zsc->zsc_softintr); 437 return (rval); 438 } 439 440 /* 441 * We need this only for TTY_DEBUG purposes. 442 */ 443 static void 444 zssoft(void *arg) 445 { 446 struct zsc_softc *zsc = (struct zsc_softc *)arg; 447 int s; 448 449 /* Make sure we call the tty layer at spltty. */ 450 s = spltty(); 451 (void)zsc_intr_soft(zsc); 452 #ifdef TTY_DEBUG 453 { 454 struct zstty_softc *zst0 = zsc->zsc_cs[0]->cs_private; 455 struct zstty_softc *zst1 = zsc->zsc_cs[1]->cs_private; 456 if (zst0->zst_overflows || zst1->zst_overflows ) { 457 struct trapframe *frame = (struct trapframe *)arg; 458 459 printf("zs silo overflow from %p\n", 460 (long)frame->tf_pc); 461 } 462 } 463 #endif 464 splx(s); 465 } 466 467 468 /* 469 * Compute the current baud rate given a ZS channel. 470 */ 471 static int 472 zs_get_speed(struct zs_chanstate *cs) 473 { 474 int tconst; 475 476 tconst = zs_read_reg(cs, 12); 477 tconst |= zs_read_reg(cs, 13) << 8; 478 return (TCONST_TO_BPS(cs->cs_brg_clk, tconst)); 479 } 480 481 /* 482 * MD functions for setting the baud rate and control modes. 483 */ 484 int 485 zs_set_speed(struct zs_chanstate *cs, int bps) 486 { 487 int tconst, real_bps; 488 489 if (bps == 0) 490 return (0); 491 492 #ifdef DIAGNOSTIC 493 if (cs->cs_brg_clk == 0) 494 panic("zs_set_speed"); 495 #endif 496 497 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 498 if (tconst < 0) 499 return (EINVAL); 500 501 /* Convert back to make sure we can do it. */ 502 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 503 504 /* XXX - Allow some tolerance here? */ 505 if (real_bps != bps) 506 return (EINVAL); 507 508 cs->cs_preg[12] = tconst; 509 cs->cs_preg[13] = tconst >> 8; 510 511 /* Caller will stuff the pending registers. */ 512 return (0); 513 } 514 515 int 516 zs_set_modes(struct zs_chanstate *cs, int cflag) 517 { 518 int s; 519 520 /* 521 * Output hardware flow control on the chip is horrendous: 522 * if carrier detect drops, the receiver is disabled, and if 523 * CTS drops, the transmitter is stopped IN MID CHARACTER! 524 * Therefore, NEVER set the HFC bit, and instead use the 525 * status interrupt to detect CTS changes. 526 */ 527 s = splzs(); 528 cs->cs_rr0_pps = 0; 529 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 530 cs->cs_rr0_dcd = 0; 531 if ((cflag & MDMBUF) == 0) 532 cs->cs_rr0_pps = ZSRR0_DCD; 533 } else 534 cs->cs_rr0_dcd = ZSRR0_DCD; 535 if ((cflag & CRTSCTS) != 0) { 536 cs->cs_wr5_dtr = ZSWR5_DTR; 537 cs->cs_wr5_rts = ZSWR5_RTS; 538 cs->cs_rr0_cts = ZSRR0_CTS; 539 #if 0 /* JLW */ 540 } else if ((cflag & CDTRCTS) != 0) { 541 cs->cs_wr5_dtr = 0; 542 cs->cs_wr5_rts = ZSWR5_DTR; 543 cs->cs_rr0_cts = ZSRR0_CTS; 544 #endif 545 } else if ((cflag & MDMBUF) != 0) { 546 cs->cs_wr5_dtr = 0; 547 cs->cs_wr5_rts = ZSWR5_DTR; 548 cs->cs_rr0_cts = ZSRR0_DCD; 549 } else { 550 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 551 cs->cs_wr5_rts = 0; 552 cs->cs_rr0_cts = 0; 553 } 554 splx(s); 555 556 /* Caller will stuff the pending registers. */ 557 return (0); 558 } 559 560 561 /* 562 * Read or write the chip with suitable delays. 563 */ 564 565 u_char 566 zs_read_reg(struct zs_chanstate *cs, u_char reg) 567 { 568 u_char val; 569 570 *cs->cs_reg_csr = reg; 571 ZS_DELAY(); 572 val = *cs->cs_reg_csr; 573 ZS_DELAY(); 574 return (val); 575 } 576 577 void 578 zs_write_reg(struct zs_chanstate *cs, u_char reg, u_char val) 579 { 580 *cs->cs_reg_csr = reg; 581 ZS_DELAY(); 582 *cs->cs_reg_csr = val; 583 ZS_DELAY(); 584 } 585 586 u_char 587 zs_read_csr(struct zs_chanstate *cs) 588 { 589 u_char val; 590 591 val = *cs->cs_reg_csr; 592 ZS_DELAY(); 593 return (val); 594 } 595 596 void 597 zs_write_csr(struct zs_chanstate *cs, u_char val) 598 { 599 *cs->cs_reg_csr = val; 600 ZS_DELAY(); 601 } 602 603 u_char 604 zs_read_data(struct zs_chanstate *cs) 605 { 606 u_char val; 607 608 val = *cs->cs_reg_data; 609 ZS_DELAY(); 610 return (val); 611 } 612 613 void 614 zs_write_data(struct zs_chanstate *cs, u_char val) 615 { 616 *cs->cs_reg_data = val; 617 ZS_DELAY(); 618 } 619 620 /**************************************************************** 621 * Console support functions (Sun specific!) 622 * Note: this code is allowed to know about the layout of 623 * the chip registers, and uses that to keep things simple. 624 * XXX - I think I like the mvme167 code better. -gwr 625 ****************************************************************/ 626 627 /* 628 * Handle user request to enter kernel debugger. 629 */ 630 void 631 zs_abort(struct zs_chanstate *cs) 632 { 633 volatile struct zschan *zc = zs_conschan_get; 634 int rr0; 635 636 /* Wait for end of break to avoid PROM abort. */ 637 /* XXX - Limit the wait? */ 638 do { 639 rr0 = zc->zc_csr; 640 ZS_DELAY(); 641 } while (rr0 & ZSRR0_BREAK); 642 643 #if defined(DDB) 644 { 645 extern int db_active; 646 647 if (!db_active) 648 db_enter(); 649 else 650 /* Debugger is probably hozed */ 651 callrom(); 652 } 653 #else 654 printf("stopping on keyboard abort\n"); 655 callrom(); 656 #endif 657 } 658 659 660 /* 661 * Polled input char. 662 */ 663 int 664 zs_getc(void *arg) 665 { 666 volatile struct zschan *zc = arg; 667 int s, c, rr0; 668 669 s = splhigh(); 670 /* Wait for a character to arrive. */ 671 do { 672 rr0 = zc->zc_csr; 673 ZS_DELAY(); 674 } while ((rr0 & ZSRR0_RX_READY) == 0); 675 676 c = zc->zc_data; 677 ZS_DELAY(); 678 splx(s); 679 680 return (c); 681 } 682 683 /* 684 * Polled output char. 685 */ 686 void 687 zs_putc(void *arg, int c) 688 { 689 volatile struct zschan *zc = arg; 690 int s, rr0; 691 692 s = splhigh(); 693 694 /* Wait for transmitter to become ready. */ 695 do { 696 rr0 = zc->zc_csr; 697 ZS_DELAY(); 698 } while ((rr0 & ZSRR0_TX_READY) == 0); 699 700 /* 701 * Send the next character. 702 * Now you'd think that this could be followed by a ZS_DELAY() 703 * just like all the other chip accesses, but it turns out that 704 * the `transmit-ready' interrupt isn't de-asserted until 705 * some period of time after the register write completes 706 * (more than a couple instructions). So to avoid stray 707 * interrupts we put in the 2us delay regardless of cpu model. 708 */ 709 zc->zc_data = c; 710 delay(2); 711 712 splx(s); 713 } 714 715 /*****************************************************************/ 716 717 718 719 720 /* 721 * Polled console input putchar. 722 */ 723 static int 724 zscngetc(dev_t dev) 725 { 726 return (zs_getc(zs_conschan_get)); 727 } 728 729 /* 730 * Polled console output putchar. 731 */ 732 static void 733 zscnputc(dev_t dev, int c) 734 { 735 zs_putc(zs_conschan_put, c); 736 } 737 738 int 739 zs_console_flags(int promunit, int node, int channel) 740 { 741 int cookie, flags = 0; 742 u_int options; 743 char buf[255]; 744 745 /* 746 * We'll just to the OBP grovelling down here since that's 747 * the only type of firmware we support. 748 */ 749 options = OF_finddevice("/options"); 750 751 /* Default to channel 0 if there are no explicit prom args */ 752 cookie = 0; 753 754 if (node == OF_instance_to_package(OF_stdin())) { 755 if (OF_getprop(options, "input-device", 756 buf, sizeof(buf)) != -1) { 757 if (strncmp("ttyb", buf, strlen("ttyb")) == 0) 758 cookie = 1; 759 } 760 761 if (channel == cookie) 762 flags |= ZS_HWFLAG_CONSOLE_INPUT; 763 } 764 765 if (node == OF_instance_to_package(OF_stdout())) { 766 if (OF_getprop(options, "output-device", 767 buf, sizeof(buf)) != -1) { 768 if (strncmp("ttyb", buf, strlen("ttyb")) == 0) 769 cookie = 1; 770 } 771 772 if (channel == cookie) 773 flags |= ZS_HWFLAG_CONSOLE_OUTPUT; 774 } 775 776 return (flags); 777 } 778