📄 si.c
字号:
(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); break; case TIOCCDTR: (void) si_modem(pp, SET, 0); break; case TIOCMSET: (void) si_modem(pp, SET, *(int *)data); break; case TIOCMBIS: (void) si_modem(pp, BIS, *(int *)data); break; case TIOCMBIC: (void) si_modem(pp, BIC, *(int *)data); break; case TIOCMGET: *(int *)data = si_modem(pp, GET, 0); break; case TIOCMSDTRWAIT: /* must be root since the wait applies to following logins */ error = suser(p->p_ucred, &p->p_acflag); if (error != 0) { goto outspl; } pp->sp_dtr_wait = *(int *)data * hz / 100; break; case TIOCMGDTRWAIT: *(int *)data = pp->sp_dtr_wait * 100 / hz; break; default: error = ENOTTY; } error = 0;outspl: splx(oldspl);out: DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); if (blocked) si_write_enable(pp, 1); return(error);}/* * Handle the Specialix ioctls. All MUST be called via the CONTROL device */static intsi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p){ struct si_softc *xsc; register struct si_port *xpp; volatile struct si_reg *regp; struct si_tcsi *dp; struct si_pstat *sps; int *ip, error = 0; int oldspl; int card, port; int mynor = minor(dev); DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", dev, cmd, data, flag));#if 1 DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));#endif if (!IS_CONTROLDEV(mynor)) { DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); return(ENODEV); } oldspl = spltty(); /* better safe than sorry */ ip = (int *)data;#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out switch (cmd) { case TCSIPORTS: *ip = si_Nports; goto out; case TCSIMODULES: *ip = si_Nmodules; goto out; case TCSISDBG_ALL: SUCHECK; si_debug = *ip; goto out; case TCSIGDBG_ALL: *ip = si_debug; goto out; default: /* * Check that a controller for this port exists */ /* may also be a struct si_pstat, a superset of si_tcsi */ dp = (struct si_tcsi *)data; sps = (struct si_pstat *)data; card = dp->tc_card; xsc = &si_softc[card]; /* check.. */ if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { error = ENOENT; goto out; } /* * And check that a port exists */ port = dp->tc_port; if (port < 0 || port >= xsc->sc_nport) { error = ENOENT; goto out; } xpp = xsc->sc_ports + port; regp = (struct si_reg *)xsc->sc_maddr; } switch (cmd) { case TCSIDEBUG:#ifdef SI_DEBUG SUCHECK; if (xpp->sp_debug) xpp->sp_debug = 0; else { xpp->sp_debug = DBG_ALL; DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); } break;#else error = ENODEV; goto out;#endif case TCSISDBG_LEVEL: case TCSIGDBG_LEVEL:#ifdef SI_DEBUG if (cmd == TCSIGDBG_LEVEL) { dp->tc_dbglvl = xpp->sp_debug; } else { SUCHECK; xpp->sp_debug = dp->tc_dbglvl; } break;#else error = ENODEV; goto out;#endif case TCSIGRXIT: dp->tc_int = regp->rx_int_count; break; case TCSIRXIT: SUCHECK; regp->rx_int_count = dp->tc_int; break; case TCSIGIT: dp->tc_int = regp->int_count; break; case TCSIIT: SUCHECK; regp->int_count = dp->tc_int; break; case TCSISTATE: dp->tc_int = xpp->sp_ccb->hi_ip; break; /* these next three use a different structure */ case TCSI_PORT: SUCHECK; sps->tc_siport = *xpp; break; case TCSI_CCB: SUCHECK; sps->tc_ccb = *xpp->sp_ccb; break; case TCSI_TTY: SUCHECK; sps->tc_tty = *xpp->sp_tty; break; default: error = EINVAL; goto out; }out: splx(oldspl); return(error); /* success */}/* * siparam() : Configure line params * called at spltty(); * this may sleep, does not flush, nor wait for drain, nor block writes * caller must arrange this if it's important.. */intsiparam(tp, t) register struct tty *tp; register struct termios *t;{ register struct si_port *pp = TP2PP(tp); volatile struct si_channel *ccbp; int oldspl, cflag, iflag, oflag, lflag; int error = 0; /* shutup gcc */ int ispeed = 0; /* shutup gcc */ int ospeed = 0; /* shutup gcc */ BYTE val; DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); cflag = t->c_cflag; iflag = t->c_iflag; oflag = t->c_oflag; lflag = t->c_lflag; DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", oflag, cflag, iflag, lflag)); /* if not hung up.. */ if (t->c_ospeed != 0) { /* translate baud rate to firmware values */ ospeed = ttspeedtab(t->c_ospeed, bdrates); ispeed = t->c_ispeed ? ttspeedtab(t->c_ispeed, bdrates) : ospeed; /* enforce legit baud rate */ if (ospeed < 0 || ispeed < 0) return (EINVAL); } oldspl = spltty(); ccbp = pp->sp_ccb; /* ========== set hi_break ========== */ val = 0; if (iflag & IGNBRK) /* Breaks */ val |= BR_IGN; if (iflag & BRKINT) /* Interrupt on break? */ val |= BR_INT; if (iflag & PARMRK) /* Parity mark? */ val |= BR_PARMRK; if (iflag & IGNPAR) /* Ignore chars with parity errors? */ val |= BR_PARIGN; ccbp->hi_break = val; /* ========== set hi_csr ========== */ /* if not hung up.. */ if (t->c_ospeed != 0) { /* Set I/O speeds */ val = (ispeed << 4) | ospeed; } ccbp->hi_csr = val; /* ========== set hi_mr2 ========== */ val = 0; if (cflag & CSTOPB) /* Stop bits */ val |= MR2_2_STOP; else val |= MR2_1_STOP; /* * Enable H/W RTS/CTS handshaking. The default TA/MTA is * a DCE, hence the reverse sense of RTS and CTS */ /* Output Flow - RTS must be raised before data can be sent */ if (cflag & CCTS_OFLOW) val |= MR2_RTSCONT; ccbp->hi_mr2 = val; /* ========== set hi_mr1 ========== */ val = 0; if (!(cflag & PARENB)) /* Parity */ val |= MR1_NONE; else val |= MR1_WITH; if (cflag & PARODD) val |= MR1_ODD; if ((cflag & CS8) == CS8) { /* 8 data bits? */ val |= MR1_8_BITS; } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ val |= MR1_7_BITS; } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ val |= MR1_6_BITS; } else { /* Must be 5 */ val |= MR1_5_BITS; } /* * Enable H/W RTS/CTS handshaking. The default TA/MTA is * a DCE, hence the reverse sense of RTS and CTS */ /* Input Flow - CTS is raised when port is ready to receive data */ if (cflag & CRTS_IFLOW) val |= MR1_CTSCONT; ccbp->hi_mr1 = val; /* ========== set hi_mask ========== */ val = 0xff; if ((cflag & CS8) == CS8) { /* 8 data bits? */ val &= 0xFF; } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ val &= 0x7F; } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ val &= 0x3F; } else { /* Must be 5 */ val &= 0x1F; } if (iflag & ISTRIP) val &= 0x7F; ccbp->hi_mask = val; /* ========== set hi_prtcl ========== */ val = 0; /* Monitor DCD etc. if a modem */ if (!(cflag & CLOCAL)) val |= SP_DCEN; if (iflag & IXANY) val |= SP_TANY; if (iflag & IXON) val |= SP_TXEN; if (iflag & IXOFF) val |= SP_RXEN; if (iflag & INPCK) val |= SP_PAEN; ccbp->hi_prtcl = val; /* ========== set hi_{rx|tx}{on|off} ========== */ /* XXX: the card TOTALLY shields us from the flow control... */ ccbp->hi_txon = t->c_cc[VSTART]; ccbp->hi_txoff = t->c_cc[VSTOP]; ccbp->hi_rxon = t->c_cc[VSTART]; ccbp->hi_rxoff = t->c_cc[VSTOP]; /* ========== send settings to the card ========== */ /* potential sleep here */ if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ si_command(pp, LOPEN, SI_WAIT); /* open it */ else si_command(pp, CONFIG, SI_WAIT); /* change params */ /* ========== set DTR etc ========== */ /* Hangup if ospeed == 0 */ if (t->c_ospeed == 0) { (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); } else { /* * If the previous speed was 0, may need to re-enable * the modem signals */ (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); } DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); splx(oldspl); return(error);}/* * Enable or Disable the writes to this channel... * "state" -> enabled = 1; disabled = 0; */static voidsi_write_enable(pp, state) register struct si_port *pp; int state;{ int oldspl; oldspl = spltty(); if (state) { pp->sp_state &= ~SS_BLOCKWRITE; if (pp->sp_state & SS_WAITWRITE) { pp->sp_state &= ~SS_WAITWRITE; /* thunder away! */ wakeup((caddr_t)pp); } } else { pp->sp_state |= SS_BLOCKWRITE; } splx(oldspl);}/* * Set/Get state of modem control lines. * Due to DCE-like behaviour of the adapter, some signals need translation: * TIOCM_DTR DSR * TIOCM_RTS CTS */static intsi_modem(pp, cmd, bits) struct si_port *pp; enum si_mctl cmd; int bits;{ volatile struct si_channel *ccbp; int x; DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); ccbp = pp->sp_ccb; /* Find channel address */ switch (cmd) { case GET: x = ccbp->hi_ip; bits = TIOCM_LE; if (x & IP_DCD) bits |= TIOCM_CAR; if (x & IP_DTR) bits |= TIOCM_DTR; if (x & IP_RTS) bits |= TIOCM_RTS; if (x & IP_RI) bits |= TIOCM_RI; return(bits); case SET: ccbp->hi_op &= ~(OP_DSR|OP_CTS); /* fall through */ case BIS: x = 0; if (bits & TIOCM_DTR) x |= OP_DSR; if (bits & TIOCM_RTS) x |= OP_CTS; ccbp->hi_op |= x; break; case BIC: if (bits & TIOCM_DTR) ccbp->hi_op &= ~OP_DSR; if (bits & TIOCM_RTS) ccbp->hi_op &= ~OP_CTS; } return 0;}/* * Handle change of modem state */static voidsi_modem_state(pp, tp, hi_ip) register struct si_port *pp; register struct tty *tp; register int hi_ip;{ /* if a modem dev */ if (hi_ip & IP_DCD) { if ( !(pp->sp_last_hi_ip & IP_DCD)) { DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", tp->t_line)); (void)(*linesw[tp->t_line].l_modem)(tp, 1); } } else { if (pp->sp_last_hi_ip & IP_DCD) { DPRINT((pp, DBG_INTR, "modem carr off\n")); if ((*linesw[tp->t_line].l_modem)(tp, 0)) (void) si_modem(pp, SET, 0); } } pp->sp_last_hi_ip = hi_ip;}/* * Poller to catch missed interrupts. * * Note that the SYSV Specialix drivers poll at 100 times per second to get * better response. We could really use a "periodic" version timeout(). :-) */#ifdef POLLstatic voidsi_poll(void *nothing){ register struct si_softc *sc; register int i; volatile struct si_reg *regp; register struct si_port *pp; int lost, oldspl, port; DPRINT((0, DBG_POLL, "si_poll()\n")); oldspl = spltty(); if (in_intr) goto out; lost = 0; for (i=0; i<NSI; i++) { sc = &si_softc[i]; if (sc->sc_type == SIEMPTY) continue; regp = (struct si_reg *)sc->sc_maddr; /* * See if there has been a pending interrupt for 2 seconds * or so. The test <int_scounter >= 200) won't correspond * to 2 seconds if int_count gets changed. */ if (regp->int_pending != 0) { if (regp->int_scounter >= 200 && regp->initstat == 1) { printf("si%d: lost intr\n", i); lost++; } } else { regp->int_scounter = 0; } /* * gripe about no input flow control.. */ pp = sc->sc_ports; for (port = 0; port < sc->sc_nport; pp++, port++) { if (pp->sp_delta_overflows > 0) { printf("si%d: %d tty level buffer overflows\n", i, pp->sp_delta_overflows); pp->sp_delta_overflows = 0; } } } if (lost) siintr(-1); /* call intr with fake vector */out: splx(oldspl); timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);}#endif /* ifdef POLL *//* * The interrupt handler polls ALL ports on ALL adapters each time * it is called. */static BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */voidsiintr(int unit){ register struct si_softc *sc; register struct si_port *pp; volatile struct si_channel *ccbp; register struct tty *tp; volatile caddr_t maddr; BYTE op, ip; int x, card, port, n, i, isopen; volatile BYTE *z; BYTE c; DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); if (in_intr) { if (unit < 0) /* should never happen */ return; printf("si%d: Warning interrupt handler re-entered\n", unit); return; } in_intr = 1; /* * When we get an int we poll all the channels and do ALL pending * work, not just the first one we find. This allows all cards to * share the same vector. */ for (card=0; card < NSI; card++) { sc = &si_softc[card]; if (sc->sc_type == SIEMPTY) continue; /* * First, clear the interrupt */ switch(sc->sc_type) { case SIHOST : maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; /* flag nothing pending */ *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ break; case SIHOST2:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -