Annotation of sys/arch/sparc/dev/zs.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: zs.c,v 1.43 2006/01/09 20:57:00 miod Exp $ */
! 2: /* $NetBSD: zs.c,v 1.50 1997/10/18 00:00:40 gwr 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: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Zilog Z8530 Dual UART driver (machine-dependent part)
! 42: *
! 43: * Runs two serial lines per chip using slave drivers.
! 44: * Plain tty/async lines use the zs_async slave.
! 45: * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
! 46: */
! 47:
! 48: #include <sys/param.h>
! 49: #include <sys/systm.h>
! 50: #include <sys/conf.h>
! 51: #include <sys/device.h>
! 52: #include <sys/file.h>
! 53: #include <sys/ioctl.h>
! 54: #include <sys/kernel.h>
! 55: #include <sys/proc.h>
! 56: #include <sys/tty.h>
! 57: #include <sys/time.h>
! 58: #include <sys/syslog.h>
! 59:
! 60: #include <machine/autoconf.h>
! 61: #include <machine/bsd_openprom.h>
! 62: #include <machine/conf.h>
! 63: #include <machine/cpu.h>
! 64: #include <machine/eeprom.h>
! 65: #if defined(SUN4)
! 66: #include <machine/oldmon.h>
! 67: #endif
! 68: #include <machine/psl.h>
! 69: #include <machine/z8530var.h>
! 70:
! 71: #include <dev/cons.h>
! 72: #include <sparc/dev/z8530reg.h>
! 73:
! 74: #include <sparc/sparc/vaddrs.h>
! 75: #include <sparc/sparc/auxioreg.h>
! 76: #include <sparc/dev/cons.h>
! 77:
! 78: #ifdef solbourne
! 79: #include <machine/prom.h>
! 80: #endif
! 81:
! 82: #include <uvm/uvm_extern.h>
! 83:
! 84: #include "zskbd.h"
! 85: #include "zs.h"
! 86:
! 87: /* Make life easier for the initialized arrays here. */
! 88: #if NZS < 3
! 89: #undef NZS
! 90: #define NZS 3
! 91: #endif
! 92:
! 93: /*
! 94: * Some warts needed by z8530tty.c -
! 95: * The default parity REALLY needs to be the same as the PROM uses,
! 96: * or you can not see messages done with printf during boot-up...
! 97: */
! 98: int zs_def_cflag = (CREAD | CS8 | HUPCL);
! 99: int zs_major = 12;
! 100:
! 101: /*
! 102: * The Sun provides a 4.9152 MHz clock to the ZS chips.
! 103: */
! 104: #define PCLK (9600 * 512) /* PCLK pin input clock rate */
! 105:
! 106: /*
! 107: * Select software interrupt bit based on TTY ipl.
! 108: */
! 109: #if IPL_TTY == 1
! 110: # define IE_ZSSOFT IE_L1
! 111: #elif IPL_TTY == 4
! 112: # define IE_ZSSOFT IE_L4
! 113: #elif IPL_TTY == 6
! 114: # define IE_ZSSOFT IE_L6
! 115: #else
! 116: # error "no suitable software interrupt bit"
! 117: #endif
! 118:
! 119: #define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(2))
! 120:
! 121: /* The layout of this is hardware-dependent (padding, order). */
! 122: struct zschan {
! 123: #if defined(SUN4) || defined(SUN4C) || defined(SUN4M)
! 124: volatile u_char zc_csr; /* ctrl,status, and indirect access */
! 125: u_char zc_xxx0;
! 126: volatile u_char zc_data; /* data */
! 127: u_char zc_xxx1;
! 128: #endif
! 129: #if defined(solbourne)
! 130: volatile u_char zc_csr; /* ctrl,status, and indirect access */
! 131: u_char zc_xxx0[7];
! 132: volatile u_char zc_data; /* data */
! 133: u_char zc_xxx1[7];
! 134: #endif
! 135: };
! 136: struct zsdevice {
! 137: /* Yes, they are backwards. */
! 138: struct zschan zs_chan_b;
! 139: struct zschan zs_chan_a;
! 140: };
! 141:
! 142: /* Saved PROM mappings */
! 143: struct zsdevice *zsaddr[NZS];
! 144:
! 145: /* Flags from cninit() */
! 146: int zs_hwflags[NZS][2];
! 147:
! 148: /* Default speed for each channel */
! 149: int zs_defspeed[NZS][2] = {
! 150: { 9600, /* ttya */
! 151: 9600 }, /* ttyb */
! 152: { 1200, /* keyboard */
! 153: 1200 }, /* mouse */
! 154: { 9600, /* ttyc */
! 155: 9600 }, /* ttyd */
! 156: };
! 157:
! 158: u_char zs_init_reg[16] = {
! 159: 0, /* 0: CMD (reset, etc.) */
! 160: 0, /* 1: No interrupts yet. */
! 161: 0, /* 2: IVECT */
! 162: ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
! 163: ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
! 164: ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
! 165: 0, /* 6: TXSYNC/SYNCLO */
! 166: 0, /* 7: RXSYNC/SYNCHI */
! 167: 0, /* 8: alias for data port */
! 168: ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR,
! 169: 0, /*10: Misc. TX/RX control bits */
! 170: ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
! 171: ((PCLK/32)/9600)-2, /*12: BAUDLO (default=9600) */
! 172: 0, /*13: BAUDHI (default=9600) */
! 173: ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
! 174: ZSWR15_BREAK_IE /* | ZSWR15_DCD_IE */,
! 175: };
! 176:
! 177: struct zschan *
! 178: zs_get_chan_addr(zs_unit, channel)
! 179: int zs_unit, channel;
! 180: {
! 181: struct zsdevice *addr;
! 182: struct zschan *zc;
! 183:
! 184: if (zs_unit >= NZS)
! 185: return NULL;
! 186: addr = zsaddr[zs_unit];
! 187: if (addr == NULL)
! 188: addr = zsaddr[zs_unit] = findzs(zs_unit);
! 189: if (addr == NULL)
! 190: return NULL;
! 191: if (channel == 0) {
! 192: zc = &addr->zs_chan_a;
! 193: } else {
! 194: zc = &addr->zs_chan_b;
! 195: }
! 196: return (zc);
! 197: }
! 198:
! 199:
! 200: /****************************************************************
! 201: * Autoconfig
! 202: ****************************************************************/
! 203:
! 204: /* Definition of the driver for autoconfig. */
! 205: int zs_match(struct device *, void *, void *);
! 206: void zs_attach(struct device *, struct device *, void *);
! 207: int zs_print(void *, const char *nam);
! 208:
! 209: /* Power management hooks (for Tadpole SPARCbooks) */
! 210: void zs_disable(struct zs_chanstate *);
! 211: int zs_enable(struct zs_chanstate *);
! 212:
! 213: struct cfattach zs_ca = {
! 214: sizeof(struct zsc_softc), zs_match, zs_attach
! 215: };
! 216:
! 217: struct cfdriver zs_cd = {
! 218: NULL, "zs", DV_DULL
! 219: };
! 220:
! 221: /* Interrupt handlers. */
! 222: int zshard(void *);
! 223: int zssoft(void *);
! 224: struct intrhand levelhard = { zshard };
! 225: struct intrhand levelsoft = { zssoft };
! 226:
! 227: int zs_get_speed(struct zs_chanstate *);
! 228:
! 229:
! 230: /*
! 231: * Is the zs chip present?
! 232: */
! 233: int
! 234: zs_match(parent, vcf, aux)
! 235: struct device *parent;
! 236: void *vcf, *aux;
! 237: {
! 238: struct cfdata *cf = (struct cfdata *)vcf;
! 239: struct confargs *ca = (struct confargs *)aux;
! 240: struct romaux *ra = &ca->ca_ra;
! 241:
! 242: if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
! 243: return (0);
! 244:
! 245: #ifdef solbourne
! 246: if (CPU_ISKAP)
! 247: return (ca->ca_bustype == BUS_OBIO);
! 248: #endif
! 249:
! 250: if ((ca->ca_bustype == BUS_MAIN && !CPU_ISSUN4) ||
! 251: (ca->ca_bustype == BUS_OBIO && CPU_ISSUN4M))
! 252: return (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit);
! 253: ra->ra_len = NBPG;
! 254: return (probeget(ra->ra_vaddr, 1) != -1);
! 255: }
! 256:
! 257: /*
! 258: * Attach a found zs.
! 259: *
! 260: * USE ROM PROPERTIES port-a-ignore-cd AND port-b-ignore-cd FOR
! 261: * SOFT CARRIER, AND keyboard PROPERTY FOR KEYBOARD/MOUSE?
! 262: */
! 263: void
! 264: zs_attach(parent, self, aux)
! 265: struct device *parent;
! 266: struct device *self;
! 267: void *aux;
! 268: {
! 269: struct zsc_softc *zsc = (void *) self;
! 270: struct confargs *ca = aux;
! 271: struct romaux *ra = &ca->ca_ra;
! 272: struct zsc_attach_args zsc_args;
! 273: volatile struct zschan *zc;
! 274: struct zs_chanstate *cs;
! 275: int pri, s, zs_unit, channel;
! 276: static int didintr, prevpri;
! 277:
! 278: zs_unit = zsc->zsc_dev.dv_unit;
! 279:
! 280: /* Use the mapping setup by the Sun PROM. */
! 281: if (zsaddr[zs_unit] == NULL)
! 282: zsaddr[zs_unit] = findzs(zs_unit);
! 283:
! 284: if (ca->ca_bustype==BUS_MAIN)
! 285: if ((void*)zsaddr[zs_unit] != ra->ra_vaddr)
! 286: panic("zsattach");
! 287: if (ra->ra_nintr != 1) {
! 288: printf(": expected 1 interrupt, got %d\n", ra->ra_nintr);
! 289: return;
! 290: }
! 291: pri = ra->ra_intr[0].int_pri;
! 292: printf(" pri %d, softpri %d\n", pri, IPL_TTY);
! 293:
! 294: /*
! 295: * Initialize software state for each channel.
! 296: */
! 297: for (channel = 0; channel < 2; channel++) {
! 298: zsc_args.type = "serial";
! 299: /* XXX hardcoded */
! 300: if (zs_unit == 1) {
! 301: if (channel == 0)
! 302: zsc_args.type = "keyboard";
! 303: if (channel == 1)
! 304: zsc_args.type = "mouse";
! 305: }
! 306:
! 307: zsc_args.channel = channel;
! 308: zsc_args.hwflags = zs_hwflags[zs_unit][channel];
! 309: cs = &zsc->zsc_cs[channel];
! 310:
! 311: cs->cs_channel = channel;
! 312: cs->cs_private = NULL;
! 313: cs->cs_ops = &zsops_null;
! 314: cs->cs_brg_clk = PCLK / 16;
! 315:
! 316: zc = zs_get_chan_addr(zs_unit, channel);
! 317:
! 318: cs->cs_reg_csr = &zc->zc_csr;
! 319: cs->cs_reg_data = &zc->zc_data;
! 320:
! 321: bcopy(zs_init_reg, cs->cs_creg, 16);
! 322: bcopy(zs_init_reg, cs->cs_preg, 16);
! 323:
! 324: /* XXX: Get these from the PROM properties! */
! 325: /* XXX: See the mvme167 code. Better. */
! 326: if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
! 327: cs->cs_defspeed = zs_get_speed(cs);
! 328: else
! 329: cs->cs_defspeed = zs_defspeed[zs_unit][channel];
! 330: cs->cs_defcflag = zs_def_cflag;
! 331:
! 332: /* Make these correspond to cs_defcflag (-crtscts) */
! 333: cs->cs_rr0_dcd = ZSRR0_DCD;
! 334: cs->cs_rr0_cts = 0;
! 335: cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
! 336: cs->cs_wr5_rts = 0;
! 337:
! 338: /*
! 339: * Clear the master interrupt enable.
! 340: * The INTENA is common to both channels,
! 341: * so just do it on the A channel.
! 342: */
! 343: if (channel == 0) {
! 344: zs_write_reg(cs, 9, 0);
! 345: }
! 346:
! 347: /*
! 348: * Look for a child driver for this channel.
! 349: * The child attach will setup the hardware.
! 350: */
! 351: if (!config_found(self, (void *)&zsc_args, zs_print)) {
! 352: /* No sub-driver. Just reset it. */
! 353: u_char reset = (channel == 0) ?
! 354: ZSWR9_A_RESET : ZSWR9_B_RESET;
! 355: s = splzs();
! 356: zs_write_reg(cs, 9, reset);
! 357: splx(s);
! 358: }
! 359: }
! 360:
! 361: /*
! 362: * Now safe to install interrupt handlers. Note the arguments
! 363: * to the interrupt handlers aren't used. Note, we only do this
! 364: * once since both SCCs interrupt at the same level and vector.
! 365: */
! 366: if (!didintr) {
! 367: didintr = 1;
! 368: prevpri = pri;
! 369: intr_establish(pri, &levelhard, IPL_ZS, self->dv_xname);
! 370: intr_establish(IPL_TTY, &levelsoft, IPL_TTY, self->dv_xname);
! 371: } else if (pri != prevpri)
! 372: panic("broken zs interrupt scheme");
! 373:
! 374: /*
! 375: * Set the master interrupt enable and interrupt vector.
! 376: * (common to both channels, do it on A)
! 377: */
! 378: cs = &zsc->zsc_cs[0];
! 379: s = splhigh();
! 380: /* interrupt vector */
! 381: zs_write_reg(cs, 2, zs_init_reg[2]);
! 382: /* master interrupt control (enable) */
! 383: zs_write_reg(cs, 9, zs_init_reg[9]);
! 384: splx(s);
! 385:
! 386: #ifdef SUN4M
! 387: /* register power management routines if necessary */
! 388: if (CPU_ISSUN4M) {
! 389: if (getpropint(ra->ra_node, "pwr-on-auxio2", 0))
! 390: for (channel = 0; channel < 2; channel++) {
! 391: cs = &zsc->zsc_cs[channel];
! 392: cs->disable = zs_disable;
! 393: cs->enable = zs_enable;
! 394: cs->enabled = 0;
! 395: }
! 396: }
! 397: #endif
! 398:
! 399: #if 0
! 400: /*
! 401: * XXX: L1A hack - We would like to be able to break into
! 402: * the debugger during the rest of autoconfiguration, so
! 403: * lower interrupts just enough to let zs interrupts in.
! 404: * This is done after both zs devices are attached.
! 405: */
! 406: if (zs_unit == 1) {
! 407: printf("zs1: enabling zs interrupts\n");
! 408: (void)splfd(); /* XXX: splzs - 1 */
! 409: }
! 410: #endif
! 411: }
! 412:
! 413: int
! 414: zs_print(aux, name)
! 415: void *aux;
! 416: const char *name;
! 417: {
! 418: struct zsc_attach_args *args = aux;
! 419:
! 420: if (name != NULL)
! 421: printf("%s:", name);
! 422:
! 423: if (args->channel != -1)
! 424: printf(" channel %d", args->channel);
! 425:
! 426: return UNCONF;
! 427: }
! 428:
! 429: volatile int zssoftpending;
! 430:
! 431: /*
! 432: * Our ZS chips all share a common, autovectored interrupt,
! 433: * so we have to look at all of them on each interrupt.
! 434: */
! 435: int
! 436: zshard(arg)
! 437: void *arg;
! 438: {
! 439: struct zsc_softc *zsc;
! 440: int unit, rr3, rval, softreq;
! 441:
! 442: rval = softreq = 0;
! 443: for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
! 444: zsc = zs_cd.cd_devs[unit];
! 445: if (zsc == NULL)
! 446: continue;
! 447: rr3 = zsc_intr_hard(zsc);
! 448: /* Count up the interrupts. */
! 449: if (rr3) {
! 450: rval |= rr3;
! 451: }
! 452: softreq |= zsc->zsc_cs[0].cs_softreq;
! 453: softreq |= zsc->zsc_cs[1].cs_softreq;
! 454: }
! 455:
! 456: /* We are at splzs here, so no need to lock. */
! 457: if (softreq && (zssoftpending == 0)) {
! 458: zssoftpending = IE_ZSSOFT;
! 459: #if defined(SUN4M)
! 460: if (CPU_ISSUN4M)
! 461: raise(0, IPL_TTY);
! 462: else
! 463: #endif
! 464: ienab_bis(IE_ZSSOFT);
! 465: }
! 466: return (rval);
! 467: }
! 468:
! 469: /*
! 470: * Similar scheme as for zshard (look at all of them)
! 471: */
! 472: int
! 473: zssoft(arg)
! 474: void *arg;
! 475: {
! 476: struct zsc_softc *zsc;
! 477: int s, unit;
! 478:
! 479: /* This is not the only ISR on this IPL. */
! 480: if (zssoftpending == 0)
! 481: return (0);
! 482:
! 483: /*
! 484: * The soft intr. bit will be set by zshard only if
! 485: * the variable zssoftpending is zero. The order of
! 486: * these next two statements prevents our clearing
! 487: * the soft intr bit just after zshard has set it.
! 488: */
! 489: /* ienab_bic(IE_ZSSOFT); */
! 490: zssoftpending = 0;
! 491:
! 492: /* Make sure we call the tty layer at spltty. */
! 493: s = spltty();
! 494: for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
! 495: zsc = zs_cd.cd_devs[unit];
! 496: if (zsc == NULL)
! 497: continue;
! 498: (void)zsc_intr_soft(zsc);
! 499: }
! 500: splx(s);
! 501: return (1);
! 502: }
! 503:
! 504:
! 505: /*
! 506: * Compute the current baud rate given a ZS channel.
! 507: */
! 508: int
! 509: zs_get_speed(cs)
! 510: struct zs_chanstate *cs;
! 511: {
! 512: int tconst;
! 513:
! 514: tconst = zs_read_reg(cs, 12);
! 515: tconst |= zs_read_reg(cs, 13) << 8;
! 516: return (TCONST_TO_BPS(cs->cs_brg_clk, tconst));
! 517: }
! 518:
! 519: /*
! 520: * MD functions for setting the baud rate and control modes.
! 521: */
! 522: int
! 523: zs_set_speed(cs, bps)
! 524: struct zs_chanstate *cs;
! 525: int bps; /* bits per second */
! 526: {
! 527: int tconst, real_bps;
! 528:
! 529: if (bps == 0)
! 530: return (0);
! 531:
! 532: #ifdef DIAGNOSTIC
! 533: if (cs->cs_brg_clk == 0)
! 534: panic("zs_set_speed");
! 535: #endif
! 536:
! 537: tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
! 538: if (tconst < 0)
! 539: return (EINVAL);
! 540:
! 541: /* Convert back to make sure we can do it. */
! 542: real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
! 543:
! 544: /* XXX - Allow some tolerance here? */
! 545: if (real_bps != bps)
! 546: return (EINVAL);
! 547:
! 548: cs->cs_preg[12] = tconst;
! 549: cs->cs_preg[13] = tconst >> 8;
! 550:
! 551: /* Caller will stuff the pending registers. */
! 552: return (0);
! 553: }
! 554:
! 555: int
! 556: zs_set_modes(cs, cflag)
! 557: struct zs_chanstate *cs;
! 558: int cflag; /* bits per second */
! 559: {
! 560: int s;
! 561:
! 562: /*
! 563: * Output hardware flow control on the chip is horrendous:
! 564: * if carrier detect drops, the receiver is disabled, and if
! 565: * CTS drops, the transmitter is stoped IN MID CHARACTER!
! 566: * Therefore, NEVER set the HFC bit, and instead use the
! 567: * status interrupt to detect CTS changes.
! 568: */
! 569: s = splzs();
! 570: cs->cs_rr0_pps = 0;
! 571: if ((cflag & (CLOCAL | MDMBUF)) != 0) {
! 572: cs->cs_rr0_dcd = 0;
! 573: if ((cflag & MDMBUF) == 0)
! 574: cs->cs_rr0_pps = ZSRR0_DCD;
! 575: } else
! 576: cs->cs_rr0_dcd = ZSRR0_DCD;
! 577: if ((cflag & CRTSCTS) != 0) {
! 578: cs->cs_wr5_dtr = ZSWR5_DTR;
! 579: cs->cs_wr5_rts = ZSWR5_RTS;
! 580: cs->cs_rr0_cts = ZSRR0_CTS;
! 581: #if 0 /* JLW */
! 582: } else if ((cflag & CDTRCTS) != 0) {
! 583: cs->cs_wr5_dtr = 0;
! 584: cs->cs_wr5_rts = ZSWR5_DTR;
! 585: cs->cs_rr0_cts = ZSRR0_CTS;
! 586: #endif
! 587: } else if ((cflag & MDMBUF) != 0) {
! 588: cs->cs_wr5_dtr = 0;
! 589: cs->cs_wr5_rts = ZSWR5_DTR;
! 590: cs->cs_rr0_cts = ZSRR0_DCD;
! 591: } else {
! 592: cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
! 593: cs->cs_wr5_rts = 0;
! 594: cs->cs_rr0_cts = 0;
! 595: }
! 596: splx(s);
! 597:
! 598: /* Caller will stuff the pending registers. */
! 599: return (0);
! 600: }
! 601:
! 602:
! 603: /*
! 604: * Read or write the chip with suitable delays.
! 605: */
! 606:
! 607: u_char
! 608: zs_read_reg(cs, reg)
! 609: struct zs_chanstate *cs;
! 610: u_char reg;
! 611: {
! 612: u_char val;
! 613:
! 614: *cs->cs_reg_csr = reg;
! 615: ZS_DELAY();
! 616: val = *cs->cs_reg_csr;
! 617: ZS_DELAY();
! 618: return val;
! 619: }
! 620:
! 621: void
! 622: zs_write_reg(cs, reg, val)
! 623: struct zs_chanstate *cs;
! 624: u_char reg, val;
! 625: {
! 626: *cs->cs_reg_csr = reg;
! 627: ZS_DELAY();
! 628: *cs->cs_reg_csr = val;
! 629: ZS_DELAY();
! 630: }
! 631:
! 632: u_char zs_read_csr(cs)
! 633: struct zs_chanstate *cs;
! 634: {
! 635: register u_char val;
! 636:
! 637: val = *cs->cs_reg_csr;
! 638: ZS_DELAY();
! 639: return val;
! 640: }
! 641:
! 642: void zs_write_csr(cs, val)
! 643: struct zs_chanstate *cs;
! 644: u_char val;
! 645: {
! 646: *cs->cs_reg_csr = val;
! 647: ZS_DELAY();
! 648: }
! 649:
! 650: u_char zs_read_data(cs)
! 651: struct zs_chanstate *cs;
! 652: {
! 653: register u_char val;
! 654:
! 655: val = *cs->cs_reg_data;
! 656: ZS_DELAY();
! 657: return val;
! 658: }
! 659:
! 660: void zs_write_data(cs, val)
! 661: struct zs_chanstate *cs;
! 662: u_char val;
! 663: {
! 664: *cs->cs_reg_data = val;
! 665: ZS_DELAY();
! 666: }
! 667:
! 668: #ifdef SUN4M
! 669: /*
! 670: * Power management hooks for zsopen() and zsclose().
! 671: * We use them to power on/off the ports on the Tadpole SPARCbook machines
! 672: * (on other sun4m machines, this is a no-op).
! 673: */
! 674:
! 675: /*
! 676: * Since the serial power control is global, we need to remember which channels
! 677: * have their ports open, so as not to power off when closing one channel if
! 678: * both were open. Simply xor'ing the zs_chanstate pointers is enough to let us
! 679: * know if the serial lines are used or not.
! 680: */
! 681: static vaddr_t zs_sb_enable = 0;
! 682:
! 683: int
! 684: zs_enable(struct zs_chanstate *cs)
! 685: {
! 686: if (cs->enabled == 0) {
! 687: if (zs_sb_enable == 0)
! 688: sb_auxregbisc(1, AUXIO2_SERIAL, 0);
! 689: zs_sb_enable ^= (vaddr_t)cs;
! 690: cs->enabled = 1;
! 691: }
! 692: return (0);
! 693: }
! 694:
! 695: void
! 696: zs_disable(struct zs_chanstate *cs)
! 697: {
! 698: if (cs->enabled != 0) {
! 699: cs->enabled = 0;
! 700: zs_sb_enable ^= (vaddr_t)cs;
! 701: if (zs_sb_enable == 0)
! 702: sb_auxregbisc(1, 0, AUXIO2_SERIAL);
! 703: }
! 704: }
! 705:
! 706: #endif /* SUN4M */
! 707:
! 708: /****************************************************************
! 709: * Console support functions (Sun specific!)
! 710: * Note: this code is allowed to know about the layout of
! 711: * the chip registers, and uses that to keep things simple.
! 712: * XXX - I think I like the mvme167 code better. -gwr
! 713: ****************************************************************/
! 714:
! 715: extern void Debugger(void);
! 716: void *zs_conschan;
! 717:
! 718: /*
! 719: * Handle user request to enter kernel debugger.
! 720: */
! 721: void
! 722: zs_abort(cs)
! 723: struct zs_chanstate *cs;
! 724: {
! 725: volatile struct zschan *zc = zs_conschan;
! 726: int rr0;
! 727:
! 728: /* Wait for end of break to avoid PROM abort. */
! 729: /* XXX - Limit the wait? */
! 730: do {
! 731: rr0 = zc->zc_csr;
! 732: ZS_DELAY();
! 733: } while (rr0 & ZSRR0_BREAK);
! 734:
! 735: #if defined(KGDB)
! 736: zskgdb(cs);
! 737: #elif defined(DDB)
! 738: {
! 739: extern int db_active;
! 740:
! 741: if (!db_active)
! 742: Debugger();
! 743: else
! 744: /* Debugger is probably hosed */
! 745: callrom();
! 746: }
! 747: #else
! 748: printf("stopping on keyboard abort\n");
! 749: callrom();
! 750: #endif
! 751: }
! 752:
! 753: /*
! 754: * Polled input char.
! 755: */
! 756: int
! 757: zs_getc(arg)
! 758: void *arg;
! 759: {
! 760: volatile struct zschan *zc = arg;
! 761: int s, c, rr0;
! 762:
! 763: s = splhigh();
! 764: /* Wait for a character to arrive. */
! 765: do {
! 766: rr0 = zc->zc_csr;
! 767: ZS_DELAY();
! 768: } while ((rr0 & ZSRR0_RX_READY) == 0);
! 769:
! 770: c = zc->zc_data;
! 771: ZS_DELAY();
! 772: splx(s);
! 773:
! 774: return (c);
! 775: }
! 776:
! 777: /*
! 778: * Polled output char.
! 779: */
! 780: void
! 781: zs_putc(arg, c)
! 782: void *arg;
! 783: int c;
! 784: {
! 785: volatile struct zschan *zc = arg;
! 786: int s, rr0;
! 787:
! 788: s = splhigh();
! 789: /* Wait for transmitter to become ready. */
! 790: do {
! 791: rr0 = zc->zc_csr;
! 792: ZS_DELAY();
! 793: } while ((rr0 & ZSRR0_TX_READY) == 0);
! 794:
! 795: /*
! 796: * Send the next character.
! 797: * Now you'd think that this could be followed by a ZS_DELAY()
! 798: * just like all the other chip accesses, but it turns out that
! 799: * the `transmit-ready' interrupt isn't de-asserted until
! 800: * some period of time after the register write completes
! 801: * (more than a couple instructions). So to avoid stray
! 802: * interrupts we put in the 2us delay regardless of cpu model.
! 803: */
! 804: zc->zc_data = c;
! 805: delay(2);
! 806:
! 807: splx(s);
! 808: }
! 809:
! 810: /*****************************************************************/
! 811:
! 812: cons_decl(zs);
! 813:
! 814: /*
! 815: * Console table shared by ttya, ttyb
! 816: */
! 817: struct consdev consdev_tty = {
! 818: zscnprobe,
! 819: zscninit,
! 820: zscngetc,
! 821: zscnputc,
! 822: zscnpollc,
! 823: };
! 824:
! 825: int zstty_unit; /* set in consinit() */
! 826:
! 827: void
! 828: zscnprobe(cn)
! 829: struct consdev *cn;
! 830: {
! 831: cn->cn_dev = makedev(zs_major, zstty_unit);
! 832: cn->cn_pri = CN_REMOTE;
! 833: }
! 834:
! 835: void
! 836: zscninit(cn)
! 837: struct consdev *cn;
! 838: {
! 839: }
! 840:
! 841: /*
! 842: * Polled console input putchar.
! 843: */
! 844: int
! 845: zscngetc(dev)
! 846: dev_t dev;
! 847: {
! 848: return (zs_getc(zs_conschan));
! 849: }
! 850:
! 851: /*
! 852: * Polled console output putchar.
! 853: */
! 854: void
! 855: zscnputc(dev, c)
! 856: dev_t dev;
! 857: int c;
! 858: {
! 859: zs_putc(zs_conschan, c);
! 860: }
! 861:
! 862: int swallow_zsintrs;
! 863:
! 864: void
! 865: zscnpollc(dev, on)
! 866: dev_t dev;
! 867: int on;
! 868: {
! 869: /*
! 870: * Need to tell zs driver to acknowledge all interrupts or we get
! 871: * annoying spurious interrupt messages. This is because mucking
! 872: * with spl() levels during polling does not prevent interrupts from
! 873: * being generated.
! 874: */
! 875:
! 876: if (on) swallow_zsintrs++;
! 877: else swallow_zsintrs--;
! 878: }
! 879:
! 880: /*****************************************************************/
! 881:
! 882: #if defined(SUN4) || defined(SUN4C) || defined(SUN4M)
! 883:
! 884: cons_decl(prom);
! 885:
! 886: /*
! 887: * The console is set to this one initially,
! 888: * which lets us use the PROM until consinit()
! 889: * is called to select a real console.
! 890: */
! 891: struct consdev consdev_prom = {
! 892: promcnprobe,
! 893: promcninit,
! 894: promcngetc,
! 895: promcnputc,
! 896: nullcnpollc,
! 897: };
! 898:
! 899: /*
! 900: * The console table pointer is statically initialized
! 901: * to point to the PROM (output only) table, so that
! 902: * early calls to printf will work.
! 903: */
! 904: struct consdev *cn_tab = &consdev_prom;
! 905:
! 906: void
! 907: promcnprobe(cn)
! 908: struct consdev *cn;
! 909: {
! 910: cn->cn_dev = makedev(0, 0);
! 911: cn->cn_pri = CN_INTERNAL;
! 912: }
! 913:
! 914: void
! 915: promcninit(cn)
! 916: struct consdev *cn;
! 917: {
! 918: }
! 919:
! 920: /*
! 921: * PROM console input putchar.
! 922: */
! 923: int
! 924: promcngetc(dev)
! 925: dev_t dev;
! 926: {
! 927: int s, c;
! 928:
! 929: if (promvec->pv_romvec_vers > 2) {
! 930: int n = 0;
! 931: unsigned char c0;
! 932:
! 933: s = splhigh();
! 934: while (n <= 0) {
! 935: n = (*promvec->pv_v2devops.v2_read)
! 936: (*promvec->pv_v2bootargs.v2_fd0, &c0, 1);
! 937: }
! 938: splx(s);
! 939:
! 940: c = c0;
! 941: } else {
! 942: #if defined(SUN4)
! 943: /* SUN4 PROM: must turn off local echo */
! 944: extern struct om_vector *oldpvec;
! 945: int saveecho = 0;
! 946: #endif
! 947: s = splhigh();
! 948: #if defined(SUN4)
! 949: if (CPU_ISSUN4) {
! 950: saveecho = *(oldpvec->echo);
! 951: *(oldpvec->echo) = 0;
! 952: }
! 953: #endif
! 954: c = (*promvec->pv_getchar)();
! 955: #if defined(SUN4)
! 956: if (CPU_ISSUN4)
! 957: *(oldpvec->echo) = saveecho;
! 958: #endif
! 959: splx(s);
! 960: }
! 961:
! 962: if (c == '\r')
! 963: c = '\n';
! 964:
! 965: return (c);
! 966: }
! 967:
! 968: /*
! 969: * PROM console output putchar.
! 970: */
! 971: void
! 972: promcnputc(dev, c)
! 973: dev_t dev;
! 974: int c;
! 975: {
! 976: int s;
! 977: char c0 = (c & 0x7f);
! 978:
! 979: s = splhigh();
! 980: if (promvec->pv_romvec_vers > 2)
! 981: (*promvec->pv_v2devops.v2_write)
! 982: (*promvec->pv_v2bootargs.v2_fd1, &c0, 1);
! 983: else
! 984: (*promvec->pv_putchar)(c);
! 985: splx(s);
! 986: }
! 987:
! 988: #endif /* SUN4 || SUN4C || SUN4M */
! 989:
! 990: /*****************************************************************/
! 991:
! 992: #if 0
! 993: extern struct consdev consdev_kd;
! 994: #endif
! 995:
! 996: char *prom_inSrc_name[] = {
! 997: "keyboard/display",
! 998: "ttya", "ttyb",
! 999: "ttyc", "ttyd" };
! 1000:
! 1001: /*
! 1002: * This function replaces sys/dev/cninit.c
! 1003: * Determine which device is the console using
! 1004: * the PROM "input source" and "output sink".
! 1005: */
! 1006: void
! 1007: consinit()
! 1008: {
! 1009: struct zschan *zc;
! 1010: struct consdev *console = cn_tab;
! 1011: int channel, zs_unit;
! 1012: int inSource, outSink;
! 1013:
! 1014: #if defined(SUN4) || defined(SUN4C) || defined(SUN4M)
! 1015: if (promvec->pv_romvec_vers > 2) {
! 1016: /* We need to probe the PROM device tree */
! 1017: int node,fd;
! 1018: char buffer[128];
! 1019: struct nodeops *no;
! 1020: struct v2devops *op;
! 1021: char *cp;
! 1022: extern int fbnode;
! 1023:
! 1024: inSource = outSink = -1;
! 1025: no = promvec->pv_nodeops;
! 1026: op = &promvec->pv_v2devops;
! 1027:
! 1028: node = findroot();
! 1029: if (no->no_proplen(node, "stdin-path") >= sizeof(buffer)) {
! 1030: printf("consinit: increase buffer size and recompile\n");
! 1031: goto setup_output;
! 1032: }
! 1033: /* XXX: fix above */
! 1034:
! 1035: no->no_getprop(node, "stdin-path",buffer);
! 1036:
! 1037: /*
! 1038: * Open an "instance" of this device.
! 1039: * You'd think it would be appropriate to call v2_close()
! 1040: * on the handle when we're done with it. But that seems
! 1041: * to cause the device to shut down somehow; for the moment,
! 1042: * we simply leave it open...
! 1043: */
! 1044: if ((fd = op->v2_open(buffer)) == 0 ||
! 1045: (node = op->v2_fd_phandle(fd)) == 0) {
! 1046: printf("consinit: bogus stdin path %s.\n",buffer);
! 1047: goto setup_output;
! 1048: }
! 1049: if (no->no_proplen(node,"keyboard") >= 0) {
! 1050: inSource = PROMDEV_KBD;
! 1051: goto setup_output;
! 1052: }
! 1053: if (strcmp(getpropstring(node,"device_type"),"serial") != 0) {
! 1054: /* not a serial, not keyboard. what is it?!? */
! 1055: inSource = -1;
! 1056: goto setup_output;
! 1057: }
! 1058: /*
! 1059: * At this point we assume the device path is in the form
! 1060: * ....device@x,y:a for ttya and ...device@x,y:b for ttyb.
! 1061: * If it isn't, we defer to the ROM
! 1062: */
! 1063: cp = buffer;
! 1064: while (*cp)
! 1065: cp++;
! 1066: cp -= 2;
! 1067: #ifdef DEBUG
! 1068: if (cp < buffer)
! 1069: panic("consinit: bad stdin path %s",buffer);
! 1070: #endif
! 1071: /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
! 1072: if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z')
! 1073: inSource = PROMDEV_TTYA + (cp[1] - 'a');
! 1074: /* else use rom */
! 1075: setup_output:
! 1076: node = findroot();
! 1077: if (no->no_proplen(node, "stdout-path") >= sizeof(buffer)) {
! 1078: printf("consinit: increase buffer size and recompile\n");
! 1079: goto setup_console;
! 1080: }
! 1081: /* XXX: fix above */
! 1082:
! 1083: no->no_getprop(node, "stdout-path", buffer);
! 1084:
! 1085: if ((fd = op->v2_open(buffer)) == 0 ||
! 1086: (node = op->v2_fd_phandle(fd)) == 0) {
! 1087: printf("consinit: bogus stdout path %s.\n",buffer);
! 1088: goto setup_output;
! 1089: }
! 1090: if (strcmp(getpropstring(node,"device_type"),"display") == 0) {
! 1091: /* frame buffer output */
! 1092: outSink = PROMDEV_SCREEN;
! 1093: fbnode = node;
! 1094: } else if (strcmp(getpropstring(node,"device_type"), "serial")
! 1095: != 0) {
! 1096: /* not screen, not serial. Whatzit? */
! 1097: outSink = -1;
! 1098: } else { /* serial console. which? */
! 1099: /*
! 1100: * At this point we assume the device path is in the
! 1101: * form:
! 1102: * ....device@x,y:a for ttya, etc.
! 1103: * If it isn't, we defer to the ROM
! 1104: */
! 1105: cp = buffer;
! 1106: while (*cp)
! 1107: cp++;
! 1108: cp -= 2;
! 1109: #ifdef DEBUG
! 1110: if (cp < buffer)
! 1111: panic("consinit: bad stdout path %s",buffer);
! 1112: #endif
! 1113: /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
! 1114: if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z')
! 1115: outSink = PROMDEV_TTYA + (cp[1] - 'a');
! 1116: else outSink = -1;
! 1117: }
! 1118: } else {
! 1119: inSource = *promvec->pv_stdin;
! 1120: outSink = *promvec->pv_stdout;
! 1121: }
! 1122: #endif /* SUN4 || SUN4C || SUN4M */
! 1123: #ifdef solbourne
! 1124: if (CPU_ISKAP) {
! 1125: const char *dev;
! 1126:
! 1127: inSource = PROMDEV_TTYA; /* default */
! 1128: dev = prom_getenv(ENV_INPUTDEVICE);
! 1129: if (dev != NULL) {
! 1130: if (strcmp(dev, "ttyb") == 0)
! 1131: inSource = PROMDEV_TTYB;
! 1132: if (strcmp(dev, "keyboard") == 0)
! 1133: inSource = PROMDEV_KBD;
! 1134: }
! 1135:
! 1136: outSink = PROMDEV_TTYA; /* default */
! 1137: dev = prom_getenv(ENV_OUTPUTDEVICE);
! 1138: if (dev != NULL) {
! 1139: if (strcmp(dev, "ttyb") == 0)
! 1140: outSink = PROMDEV_TTYB;
! 1141: if (strcmp(dev, "screen") == 0)
! 1142: outSink = PROMDEV_SCREEN;
! 1143: }
! 1144: }
! 1145: #endif
! 1146:
! 1147: #if defined(SUN4) || defined(SUN4C) || defined(SUN4M)
! 1148: setup_console:
! 1149: #endif
! 1150:
! 1151: if (inSource != outSink) {
! 1152: printf("cninit: mismatched PROM output selector\n");
! 1153: }
! 1154:
! 1155: switch (inSource) {
! 1156: default:
! 1157: printf("cninit: invalid inSource=%d\n", inSource);
! 1158: callrom();
! 1159: inSource = PROMDEV_KBD;
! 1160: /* FALLTHROUGH */
! 1161:
! 1162: case PROMDEV_KBD: /* keyboard/display */
! 1163: #if NZSKBD > 0
! 1164: zs_unit = 1;
! 1165: channel = 0;
! 1166: break;
! 1167: #else /* NZSKBD */
! 1168: printf("cninit: kdb/display not configured\n");
! 1169: callrom();
! 1170: inSource = PROMDEV_TTYA;
! 1171: /* FALLTHROUGH */
! 1172: #endif /* NZSKBD */
! 1173:
! 1174: case PROMDEV_TTYA:
! 1175: case PROMDEV_TTYB:
! 1176: zstty_unit = inSource - PROMDEV_TTYA;
! 1177: zs_unit = 0;
! 1178: channel = zstty_unit & 1;
! 1179: console = &consdev_tty;
! 1180: break;
! 1181:
! 1182: }
! 1183: /* Now that inSource has been validated, print it. */
! 1184: printf("console is %s\n", prom_inSrc_name[inSource]);
! 1185:
! 1186: zc = zs_get_chan_addr(zs_unit, channel);
! 1187: if (zc == NULL) {
! 1188: printf("cninit: zs not mapped.\n");
! 1189: return;
! 1190: }
! 1191: zs_conschan = zc;
! 1192: zs_hwflags[zs_unit][channel] = ZS_HWFLAG_CONSOLE;
! 1193: /* switch to selected console */
! 1194: cn_tab = console;
! 1195: (*cn_tab->cn_probe)(cn_tab);
! 1196: (*cn_tab->cn_init)(cn_tab);
! 1197: #ifdef KGDB
! 1198: zs_kgdb_init();
! 1199: #endif
! 1200: }
CVSweb