📄 si.c
字号:
maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; *(maddr+SIPLIRQCLR) = 0x00; *(maddr+SIPLIRQCLR) = 0x10; break; case SIEISA:#if NEISA > 0 maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; (void)inb(sc->sc_eisa_iobase+3); break;#endif /* fall through if not EISA kernel */ case SIEMPTY: default: continue; } ((volatile struct si_reg *)maddr)->int_scounter = 0; /* * check each port */ for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { ccbp = pp->sp_ccb; tp = pp->sp_tty; /* * See if a command has completed ? */ if (ccbp->hi_stat != pp->sp_pend) { DPRINT((pp, DBG_INTR, "siintr hi_stat = 0x%x, pend = %d\n", ccbp->hi_stat, pp->sp_pend)); switch(pp->sp_pend) { case LOPEN: case MPEND: case MOPEN: case CONFIG: case SBREAK: case EBREAK: pp->sp_pend = ccbp->hi_stat; /* sleeping in si_command */ wakeup(&pp->sp_state); break; default: pp->sp_pend = ccbp->hi_stat; } } /* * Continue on if it's closed */ if (ccbp->hi_stat == IDLE_CLOSE) { continue; } /* * Do modem state change if not a local device */ si_modem_state(pp, tp, ccbp->hi_ip); /* * Check to see if there's we should 'receive' * characters. */ if (tp->t_state & TS_CONNECTED && tp->t_state & TS_ISOPEN) isopen = 1; else isopen = 0; /* * Do input break processing */ if (ccbp->hi_state & ST_BREAK) { if (isopen) { (*linesw[tp->t_line].l_rint)(TTY_BI, tp); } ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ DPRINT((pp, DBG_INTR, "si_intr break\n")); } /* * Do RX stuff - if not open then dump any characters. * XXX: This is VERY messy and needs to be cleaned up. * * XXX: can we leave data in the host adapter buffer * when the clists are full? That may be dangerous * if the user cannot get an interrupt signal through. */ more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ if (!isopen) { ccbp->hi_rxopos = ccbp->hi_rxipos; goto end_rx; } /* * If the tty input buffers are blocked, stop emptying * the incoming buffers and let the auto flow control * assert.. */ if (tp->t_state & TS_TBLOCK) { goto end_rx; } /* * Process read characters if not skipped above */ op = ccbp->hi_rxopos; ip = ccbp->hi_rxipos; c = ip - op; if (c == 0) { goto end_rx; } n = c & 0xff; if (n > 250) n = 250; DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", n, op, ip)); /* * Suck characters out of host card buffer into the * "input staging buffer" - so that we dont leave the * host card in limbo while we're possibly echoing * characters and possibly flushing input inside the * ldisc l_rint() routine. */ if (n <= SI_BUFFERSIZE - op) { DPRINT((pp, DBG_INTR, "\tsingle copy\n")); z = ccbp->hi_rxbuf + op; bcopy((caddr_t)z, si_rxbuf, n); op += n; } else { x = SI_BUFFERSIZE - op; DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); z = ccbp->hi_rxbuf + op; bcopy((caddr_t)z, si_rxbuf, x); DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); z = ccbp->hi_rxbuf; bcopy((caddr_t)z, si_rxbuf+x, n-x); op += n; } /* clear collected characters from buffer */ ccbp->hi_rxopos = op; DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", n, op, ip)); /* * at this point... * n = number of chars placed in si_rxbuf */ /* * Avoid the grotesquely inefficient lineswitch * routine (ttyinput) in "raw" mode. It usually * takes about 450 instructions (that's without * canonical processing or echo!). slinput is * reasonably fast (usually 40 instructions * plus call overhead). */ if (tp->t_state & TS_CAN_BYPASS_L_RINT) { /* block if the driver supports it */ if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER && (tp->t_cflag & CRTS_IFLOW || tp->t_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK)) ttyblock(tp); tk_nin += n; tk_rawcc += n; tp->t_rawcc += n; pp->sp_delta_overflows += b_to_q((char *)si_rxbuf, n, &tp->t_rawq); ttwakeup(tp); if (tp->t_state & TS_TTSTOP && (tp->t_iflag & IXANY || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { tp->t_state &= ~TS_TTSTOP; tp->t_lflag &= ~FLUSHO; si_start(tp); } } else { /* * It'd be nice to not have to go through the * function call overhead for each char here. * It'd be nice to block input it, saving a * loop here and the call/return overhead. */ for(x = 0; x < n; x++) { i = si_rxbuf[x]; if ((*linesw[tp->t_line].l_rint)(i, tp) == -1) { pp->sp_delta_overflows++; } /* * doesn't seem to be much point doing * this here.. this driver has no * softtty processing! ?? */ if (pp->sp_hotchar && i == pp->sp_hotchar) { setsofttty(); } } } goto more_rx; /* try for more until RXbuf is empty */ end_rx: /* XXX: Again, sorry about the gotos.. :-) */ /* * Do TX stuff */ (*linesw[tp->t_line].l_start)(tp); } /* end of for (all ports on this controller) */ } /* end of for (all controllers) */ in_intr = 0; DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit));}/* * Nudge the transmitter... * * XXX: I inherited some funny code here. It implies the host card only * interrupts when the transmit buffer reaches the low-water-mark, and does * not interrupt when it's actually hits empty. In some cases, we have * processes waiting for complete drain, and we need to simulate an interrupt * about when we think the buffer is going to be empty (and retry if not). * I really am not certain about this... I *need* the hardware manuals. */static voidsi_start(tp) register struct tty *tp;{ struct si_port *pp; volatile struct si_channel *ccbp; register struct clist *qp; register char *dptr; BYTE ipos; int nchar; int oldspl, count, n, amount, buffer_full; int do_exitproc; oldspl = spltty(); qp = &tp->t_outq; pp = TP2PP(tp); DPRINT((pp, DBG_ENTRY|DBG_START, "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", tp, tp->t_state, pp->sp_state, qp->c_cc)); if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) goto out; do_exitproc = 0; buffer_full = 0; ccbp = pp->sp_ccb; /* * Handle the case where ttywait() is called on process exit * this may be BSDI specific, I dont know... */ if (tp->t_session != NULL && tp->t_session->s_leader != NULL && (tp->t_session->s_leader->p_flag & P_WEXIT)) { do_exitproc++; } count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); dptr = (char *)ccbp->hi_txbuf; /* data buffer */ while ((nchar = qp->c_cc) > 0) { if ((BYTE)count >= 255) { buffer_full++; break; } amount = min(nchar, (255 - (BYTE)count)); ipos = (unsigned int)ccbp->hi_txipos; /* will it fit in one lump? */ if ((SI_BUFFERSIZE - ipos) >= amount) { n = q_to_b(&tp->t_outq, (char *)&ccbp->hi_txbuf[ipos], amount); } else { n = q_to_b(&tp->t_outq, (char *)&ccbp->hi_txbuf[ipos], SI_BUFFERSIZE-ipos); if (n == SI_BUFFERSIZE-ipos) { n += q_to_b(&tp->t_outq, (char *)&ccbp->hi_txbuf[0], amount - (SI_BUFFERSIZE-ipos)); } } ccbp->hi_txipos += n; count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; } if (count != 0 && nchar == 0) { tp->t_state |= TS_BUSY; } else { tp->t_state &= ~TS_BUSY; } /* wakeup time? */ ttwwakeup(tp); DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", (BYTE)count, nchar, tp->t_state)); if ((tp->t_state & TS_BUSY) || do_exitproc) { int time; if (do_exitproc != 0) { time = hz / 10; } else { time = ttspeedtab(tp->t_ospeed, chartimes); if (time > 0) { if (time < nchar) time = nchar / time; else time = 2; } else { DPRINT((pp, DBG_START, "bad char time value! %d\n", time)); time = hz/10; } } if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { untimeout((timeout_func_t)si_lstart, (caddr_t)pp); } else { pp->sp_state |= SS_LSTART; } DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); }out: splx(oldspl); DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));}/* * Note: called at splsoftclock from the timeout code * This has to deal with two things... cause wakeups while waiting for * tty drains on last process exit, and call l_start at about the right * time for protocols like ppp. */static voidsi_lstart(pp) register struct si_port *pp;{ register struct tty *tp; int oldspl; DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", pp, pp->sp_state)); oldspl = spltty(); if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { splx(oldspl); return; } pp->sp_state &= ~SS_LSTART; pp->sp_state |= SS_INLSTART; tp = pp->sp_tty; /* deal with the process exit case */ ttwwakeup(tp); /* nudge protocols - eg: ppp */ (*linesw[tp->t_line].l_start)(tp); pp->sp_state &= ~SS_INLSTART; splx(oldspl);}/* * Stop output on a line. called at spltty(); */voidsistop(tp, rw) register struct tty *tp; int rw;{ volatile struct si_channel *ccbp; struct si_port *pp; pp = TP2PP(tp); ccbp = pp->sp_ccb; DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ if (rw & FWRITE) { /* what level are we meant to be flushing anyway? */ if (tp->t_state & TS_BUSY) { si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); tp->t_state &= ~TS_BUSY; ttwwakeup(tp); /* Bruce???? */ } }#if 1 /* XXX: this doesn't work right yet.. */ /* XXX: this may have been failing because we used to call l_rint() * while we were looping based on these two counters. Now, we collect * the data and then loop stuffing it into l_rint(), making this * useless. Should we cause this to blow away the staging buffer? */ if (rw & FREAD) { ccbp->hi_rxopos = ccbp->hi_rxipos; }#endif}/* * Issue a command to the Z280 host card CPU. */static voidsi_command(pp, cmd, waitflag) struct si_port *pp; /* port control block (local) */ int cmd; int waitflag;{ int oldspl; volatile struct si_channel *ccbp = pp->sp_ccb; int x; DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", pp, cmd, waitflag, ccbp->hi_stat)); oldspl = spltty(); /* Keep others out */ /* wait until it's finished what it was doing.. */ /* XXX: sits in IDLE_BREAK until something disturbs it or break * is turned off. */ while((x = ccbp->hi_stat) != IDLE_OPEN && x != IDLE_CLOSE && x != IDLE_BREAK && x != cmd) { if (in_intr) { /* Prevent sleep in intr */ DPRINT((pp, DBG_PARAM, "cmd intr collision - completing %d\trequested %d\n", x, cmd)); splx(oldspl); return; } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, "sicmd1", 1)) { splx(oldspl); return; } } /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ /* if there was a pending command, cause a state-change wakeup */ switch(pp->sp_pend) { case LOPEN: case MPEND: case MOPEN: case CONFIG: case SBREAK: case EBREAK: wakeup(&pp->sp_state); break; default: break; } pp->sp_pend = cmd; /* New command pending */ ccbp->hi_stat = cmd; /* Post it */ if (waitflag) { if (in_intr) { /* If in interrupt handler */ DPRINT((pp, DBG_PARAM, "attempt to sleep in si_intr - cmd req %d\n", cmd)); splx(oldspl); return; } else while(ccbp->hi_stat != IDLE_OPEN && ccbp->hi_stat != IDLE_BREAK) { if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, "sicmd2", 0)) break; } } splx(oldspl);}static voidsi_disc_optim(tp, t, pp) struct tty *tp; struct termios *t; struct si_port *pp;{ /* * XXX can skip a lot more cases if Smarts. Maybe * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. */ if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) && (!(t->c_iflag & PARMRK) || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) && linesw[tp->t_line].l_rint == ttyinput) tp->t_state |= TS_CAN_BYPASS_L_RINT; else tp->t_state &= ~TS_CAN_BYPASS_L_RINT; /* * Prepare to reduce input latency for packet * discplines with a end of packet character. */ if (tp->t_line == SLIPDISC) pp->sp_hotchar = 0xc0; else if (tp->t_line == PPPDISC) pp->sp_hotchar = 0x7e; else pp->sp_hotchar = 0; DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", pp->sp_hotchar));}#ifdef SI_DEBUGstatic voidsi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6) struct si_port *pp; int flags; char *str; int a1, a2, a3, a4, a5, a6;{ if ((pp == NULL && (si_debug&flags)) || (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { if (pp != NULL) printf("%ci%d(%d): ", 's', (int)SI_CARD(pp->sp_tty->t_dev), (int)SI_PORT(pp->sp_tty->t_dev)); printf(str, a1, a2, a3, a4, a5, a6); }}static char *si_mctl2str(cmd) enum si_mctl cmd;{ switch (cmd) { case GET: return("GET"); case SET: return("SET"); case BIS: return("BIS"); case BIC: return("BIC"); } return("BAD");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -