diff --git a/sys/dev/ic/z8530sc.c b/sys/dev/ic/z8530sc.c index 9f7207e71668..fa6159017382 100644 --- a/sys/dev/ic/z8530sc.c +++ b/sys/dev/ic/z8530sc.c @@ -1,4 +1,4 @@ -/* $NetBSD: z8530sc.c,v 1.4 1996/05/17 19:30:34 gwr Exp $ */ +/* $NetBSD: z8530sc.c,v 1.5 1996/12/17 20:42:40 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -67,7 +67,7 @@ #include #include -int +void zs_break(cs, set) struct zs_chanstate *cs; int set; @@ -87,20 +87,6 @@ zs_break(cs, set) } -/* - * Compute the current baud rate given a ZSCC channel. - */ -int -zs_getspeed(cs) - struct zs_chanstate *cs; -{ - int tconst; - - tconst = zs_read_reg(cs, 12); - tconst |= zs_read_reg(cs, 13) << 8; - return (TCONST_TO_BPS(cs->cs_brg_clk, tconst)); -} - /* * drain on-chip fifo */ @@ -142,7 +128,6 @@ zs_loadchannelregs(cs) struct zs_chanstate *cs; { u_char *reg; - int i; /* Copy "pending" regs to "current" */ bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16); @@ -158,6 +143,9 @@ zs_loadchannelregs(cs) zs_iflush(cs); /* XXX */ #endif + /* disable interrupts */ + zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK); + /* baud clock divisor, stop bits, parity */ zs_write_reg(cs, 4, reg[4]); @@ -168,8 +156,9 @@ zs_loadchannelregs(cs) zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); - /* interrupt enables: TX, TX, STATUS */ - zs_write_reg(cs, 1, reg[1]); + /* synchronous mode stuff */ + zs_write_reg(cs, 6, reg[6]); + zs_write_reg(cs, 7, reg[7]); #if 0 /* @@ -185,6 +174,14 @@ zs_loadchannelregs(cs) zs_write_reg(cs, 9, reg[9]); #endif + /* Shut down the BRG */ + zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA); + +#ifdef ZS_MD_SETCLK + /* Let the MD code setup any external clock. */ + ZS_MD_SETCLK(cs); +#endif /* ZS_MD_SETCLK */ + /* clock mode control */ zs_write_reg(cs, 11, reg[11]); @@ -198,9 +195,21 @@ zs_loadchannelregs(cs) /* which lines cause status interrupts */ zs_write_reg(cs, 15, reg[15]); + /* + * Zilog docs recommend resetting external status twice at this + * point. Mainly as the status bits are latched, and the first + * interrupt clear might unlatch them to new values, generating + * a second interrupt request. + */ + zs_write_csr(cs, ZSM_RESET_STINT); + zs_write_csr(cs, ZSM_RESET_STINT); + /* char size, enable (RX/TX)*/ zs_write_reg(cs, 3, reg[3]); zs_write_reg(cs, 5, reg[5]); + + /* interrupt enables: RX, TX, STATUS */ + zs_write_reg(cs, 1, reg[1]); } @@ -223,48 +232,49 @@ zsc_intr_hard(arg) register struct zs_chanstate *cs_a; register struct zs_chanstate *cs_b; register int rval; - register u_char rr3; + register u_char rr3, rr3a; - cs_a = &zsc->zsc_cs[0]; - cs_b = &zsc->zsc_cs[1]; + cs_a = zsc->zsc_cs[0]; + cs_b = zsc->zsc_cs[1]; rval = 0; + rr3a = 0; /* Note: only channel A has an RR3 */ - rr3 = zs_read_reg(cs_a, 3); + while ((rr3 = zs_read_reg(cs_a, 3)) != 0) { - /* Handle receive interrupts first. */ - if (rr3 & ZSRR3_IP_A_RX) - (*cs_a->cs_ops->zsop_rxint)(cs_a); - if (rr3 & ZSRR3_IP_B_RX) - (*cs_b->cs_ops->zsop_rxint)(cs_b); + /* Handle receive interrupts first. */ + if (rr3 & ZSRR3_IP_A_RX) + (*cs_a->cs_ops->zsop_rxint)(cs_a); + if (rr3 & ZSRR3_IP_B_RX) + (*cs_b->cs_ops->zsop_rxint)(cs_b); - /* Handle status interrupts (i.e. flow control). */ - if (rr3 & ZSRR3_IP_A_STAT) - (*cs_a->cs_ops->zsop_stint)(cs_a); - if (rr3 & ZSRR3_IP_B_STAT) - (*cs_b->cs_ops->zsop_stint)(cs_b); + /* Handle status interrupts (i.e. flow control). */ + if (rr3 & ZSRR3_IP_A_STAT) + (*cs_a->cs_ops->zsop_stint)(cs_a); + if (rr3 & ZSRR3_IP_B_STAT) + (*cs_b->cs_ops->zsop_stint)(cs_b); - /* Handle transmit done interrupts. */ - if (rr3 & ZSRR3_IP_A_TX) - (*cs_a->cs_ops->zsop_txint)(cs_a); - if (rr3 & ZSRR3_IP_B_TX) - (*cs_b->cs_ops->zsop_txint)(cs_b); + /* Handle transmit done interrupts. */ + if (rr3 & ZSRR3_IP_A_TX) + (*cs_a->cs_ops->zsop_txint)(cs_a); + if (rr3 & ZSRR3_IP_B_TX) + (*cs_b->cs_ops->zsop_txint)(cs_b); + + /* Accumulate so we know what needs to be cleared. */ + rr3a |= rr3; + } /* Clear interrupt. */ - if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) { + if (rr3a & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) { zs_write_csr(cs_a, ZSWR0_CLR_INTR); rval |= 1; } - if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) { + if (rr3a & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) { zs_write_csr(cs_b, ZSWR0_CLR_INTR); rval |= 2; } - if ((cs_a->cs_softreq) || (cs_b->cs_softreq)) { - /* This is a machine-dependent function (or macro). */ - zsc_req_softint(zsc); - } - + /* Note: caller will check cs_x->cs_softreq and DTRT. */ return (rval); } @@ -278,11 +288,11 @@ zsc_intr_soft(arg) { register struct zsc_softc *zsc = arg; register struct zs_chanstate *cs; - register int rval, unit; + register int rval, chan; rval = 0; - for (unit = 0; unit < 2; unit++) { - cs = &zsc->zsc_cs[unit]; + for (chan = 0; chan < 2; chan++) { + cs = zsc->zsc_cs[chan]; /* * The softint flag can be safely cleared once @@ -292,25 +302,33 @@ zsc_intr_soft(arg) if (cs->cs_softreq) { cs->cs_softreq = 0; (*cs->cs_ops->zsop_softint)(cs); - rval = 1; + rval++; } } return (rval); } +/* + * Provide a null zs "ops" vector. + */ + +static void zsnull_intr __P((struct zs_chanstate *)); +static void zsnull_softint __P((struct zs_chanstate *)); static void zsnull_intr(cs) struct zs_chanstate *cs; { - zs_write_reg(cs, 1, 0); - zs_write_reg(cs, 15, 0); + /* Ask for softint() call. */ + cs->cs_softreq = 1; } static void zsnull_softint(cs) struct zs_chanstate *cs; { + zs_write_reg(cs, 1, 0); + zs_write_reg(cs, 15, 0); } struct zsops zsops_null = { diff --git a/sys/dev/ic/z8530sc.h b/sys/dev/ic/z8530sc.h index 08c95fd6015b..fe4148d7addc 100644 --- a/sys/dev/ic/z8530sc.h +++ b/sys/dev/ic/z8530sc.h @@ -1,4 +1,4 @@ -/* $NetBSD: z8530sc.h,v 1.4 1996/10/16 20:34:54 gwr Exp $ */ +/* $NetBSD: z8530sc.h,v 1.5 1996/12/17 20:42:42 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -49,11 +49,13 @@ /* * Function vector - per channel */ +struct zs_chanstate; +typedef void (*zsop_t) __P((struct zs_chanstate *)); struct zsops { - void (*zsop_rxint)(); /* receive char available */ - void (*zsop_stint)(); /* external/status */ - void (*zsop_txint)(); /* xmit buffer empty */ - void (*zsop_softint)(); /* process software interrupt */ + zsop_t zsop_rxint; /* receive char available */ + zsop_t zsop_stint; /* external/status */ + zsop_t zsop_txint; /* xmit buffer empty */ + zsop_t zsop_softint; /* process software interrupt */ }; extern struct zsops zsops_null; @@ -74,7 +76,8 @@ struct zs_chanstate { int cs_brg_clk; /* BAUD Rate Generator clock * (usually PCLK / 16) */ - int cs_defspeed; /* default baud rate (from PROM) */ + int cs_defspeed; /* default baud rate */ + int cs_defcflag; /* default cflag */ /* * We must keep a copy of the write registers as they are @@ -91,22 +94,41 @@ struct zs_chanstate { */ u_char cs_creg[16]; /* current values */ u_char cs_preg[16]; /* pending values */ + int cs_heldchange; /* change pending (creg != preg) */ - u_char cs_heldchange; /* change pending (creg != preg) */ u_char cs_rr0; /* last rr0 processed */ u_char cs_rr0_delta; /* rr0 changes at status intr. */ + u_char cs_rr0_dcd; /* which bit to read as DCD */ + u_char cs_rr0_cts; /* which bit to read as CTS */ + /* the above is set only while CRTSCTS is enabled. */ + + u_char cs_wr5_dtr; /* which bit to write as DTR */ + u_char cs_wr5_rts; /* which bit to write as RTS */ + /* the above is set only while CRTSCTS is enabled. */ char cs_softreq; /* need soft interrupt call */ -}; - -struct zsc_softc { - struct device zsc_dev; /* required first: base device */ - struct zs_chanstate zsc_cs[2]; /* channel A and B soft state */ + char cs_pad[1]; + /* MD code might define a larger variant of this. */ }; struct zsc_attach_args { int channel; /* two serial channels per zsc */ int hwflags; }; -#define ZS_HWFLAG_CONSOLE 1 +#define ZS_HWFLAG_CONSOLE 1 +#define ZS_HWFLAG_NO_DCD 2 /* Ignore the DCD bit */ +#define ZS_HWFLAG_NO_CTS 4 /* Ignore the CTS bit */ +#define ZS_HWFLAG_RAW 8 /* advise raw mode */ + +int zsc_intr_soft __P((void *)); +int zsc_intr_hard __P((void *)); + +void zs_abort __P((struct zs_chanstate *)); +void zs_break __P((struct zs_chanstate *, int)); +void zs_iflush __P((struct zs_chanstate *)); +void zs_loadchannelregs __P((struct zs_chanstate *)); +int zs_set_speed __P((struct zs_chanstate *, int)); +int zs_set_modes __P((struct zs_chanstate *, int)); + +extern int zs_major; diff --git a/sys/dev/ic/z8530tty.c b/sys/dev/ic/z8530tty.c index 0c80f06b1947..68d55a17ca6f 100644 --- a/sys/dev/ic/z8530tty.c +++ b/sys/dev/ic/z8530tty.c @@ -1,4 +1,4 @@ -/* $NetBSD: z8530tty.c,v 1.13 1996/10/16 20:42:14 gwr Exp $ */ +/* $NetBSD: z8530tty.c,v 1.14 1996/12/17 20:42:43 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -85,14 +85,6 @@ extern int zs_check_kgdb(); #endif -/* - * Allow the MD var.h to override the default CFLAG so that - * console messages during boot come out with correct parity. - */ -#ifndef ZSTTY_DEF_CFLAG -#define ZSTTY_DEF_CFLAG TTYDEF_CFLAG -#endif - /* * How many input characters we can buffer. * The port-specific var.h may override this. @@ -158,7 +150,11 @@ struct zstty_softc { /* Definition of the driver for autoconfig. */ +#ifdef __BROKEN_INDIRECT_CONFIG static int zstty_match(struct device *, void *, void *); +#else +static int zstty_match(struct device *, struct cfdata *, void *); +#endif static void zstty_attach(struct device *, struct device *, void *); struct cfattach zstty_ca = { @@ -174,21 +170,22 @@ struct zsops zsops_tty; /* Routines called from other code. */ cdev_decl(zs); /* open, close, read, write, ioctl, stop, ... */ -static void zsstart(struct tty *); -static int zsparam(struct tty *, struct termios *); -static void zs_modem(struct zstty_softc *zst, int onoff); -static int zshwiflow(struct tty *, int); -static void zs_hwiflow(struct zstty_softc *, int); +static void zsstart __P((struct tty *)); +static int zsparam __P((struct tty *, struct termios *)); +static void zs_modem __P((struct zstty_softc *zst, int onoff)); +static int zshwiflow __P((struct tty *, int)); +static void zs_hwiflow __P((struct zstty_softc *, int)); /* * zstty_match: how is this zs channel configured? */ +#ifdef __BROKEN_INDIRECT_CONFIG int -zstty_match(parent, match, aux) +zstty_match(parent, vcf, aux) struct device *parent; - void *match, *aux; + void *vcf, *aux; { - struct cfdata *cf = match; + struct cfdata *cf = vcf; struct zsc_attach_args *args = aux; /* Exact match is better than wildcard. */ @@ -201,6 +198,26 @@ zstty_match(parent, match, aux) return 0; } +#else /* __BROKEN_INDIRECT_CONFIG */ +int +zstty_match(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + struct zsc_attach_args *args = aux; + + /* Exact match is better than wildcard. */ + if (cf->cf_loc[0] == args->channel) + return 2; + + /* This driver accepts wildcard. */ + if (cf->cf_loc[0] == -1) + return 1; + + return 0; +} +#endif /* __BROKEN_INDIRECT_CONFIG */ void zstty_attach(parent, self, aux) @@ -210,24 +227,23 @@ zstty_attach(parent, self, aux) { struct zsc_softc *zsc = (void *) parent; struct zstty_softc *zst = (void *) self; + struct cfdata *cf = self->dv_cfdata; struct zsc_attach_args *args = aux; struct zs_chanstate *cs; - struct cfdata *cf; struct tty *tp; int channel, tty_unit; dev_t dev; - cf = zst->zst_dev.dv_cfdata; tty_unit = zst->zst_dev.dv_unit; channel = args->channel; - cs = &zsc->zsc_cs[channel]; + cs = zsc->zsc_cs[channel]; cs->cs_private = zst; cs->cs_ops = &zsops_tty; zst->zst_cs = cs; zst->zst_swflags = cf->cf_flags; /* softcar, etc. */ zst->zst_hwflags = args->hwflags; - dev = makedev(ZSTTY_MAJOR, tty_unit); + dev = makedev(zs_major, tty_unit); if (zst->zst_swflags) printf(" flags 0x%x", zst->zst_swflags); @@ -266,18 +282,26 @@ zstty_attach(parent, self, aux) zst->zst_rbuf = malloc(zstty_rbuf_size * sizeof(zst->zst_rbuf[0]), M_DEVBUF, M_WAITOK); + /* XXX - Do we need an MD hook here? */ + /* * Hardware init */ if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE) { - /* This unit is the console. */ + /* Call zsparam similar to open. */ + struct termios t; + + /* Make console output work while closed. */ zst->zst_swflags |= TIOCFLAG_SOFTCAR; - /* Call _param so interrupts get enabled. */ - cs->cs_defspeed = zs_getspeed(cs); - tp->t_ispeed = cs->cs_defspeed; - tp->t_ospeed = cs->cs_defspeed; - tp->t_cflag = ZSTTY_DEF_CFLAG; - (void) zsparam(tp, &tp->t_termios); + /* Setup the "new" parameters in t. */ + bzero((void*)&t, sizeof(t)); + t.c_cflag = cs->cs_defcflag; + t.c_ospeed = cs->cs_defspeed; + /* Enable interrupts. */ + cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE; + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void) zsparam(tp, &t); } else { /* Not the console; may need reset. */ int reset, s; @@ -357,48 +381,77 @@ zsopen(dev, flags, mode, p) if ((tp->t_state & TS_ISOPEN) == 0) { /* First open. */ - ttychars(tp); - tp->t_iflag = TTYDEF_IFLAG; - tp->t_oflag = TTYDEF_OFLAG; - tp->t_cflag = ZSTTY_DEF_CFLAG; + struct termios t; + + /* + * Setup the "new" parameters in t. + * Can not use tp->t because zsparam + * deals only with what has changed. + */ + bzero((void*)&t, sizeof(t)); + t.c_cflag = cs->cs_defcflag; if (zst->zst_swflags & TIOCFLAG_CLOCAL) - tp->t_cflag |= CLOCAL; + t.c_cflag |= CLOCAL; if (zst->zst_swflags & TIOCFLAG_CRTSCTS) - tp->t_cflag |= CRTSCTS; + t.c_cflag |= CRTSCTS; if (zst->zst_swflags & TIOCFLAG_MDMBUF) - tp->t_cflag |= MDMBUF; - tp->t_lflag = TTYDEF_LFLAG; - tp->t_ispeed = tp->t_ospeed = cs->cs_defspeed; - (void) zsparam(tp, &tp->t_termios); + t.c_cflag |= MDMBUF; + t.c_ospeed = cs->cs_defspeed; + /* Enable interrupts. */ + cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE; + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void) zsparam(tp, &t); + /* + * Note: zsparam has done: cflag, ispeed, ospeed + * so we just need to do: iflag, oflag, lflag, cc + * For "raw" mode, just leave all zeros. + */ + if ((zst->zst_hwflags & ZS_HWFLAG_RAW) == 0) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + ttychars(tp); + } ttsetwater(tp); /* Flush any pending input. */ zst->zst_rbget = zst->zst_rbput; zs_iflush(cs); /* XXX */ - /* Turn on DTR */ - zs_modem(zst, 1); + /* DTR was turned on by zsparam. */ if (zst->zst_swflags & TIOCFLAG_SOFTCAR) { tp->t_state |= TS_CARR_ON; } + /* XXX - The MD code could just force CLOCAL instead. */ + if (zst->zst_hwflags & ZS_HWFLAG_NO_DCD) { + tp->t_state |= TS_CARR_ON; + } } error = 0; - /* Wait for carrier. */ - for (;;) { + /* In this section, we may touch the chip. */ + (void)splzs(); - /* Might never get status intr if carrier already on. */ - cs->cs_rr0 = zs_read_csr(cs); - if (cs->cs_rr0 & ZSRR0_DCD) { + /* + * Get initial value of RR0. This is done after we + * raise DTR in case the cable loops DTR back to CTS. + */ + cs->cs_rr0 = zs_read_csr(cs); + + /* + * Wait for DCD (if necessary). Note that we might + * never get status interrupt if DCD is already on. + */ + for (;;) { + /* Check the DCD bit (if we have one). */ + if (cs->cs_rr0 & cs->cs_rr0_dcd) tp->t_state |= TS_CARR_ON; - break; - } if ((tp->t_state & TS_CARR_ON) || (tp->t_cflag & CLOCAL) || (flags & O_NONBLOCK) ) - { break; - } + /* Sleep waiting for a status interrupt. */ tp->t_state |= TS_WOPEN; error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0); @@ -411,13 +464,12 @@ zsopen(dev, flags, mode, p) } break; } + /* The status interrupt changed cs->cs_rr0 */ } splx(s); - if (error == 0) error = linesw[tp->t_line].l_open(dev, tp); - return (error); } @@ -434,7 +486,6 @@ zsclose(dev, flags, mode, p) struct zstty_softc *zst; register struct zs_chanstate *cs; register struct tty *tp; - struct zsinfo *zi; int hup, s; zst = zstty_cd.cd_devs[minor(dev)]; @@ -446,6 +497,14 @@ zsclose(dev, flags, mode, p) return 0; (*linesw[tp->t_line].l_close)(tp, flags); + + /* Disable interrupts. */ + s = splzs(); + cs->cs_creg[1] = cs->cs_preg[1] = 0; + zs_write_reg(cs, 1, cs->cs_creg[1]); + splx(s); + + /* Maybe do "hangup" (drop DTR). */ hup = tp->t_cflag & HUPCL; if (zst->zst_swflags & TIOCFLAG_SOFTCAR) hup = 0; @@ -457,7 +516,6 @@ zsclose(dev, flags, mode, p) if (cs->cs_creg[5] & ZSWR5_BREAK) { zs_break(cs, 0); } - /* XXX - turn off interrupts? */ ttyclose(tp); return (0); @@ -517,10 +575,17 @@ zsioctl(dev, cmd, data, flag, p) error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error >= 0) return (error); + error = ttioctl(tp, cmd, data, flag, p); if (error >= 0) return (error); +#ifdef ZS_MD_IOCTL + error = ZS_MD_IOCTL; + if (error >= 0) + return (error); +#endif /* ZS_MD_IOCTL */ + switch (cmd) { case TIOCSBRK: @@ -592,10 +657,10 @@ zsstart(tp) /* * If under CRTSCTS hfc and halted, do nothing + * This flag can only be set with CRTSCTS. */ - if (tp->t_cflag & CRTSCTS) - if (zst->zst_tx_stopped) - goto out; + if (zst->zst_tx_stopped) + goto out; /* * If there are sleepers, and output has drained below low @@ -671,101 +736,116 @@ zsstop(tp, flag) * Set ZS tty parameters from termios. * XXX - Should just copy the whole termios after * making sure all the changes could be done. - * XXX - Only whack the UART when params change... */ static int zsparam(tp, t) register struct tty *tp; register struct termios *t; { - register struct zstty_softc *zst; - register struct zs_chanstate *cs; - register int s, bps, cflag, tconst; - u_char tmp3, tmp4, tmp5, reset; + struct zstty_softc *zst; + struct zs_chanstate *cs; + int s, bps, cflag, error; + u_char tmp3, tmp4, tmp5; zst = zstty_cd.cd_devs[minor(tp->t_dev)]; cs = zst->zst_cs; - - /* XXX: Need to use an MD function for this. */ bps = t->c_ospeed; + cflag = t->c_cflag; + if (bps < 0 || (t->c_ispeed && t->c_ispeed != bps)) return (EINVAL); - if (bps == 0) { - /* stty 0 => drop DTR and RTS */ - zs_modem(zst, 0); + + /* + * Only whack the UART when params change. + * Some callers need to clear tp->t_ospeed + * to make sure initialization gets done. + */ + if ((tp->t_ospeed == bps) && + (tp->t_cflag == cflag) ) return (0); - } - tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); - if (tconst < 0) - return (EINVAL); - /* Convert back to make sure we can do it. */ - bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); - if (bps != t->c_ospeed) - return (EINVAL); - tp->t_ispeed = tp->t_ospeed = bps; + /* + * Call MD functions to deal with changed + * clock modes or H/W flow control modes. + * The BRG divisor is set now. (reg 12,13) + */ + error = zs_set_speed(cs, bps); + if (error) + return (error); + error = zs_set_modes(cs, cflag); + if (error) + return (error); - cflag = t->c_cflag; + /* OK, we are now committed to do it. */ tp->t_cflag = cflag; + tp->t_ospeed = bps; + tp->t_ispeed = bps; /* * Block interrupts so that state will not * be altered until we are done setting it up. - */ - s = splzs(); - - /* + * * Initial values in cs_preg are set before * our attach routine is called. The master * interrupt enable is handled by zsc.c + * */ + s = splzs(); - cs->cs_preg[12] = tconst; - cs->cs_preg[13] = tconst >> 8; - + /* Recompute character size bits. */ + tmp3 = cs->cs_preg[3] & ~ZSWR3_RXSIZE; + tmp5 = cs->cs_preg[5] & ~ZSWR5_TXSIZE; switch (cflag & CSIZE) { case CS5: - tmp3 = ZSWR3_RX_5; - tmp5 = ZSWR5_TX_5; + /* These are |= 0 but let the optimizer deal with it. */ + tmp3 |= ZSWR3_RX_5; + tmp5 |= ZSWR5_TX_5; break; case CS6: - tmp3 = ZSWR3_RX_6; - tmp5 = ZSWR5_TX_6; + tmp3 |= ZSWR3_RX_6; + tmp5 |= ZSWR5_TX_6; break; case CS7: - tmp3 = ZSWR3_RX_7; - tmp5 = ZSWR5_TX_7; + tmp3 |= ZSWR3_RX_7; + tmp5 |= ZSWR5_TX_7; break; case CS8: default: - tmp3 = ZSWR3_RX_8; - tmp5 = ZSWR5_TX_8; + tmp3 |= ZSWR3_RX_8; + tmp5 |= ZSWR5_TX_8; break; } + /* Raise or lower DTR and RTS as appropriate. */ + if (bps) { + /* Raise DTR and RTS */ + tmp5 |= cs->cs_wr5_dtr; + } else { + /* Drop DTR and RTS */ + /* XXX: Should SOFTCAR prevent this? */ + tmp5 &= ~(cs->cs_wr5_dtr); + } + cs->cs_preg[3] = tmp3; + cs->cs_preg[5] = tmp5; - cs->cs_preg[3] = tmp3 | ZSWR3_RX_ENABLE; - cs->cs_preg[5] = tmp5 | ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS; - - tmp4 = ZSWR4_CLK_X16 | (cflag & CSTOPB ? ZSWR4_TWOSB : ZSWR4_ONESB); + /* + * Recompute the stop bits and parity bits. Note that + * zs_set_speed() may have set clock selection bits etc. + * in wr4, so those must preserved. + */ + tmp4 = cs->cs_preg[4]; + /* Recompute stop bits. */ + tmp4 &= ~ZSWR4_SBMASK; + tmp4 |= (cflag & CSTOPB) ? + ZSWR4_TWOSB : ZSWR4_ONESB; + /* Recompute parity bits. */ + tmp4 &= ~ZSWR4_PARMASK; if ((cflag & PARODD) == 0) tmp4 |= ZSWR4_EVENP; if (cflag & PARENB) tmp4 |= ZSWR4_PARENB; cs->cs_preg[4] = tmp4; - /* - * Output hardware flow control on the chip is horrendous: - * if carrier detect drops, the receiver is disabled. - * Therefore, NEVER set the HFC bit, and instead use - * the status interrupts to detect CTS changes. - */ - if (cflag & CRTSCTS) { - zst->zst_rbhiwat = zstty_rbuf_hiwat; - cs->cs_preg[15] |= ZSWR15_CTS_IE; - } else { - zst->zst_rbhiwat = zstty_rbuf_size; /* impossible value */ - cs->cs_preg[15] &= ~ZSWR15_CTS_IE; - } + /* The MD function zs_set_modes handled CRTSCTS, etc. */ /* * If nothing is being transmitted, set up new current values, @@ -775,12 +855,27 @@ zsparam(tp, t) if (zst->zst_tx_busy) { zst->zst_heldtbc = zst->zst_tbc; zst->zst_tbc = 0; - cs->cs_heldchange = 0xFF; /* XXX */ + cs->cs_heldchange = 0xFFFF; } else { zs_loadchannelregs(cs); } } splx(s); + + /* If we can throttle input, enable "high water" detection. */ + if (cflag & CHWFLOW) { + zst->zst_rbhiwat = zstty_rbuf_hiwat; + } else { + /* This impossible value prevents a "high water" trigger. */ + zst->zst_rbhiwat = zstty_rbuf_size; + /* XXX: Lost hwi ability, so unblock and restart. */ + zst->zst_rx_blocked = 0; + if (zst->zst_tx_stopped) { + zst->zst_tx_stopped = 0; + zsstart(tp); + } + } + return (0); } @@ -794,21 +889,23 @@ zs_modem(zst, onoff) int onoff; { struct zs_chanstate *cs; - struct tty *tp; - int s, bis, and; + int s, clr, set; cs = zst->zst_cs; - tp = zst->zst_tty; + if (cs->cs_wr5_dtr == 0) + return; if (onoff) { - bis = ZSWR5_DTR | ZSWR5_RTS; - and = ~0; + clr = 0; + set = cs->cs_wr5_dtr; } else { - bis = 0; - and = ~(ZSWR5_DTR | ZSWR5_RTS); + clr = cs->cs_wr5_dtr; + set = 0; } + s = splzs(); - cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and; + cs->cs_preg[5] &= ~clr; + cs->cs_preg[5] |= set; if (cs->cs_heldchange == 0) { if (zst->zst_tx_busy) { zst->zst_heldtbc = zst->zst_tbc; @@ -834,9 +931,15 @@ zshwiflow(tp, stop) int stop; { register struct zstty_softc *zst; + register struct zs_chanstate *cs; int s; zst = zstty_cd.cd_devs[minor(tp->t_dev)]; + cs = zst->zst_cs; + + /* Can not do this without some bit assigned as RTS. */ + if (cs->cs_wr5_rts == 0) + return (0); s = splzs(); if (stop) { @@ -870,23 +973,25 @@ zs_hwiflow(zst, stop) int stop; { register struct zs_chanstate *cs; - register struct tty *tp; - register int bis, and; + register int clr, set; cs = zst->zst_cs; - tp = zst->zst_tty; + + if (cs->cs_wr5_rts == 0) + return; if (stop) { /* Block input (Lower RTS) */ - bis = 0; - and = ~ZSWR5_RTS; + clr = cs->cs_wr5_rts; + set = 0; } else { /* Unblock input (Raise RTS) */ - bis = ZSWR5_RTS; - and = ~0; + clr = 0; + set = cs->cs_wr5_rts; } - cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and; + cs->cs_preg[5] &= ~clr; + cs->cs_preg[5] |= set; if (cs->cs_heldchange == 0) { if (zst->zst_tx_busy) { zst->zst_heldtbc = zst->zst_tbc; @@ -904,6 +1009,12 @@ zs_hwiflow(zst, stop) * Interface to the lower layer (zscc) ****************************************************************/ +static void zstty_rxint __P((struct zs_chanstate *)); +static void zstty_txint __P((struct zs_chanstate *)); +static void zstty_stint __P((struct zs_chanstate *)); +static void zstty_softint __P((struct zs_chanstate *)); + +static void zsoverrun __P((struct zstty_softc *, long *, char *)); /* * receiver ready interrupt. @@ -1033,11 +1144,9 @@ zstty_stint(cs) register struct zs_chanstate *cs; { register struct zstty_softc *zst; - register struct tty *tp; - register u_char rr0; + register u_char rr0, delta; zst = cs->cs_private; - tp = zst->zst_tty; rr0 = zs_read_csr(cs); zs_write_csr(cs, ZSWR0_RESET_STATUS); @@ -1049,23 +1158,10 @@ zstty_stint(cs) if ((rr0 & ZSRR0_BREAK) && (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)) { - zs_abort(); + zs_abort(cs); return; } - /* - * Need to handle CTS output flow control here. - * Output remains stopped as long as either the - * zst_tx_stopped or TS_TTSTOP flag is set. - * Never restart here; the softint routine will - * do that after things are ready to move. - */ - if (((rr0 & ZSRR0_CTS) == 0) && (tp->t_cflag & CRTSCTS)) { - zst->zst_tbc = 0; - zst->zst_heldtbc = 0; - zst->zst_tx_stopped = 1; - } - /* * We have to accumulate status line changes here. * Otherwise, if we get multiple status interrupts @@ -1073,8 +1169,24 @@ zstty_stint(cs) * some status line changes in the softint routine. * Fix from Bill Studenmund, October 1996. */ - cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0); + delta = (cs->cs_rr0 ^ rr0); + cs->cs_rr0_delta |= delta; cs->cs_rr0 = rr0; + + /* + * Need to handle CTS output flow control here. + * Output remains stopped as long as either the + * zst_tx_stopped or TS_TTSTOP flag is set. + * Never restart here; the softint routine will + * do that after things are ready to move. + */ + if ((delta & cs->cs_rr0_cts) && + ((rr0 & cs->cs_rr0_cts) == 0)) + { + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + zst->zst_tx_stopped = 1; + } zst->zst_st_check = 1; /* Ask for softint() call. */ @@ -1120,7 +1232,7 @@ zstty_softint(cs) register int get, c, s; int ringmask, overrun; register u_short ring_data; - register u_char rr0, rr1, delta; + register u_char rr0, delta; zst = cs->cs_private; tp = zst->zst_tty; @@ -1189,22 +1301,28 @@ zstty_softint(cs) if (zst->zst_st_check) { zst->zst_st_check = 0; + (void) splzs(); rr0 = cs->cs_rr0; delta = cs->cs_rr0_delta; cs->cs_rr0_delta = 0; - if (delta & ZSRR0_DCD) { - c = ((rr0 & ZSRR0_DCD) != 0); + (void) spltty(); + + /* Note, the MD code may use DCD for something else. */ + if (delta & cs->cs_rr0_dcd) { + c = ((rr0 & cs->cs_rr0_dcd) != 0); if (line->l_modem(tp, c) == 0) zs_modem(zst, c); } - if ((delta & ZSRR0_CTS) && (tp->t_cflag & CRTSCTS)) { + + /* Note, cs_rr0_cts is set only with H/W flow control. */ + if (delta & cs->cs_rr0_cts) { /* * Only do restart here. Stop is handled * at the h/w interrupt level. */ - if (rr0 & ZSRR0_CTS) { + if (rr0 & cs->cs_rr0_cts) { zst->zst_tx_stopped = 0; - tp->t_state &= ~TS_TTSTOP; + /* tp->t_state &= ~TS_TTSTOP; */ (*line->l_start)(tp); } } diff --git a/sys/dev/ic/z8530var.h b/sys/dev/ic/z8530var.h deleted file mode 100644 index 4795f3c5dcf2..000000000000 --- a/sys/dev/ic/z8530var.h +++ /dev/null @@ -1,149 +0,0 @@ -/* $NetBSD: z8530var.h,v 1.5 1996/10/23 00:38:05 gwr Exp $ */ - -/* - * Copyright (c) 1994 Gordon W. Ross - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratory. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 - */ - - -/* - * Function vector - per channel - */ -struct zs_chanstate; -typedef void (*zsop_t) __P((struct zs_chanstate *)); -struct zsops { - zsop_t zsop_rxint; /* receive char available */ - zsop_t zsop_stint; /* external/status */ - zsop_t zsop_txint; /* xmit buffer empty */ - zsop_t zsop_softint; /* process software interrupt */ -}; - -extern struct zsops zsops_null; - - -/* - * Software state, per zs channel. - */ -struct zs_chanstate { - - /* Pointers to the device registers. */ - volatile u_char *cs_reg_csr; /* ctrl, status, and reg. number. */ - volatile u_char *cs_reg_data; /* data or numbered register */ - - int cs_channel; /* sub-unit number */ - void *cs_private; /* sub-driver data pointer */ - struct zsops *cs_ops; - - int cs_brg_clk; /* BAUD Rate Generator clock - * (usually PCLK / 16) */ - int cs_defspeed; /* default baud rate */ - int cs_defcflag; /* default cflag */ - - /* - * We must keep a copy of the write registers as they are - * mostly write-only and we sometimes need to set and clear - * individual bits (e.g., in WR3). Not all of these are - * needed but 16 bytes is cheap and this makes the addressing - * simpler. Unfortunately, we can only write to some registers - * when the chip is not actually transmitting, so whenever - * we are expecting a `transmit done' interrupt the preg array - * is allowed to `get ahead' of the current values. In a - * few places we must change the current value of a register, - * rather than (or in addition to) the pending value; for these - * cs_creg[] contains the current value. - */ - u_char cs_creg[16]; /* current values */ - u_char cs_preg[16]; /* pending values */ - int cs_heldchange; /* change pending (creg != preg) */ - - u_char cs_rr0; /* last rr0 processed */ - u_char cs_rr0_delta; /* rr0 changes at status intr. */ - u_char cs_rr0_dcd; /* which bit to read as DCD */ - u_char cs_rr0_cts; /* which bit to read as CTS */ - /* the above is set only while CRTSCTS is enabled. */ - - u_char cs_wr5_dtr; /* which bit to write as DTR */ - u_char cs_wr5_rts; /* which bit to write as RTS */ - /* the above is set only while CRTSCTS is enabled. */ - - char cs_softreq; /* need soft interrupt call */ - char cs_pad[1]; - /* MD code might define a larger variant of this. */ -}; - -struct zsc_softc { - struct device zsc_dev; /* required first: base device */ - struct zs_chanstate *zsc_cs[2]; /* channel A and B soft state */ - /* MD code might define a larger variant of this. */ -}; - -struct zsc_attach_args { - int channel; /* two serial channels per zsc */ - int hwflags; -}; -#define ZS_HWFLAG_CONSOLE 1 -#define ZS_HWFLAG_NO_DCD 2 /* Ignore the DCD bit */ -#define ZS_HWFLAG_NO_CTS 4 /* Ignore the CTS bit */ -#define ZS_HWFLAG_RAW 8 /* advise raw mode */ - -int zsc_intr_soft __P((void *)); -int zsc_intr_hard __P((void *)); - -void zs_abort __P((struct zs_chanstate *)); -void zs_break __P((struct zs_chanstate *, int)); -void zs_iflush __P((struct zs_chanstate *)); -void zs_loadchannelregs __P((struct zs_chanstate *)); -int zs_set_speed __P((struct zs_chanstate *, int)); -int zs_set_modes __P((struct zs_chanstate *, int)); - -u_char zs_read_reg __P((struct zs_chanstate *, u_char)); -void zs_write_reg __P((struct zs_chanstate *, u_char, u_char)); - -u_char zs_read_csr __P((struct zs_chanstate *)); -void zs_write_csr __P((struct zs_chanstate *, u_char)); - -u_char zs_read_data __P((struct zs_chanstate *)); -void zs_write_data __P((struct zs_chanstate *, u_char)); - -extern int zs_major; -