/* * 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); }
/* * Write the given register set to the given zs channel in the proper order. * The channel must not be transmitting at the time. The receiver will * be disabled for the time it takes to write all the registers. * Call this with interrupts disabled. */ void zs_loadchannelregs(struct zs_chanstate *cs) { uint8_t *reg, v; zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */ #if 1 /* * XXX: Is this really a good idea? * XXX: Should go elsewhere! -gwr */ zs_iflush(cs); /* XXX */ #endif if (cs->cs_ctl_chan != NULL) v = ((cs->cs_ctl_chan->cs_creg[5] & (ZSWR5_RTS | ZSWR5_DTR)) != (cs->cs_ctl_chan->cs_preg[5] & (ZSWR5_RTS | ZSWR5_DTR))); else v = 0; if (memcmp((void *)cs->cs_preg, (void *)cs->cs_creg, 16) == 0 && !v) return; /* only change if values are different */ /* Copy "pending" regs to "current" */ memcpy((void *)cs->cs_creg, (void *)cs->cs_preg, 16); reg = cs->cs_creg; /* current regs */ /* disable interrupts */ zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK); /* baud clock divisor, stop bits, parity */ zs_write_reg(cs, 4, reg[4]); /* misc. TX/RX control bits */ zs_write_reg(cs, 10, reg[10]); /* char size, enable (RX/TX) */ zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); /* synchronous mode stuff */ zs_write_reg(cs, 6, reg[6]); zs_write_reg(cs, 7, reg[7]); #if 0 /* * Registers 2 and 9 are special because they are * actually common to both channels, but must be * programmed through channel A. The "zsc" attach * function takes care of setting these registers * and they should not be touched thereafter. */ /* interrupt vector */ zs_write_reg(cs, 2, reg[2]); /* master interrupt control */ 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]); /* baud rate (lo/hi) */ zs_write_reg(cs, 12, reg[12]); zs_write_reg(cs, 13, reg[13]); /* Misc. control bits */ zs_write_reg(cs, 14, reg[14]); /* 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]); /* Write the status bits on the alternate channel also. */ if (cs->cs_ctl_chan != NULL) { v = cs->cs_ctl_chan->cs_preg[5]; cs->cs_ctl_chan->cs_creg[5] = v; zs_write_reg(cs->cs_ctl_chan, 5, v); } /* interrupt enables: RX, TX, STATUS */ zs_write_reg(cs, 1, reg[1]); }