void zstty_stsoft(struct zstty_softc *zst, struct tty *tp) { struct zs_chanstate *cs = zst->zst_cs; uint8_t rr0, delta; int s; s = splzs(); rr0 = cs->cs_rr0; delta = cs->cs_rr0_delta; cs->cs_rr0_delta = 0; splx(s); if (ISSET(delta, cs->cs_rr0_dcd)) { /* * Inform the tty layer that carrier detect changed. */ (void)(*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD)); } if (ISSET(delta, cs->cs_rr0_cts)) { /* Block or unblock output according to flow control. */ if (ISSET(rr0, cs->cs_rr0_cts)) { zst->zst_tx_stopped = 0; (*linesw[tp->t_line].l_start)(tp); } else { zst->zst_tx_stopped = 1; } } }
/* * Try to block or unblock input using hardware flow-control. * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and * if this function returns non-zero, the TS_TBLOCK flag will * be set or cleared according to the "block" arg passed. */ int zshwiflow(struct tty *tp, int block) { struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); struct zs_chanstate *cs = zst->zst_cs; int s; if (cs->cs_wr5_rts == 0) return (0); s = splzs(); if (block) { if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { SET(zst->zst_rx_flags, RX_TTY_BLOCKED); zs_hwiflow(zst); } } else { if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); zst->zst_rx_ready = 1; cs->cs_softreq = 1; } if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { CLR(zst->zst_rx_flags, RX_TTY_BLOCKED); zs_hwiflow(zst); } } splx(s); return (1); }
void zskbd_softint(struct zs_chanstate *cs) { struct zskbd_softc *sc = cs->cs_private; struct zskbd_devconfig *dc = sc->sc_dc; int rr0; /* handle pending transmissions */ if (dc->txq_head != dc->txq_tail) { int s; s = splzs(); while (dc->txq_head != dc->txq_tail) { rr0 = zs_read_csr(cs); if ((rr0 & ZSRR0_TX_READY) == 0) break; zs_write_data(cs, dc->txq[dc->txq_head]); dc->txq_head = (dc->txq_head + 1) & ~ZSKBD_TXQ_LEN; } splx(s); } /* handle incoming keystrokes/config */ while (dc->rxq_head != dc->rxq_tail) { zskbd_process(cs, dc->rxq[dc->rxq_head]); dc->rxq_head = (dc->rxq_head + 1) & ~ZSKBD_RXQ_LEN; } }
static int ewskbd_zsc_init(struct zs_chanstate *cs) { int s; s = splzs(); zs_write_reg(cs, 9, ZSWR9_B_RESET); DELAY(100); zs_write_reg(cs, 9, ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR); cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE; cs->cs_preg[2] = 0; cs->cs_preg[3] = ZSWR3_RX_8 | ZSWR3_RX_ENABLE; cs->cs_preg[4] = ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_PARENB; cs->cs_preg[5] = ZSWR5_TX_8 | ZSWR5_RTS | ZSWR5_TX_ENABLE; cs->cs_preg[6] = 0; cs->cs_preg[7] = 0; cs->cs_preg[8] = 0; cs->cs_preg[9] = ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR; cs->cs_preg[10] = 0; cs->cs_preg[11] = ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD | ZSWR11_TRXC_OUT_ENA | ZSWR11_TRXC_BAUD; /* reg[11] and reg[12] are set by zs_set_speed() with cs_brg_clk */ zs_set_speed(cs, EWSKBD_BAUD); cs->cs_preg[14] = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA; cs->cs_preg[15] = 0; zs_loadchannelregs(cs); splx(s); return 0; }
void zskbd_wskbd_set_leds(void *cookie, int leds) { struct zs_chanstate *cs = cookie; int s; uint8_t a_on, a_off, b_on, b_off; a_on = a_off = b_on = b_off = 0; if (leds & WSKBD_LED_CAPS) a_on |= ZSKBD_CTRL_A_CAPSLK; else a_off |= ZSKBD_CTRL_A_CAPSLK; if (leds & WSKBD_LED_NUM) a_on |= ZSKBD_CTRL_A_NUMLK; else a_off |= ZSKBD_CTRL_A_NUMLK; if (leds & WSKBD_LED_SCROLL) b_on |= ZSKBD_CTRL_B_SCRLK; else b_off |= ZSKBD_CTRL_B_SCRLK; s = splzs(); zskbd_ctrl(cs, a_on, a_off, b_on, b_off); splx(s); }
void zskbd_wskbd_set_keyclick(void *cookie, int on) { struct zs_chanstate *cs = cookie; int s; if (on) { if (!zskbd_wskbd_get_keyclick(cookie)) { s = splzs(); zskbd_ctrl(cs, 0, ZSKBD_CTRL_A_NOCLICK, 0, 0); splx(s); } } else { if (zskbd_wskbd_get_keyclick(cookie)) { s = splzs(); zskbd_ctrl(cs, ZSKBD_CTRL_A_NOCLICK, 0, 0, 0); splx(s); } } }
/* * Polled output char. */ static void zs_putc(int c) { int s, rr0; s = splzs(); /* Wait for transmitter to become ready. */ do { rr0 = zs_read_csr(&zscn_cs); } while ((rr0 & ZSRR0_TX_READY) == 0); zs_write_data(&zscn_cs, c); splx(s); }
void zstty_txsoft(struct zstty_softc *zst, struct tty *tp) { int s; CLR(tp->t_state, TS_BUSY); if (ISSET(tp->t_state, TS_FLUSH)) CLR(tp->t_state, TS_FLUSH); else { s = splzs(); ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf)); splx(s); } (*linesw[tp->t_line].l_start)(tp); }
void zs_shutdown(struct zstty_softc *zst) { struct zs_chanstate *cs = zst->zst_cs; struct tty *tp = zst->zst_tty; int s; s = splzs(); /* If we were asserting flow control, then deassert it. */ SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); zs_hwiflow(zst); /* Clear any break condition set with TIOCSBRK. */ zs_break(cs, 0); /* Turn off PPS capture on last close. */ zst->zst_ppsmask = 0; /* * Hang up if necessary. Wait a bit, so the other side has time to * notice even if we immediately open the port again. */ if (ISSET(tp->t_cflag, HUPCL) || ISSET(tp->t_state, TS_WOPEN)) { zs_modem(zst, 0); /* hold low for 1 second */ (void)tsleep(cs, TTIPRI, ttclos, hz); } /* Turn off interrupts if not the console. */ if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE); cs->cs_creg[1] = cs->cs_preg[1]; zs_write_reg(cs, 1, cs->cs_creg[1]); } /* Call the power management hook. */ if (cs->disable) { #ifdef DIAGNOSTIC if (!cs->enabled) panic("%s: not enabled?", __func__); #endif (*cs->disable)(zst->zst_cs); } splx(s); }
/* * Stop output, e.g., for ^S or output flush. */ int zsstop(struct tty *tp, int flag) { struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); int s; s = splzs(); if (ISSET(tp->t_state, TS_BUSY)) { /* Stop transmitting at the next chunk. */ zst->zst_tbc = 0; zst->zst_heldtbc = 0; if (!ISSET(tp->t_state, TS_TTSTOP)) SET(tp->t_state, TS_FLUSH); } splx(s); return 0; }
/* * Start or restart transmission. */ void zsstart(struct tty *tp) { struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); struct zs_chanstate *cs = zst->zst_cs; u_char *tba; int tbc, rr0; int s; s = spltty(); if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) goto out; if (zst->zst_tx_stopped) goto out; ttwakeupwr(tp); if (tp->t_outq.c_cc == 0) goto out; /* Grab the first contiguous region of buffer space. */ tba = tp->t_outq.c_cf; tbc = ndqb(&tp->t_outq, 0); #if IPL_ZS != IPL_TTY (void)splzs(); #endif zst->zst_tba = tba; zst->zst_tbc = tbc; SET(tp->t_state, TS_BUSY); zst->zst_tx_busy = 1; do { rr0 = zs_read_csr(cs); if ((rr0 & ZSRR0_TX_READY) == 0) break; zs_write_data(cs, *zst->zst_tba); zst->zst_tbc--; zst->zst_tba++; } while (zst->zst_tbc > 0); out: splx(s); }
/* * Polled output char. */ void zs_putc(void *arg, int c) { register volatile struct zschan *zc = arg; register int s, rr0; s = splzs(); /* Wait for transmitter to become ready. */ do { rr0 = zc->zc_csr; ZS_DELAY(); } while ((rr0 & ZSRR0_TX_READY) == 0); zc->zc_data = c; wbflush(); ZS_DELAY(); splx(s); }
int zs_getc(void *arg) { register volatile struct zschan *zc = arg; register int s, c, rr0; s = splzs(); /* Wait for a character to arrive. */ do { rr0 = zc->zc_csr; ZS_DELAY(); } while ((rr0 & ZSRR0_RX_READY) == 0); c = zc->zc_data; ZS_DELAY(); splx(s); return (c); }
/* * Polled input char. */ static int zs_getc(void) { int s, c, rr0; s = splzs(); /* Wait for a character to arrive. */ do { rr0 = zs_read_csr(&zscn_cs); } while ((rr0 & ZSRR0_RX_READY) == 0); c = zs_read_data(&zscn_cs); splx(s); /* * This is used by the kd driver to read scan codes, * so don't translate '\r' ==> '\n' here... */ return (c); }
void zstty_diag(void *arg) { struct zstty_softc *zst = arg; int overflows, floods; int s; s = splzs(); overflows = zst->zst_overflows; zst->zst_overflows = 0; floods = zst->zst_floods; zst->zst_floods = 0; zst->zst_errors = 0; splx(s); log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n", zst->zst_dev.dv_xname, overflows, overflows == 1 ? "" : "s", floods, floods == 1 ? "" : "s"); }
void zscninit(struct consdev *cn) { volatile struct zschan *cnchan = (volatile void *)IIOV(ZSCN_PHYSADDR); int s; memset(&zscn_cs, 0, sizeof(struct zs_chanstate)); zscn_cs.cs_reg_csr = &cnchan->zc_csr; zscn_cs.cs_reg_data = &cnchan->zc_data; zscn_cs.cs_channel = 0; zscn_cs.cs_brg_clk = PCLK / 16; memcpy(zscn_cs.cs_preg, zs_init_reg, 16); zscn_cs.cs_preg[4] = ZSWR4_CLK_X16 | ZSWR4_ONESB; /* XXX */ zscn_cs.cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS; zs_set_speed(&zscn_cs, ZSCN_SPEED); s = splzs(); zs_write_reg(&zscn_cs, 9, 0); zs_write_reg(&zscn_cs, 9, ZSWR9_HARD_RESET); zs_loadchannelregs(&zscn_cs); splx(s); conschan = cnchan; }
int zs_set_modes(struct zs_chanstate *cs, int cflag) { int s; /* * Output hardware flow control on the chip is horrendous: * if carrier detect drops, the receiver is disabled, and if * CTS drops, the transmitter is stoped IN MID CHARACTER! * Therefore, NEVER set the HFC bit, and instead use the * status interrupt to detect CTS changes. */ s = splzs(); #if 0 /* XXX - See below. */ if (cflag & CLOCAL) { cs->cs_rr0_dcd = 0; cs->cs_preg[15] &= ~ZSWR15_DCD_IE; } else { /* XXX - Need to notice DCD change here... */ cs->cs_rr0_dcd = ZSRR0_DCD; cs->cs_preg[15] |= ZSWR15_DCD_IE; } #endif /* XXX */ if (cflag & CRTSCTS) { cs->cs_wr5_dtr = ZSWR5_DTR; cs->cs_wr5_rts = ZSWR5_RTS; cs->cs_rr0_cts = ZSRR0_CTS; cs->cs_preg[15] |= ZSWR15_CTS_IE; } else { cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; cs->cs_wr5_rts = 0; cs->cs_rr0_cts = 0; cs->cs_preg[15] &= ~ZSWR15_CTS_IE; } splx(s); /* Caller will stuff the pending registers. */ return (0); }
static void ewskbd_zsc_softint(struct zs_chanstate *cs) { struct ewskbd_softc *sc; struct ewskbd_devconfig *dc; sc = cs->cs_private; dc = sc->sc_dc; /* handle pending transmissions */ if (dc->txq_head != dc->txq_tail && (dc->state & TX_READY)) { int s; dc->state &= ~TX_READY; s = splzs(); zs_write_data(cs, dc->txq[dc->txq_head]); splx(s); dc->txq_head = EWSKBD_NEXTTXQ(dc->txq_head); } /* don't bother if nobody is listening */ if (!dc->enabled) { dc->rxq_head = dc->rxq_tail; return; } /* handle incoming keystrokes/config */ while (dc->rxq_head != dc->rxq_tail) { uint8_t key = dc->rxq[dc->rxq_head]; /* toss wskbd a bone */ ewskbd_wskbd_input(cs, key); dc->rxq_head = EWSKBD_NEXTRXQ(dc->rxq_head); } }
int zs_set_modes(struct zs_chanstate *cs, int cflag /* bits per second */) { int s; /* * Output hardware flow control on the chip is horrendous: * if carrier detect drops, the receiver is disabled, and if * CTS drops, the transmitter is stoped IN MID CHARACTER! * Therefore, NEVER set the HFC bit, and instead use the * status interrupt to detect CTS changes. */ s = splzs(); cs->cs_rr0_pps = 0; if ((cflag & (CLOCAL | MDMBUF)) != 0) { cs->cs_rr0_dcd = 0; if ((cflag & MDMBUF) == 0) cs->cs_rr0_pps = ZSRR0_DCD; } else cs->cs_rr0_dcd = ZSRR0_DCD; if ((cflag & CRTSCTS) != 0) { cs->cs_wr5_dtr = ZSWR5_DTR; cs->cs_wr5_rts = ZSWR5_RTS; cs->cs_rr0_cts = ZSRR0_CTS; } else if ((cflag & MDMBUF) != 0) { cs->cs_wr5_dtr = 0; cs->cs_wr5_rts = ZSWR5_DTR; cs->cs_rr0_cts = ZSRR0_DCD; } else { cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; cs->cs_wr5_rts = 0; cs->cs_rr0_cts = 0; } splx(s); /* Caller will stuff the pending registers. */ return (0); }
static void ewskbd_wskbd_set_leds(void *cookie, int leds) { struct zs_chanstate *cs; struct ewskbd_softc *sc; int s; uint8_t cmd; cs = cookie; sc = cs->cs_private; cmd = 0; if (leds & WSKBD_LED_CAPS) cmd |= EWSKBD_CAPSLOCK; sc->sc_dc->leds = cmd; cmd |= EWSKBD_SETLEDS; s = splzs(); ewskbd_zsc_send(cs, &cmd, 1); splx(s); }
int zsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); struct zs_chanstate *cs = zst->zst_cs; struct tty *tp = zst->zst_tty; int error; int s; 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 */ error = 0; s = splzs(); switch (cmd) { case TIOCSBRK: zs_break(cs, 1); break; case TIOCCBRK: zs_break(cs, 0); break; case TIOCGFLAGS: *(int *)data = zst->zst_swflags; break; case TIOCSFLAGS: error = suser(p, 0); if (error) break; zst->zst_swflags = *(int *)data; if (ISSET(zst->zst_hwflags, ZS_HWFLAG_NO_DCD)) SET(zst->zst_swflags, TIOCFLAG_SOFTCAR); break; case TIOCSDTR: zs_modem(zst, 1); break; case TIOCCDTR: zs_modem(zst, 0); break; case TIOCMSET: case TIOCMBIS: case TIOCMBIC: tiocm_to_zs(zst, cmd, *(int *)data); break; case TIOCMGET: *(int *)data = zs_to_tiocm(zst); break; default: error = ENOTTY; break; } splx(s); return (error); }
void zskbd_attach(struct device *parent, struct device *self, void *aux) { struct zskbd_softc *sc = (struct zskbd_softc *)self; struct zsc_softc *zsc = (struct zsc_softc *)parent; struct zsc_attach_args *args = aux; struct zs_chanstate *cs; struct wskbddev_attach_args wskaa; int s, channel, rc; uint8_t key; printf(": "); /* Establish ourself with the MD z8530 driver */ channel = args->channel; cs = zsc->zsc_cs[channel]; cs->cs_ops = &zskbd_zsops; cs->cs_private = sc; sc->sc_dc = malloc(sizeof(struct zskbd_devconfig), M_DEVBUF, M_WAITOK | M_ZERO); s = splzs(); zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET); cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE; cs->cs_preg[4] = (cs->cs_preg[4] & ZSWR4_CLK_MASK) | (ZSWR4_ONESB | ZSWR4_PARENB); /* 1 stop, odd parity */ cs->cs_preg[15] &= ~ZSWR15_ENABLE_ENHANCED; zs_set_speed(cs, ZSKBD_BAUD); zs_loadchannelregs(cs); /* * Empty the keyboard input buffer (if the keyboard is the console * input device and the user invoked UKC, the `enter key up' event * will still be pending in the buffer). */ while ((zs_read_csr(cs) & ZSRR0_RX_READY) != 0) (void)zs_read_data(cs); /* * Ask the keyboard for its DIP switch settings. This will also let * us know whether the keyboard is connected. */ sc->sc_dc->expected = 2; zskbd_ctrl(cs, ZSKBD_CTRL_A_RCB, 0, 0, 0); while (sc->sc_dc->expected != 0) { rc = zskbd_poll(cs, &key); if (rc != 0) { if (rc == ENXIO && sc->sc_dc->expected == 2) { printf("no keyboard"); /* * Attach wskbd nevertheless, in case the * keyboard is plugged late. */ sc->sc_dc->expected = 0; goto dip; } else { printf("i/o error\n"); return; } } zskbd_process(cs, key); } printf("dip switches %02x", sc->sc_dc->dip); dip: /* * Disable key click by default. Note that if the keyboard is not * currently connected, the bit will nevertheless stick and will * disable the click as soon as a keyboard led needs to be lit. */ zskbd_ctrl(cs, ZSKBD_CTRL_A_NOCLICK, 0, 0, 0); splx(s); printf("\n"); if (zskbd_is_console) sc->sc_dc->enabled = 1; /* attach wskbd */ wskaa.console = zskbd_is_console; wskaa.keymap = &sgikbd_wskbd_keymapdata; wskaa.accessops = &zskbd_wskbd_accessops; wskaa.accesscookie = cs; sc->sc_dc->wskbddev = config_found(self, &wskaa, wskbddevprint); }
/* * Attach a found zs. */ static void zs_attach(device_t parent, device_t self, void *aux) { struct zsc_softc *zsc = device_private(self); struct intio_attach_args *ia = aux; struct zsc_attach_args zsc_args; volatile struct zschan *zc; struct zs_chanstate *cs; int r, s, zs_unit, channel; zsc->zsc_dev = self; aprint_normal("\n"); zs_unit = device_unit(self); zsc->zsc_addr = (void *)ia->ia_addr; ia->ia_size = 8; r = intio_map_allocate_region(parent, ia, INTIO_MAP_ALLOCATE); #ifdef DIAGNOSTIC if (r) panic("zs: intio IO map corruption"); #endif /* * Initialize software state for each channel. */ for (channel = 0; channel < 2; channel++) { device_t child; zsc_args.channel = channel; zsc_args.hwflags = 0; cs = &zsc->zsc_cs_store[channel]; zsc->zsc_cs[channel] = cs; zs_lock_init(cs); cs->cs_channel = channel; cs->cs_private = NULL; cs->cs_ops = &zsops_null; cs->cs_brg_clk = PCLK / 16; if (channel == 0) zc = (volatile void *)IIOV(&zsc->zsc_addr->zs_chan_a); else zc = (volatile void *)IIOV(&zsc->zsc_addr->zs_chan_b); cs->cs_reg_csr = &zc->zc_csr; cs->cs_reg_data = &zc->zc_data; zs_init_reg[2] = ia->ia_intr; memcpy(cs->cs_creg, zs_init_reg, 16); memcpy(cs->cs_preg, zs_init_reg, 16); if (zc == conschan) { zsc_args.hwflags |= ZS_HWFLAG_CONSOLE; cs->cs_defspeed = zs_get_speed(cs); cs->cs_defcflag = zscn_def_cflag; } else { cs->cs_defspeed = 9600; cs->cs_defcflag = zs_def_cflag; } /* Make these correspond to cs_defcflag (-crtscts) */ cs->cs_rr0_dcd = ZSRR0_DCD; cs->cs_rr0_cts = 0; cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; cs->cs_wr5_rts = 0; /* * Clear the master interrupt enable. * The INTENA is common to both channels, * so just do it on the A channel. */ if (channel == 0) { s = splzs(); zs_write_reg(cs, 9, 0); splx(s); } /* * Look for a child driver for this channel. * The child attach will setup the hardware. */ child = config_found(self, (void *)&zsc_args, zs_print); #if ZSTTY > 0 if (zc == conschan && ((child && strcmp(device_xname(child), "zstty0")) || child == NULL)) /* XXX */ panic("%s: console device mismatch", __func__); #endif if (child == NULL) { /* No sub-driver. Just reset it. */ uint8_t reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; s = splzs(); zs_write_reg(cs, 9, reset); splx(s); } } /* * Now safe to install interrupt handlers. */ if (intio_intr_establish(ia->ia_intr, "zs", zshard, zsc)) panic("%s: interrupt vector busy", __func__); zsc->zsc_softintr_cookie = softint_establish(SOFTINT_SERIAL, (void (*)(void *))zsc_intr_soft, zsc); /* XXX; evcnt_attach() ? */ /* * Set the master interrupt enable and interrupt vector. * (common to both channels, do it on A) */ cs = zsc->zsc_cs[0]; s = splzs(); /* interrupt vector */ zs_write_reg(cs, 2, ia->ia_intr); /* master interrupt control (enable) */ zs_write_reg(cs, 9, zs_init_reg[9]); splx(s); }
/* * Set ZS tty parameters from termios. * XXX - Should just copy the whole termios after * making sure all the changes could be done. */ int zsparam(struct tty *tp, struct termios *t) { struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); struct zs_chanstate *cs = zst->zst_cs; int ospeed; tcflag_t cflag; uint8_t tmp3, tmp4, tmp5; int s, error; ospeed = t->c_ospeed; cflag = t->c_cflag; /* Check requested parameters. */ if (ospeed < 0) return (EINVAL); if (t->c_ispeed && t->c_ispeed != ospeed) return (EINVAL); /* * For the console, always force CLOCAL and !HUPCL, so that the port * is always active. */ if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) || ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { SET(cflag, CLOCAL); CLR(cflag, HUPCL); } /* * 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 == ospeed && tp->t_cflag == cflag) return (0); /* * 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, ospeed); if (error) return (error); error = zs_set_modes(cs, cflag); if (error) return (error); /* * Block interrupts so that state will not * be altered until we are done setting it up. * * Initial values in cs_preg are set before * our attach routine is called. The master * interrupt enable is handled by zsc.c * */ s = splzs(); /* * Recalculate which status ints to enable. */ zs_maskintr(zst); /* Recompute character size bits. */ tmp3 = cs->cs_preg[3]; tmp5 = cs->cs_preg[5]; CLR(tmp3, ZSWR3_RXSIZE); CLR(tmp5, ZSWR5_TXSIZE); switch (ISSET(cflag, CSIZE)) { case CS5: SET(tmp3, ZSWR3_RX_5); SET(tmp5, ZSWR5_TX_5); break; case CS6: SET(tmp3, ZSWR3_RX_6); SET(tmp5, ZSWR5_TX_6); break; case CS7: SET(tmp3, ZSWR3_RX_7); SET(tmp5, ZSWR5_TX_7); break; case CS8: SET(tmp3, ZSWR3_RX_8); SET(tmp5, ZSWR5_TX_8); break; } cs->cs_preg[3] = tmp3; cs->cs_preg[5] = tmp5; /* * 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]; CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK); if (ISSET(cflag, CSTOPB)) SET(tmp4, ZSWR4_TWOSB); else SET(tmp4, ZSWR4_ONESB); if (!ISSET(cflag, PARODD)) SET(tmp4, ZSWR4_EVENP); if (ISSET(cflag, PARENB)) SET(tmp4, ZSWR4_PARENB); cs->cs_preg[4] = tmp4; /* And copy to tty. */ tp->t_ispeed = 0; tp->t_ospeed = ospeed; tp->t_cflag = cflag; /* * If nothing is being transmitted, set up new current values, * else mark them as pending. */ if (!cs->cs_heldchange) { if (zst->zst_tx_busy) { zst->zst_heldtbc = zst->zst_tbc; zst->zst_tbc = 0; cs->cs_heldchange = 1; } else zs_loadchannelregs(cs); } /* * If hardware flow control is disabled, turn off the buffer water * marks and unblock any soft flow control state. Otherwise, enable * the water marks. */ if (!ISSET(cflag, CHWFLOW)) { zst->zst_r_hiwat = 0; zst->zst_r_lowat = 0; if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); zst->zst_rx_ready = 1; cs->cs_softreq = 1; } if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) { CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED); zs_hwiflow(zst); } } else { zst->zst_r_hiwat = zstty_rbuf_hiwat; zst->zst_r_lowat = zstty_rbuf_lowat; } /* * Force a recheck of the hardware carrier and flow control status, * since we may have changed which bits we're looking at. */ zstty_stint(cs, 1); splx(s); /* * If hardware flow control is disabled, unblock any hard flow control * state. */ if (!ISSET(cflag, CHWFLOW)) { if (zst->zst_tx_stopped) { zst->zst_tx_stopped = 0; zsstart(tp); } } zstty_softint(cs); return (0); }
void zstty_rxsoft(struct zstty_softc *zst, struct tty *tp) { struct zs_chanstate *cs = zst->zst_cs; int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint; uint8_t *get, *end; u_int cc, scc; uint8_t rr1; int code; int s; end = zst->zst_ebuf; get = zst->zst_rbget; scc = cc = zstty_rbuf_size - zst->zst_rbavail; if (cc == zstty_rbuf_size) { zst->zst_floods++; if (zst->zst_errors++ == 0) timeout_add_sec(&zst->zst_diag_ch, 60); } /* If not yet open, drop the entire buffer content here */ if (!ISSET(tp->t_state, TS_ISOPEN)) { get += cc << 1; if (get >= end) get -= zstty_rbuf_size << 1; cc = 0; } while (cc) { code = get[0]; rr1 = get[1]; if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) { if (ISSET(rr1, ZSRR1_DO)) { zst->zst_overflows++; if (zst->zst_errors++ == 0) timeout_add_sec(&zst->zst_diag_ch, 60); } if (ISSET(rr1, ZSRR1_FE)) SET(code, TTY_FE); if (ISSET(rr1, ZSRR1_PE)) SET(code, TTY_PE); } if ((*rint)(code, tp) == -1) { /* * The line discipline's buffer is out of space. */ if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { /* * We're either not using flow control, or the * line discipline didn't tell us to block for * some reason. Either way, we have no way to * know when there's more space available, so * just drop the rest of the data. */ get += cc << 1; if (get >= end) get -= zstty_rbuf_size << 1; cc = 0; } else { /* * Don't schedule any more receive processing * until the line discipline tells us there's * space available (through comhwiflow()). * Leave the rest of the data in the input * buffer. */ SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED); } break; } get += 2; if (get >= end) get = zst->zst_rbuf; cc--; } if (cc != scc) { zst->zst_rbget = get; s = splzs(); cc = zst->zst_rbavail += scc - cc; /* Buffers should be ok again, release possible block. */ if (cc >= zst->zst_r_lowat) { if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) { CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); SET(cs->cs_preg[1], ZSWR1_RIE); cs->cs_creg[1] = cs->cs_preg[1]; zs_write_reg(cs, 1, cs->cs_creg[1]); } if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) { CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED); zs_hwiflow(zst); } } splx(s); } }
/* * Open a zs serial (tty) port. */ int zsopen(dev_t dev, int flags, int mode, struct proc *p) { struct zstty_softc *zst; struct zs_chanstate *cs; struct tty *tp; int s; #if IPL_ZS != IPL_TTY int s2; #endif int error; zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); if (zst == NULL) return (ENXIO); tp = zst->zst_tty; cs = zst->zst_cs; /* If KGDB took the line, then tp==NULL */ if (tp == NULL) return (EBUSY); if (ISSET(tp->t_state, TS_ISOPEN) && ISSET(tp->t_state, TS_XCLUDE) && suser(p, 0) != 0) return (EBUSY); s = spltty(); /* * Do the following iff this is a first open. */ if (!ISSET(tp->t_state, TS_ISOPEN)) { struct termios t; tp->t_dev = dev; /* Call the power management hook. */ if (cs->enable) { if ((*cs->enable)(cs)) { splx(s); printf("%s: device enable failed\n", zst->zst_dev.dv_xname); return (EIO); } } /* * Initialize the termios status to the defaults. Add in the * sticky bits from TIOCSFLAGS. */ t.c_ispeed = 0; t.c_ospeed = cs->cs_defspeed; t.c_cflag = cs->cs_defcflag; if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL)) SET(t.c_cflag, CLOCAL); if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS)) SET(t.c_cflag, CRTSCTS); if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF)) SET(t.c_cflag, MDMBUF); #if IPL_ZS != IPL_TTY s2 = splzs(); #endif /* * Turn on receiver and status interrupts. * We defer the actual write of the register to zsparam(), * but we must make sure status interrupts are turned on by * the time zsparam() reads the initial rr0 state. */ SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE); /* Clear PPS capture state on first open. */ zst->zst_ppsmask = 0; #if IPL_ZS != IPL_TTY splx(s2); #endif /* 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 (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) { tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; } else { tp->t_iflag = 0; tp->t_oflag = 0; tp->t_lflag = 0; } ttychars(tp); ttsetwater(tp); if (ZSDIALOUT(dev)) SET(tp->t_state, TS_CARR_ON); else CLR(tp->t_state, TS_CARR_ON); #if IPL_ZS != IPL_TTY s2 = splzs(); #endif /* Clear the input ring, and unblock. */ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; zst->zst_rbavail = zstty_rbuf_size; zs_iflush(cs); CLR(zst->zst_rx_flags, RX_ANY_BLOCK); zs_hwiflow(zst); #if IPL_ZS != IPL_TTY splx(s2); #endif } if (ZSDIALOUT(dev)) { if (ISSET(tp->t_state, TS_ISOPEN)) { /* someone already is dialed in... */ splx(s); return EBUSY; } cs->cs_cua = 1; } error = 0; /* wait for carrier if necessary */ if (ISSET(flags, O_NONBLOCK)) { if (!ZSDIALOUT(dev) && cs->cs_cua) { /* Opening TTY non-blocking... but the CUA is busy */ error = EBUSY; } } else while (cs->cs_cua || (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON))) { int rr0; error = 0; SET(tp->t_state, TS_WOPEN); if (!ZSDIALOUT(dev) && !cs->cs_cua) { /* * Turn on DTR. We must always do this on non-CUA * devices, even if carrier is not present, because * otherwise we'd have to use TIOCSDTR immediately * after setting CLOCAL, which applications do not * expect. We always assert DTR while the device is * open unless explicitly requested to deassert it. */ #if IPL_ZS != IPL_TTY s2 = splzs(); #endif zs_modem(zst, 1); rr0 = zs_read_csr(cs); #if IPL_ZS != IPL_TTY splx(s2); #endif /* loop, turning on the device, until carrier present */ if (ISSET(rr0, ZSRR0_DCD) || ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR)) SET(tp->t_state, TS_CARR_ON); } if ((ISSET(tp->t_cflag, CLOCAL) || ISSET(tp->t_state, TS_CARR_ON)) && !cs->cs_cua) break; error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0); if (!ZSDIALOUT(dev) && cs->cs_cua && error == EINTR) { error = 0; continue; } if (error) { if (!ISSET(tp->t_state, TS_ISOPEN)) { #if IPL_ZS != IPL_TTY s2 = splzs(); #endif zs_modem(zst, 0); #if IPL_ZS != IPL_TTY splx(s2); #endif CLR(tp->t_state, TS_WOPEN); ttwakeup(tp); } if (ZSDIALOUT(dev)) cs->cs_cua = 0; CLR(tp->t_state, TS_WOPEN); break; } if (!ZSDIALOUT(dev) && cs->cs_cua) continue; } splx(s); if (error == 0) error = ((*linesw[tp->t_line].l_open)(dev, tp, p)); if (error) goto bad; return (0); bad: if (!ISSET(tp->t_state, TS_ISOPEN)) { /* * We failed to open the device, and nobody else had it opened. * Clean up the state as appropriate. */ zs_shutdown(zst); } return (error); }
void zstty_attach(struct device *parent, struct device *self, void *aux) { struct zsc_softc *zsc = (struct zsc_softc *)parent; struct zstty_softc *zst = (struct zstty_softc *)self; struct cfdata *cf = self->dv_cfdata; struct zsc_attach_args *args = aux; struct zs_chanstate *cs; struct tty *tp; int channel, s, tty_unit; dev_t dev; const char *i, *o; int dtr_on; int resetbit; timeout_set(&zst->zst_diag_ch, zstty_diag, zst); tty_unit = zst->zst_dev.dv_unit; channel = args->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(zs_major, tty_unit); if (zst->zst_swflags) printf(" flags 0x%x", zst->zst_swflags); if (ISSET(zst->zst_hwflags, ZS_HWFLAG_NO_DCD)) SET(zst->zst_swflags, TIOCFLAG_SOFTCAR); /* * Check whether we serve as a console device. * XXX - split console input/output channels aren't * supported yet on /dev/console */ i = o = NULL; if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) { i = " input"; if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { args->consdev->cn_dev = dev; cn_tab->cn_pollc = args->consdev->cn_pollc; cn_tab->cn_getc = args->consdev->cn_getc; } cn_tab->cn_dev = dev; } if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) { o = " output"; if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { cn_tab->cn_putc = args->consdev->cn_putc; } cn_tab->cn_dev = dev; } if (i != NULL || o != NULL) { printf(": console%s", i ? (o ? "" : i) : o); } #ifdef KGDB if (zs_check_kgdb(cs, dev)) { /* * Allow kgdb to "take over" this port. Returns true * if this serial port is in-use by kgdb. */ printf(": kgdb\n"); /* * This is the kgdb port (exclusive use) * so skip the normal attach code. */ return; } #endif #if defined(__sparc__) || defined(__sparc64__) if (strcmp(args->type, "keyboard") == 0 || strcmp(args->type, "mouse") == 0) printf(": %s", args->type); #endif printf("\n"); tp = ttymalloc(0); tp->t_dev = dev; tp->t_oproc = zsstart; tp->t_param = zsparam; tp->t_hwiflow = zshwiflow; zst->zst_tty = tp; zst->zst_rbuf = mallocarray(zstty_rbuf_size, 2, M_DEVBUF, M_WAITOK); zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size * 2); /* Disable the high water mark. */ zst->zst_r_hiwat = 0; zst->zst_r_lowat = 0; zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; zst->zst_rbavail = zstty_rbuf_size; /* if there are no enable/disable functions, assume the device is always enabled */ if (!cs->enable) cs->enabled = 1; /* * Hardware init */ dtr_on = 0; resetbit = 0; if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { /* Call zsparam similar to open. */ struct termios t; /* Wait a while for previous console output to complete */ DELAY(10000); /* Setup the "new" parameters in t. */ t.c_ispeed = 0; t.c_ospeed = cs->cs_defspeed; t.c_cflag = cs->cs_defcflag; s = splzs(); /* * Turn on receiver and status interrupts. * We defer the actual write of the register to zsparam(), * but we must make sure status interrupts are turned on by * the time zsparam() reads the initial rr0 state. */ SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE); splx(s); /* Make sure zsparam will see changes. */ tp->t_ospeed = 0; (void)zsparam(tp, &t); /* Make sure DTR is on now. */ dtr_on = 1; } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) { /* Not the console; may need reset. */ resetbit = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; } s = splzs(); if (resetbit) zs_write_reg(cs, 9, resetbit); zs_modem(zst, dtr_on); splx(s); }
/* * Attach a found zs. * * Match slave number to zs unit number, so that misconfiguration will * not set up the keyboard as ttya, etc. */ void zsc_attach(struct device *parent, struct device *self, void *aux) { struct zsc_softc *zsc = (void *)self; struct confargs *ca = aux; struct zsc_attach_args zsc_args; volatile struct zschan *zc; struct xzs_chanstate *xcs; struct zs_chanstate *cs; struct zsdevice *zsd; int zsc_unit, channel; int s, theflags; int node, intr[3][3]; u_int regs[16]; zsc_unit = zsc->zsc_dev.dv_unit; zsd = mapiodev(ca->ca_baseaddr + ca->ca_reg[0], ca->ca_reg[1]); node = OF_child(ca->ca_node); /* ch-a */ for (channel = 0; channel < 2; channel++) { if (OF_getprop(node, "AAPL,interrupts", intr[channel], sizeof(intr[0])) == -1 && OF_getprop(node, "interrupts", intr[channel], sizeof(intr[0])) == -1) { printf(": cannot find interrupt property\n"); return; } if (OF_getprop(node, "reg", regs, sizeof(regs)) < 24) { printf(": cannot find reg property\n"); return; } regs[2] += ca->ca_baseaddr; regs[4] += ca->ca_baseaddr; #ifdef ZS_TXDMA zsc->zsc_txdmareg[channel] = mapiodev(regs[2], regs[3]); zsc->zsc_txdmacmd[channel] = dbdma_alloc(sizeof(dbdma_command_t) * 3); memset(zsc->zsc_txdmacmd[channel], 0, sizeof(dbdma_command_t) * 3); dbdma_reset(zsc->zsc_txdmareg[channel]); #endif node = OF_peer(node); /* ch-b */ } printf(": irq %d,%d\n", intr[0][0], intr[1][0]); /* * Initialize software state for each channel. */ for (channel = 0; channel < 2; channel++) { zsc_args.channel = channel; zsc_args.hwflags = zs_hwflags[zsc_unit][channel]; xcs = &zsc->xzsc_xcs_store[channel]; cs = &xcs->xzs_cs; zsc->zsc_cs[channel] = cs; cs->cs_channel = channel; cs->cs_private = NULL; cs->cs_ops = &zsops_null; zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b; cs->cs_reg_csr = &zc->zc_csr; cs->cs_reg_data = &zc->zc_data; memcpy(cs->cs_creg, zs_init_reg, 16); memcpy(cs->cs_preg, zs_init_reg, 16); /* Current BAUD rate generator clock. */ /* RTxC is 230400*16, so use 230400 */ cs->cs_brg_clk = PCLK / 16; if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) cs->cs_defspeed = zs_get_speed(cs); else cs->cs_defspeed = zs_defspeed[zsc_unit][channel]; cs->cs_defcflag = zs_def_cflag; /* Make these correspond to cs_defcflag (-crtscts) */ cs->cs_rr0_dcd = ZSRR0_DCD; cs->cs_rr0_cts = 0; cs->cs_wr5_dtr = ZSWR5_DTR; cs->cs_wr5_rts = 0; #ifdef __notyet__ cs->cs_slave_type = ZS_SLAVE_NONE; #endif /* Define BAUD rate stuff. */ xcs->cs_clocks[0].clk = PCLK; xcs->cs_clocks[0].flags = ZSC_RTXBRG | ZSC_RTXDIV; xcs->cs_clocks[1].flags = ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN; xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE; xcs->cs_clock_count = 3; if (channel == 0) { theflags = 0; /*mac68k_machine.modem_flags;*/ /*xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;*/ /*xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;*/ xcs->cs_clocks[1].clk = 0; xcs->cs_clocks[2].clk = 0; } else { theflags = 0; /*mac68k_machine.print_flags;*/ xcs->cs_clocks[1].flags = ZSC_VARIABLE; /* * Yes, we aren't defining ANY clock source enables for the * printer's DCD clock in. The hardware won't let us * use it. But a clock will freak out the chip, so we * let you set it, telling us to bar interrupts on the line. */ /*xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;*/ /*xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;*/ xcs->cs_clocks[1].clk = 0; xcs->cs_clocks[2].clk = 0; } if (xcs->cs_clocks[1].clk) zsc_args.hwflags |= ZS_HWFLAG_NO_DCD; if (xcs->cs_clocks[2].clk) zsc_args.hwflags |= ZS_HWFLAG_NO_CTS; /* Set defaults in our "extended" chanstate. */ xcs->cs_csource = 0; xcs->cs_psource = 0; xcs->cs_cclk_flag = 0; /* Nothing fancy by default */ xcs->cs_pclk_flag = 0; if (theflags & ZSMAC_RAW) { zsc_args.hwflags |= ZS_HWFLAG_RAW; printf(" (raw defaults)"); } /* * XXX - This might be better done with a "stub" driver * (to replace zstty) that ignores LocalTalk for now. */ if (theflags & ZSMAC_LOCALTALK) { printf(" shielding from LocalTalk"); cs->cs_defspeed = 1; cs->cs_creg[ZSRR_BAUDLO] = cs->cs_preg[ZSRR_BAUDLO] = 0xff; cs->cs_creg[ZSRR_BAUDHI] = cs->cs_preg[ZSRR_BAUDHI] = 0xff; zs_write_reg(cs, ZSRR_BAUDLO, 0xff); zs_write_reg(cs, ZSRR_BAUDHI, 0xff); /* * If we might have LocalTalk, then make sure we have the * Baud rate low-enough to not do any damage. */ } /* * We used to disable chip interrupts here, but we now * do that in zscnprobe, just in case MacOS left the chip on. */ xcs->cs_chip = 0; /* Stash away a copy of the final H/W flags. */ xcs->cs_hwflags = zsc_args.hwflags; /* * Look for a child driver for this channel. * The child attach will setup the hardware. */ if (!config_found(self, (void *)&zsc_args, zsc_print)) { /* No sub-driver. Just reset it. */ u_char reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; s = splzs(); zs_write_reg(cs, 9, reset); splx(s); } } /* XXX - Now safe to install interrupt handlers. */ mac_intr_establish(parent, intr[0][0], IST_LEVEL, IPL_TTY, zshard, NULL, "zs0"); mac_intr_establish(parent, intr[1][0], IST_LEVEL, IPL_TTY, zshard, NULL, "zs1"); #ifdef ZS_TXDMA mac_intr_establish(parent, intr[0][1], IST_LEVEL, IPL_TTY, zs_txdma_int, (void *)0, "zsdma0"); mac_intr_establish(parent, intr[1][1], IST_LEVEL, IPL_TTY, zs_txdma_int, (void *)1, "zsdma1"); #endif zsc->zsc_softintr = softintr_establish(IPL_SOFTTTY, zssoft, zsc); if (zsc->zsc_softintr == NULL) panic("zsattach: could not establish soft interrupt"); /* * Set the master interrupt enable and interrupt vector. * (common to both channels, do it on A) */ cs = zsc->zsc_cs[0]; s = splzs(); /* interrupt vector */ zs_write_reg(cs, 2, zs_init_reg[2]); /* master interrupt control (enable) */ zs_write_reg(cs, 9, zs_init_reg[9]); splx(s); /* connect power management for port 0 */ cs->enable = zs_enable; cs->disable = zs_disable; }
void zs_config(struct zsc_softc *zsc, char *base) { struct zsc_attach_args zsc_args; struct zs_chanstate *cs; int zsc_unit, channel, s; zsc_unit = device_unit(zsc->zsc_dev); aprint_normal(": Zilog 8530 SCC\n"); /* * Initialize software state for each channel. */ for (channel = 0; channel < 2; channel++) { zsc_args.channel = channel; zsc_args.hwflags = zs_hwflags[zsc_unit][channel]; /* * If we're the console, copy the channel state, and * adjust the console channel pointer. */ if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) { cs = &zs_conschan_store; } else { cs = malloc(sizeof(struct zs_chanstate), M_DEVBUF, M_NOWAIT | M_ZERO); if(channel==0){ cs->cs_reg_csr = base + 7; cs->cs_reg_data = base + 15; } else { cs->cs_reg_csr = base + 3; cs->cs_reg_data = base + 11; } memcpy(cs->cs_creg, zs_init_reg, 16); memcpy(cs->cs_preg, zs_init_reg, 16); cs->cs_defspeed = 9600; } zsc->zsc_cs[channel] = cs; zs_lock_init(cs); cs->cs_defcflag = CREAD | CS8 | HUPCL; /* Make these correspond to cs_defcflag (-crtscts) */ cs->cs_rr0_dcd = ZSRR0_DCD; cs->cs_rr0_cts = 0; cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; cs->cs_wr5_rts = 0; cs->cs_channel = channel; cs->cs_private = NULL; cs->cs_ops = &zsops_null; cs->cs_brg_clk = 4000000 / 16; /* * Clear the master interrupt enable. * The INTENA is common to both channels, * so just do it on the A channel. */ if (channel == 0) { zs_write_reg(cs, 9, 0); } /* * Look for a child driver for this channel. * The child attach will setup the hardware. */ if (!config_found(zsc->zsc_dev, (void *)&zsc_args, zsc_print)) { /* No sub-driver. Just reset it. */ uint8_t reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; s = splzs(); zs_write_reg(cs, 9, reset); splx(s); } } }