Annotation of sys/arch/mac68k/dev/zs.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: zs.c,v 1.23 2007/01/14 18:50:23 martin Exp $ */
! 2: /* $NetBSD: zs.c,v 1.19 1998/01/12 19:22:18 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1996-1998 Bill Studenmund
! 6: * Copyright (c) 1995 Gordon W. Ross
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. The name of the author may not be used to endorse or promote products
! 18: * derived from this software without specific prior written permission.
! 19: * 4. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by Gordon Ross
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 33: */
! 34:
! 35: /*
! 36: * Zilog Z8530 Dual UART driver (machine-dependent part)
! 37: *
! 38: * Runs two serial lines per chip using slave drivers.
! 39: * Plain tty/async lines use the zs_async slave.
! 40: * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
! 41: * Other ports use their own mice & keyboard slaves.
! 42: *
! 43: * Credits & history:
! 44: *
! 45: * With NetBSD 1.1, port-mac68k started using a port of the port-sparc
! 46: * (port-sun3?) zs.c driver (which was in turn based on code in the
! 47: * Berkeley 4.4 Lite release). Bill Studenmund did the port, with
! 48: * help from Allen Briggs and Gordon Ross <gwr@netbsd.org>. Noud de
! 49: * Brouwer field-tested the driver at a local ISP.
! 50: *
! 51: * Bill Studenmund and Gordon Ross then ported the machine-independant
! 52: * z8530 driver to work with port-mac68k. NetBSD 1.2 contained an
! 53: * intermediate version (mac68k using a local, patched version of
! 54: * the m.i. drivers), with NetBSD 1.3 containing a full version.
! 55: */
! 56:
! 57: #include <sys/param.h>
! 58: #include <sys/systm.h>
! 59: #include <sys/proc.h>
! 60: #include <sys/device.h>
! 61: #include <sys/conf.h>
! 62: #include <sys/file.h>
! 63: #include <sys/ioctl.h>
! 64: #include <sys/tty.h>
! 65: #include <sys/time.h>
! 66: #include <sys/kernel.h>
! 67: #include <sys/syslog.h>
! 68:
! 69: #include <dev/cons.h>
! 70:
! 71: #include <mac68k/dev/z8530reg.h>
! 72: #include <machine/z8530var.h>
! 73:
! 74: #include <machine/autoconf.h>
! 75: #include <machine/cpu.h>
! 76: #include <machine/psc.h>
! 77: #include <machine/viareg.h>
! 78:
! 79: #ifdef DDB
! 80: #include <ddb/db_var.h>
! 81: #endif
! 82:
! 83: /* Are these in a header file anywhere? */
! 84: /* Booter flags interface */
! 85: #define ZSMAC_RAW 0x01
! 86: #define ZSMAC_LOCALTALK 0x02
! 87: #define ZS_STD_BRG (57600*4)
! 88:
! 89: #include "zsc.h" /* get the # of zs chips defined */
! 90:
! 91: /*
! 92: * Some warts needed by z8530tty.c -
! 93: */
! 94: int zs_def_cflag = (CREAD | CS8 | HUPCL);
! 95: int zs_major = 12;
! 96:
! 97: /*
! 98: * abort detection on console will now timeout after iterating on a loop
! 99: * the following # of times. Cheep hack. Also, abort detection is turned
! 100: * off after a timeout (i.e. maybe there's not a terminal hooked up).
! 101: */
! 102: #define ZSABORT_DELAY 3000000
! 103:
! 104: /*
! 105: * Define interrupt levels.
! 106: */
! 107: #define ZSHARD_PRI 4 /* Wired on the CPU board... */
! 108: /*
! 109: * Serial port cards with zs chips on them are actually at the
! 110: * NuBus interrupt level, which is lower than 4. But blocking
! 111: * level 4 interrupts will block those interrupts too, so level
! 112: * 4 is fine.
! 113: */
! 114:
! 115: /* The layout of this is hardware-dependent (padding, order). */
! 116: struct zschan {
! 117: volatile u_char zc_csr; /* ctrl,status, and indirect access */
! 118: u_char zc_xxx0;
! 119: u_char zc_xxx1; /* part of the other channel lives here!*/
! 120: u_char zc_xxx2; /* Yea Apple! */
! 121: volatile u_char zc_data; /* data */
! 122: u_char zc_xxx3;
! 123: u_char zc_xxx4;
! 124: u_char zc_xxx5;
! 125: };
! 126:
! 127: /* Saved PROM mappings */
! 128: static char *zsaddr[NZSC]; /* See zs_init() */
! 129: /* Flags from cninit() */
! 130: static int zs_hwflags[NZSC][2];
! 131: /* Default speed for each channel */
! 132: static int zs_defspeed[NZSC][2] = {
! 133: { 9600, /* tty00 */
! 134: 9600 }, /* tty01 */
! 135: };
! 136: void *zs_conschan = 0;
! 137: int zs_consunit;
! 138: /* device to which the console is attached--if serial. */
! 139: dev_t mac68k_zsdev;
! 140: /* Mac stuff */
! 141: volatile unsigned char *sccA = 0;
! 142: int nzsc_attached = 0; /* needed as long as we have spurious
! 143: * interrupt problems.
! 144: */
! 145:
! 146: static struct zschan *zs_get_chan_addr(int zsc_unit, int channel);
! 147: void zs_init(void);
! 148: int zs_cn_check_speed(int bps);
! 149:
! 150: static struct zschan *
! 151: zs_get_chan_addr(zsc_unit, channel)
! 152: int zsc_unit, channel;
! 153: {
! 154: char *addr;
! 155: struct zschan *zc;
! 156:
! 157: if (zsc_unit >= NZSC)
! 158: return NULL;
! 159: addr = zsaddr[zsc_unit];
! 160: if (addr == NULL)
! 161: return NULL;
! 162: if (channel == 0) {
! 163: zc = (struct zschan *)(addr +2);
! 164: /* handle the fact the ports are intertwined. */
! 165: } else {
! 166: zc = (struct zschan *)(addr);
! 167: }
! 168: return (zc);
! 169: }
! 170:
! 171:
! 172: /* Find PROM mappings (for console support). */
! 173: int zsinited = 0; /* 0 = not, 1 = inited, not attached, 2= attached */
! 174:
! 175: void
! 176: zs_init()
! 177: {
! 178: if ((zsinited == 2)&&(zsaddr[0] != (char *) sccA))
! 179: panic("Moved zs0 address after attached!");
! 180: zsaddr[0] = (char *) sccA;
! 181: zsinited = 1;
! 182: if (zs_conschan != 0){ /* we might have moved io under the console */
! 183: zs_conschan = zs_get_chan_addr(0, zs_consunit);
! 184: /* so recalc the console port */
! 185: }
! 186: }
! 187:
! 188:
! 189: /*
! 190: * Even though zsparam will set up the clock multiples, etc., we
! 191: * still set them here as: 1) mice & keyboards don't use zsparam,
! 192: * and 2) the console stuff uses these defaults before device
! 193: * attach.
! 194: */
! 195:
! 196: static u_char zs_init_reg[16] = {
! 197: 0, /* 0: CMD (reset, etc.) */
! 198: ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE,
! 199: 0x18 + ZSHARD_PRI, /* IVECT */
! 200: ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
! 201: ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
! 202: ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
! 203: 0, /* 6: TXSYNC/SYNCLO */
! 204: 0, /* 7: RXSYNC/SYNCHI */
! 205: 0, /* 8: alias for data port */
! 206: ZSWR9_MASTER_IE,
! 207: 0, /*10: Misc. TX/RX control bits */
! 208: ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
! 209: 14, /*12: BAUDLO (default=9600) */
! 210: 0, /*13: BAUDHI (default=9600) */
! 211: ZSWR14_BAUD_ENA,
! 212: ZSWR15_BREAK_IE | ZSWR15_DCD_IE | ZSWR15_CTS_IE,
! 213: };
! 214:
! 215:
! 216: /****************************************************************
! 217: * Autoconfig
! 218: ****************************************************************/
! 219:
! 220: /* Definition of the driver for autoconfig. */
! 221: static int zsc_match(struct device *, void *, void *);
! 222: static void zsc_attach(struct device *, struct device *, void *);
! 223: static int zsc_print(void *, const char *name);
! 224:
! 225: struct cfattach zsc_ca = {
! 226: sizeof(struct zsc_softc), zsc_match, zsc_attach
! 227: };
! 228:
! 229: struct cfdriver zsc_cd = {
! 230: NULL, "zsc", DV_DULL
! 231: };
! 232:
! 233: int zshard(void *);
! 234: int zssoft(void *);
! 235:
! 236:
! 237: /*
! 238: * Is the zs chip present?
! 239: */
! 240: static int
! 241: zsc_match(parent, vcf, aux)
! 242: struct device *parent;
! 243: void *vcf;
! 244: void *aux;
! 245: {
! 246: return 1;
! 247: }
! 248:
! 249: /*
! 250: * Attach a found zs.
! 251: *
! 252: * Match slave number to zs unit number, so that misconfiguration will
! 253: * not set up the keyboard as ttya, etc.
! 254: */
! 255: static void
! 256: zsc_attach(parent, self, aux)
! 257: struct device *parent;
! 258: struct device *self;
! 259: void *aux;
! 260: {
! 261: struct zsc_softc *zsc = (void *)self;
! 262: struct zsc_attach_args zsc_args;
! 263: volatile struct zschan *zc;
! 264: struct xzs_chanstate *xcs;
! 265: struct zs_chanstate *cs;
! 266: int zsc_unit, channel;
! 267: int s, chip, theflags;
! 268:
! 269: if (!zsinited)
! 270: zs_init();
! 271: zsinited = 2;
! 272:
! 273: zsc_unit = zsc->zsc_dev.dv_unit;
! 274:
! 275: /* Make sure everything's inited ok. */
! 276: if (zsaddr[zsc_unit] == NULL)
! 277: panic("zs_attach: zs%d not mapped", zsc_unit);
! 278:
! 279: chip = 0;
! 280: #ifdef DEBUG
! 281: printf(" chip type %d",chip);
! 282: #endif
! 283: printf("\n");
! 284:
! 285: /*
! 286: * Initialize software state for each channel.
! 287: */
! 288: for (channel = 0; channel < 2; channel++) {
! 289: zsc_args.channel = channel;
! 290: zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
! 291: xcs = &zsc->xzsc_xcs_store[channel];
! 292: cs = &xcs->xzs_cs;
! 293: zsc->zsc_cs[channel] = cs;
! 294:
! 295: cs->cs_channel = channel;
! 296: cs->cs_private = NULL;
! 297: cs->cs_ops = &zsops_null;
! 298:
! 299: zc = zs_get_chan_addr(zsc_unit, channel);
! 300: cs->cs_reg_csr = &zc->zc_csr;
! 301: cs->cs_reg_data = &zc->zc_data;
! 302:
! 303: if (channel == 0) /* Double check interrupts are off */
! 304: zs_write_reg(cs, 9, 0);
! 305:
! 306: bcopy(zs_init_reg, cs->cs_creg, 16);
! 307: bcopy(zs_init_reg, cs->cs_preg, 16);
! 308:
! 309: /* Current BAUD rate generator clock. */
! 310: cs->cs_brg_clk = ZS_STD_BRG; /* RTxC is 230400*16, so use 230400 */
! 311: cs->cs_defspeed = zs_defspeed[zsc_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;
! 318: cs->cs_wr5_rts = 0;
! 319:
! 320: #ifdef __notyet__
! 321: cs->cs_slave_type = ZS_SLAVE_NONE;
! 322: #endif
! 323:
! 324: /* Define BAUD rate stuff. */
! 325: xcs->cs_clocks[0].clk = ZS_STD_BRG * 16;
! 326: xcs->cs_clocks[0].flags = ZSC_RTXBRG;
! 327: xcs->cs_clocks[1].flags =
! 328: ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
! 329: xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
! 330: xcs->cs_clock_count = 3;
! 331:
! 332: if (channel == 0) {
! 333: theflags = mac68k_machine.modem_flags;
! 334: xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;
! 335: xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;
! 336: } else {
! 337: theflags = mac68k_machine.print_flags;
! 338: xcs->cs_clocks[1].flags = ZSC_VARIABLE;
! 339: /*
! 340: * Yes, we aren't defining ANY clock source enables for
! 341: * the printer's DCD clock in. The hardware won't let
! 342: * us use it. But a clock will freak out the chip, so
! 343: * we let you set it, telling us to bar interrupts on
! 344: * the line.
! 345: */
! 346: xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;
! 347: xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;
! 348: }
! 349: if (xcs->cs_clocks[1].clk)
! 350: zsc_args.hwflags |= ZS_HWFLAG_NO_DCD;
! 351: if (xcs->cs_clocks[2].clk)
! 352: zsc_args.hwflags |= ZS_HWFLAG_NO_CTS;
! 353:
! 354: #ifdef DEBUG
! 355: printf("zsc%d channel %d: d_speed %6d DCD clk %ld CTS clk %ld",
! 356: zsc_unit, channel, cs->cs_defspeed,
! 357: xcs->cs_clocks[1].clk, xcs->cs_clocks[2].clk);
! 358: #endif
! 359:
! 360: /* Set defaults in our "extended" chanstate. */
! 361: xcs->cs_csource = 0;
! 362: xcs->cs_psource = 0;
! 363: xcs->cs_cclk_flag = 0; /* Nothing fancy by default */
! 364: xcs->cs_pclk_flag = 0;
! 365:
! 366: if (theflags & ZSMAC_RAW) {
! 367: zsc_args.hwflags |= ZS_HWFLAG_RAW;
! 368: #ifdef DEBUG
! 369: printf(" (raw defaults)");
! 370: #endif
! 371: }
! 372:
! 373: /*
! 374: * XXX - This might be better done with a "stub" driver
! 375: * (to replace zstty) that ignores LocalTalk for now.
! 376: */
! 377: if (theflags & ZSMAC_LOCALTALK) {
! 378: printf(" shielding from LocalTalk");
! 379: cs->cs_defspeed = 1;
! 380: cs->cs_creg[ZSRR_BAUDLO] = cs->cs_preg[ZSRR_BAUDLO] = 0xff;
! 381: cs->cs_creg[ZSRR_BAUDHI] = cs->cs_preg[ZSRR_BAUDHI] = 0xff;
! 382: zs_write_reg(cs, ZSRR_BAUDLO, 0xff);
! 383: zs_write_reg(cs, ZSRR_BAUDHI, 0xff);
! 384: /*
! 385: * If we might have LocalTalk, then make sure we have
! 386: * the Baud rate low-enough to not do any damage.
! 387: */
! 388: }
! 389:
! 390: /*
! 391: * We used to disable chip interrupts here, but we now
! 392: * do that in zscnprobe, just in case MacOS left the chip on.
! 393: */
! 394:
! 395: xcs->cs_chip = chip;
! 396:
! 397: /* Stash away a copy of the final H/W flags. */
! 398: xcs->cs_hwflags = zsc_args.hwflags;
! 399:
! 400: #ifdef DEBUG
! 401: printf("\n");
! 402: #endif
! 403:
! 404: /*
! 405: * Look for a child driver for this channel.
! 406: * The child attach will setup the hardware.
! 407: */
! 408: if (!config_found(self, (void *)&zsc_args, zsc_print)) {
! 409: /* No sub-driver. Just reset it. */
! 410: u_char reset = (channel == 0) ?
! 411: ZSWR9_A_RESET : ZSWR9_B_RESET;
! 412: s = splzs();
! 413: zs_write_reg(cs, 9, reset);
! 414: splx(s);
! 415: }
! 416: }
! 417:
! 418: if (current_mac_model->class == MACH_CLASSAV) {
! 419: add_psc_lev4_intr(PSCINTR_SCCA, zshard, zsc);
! 420: add_psc_lev4_intr(PSCINTR_SCCB, zshard, zsc);
! 421: } else {
! 422: intr_establish(zshard, zsc, ZSHARD_PRI, self->dv_xname);
! 423: }
! 424:
! 425: /* XXX - Now safe to install interrupt handlers. */
! 426:
! 427: /*
! 428: * Set the master interrupt enable and interrupt vector.
! 429: * (common to both channels, do it on A)
! 430: */
! 431: cs = zsc->zsc_cs[0];
! 432: s = splzs();
! 433: /* interrupt vector */
! 434: zs_write_reg(cs, 2, zs_init_reg[2]);
! 435: /* master interrupt control (enable) */
! 436: zs_write_reg(cs, 9, zs_init_reg[9]);
! 437: nzsc_attached++;
! 438: splx(s);
! 439: }
! 440:
! 441: static int
! 442: zsc_print(aux, name)
! 443: void *aux;
! 444: const char *name;
! 445: {
! 446: struct zsc_attach_args *args = aux;
! 447:
! 448: if (name != NULL)
! 449: printf("%s: ", name);
! 450:
! 451: if (args->channel != -1)
! 452: printf(" channel %d", args->channel);
! 453: return UNCONF;
! 454: }
! 455:
! 456: int
! 457: zsmdioctl(cs, cmd, data)
! 458: struct zs_chanstate *cs;
! 459: u_long cmd;
! 460: caddr_t data;
! 461: {
! 462: switch (cmd) {
! 463: default:
! 464: return (-1);
! 465: }
! 466: return (0);
! 467: }
! 468:
! 469: void
! 470: zsmd_setclock(cs)
! 471: struct zs_chanstate *cs;
! 472: {
! 473: struct xzs_chanstate *xcs = (void *)cs;
! 474:
! 475: if (cs->cs_channel != 0)
! 476: return;
! 477:
! 478: /*
! 479: * If the new clock has the external bit set, then select the
! 480: * external source.
! 481: */
! 482: via_set_modem((xcs->cs_pclk_flag & ZSC_EXTERN) ? 1 : 0);
! 483: }
! 484:
! 485: static int zssoftpending;
! 486:
! 487: /*
! 488: * Do the minimum work to pull data off of the chip and queue it up
! 489: * for later processing.
! 490: */
! 491: int
! 492: zshard(arg)
! 493: void *arg;
! 494: {
! 495: struct zsc_softc *zsc = (struct zsc_softc *)arg;
! 496: int rval;
! 497:
! 498: if (zsc == NULL)
! 499: return 0;
! 500:
! 501: rval = 0;
! 502: rval |= zsc_intr_hard(zsc);
! 503: if ((zsc->zsc_cs[0]->cs_softreq) || (zsc->zsc_cs[1]->cs_softreq)) {
! 504: /* zsc_req_softint(zsc); */
! 505: /* We are at splzs here, so no need to lock. */
! 506: if (zssoftpending == 0) {
! 507: zssoftpending = 1;
! 508: setsoftserial();
! 509: }
! 510: }
! 511: return (rval);
! 512: }
! 513:
! 514: /*
! 515: * Similar scheme as for zshard (look at all of them)
! 516: */
! 517: int
! 518: zssoft(arg)
! 519: void *arg;
! 520: {
! 521: register struct zsc_softc *zsc;
! 522: register int unit;
! 523:
! 524: /* This is not the only ISR on this IPL. */
! 525: if (zssoftpending == 0)
! 526: return (0);
! 527:
! 528: /*
! 529: * The soft intr. bit will be set by zshard only if
! 530: * the variable zssoftpending is zero.
! 531: */
! 532: zssoftpending = 0;
! 533:
! 534: for (unit = 0; unit < zsc_cd.cd_ndevs; ++unit) {
! 535: zsc = zsc_cd.cd_devs[unit];
! 536: if (zsc == NULL)
! 537: continue;
! 538: (void) zsc_intr_soft(zsc);
! 539: }
! 540: return (1);
! 541: }
! 542:
! 543:
! 544: #ifndef ZS_TOLERANCE
! 545: #define ZS_TOLERANCE 51
! 546: /* 5% in tenths of a %, plus 1 so that exactly 5% will be ok. */
! 547: #endif
! 548:
! 549: /*
! 550: * check out a rate for acceptability from the internal clock
! 551: * source. Used in console config to validate a requested
! 552: * default speed. Placed here so that all the speed checking code is
! 553: * in one place.
! 554: *
! 555: * != 0 means ok.
! 556: */
! 557: int
! 558: zs_cn_check_speed(bps)
! 559: int bps; /* target rate */
! 560: {
! 561: int tc, rate;
! 562:
! 563: tc = BPS_TO_TCONST(ZS_STD_BRG, bps);
! 564: if (tc < 0)
! 565: return 0;
! 566: rate = TCONST_TO_BPS(ZS_STD_BRG, tc);
! 567: if (ZS_TOLERANCE > abs(((rate - bps)*1000)/bps))
! 568: return 1;
! 569: else
! 570: return 0;
! 571: }
! 572:
! 573: /*
! 574: * Search through the signal sources in the channel, and
! 575: * pick the best one for the baud rate requested. Return
! 576: * a -1 if not achievable in tolerance. Otherwise return 0
! 577: * and fill in the values.
! 578: *
! 579: * This routine draws inspiration from the Atari port's zs.c
! 580: * driver in NetBSD 1.1 which did the same type of source switching.
! 581: * Tolerance code inspired by comspeed routine in isa/com.c.
! 582: *
! 583: * By Bill Studenmund, 1996-05-12
! 584: */
! 585: int
! 586: zs_set_speed(cs, bps)
! 587: struct zs_chanstate *cs;
! 588: int bps; /* bits per second */
! 589: {
! 590: struct xzs_chanstate *xcs = (void *) cs;
! 591: int i, tc, tc0 = 0, tc1, s, sf = 0;
! 592: int src, rate0, rate1, err, tol;
! 593:
! 594: if (bps == 0)
! 595: return (0);
! 596:
! 597: src = -1; /* no valid source yet */
! 598: tol = ZS_TOLERANCE;
! 599:
! 600: /*
! 601: * Step through all the sources and see which one matches
! 602: * the best. A source has to match BETTER than tol to be chosen.
! 603: * Thus if two sources give the same error, the first one will be
! 604: * chosen. Also, allow for the possability that one source might run
! 605: * both the BRG and the direct divider (i.e. RTxC).
! 606: */
! 607: for (i=0; i < xcs->cs_clock_count; i++) {
! 608: if (xcs->cs_clocks[i].clk <= 0)
! 609: continue; /* skip non-existant or bad clocks */
! 610: if (xcs->cs_clocks[i].flags & ZSC_BRG) {
! 611: /* check out BRG at /16 */
! 612: tc1 = BPS_TO_TCONST(xcs->cs_clocks[i].clk >> 4, bps);
! 613: if (tc1 >= 0) {
! 614: rate1 = TCONST_TO_BPS(xcs->cs_clocks[i].clk >> 4, tc1);
! 615: err = abs(((rate1 - bps)*1000)/bps);
! 616: if (err < tol) {
! 617: tol = err;
! 618: src = i;
! 619: sf = xcs->cs_clocks[i].flags & ~ZSC_DIV; tc0 = tc1;
! 620: rate0 = rate1;
! 621: }
! 622: }
! 623: }
! 624: if (xcs->cs_clocks[i].flags & ZSC_DIV) {
! 625: /*
! 626: * Check out either /1, /16, /32, or /64
! 627: * Note: for /1, you'd better be using a synchronized
! 628: * clock!
! 629: */
! 630: int b0 = xcs->cs_clocks[i].clk, e0 = abs(b0-bps);
! 631: int b1 = b0 >> 4, e1 = abs(b1-bps);
! 632: int b2 = b1 >> 1, e2 = abs(b2-bps);
! 633: int b3 = b2 >> 1, e3 = abs(b3-bps);
! 634:
! 635: if (e0 < e1 && e0 < e2 && e0 < e3) {
! 636: err = e0;
! 637: rate1 = b0;
! 638: tc1 = ZSWR4_CLK_X1;
! 639: } else if (e0 > e1 && e1 < e2 && e1 < e3) {
! 640: err = e1;
! 641: rate1 = b1;
! 642: tc1 = ZSWR4_CLK_X16;
! 643: } else if (e0 > e2 && e1 > e2 && e2 < e3) {
! 644: err = e2;
! 645: rate1 = b2;
! 646: tc1 = ZSWR4_CLK_X32;
! 647: } else {
! 648: err = e3;
! 649: rate1 = b3;
! 650: tc1 = ZSWR4_CLK_X64;
! 651: }
! 652:
! 653: err = (err * 1000)/bps;
! 654: if (err < tol) {
! 655: tol = err;
! 656: src = i;
! 657: sf = xcs->cs_clocks[i].flags & ~ZSC_BRG;
! 658: tc0 = tc1;
! 659: rate0 = rate1;
! 660: }
! 661: }
! 662: }
! 663: #ifdef ZSMACDEBUG
! 664: printf("Checking for rate %d. Found source #%d.\n",bps, src);
! 665: #endif
! 666: if (src == -1)
! 667: return (EINVAL); /* no can do */
! 668:
! 669: /*
! 670: * The M.I. layer likes to keep cs_brg_clk current, even though
! 671: * we are the only ones who should be touching the BRG's rate.
! 672: *
! 673: * Note: we are assuming that any ZSC_EXTERN signal source comes in
! 674: * on the RTxC pin. Correct for the mac68k obio zsc.
! 675: */
! 676: if (sf & ZSC_EXTERN)
! 677: cs->cs_brg_clk = xcs->cs_clocks[i].clk >> 4;
! 678: else
! 679: cs->cs_brg_clk = ZS_STD_BRG;
! 680:
! 681: /*
! 682: * Now we have a source, so set it up.
! 683: */
! 684: s = splzs();
! 685: xcs->cs_psource = src;
! 686: xcs->cs_pclk_flag = sf;
! 687: bps = rate0;
! 688: if (sf & ZSC_BRG) {
! 689: cs->cs_preg[4] = ZSWR4_CLK_X16;
! 690: cs->cs_preg[11]= ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD;
! 691: if (sf & ZSC_PCLK) {
! 692: cs->cs_preg[14] = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK;
! 693: } else {
! 694: cs->cs_preg[14] = ZSWR14_BAUD_ENA;
! 695: }
! 696: tc = tc0;
! 697: } else {
! 698: cs->cs_preg[4] = tc0;
! 699: if (sf & ZSC_RTXDIV) {
! 700: cs->cs_preg[11] = ZSWR11_RXCLK_RTXC | ZSWR11_TXCLK_RTXC; } else {
! 701: cs->cs_preg[11] = ZSWR11_RXCLK_TRXC | ZSWR11_TXCLK_TRXC; }
! 702: cs->cs_preg[14]= 0;
! 703: tc = 0xffff;
! 704: }
! 705: /* Set the BAUD rate divisor. */
! 706: cs->cs_preg[12] = tc;
! 707: cs->cs_preg[13] = tc >> 8;
! 708: splx(s);
! 709:
! 710: #ifdef ZSMACDEBUG
! 711: printf("Rate is %7d, tc is %7d, source no. %2d, flags %4x\n", \
! 712: bps, tc, src, sf);
! 713: printf("Registers are: 4 %x, 11 %x, 14 %x\n\n",
! 714: cs->cs_preg[4], cs->cs_preg[11], cs->cs_preg[14]);
! 715: #endif
! 716:
! 717: cs->cs_preg[5] |= ZSWR5_RTS; /* Make sure the drivers are on! */
! 718:
! 719: /* Caller will stuff the pending registers. */
! 720: return (0);
! 721: }
! 722:
! 723: int
! 724: zs_set_modes(cs, cflag)
! 725: struct zs_chanstate *cs;
! 726: int cflag; /* bits per second */
! 727: {
! 728: struct xzs_chanstate *xcs = (void*)cs;
! 729: int s;
! 730:
! 731: /*
! 732: * Make sure we don't enable hfc on a signal line we're ignoring.
! 733: * As we enable CTS interrupts only if we have CRTSCTS or CDTRCTS,
! 734: * this code also effectivly turns off ZSWR15_CTS_IE.
! 735: *
! 736: * Also, disable DCD interrupts if we've been told to ignore
! 737: * the DCD pin. Happens on mac68k because the input line for
! 738: * DCD can also be used as a clock input. (Just set CLOCAL.)
! 739: *
! 740: * If someone tries to turn an invalid flow mode on, Just Say No
! 741: * (Suggested by gwr)
! 742: */
! 743: #if 0
! 744: if ((cflag & CDTRCTS) && (cflag & (CRTSCTS | MDMBUF)))
! 745: return (EINVAL);
! 746: #endif
! 747: if (xcs->cs_hwflags & ZS_HWFLAG_NO_DCD) {
! 748: if (cflag & MDMBUF)
! 749: return (EINVAL);
! 750: cflag |= CLOCAL;
! 751: }
! 752: #if 0
! 753: if ((xcs->cs_hwflags & ZS_HWFLAG_NO_CTS) && (cflag & (CRTSCTS | CDTRCTS)))
! 754: return (EINVAL);
! 755: #endif
! 756:
! 757: /*
! 758: * Output hardware flow control on the chip is horrendous:
! 759: * if carrier detect drops, the receiver is disabled, and if
! 760: * CTS drops, the transmitter is stoped IN MID CHARACTER!
! 761: * Therefore, NEVER set the HFC bit, and instead use the
! 762: * status interrupt to detect CTS changes.
! 763: */
! 764: s = splzs();
! 765: if ((cflag & (CLOCAL | MDMBUF)) != 0)
! 766: cs->cs_rr0_dcd = 0;
! 767: else
! 768: cs->cs_rr0_dcd = ZSRR0_DCD;
! 769: /*
! 770: * The mac hardware only has one output, DTR (HSKo in Mac
! 771: * parlance). In HFC mode, we use it for the functions
! 772: * typically served by RTS and DTR on other ports, so we
! 773: * have to fake the upper layer out some.
! 774: *
! 775: * CRTSCTS we use CTS as an input which tells us when to shut up.
! 776: * We make no effort to shut up the other side of the connection.
! 777: * DTR is used to hang up the modem.
! 778: *
! 779: * In CDTRCTS, we use CTS to tell us to stop, but we use DTR to
! 780: * shut up the other side.
! 781: */
! 782: if ((cflag & CRTSCTS) != 0){
! 783: cs->cs_wr5_dtr = ZSWR5_DTR;
! 784: cs->cs_wr5_rts = 0;
! 785: cs->cs_rr0_cts = ZSRR0_CTS;
! 786: #if 0
! 787: } else if ((cflag & CDTRCTS) != 0) {
! 788: cs->cs_wr5_dtr = 0;
! 789: cs->cs_wr5_rts = ZSWR5_DTR;
! 790: cs->cs_rr0_cts = ZSRR0_CTS;
! 791: #endif
! 792: } else if ((cflag & MDMBUF) != 0) {
! 793: cs->cs_wr5_dtr = 0;
! 794: cs->cs_wr5_rts = ZSWR5_DTR;
! 795: cs->cs_rr0_cts = ZSRR0_DCD;
! 796: } else {
! 797: cs->cs_wr5_dtr = ZSWR5_DTR;
! 798: cs->cs_wr5_rts = 0;
! 799: cs->cs_rr0_cts = 0;
! 800: }
! 801: splx(s);
! 802:
! 803: /* Caller will stuff the pending registers. */
! 804: return(0);
! 805: }
! 806:
! 807: /*
! 808: * Read or write the chip with suitable delays.
! 809: * MacII hardware has the delay built in.
! 810: * No need for extra delay. :-) However, some clock-chiped
! 811: * macs, or zsc's on serial add-on boards might need it.
! 812: */
! 813: #define ZS_DELAY()
! 814:
! 815: u_char
! 816: zs_read_reg(cs, reg)
! 817: struct zs_chanstate *cs;
! 818: u_char reg;
! 819: {
! 820: u_char val;
! 821:
! 822: *cs->cs_reg_csr = reg;
! 823: ZS_DELAY();
! 824: val = *cs->cs_reg_csr;
! 825: ZS_DELAY();
! 826: return val;
! 827: }
! 828:
! 829: void
! 830: zs_write_reg(cs, reg, val)
! 831: struct zs_chanstate *cs;
! 832: u_char reg, val;
! 833: {
! 834: *cs->cs_reg_csr = reg;
! 835: ZS_DELAY();
! 836: *cs->cs_reg_csr = val;
! 837: ZS_DELAY();
! 838: }
! 839:
! 840: u_char zs_read_csr(cs)
! 841: struct zs_chanstate *cs;
! 842: {
! 843: u_char val;
! 844:
! 845: val = *cs->cs_reg_csr;
! 846: ZS_DELAY();
! 847: /* make up for the fact CTS is wired backwards */
! 848: val ^= ZSRR0_CTS;
! 849: return val;
! 850: }
! 851:
! 852: void zs_write_csr(cs, val)
! 853: struct zs_chanstate *cs;
! 854: register u_char val;
! 855: {
! 856: /* Note, the csr does not write CTS... */
! 857: *cs->cs_reg_csr = val;
! 858: ZS_DELAY();
! 859: }
! 860:
! 861: u_char zs_read_data(cs)
! 862: struct zs_chanstate *cs;
! 863: {
! 864: register u_char val;
! 865:
! 866: val = *cs->cs_reg_data;
! 867: ZS_DELAY();
! 868: return val;
! 869: }
! 870:
! 871: void zs_write_data(cs, val)
! 872: struct zs_chanstate *cs;
! 873: u_char val;
! 874: {
! 875: *cs->cs_reg_data = val;
! 876: ZS_DELAY();
! 877: }
! 878:
! 879: /****************************************************************
! 880: * Console support functions (mac68k specific!)
! 881: * Note: this code is allowed to know about the layout of
! 882: * the chip registers, and uses that to keep things simple.
! 883: * XXX - I think I like the mvme167 code better. -gwr
! 884: * XXX - Well :-P :-) -wrs
! 885: ****************************************************************/
! 886:
! 887: #define zscnpollc nullcnpollc
! 888: cons_decl(zs);
! 889:
! 890: static void zs_putc(register volatile struct zschan *, int);
! 891: static int zs_getc(register volatile struct zschan *);
! 892: static void zscnsetup(void);
! 893: extern int zsopen( dev_t dev, int flags, int mode, struct proc *p);
! 894:
! 895: /*
! 896: * Console functions.
! 897: */
! 898:
! 899: /*
! 900: * This code modled after the zs_setparam routine in zskgdb
! 901: * It sets the console unit to a known state so we can output
! 902: * correctly.
! 903: */
! 904: static void
! 905: zscnsetup()
! 906: {
! 907: struct xzs_chanstate xcs;
! 908: struct zs_chanstate *cs;
! 909: struct zschan *zc;
! 910: int tconst, s;
! 911:
! 912: /* Setup temporary chanstate. */
! 913: bzero((caddr_t)&xcs, sizeof(xcs));
! 914: cs = &xcs.xzs_cs;
! 915: zc = zs_conschan;
! 916: cs->cs_reg_csr = &zc->zc_csr;
! 917: cs->cs_reg_data = &zc->zc_data;
! 918: cs->cs_channel = zs_consunit;
! 919: cs->cs_brg_clk = ZS_STD_BRG;
! 920:
! 921: bcopy(zs_init_reg, cs->cs_preg, 16);
! 922: cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
! 923: cs->cs_preg[15] = ZSWR15_BREAK_IE;
! 924: tconst = BPS_TO_TCONST(cs->cs_brg_clk,
! 925: zs_defspeed[0][zs_consunit]);
! 926: cs->cs_preg[12] = tconst;
! 927: cs->cs_preg[13] = tconst >> 8;
! 928: /* can't use zs_set_speed as we haven't set up the
! 929: * signal sources, and it's not worth it for now
! 930: */
! 931:
! 932: /*
! 933: * As zs_loadchannelregs doesn't touch reg 9 (interrupt control),
! 934: * we won't accidentally turn on interrupts below
! 935: */
! 936: s = splhigh();
! 937: zs_loadchannelregs(cs);
! 938: splx(s);
! 939: }
! 940:
! 941: /*
! 942: * zscnprobe is the routine which gets called as the kernel is trying to
! 943: * figure out where the console should be. Each io driver which might
! 944: * be the console (as defined in mac68k/conf.c) gets probed. The probe
! 945: * fills in the consdev structure. Important parts are the device #,
! 946: * and the console priority. Values are CN_DEAD (don't touch me),
! 947: * CN_NORMAL (I'm here, but elsewhere might be better), CN_INTERNAL
! 948: * (the video, better than CN_NORMAL), and CN_REMOTE (pick me!)
! 949: *
! 950: * As the mac's a bit different, we do extra work here. We mainly check
! 951: * to see if we have serial echo going on. Also chould check for default
! 952: * speeds.
! 953: */
! 954: void
! 955: zscnprobe(struct consdev * cp)
! 956: {
! 957: extern u_long IOBase;
! 958: int maj, unit, i;
! 959:
! 960: for (maj = 0; maj < nchrdev; maj++) {
! 961: if (cdevsw[maj].d_open == zsopen) {
! 962: break;
! 963: }
! 964: }
! 965: if (maj != nchrdev) {
! 966: cp->cn_pri = CN_NORMAL; /* Lower than CN_INTERNAL */
! 967: if (mac68k_machine.serial_console != 0) {
! 968: cp->cn_pri = CN_REMOTE; /* Higher than CN_INTERNAL */
! 969: mac68k_machine.serial_boot_echo =0;
! 970: }
! 971:
! 972: unit = (mac68k_machine.serial_console == 1) ? 0 : 1;
! 973: zs_consunit = unit;
! 974: zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
! 975:
! 976: mac68k_zsdev = cp->cn_dev = makedev(maj, unit);
! 977: }
! 978: if (mac68k_machine.serial_boot_echo) {
! 979: /*
! 980: * at this point, we know that we don't have a serial
! 981: * console, but are doing echo
! 982: */
! 983: zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
! 984: zs_consunit = 1; /* printer port */
! 985: }
! 986:
! 987: if ((i = mac68k_machine.modem_d_speed) > 0) {
! 988: if (zs_cn_check_speed(i))
! 989: zs_defspeed[0][0] = i;
! 990: }
! 991: if ((i = mac68k_machine.print_d_speed) > 0) {
! 992: if (zs_cn_check_speed(i))
! 993: zs_defspeed[0][1] = i;
! 994: }
! 995: mac68k_set_io_offsets(IOBase);
! 996: zs_init();
! 997: /*
! 998: * zsinit will set up the addresses of the scc. It will also, if
! 999: * zs_conschan != 0, calculate the new address of the conschan for
! 1000: * unit zs_consunit. So if we are (or think we are) going to use the
! 1001: * chip for console I/O, we just set up the internal addresses for it.
! 1002: *
! 1003: * Now turn off interrupts for the chip. Note: this code piece is the
! 1004: * only vestage of the NetBSD 1.0 ser driver. :-)
! 1005: */
! 1006: unit = sccA[2]; /* reset reg. access */
! 1007: unit = sccA[0];
! 1008: sccA[2] = 9; sccA[2] = 0; /* write 0 to reg. 9, clearing MIE */
! 1009: sccA[2] = ZSWR0_CLR_INTR; unit = sccA[2]; /* reset any pending ints. */
! 1010: sccA[0] = ZSWR0_CLR_INTR; unit = sccA[0];
! 1011:
! 1012: if (mac68k_machine.serial_boot_echo)
! 1013: zscnsetup();
! 1014: }
! 1015:
! 1016: void
! 1017: zscninit(struct consdev * cp)
! 1018: {
! 1019: zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE;
! 1020: /*
! 1021: * zsinit will set up the addresses of the scc. It will also, if
! 1022: * zs_conschan != 0, calculate the new address of the conschan for
! 1023: * unit zs_consunit. So zs_init implicitly sets zs_conschan to the right
! 1024: * number. :-)
! 1025: */
! 1026: zscnsetup();
! 1027: }
! 1028:
! 1029:
! 1030: /*
! 1031: * Polled input char.
! 1032: */
! 1033: static int
! 1034: zs_getc(zc)
! 1035: register volatile struct zschan *zc;
! 1036: {
! 1037: register int s, c, rr0;
! 1038:
! 1039: s = splhigh();
! 1040: /* Wait for a character to arrive. */
! 1041: do {
! 1042: rr0 = zc->zc_csr;
! 1043: ZS_DELAY();
! 1044: } while ((rr0 & ZSRR0_RX_READY) == 0);
! 1045:
! 1046: c = zc->zc_data;
! 1047: ZS_DELAY();
! 1048: splx(s);
! 1049:
! 1050: return (c);
! 1051: }
! 1052:
! 1053: /*
! 1054: * Polled output char.
! 1055: */
! 1056: static void
! 1057: zs_putc(zc, c)
! 1058: register volatile struct zschan *zc;
! 1059: int c;
! 1060: {
! 1061: register int s, rr0;
! 1062: register long wait = 0;
! 1063:
! 1064: s = splhigh();
! 1065: /* Wait for transmitter to become ready. */
! 1066: do {
! 1067: rr0 = zc->zc_csr;
! 1068: ZS_DELAY();
! 1069: } while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000));
! 1070:
! 1071: if ((rr0 & ZSRR0_TX_READY) != 0) {
! 1072: zc->zc_data = c;
! 1073: ZS_DELAY();
! 1074: }
! 1075: splx(s);
! 1076: }
! 1077:
! 1078:
! 1079: /*
! 1080: * Polled console input putchar.
! 1081: */
! 1082: int
! 1083: zscngetc(dev)
! 1084: dev_t dev;
! 1085: {
! 1086: register volatile struct zschan *zc = zs_conschan;
! 1087: register int c;
! 1088:
! 1089: c = zs_getc(zc);
! 1090: return (c);
! 1091: }
! 1092:
! 1093: /*
! 1094: * Polled console output putchar.
! 1095: */
! 1096: void
! 1097: zscnputc(dev, c)
! 1098: dev_t dev;
! 1099: int c;
! 1100: {
! 1101: register volatile struct zschan *zc = zs_conschan;
! 1102:
! 1103: zs_putc(zc, c);
! 1104: }
! 1105:
! 1106:
! 1107:
! 1108: /*
! 1109: * Handle user request to enter kernel debugger.
! 1110: */
! 1111: void
! 1112: zs_abort(cs)
! 1113: struct zs_chanstate *cs;
! 1114: {
! 1115: volatile struct zschan *zc = zs_conschan;
! 1116: int rr0;
! 1117: register long wait = 0;
! 1118:
! 1119: /* Wait for end of break to avoid PROM abort. */
! 1120: do {
! 1121: rr0 = zc->zc_csr;
! 1122: ZS_DELAY();
! 1123: } while ((rr0 & ZSRR0_BREAK) && (wait++ < ZSABORT_DELAY));
! 1124:
! 1125: if (wait > ZSABORT_DELAY)
! 1126: return; /* XXX */
! 1127: #ifdef DDB
! 1128: if (db_console)
! 1129: Debugger();
! 1130: #endif
! 1131: }
CVSweb