?? if_cx.c
字號(hào):
outw (ARBCNT(port), DMABUFSZ); outb (ARBSTS(port), BSTS_OWN24); outw (BRBCNT(port), DMABUFSZ); outb (BRBSTS(port), BSTS_OWN24); /* Raise DTR and RTS */ cx_chan_dtr (c, 1); cx_chan_rts (c, 1); /* Enable interrupts */ outb (IER(port), IER_RXD | IER_TXD);}/* * Fill transmitter buffer with data. */static void cxput (cx_chan_t *c, char b){ struct mbuf *m; unsigned char *buf; unsigned short port = c->chip->port, len, cnt_port, sts_port; /* Choose the buffer. */ if (b == 'A') { buf = c->atbuf; cnt_port = ATBCNT(port); sts_port = ATBSTS(port); } else { buf = c->btbuf; cnt_port = BTBCNT(port); sts_port = BTBSTS(port); } /* Is it busy? */ if (inb (sts_port) & BSTS_OWN24) { if (c->ifp->if_flags & IFF_DEBUG) print (("cx%d.%d: tbuf %c already busy, bsts=%b\n", c->board->num, c->num, b, inb (sts_port), BSTS_BITS)); goto ret; } /* Get the packet to send. */ m = sppp_dequeue (c->master); if (! m) return; len = m->m_pkthdr.len; /* Count the transmitted bytes to the subchannel, not the master. */ c->master->if_obytes -= len + 3; c->ifp->if_obytes += len + 3; c->stat->obytes += len + 3; if (len >= DMABUFSZ) { printf ("cx%d.%d: too long packet: %d bytes: ", c->board->num, c->num, len); printmbuf (m); m_freem (m); return; } m_copydata (m, 0, len, buf);#if NBPFILTER > 0 if (c->ifp->if_bpf) bpf_mtap (c->ifp, m);#endif m_freem (m); /* Start transmitter. */ outw (cnt_port, len); outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24); if (c->ifp->if_flags & IFF_DEBUG) print (("cx%d.%d: enqueue %d bytes to %c\n", c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B'));ret: c->ifp->if_flags |= IFF_OACTIVE;}/* * Start output on the (slave) interface. Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */static voidcxsend (cx_chan_t *c){ unsigned short port = c->chip->port; if (c->ifp->if_flags & IFF_DEBUG) print (("cx%d.%d: cxsend\n", c->board->num, c->num)); /* No output if the interface is down. */ if (! (c->ifp->if_flags & IFF_RUNNING)) return; /* Set the current channel number. */ outb (CAR(port), c->num & 3); /* Determine the buffer order. */ if (inb (DMABSTS(port)) & DMABSTS_NTBUF) { cxput (c, 'B'); cxput (c, 'A'); } else { cxput (c, 'A'); cxput (c, 'B'); } /* Set up transmit timeout. */ if (c->master->if_flags & IFF_OACTIVE) c->master->if_timer = TXTIMEOUT; /* * Enable TXMPTY interrupt, * to catch the case when the second buffer is empty. */ if ((inb (ATBSTS(port)) & BSTS_OWN24) && (inb (BTBSTS(port)) & BSTS_OWN24)) { outb (IER(port), IER_RXD | IER_TXD | IER_TXMPTY); } else outb (IER(port), IER_RXD | IER_TXD);}/* * Start output on the (master) interface and all slave interfaces. * Always called on splimp(). */static voidcxstart (struct ifnet *ifp){ cx_chan_t *q, *c = ifp->if_softc; if (c->ifp->if_flags & IFF_DEBUG) print (("cx%d.%d: cxstart\n", c->board->num, c->num)); /* Start the master subchannel. */ cxsend (c); /* Start all slave subchannels. */ if (c->slaveq && ! sppp_isempty (c->master)) for (q=c->slaveq; q; q=q->slaveq) if ((q->ifp->if_flags & IFF_RUNNING) && ! (q->ifp->if_flags & IFF_OACTIVE)) cxsend (q);}/* * Handle transmit timeouts. * Recover after lost transmit interrupts. * Always called on splimp(). */static voidcxwatchdog (struct ifnet *ifp){ cx_chan_t *q, *c = ifp->if_softc; if (! (ifp->if_flags & IFF_RUNNING)) return; if (ifp->if_flags & IFF_DEBUG) printf ("cx%d.%d: device timeout\n", c->board->num, c->num); cxdown (c); for (q=c->slaveq; q; q=q->slaveq) cxdown (q); cxup (c); for (q=c->slaveq; q; q=q->slaveq) cxup (q); cxstart (ifp);}/* * Handle receive interrupts, including receive errors and * receive timeout interrupt. */static void cxrinth (cx_chan_t *c){ unsigned short port = c->chip->port; unsigned short len, risr = inw (RISR(port)); /* Receive errors. */ if (risr & (RIS_BUSERR | RIS_OVERRUN | RISH_CRCERR | RISH_RXABORT)) { if (c->ifp->if_flags & IFF_DEBUG) printf ("cx%d.%d: receive error, risr=%b\n", c->board->num, c->num, risr, RISH_BITS); ++c->ifp->if_ierrors; ++c->stat->ierrs; if (risr & RIS_OVERRUN) ++c->ifp->if_collisions; } else if (risr & RIS_EOBUF) { if (c->ifp->if_flags & IFF_DEBUG) print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n", c->board->num, c->num, risr, RISH_BITS, inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); ++c->stat->ipkts; /* Handle received data. */ len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port)); c->stat->ibytes += len; if (len > DMABUFSZ) { /* Fatal error: actual DMA transfer size * exceeds our buffer size. It could be caused * by incorrectly programmed DMA register or * hardware fault. Possibly, should panic here. */ printf ("cx%d.%d: panic! DMA buffer overflow: %d bytes\n", c->board->num, c->num, len); ++c->ifp->if_ierrors; } else if (! (risr & RIS_EOFR)) { /* The received frame does not fit in the DMA buffer. * It could be caused by serial lie noise, * or if the peer has too big MTU. */ if (c->ifp->if_flags & IFF_DEBUG) printf ("cx%d.%d: received frame length exceeds MTU, risr=%b\n", c->board->num, c->num, risr, RISH_BITS); ++c->ifp->if_ierrors; } else { /* Valid frame received. */ if (c->ifp->if_flags & IFF_DEBUG) print (("cx%d.%d: hdlc received %d bytes\n", c->board->num, c->num, len)); cxinput (c, (risr & RIS_BB) ? c->brbuf : c->arbuf, len); ++c->ifp->if_ipackets; } } else if (c->ifp->if_flags & IFF_DEBUG) { print (("cx%d.%d: unknown hdlc receive interrupt, risr=%b\n", c->board->num, c->num, risr, RISH_BITS)); ++c->stat->ierrs; } /* Restart receiver. */ if (! (inb (ARBSTS(port)) & BSTS_OWN24)) { outw (ARBCNT(port), DMABUFSZ); outb (ARBSTS(port), BSTS_OWN24); } if (! (inb (BRBSTS(port)) & BSTS_OWN24)) { outw (BRBCNT(port), DMABUFSZ); outb (BRBSTS(port), BSTS_OWN24); }}/* * Handle transmit interrupt. */static intcxtinth (cx_chan_t *c){ unsigned short port = c->chip->port; unsigned char tisr = inb (TISR(port)); unsigned char teoir = 0; c->ifp->if_flags &= ~IFF_OACTIVE; if (c->ifp == c->master) c->ifp->if_timer = 0; if (tisr & (TIS_BUSERR | TIS_UNDERRUN)) { /* if (c->ifp->if_flags & IFF_DEBUG) */ print (("cx%d.%d: transmit error, tisr=%b, atbsts=%b, btbsts=%b\n", c->board->num, c->num, tisr, TIS_BITS, inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS)); ++c->ifp->if_oerrors; ++c->stat->oerrs; /* Terminate the failed buffer. */ /* teoir = TEOI_TERMBUFF; */ } else if (c->ifp->if_flags & IFF_DEBUG) print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n", c->board->num, c->num, tisr, TIS_BITS, inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS)); if (tisr & TIS_EOFR) { ++c->ifp->if_opackets; ++c->stat->opkts; } /* Start output on the (sub-) channel. */ cxsend (c); return (teoir);}static voidcxintr (int bnum){ cx_board_t *b = cxboard + bnum; while (! (inw (BSR(b->port)) & BSR_NOINTR)) { /* Acknowledge the interrupt to enter the interrupt context. */ /* Read the local interrupt vector register. */ unsigned char livr = inb (IACK(b->port, BRD_INTR_LEVEL)); cx_chan_t *c = b->chan + (livr>>2 & 0xf); unsigned short port = c->chip->port; unsigned short eoiport = REOIR(port); unsigned char eoi = 0; if (c->type == T_NONE) { printf ("cx%d.%d: unexpected interrupt, livr=0x%x\n", c->board->num, c->num, livr); continue; /* incorrect channel number? */ } /* print (("cx%d.%d: interrupt, livr=0x%x\n", c->board->num, c->num, livr)); */ /* Clear RTS to stop receiver data flow while we are busy * processing the interrupt, thus avoiding underruns. */ if (! c->sopt.norts) { outb (MSVR_RTS(port), 0); c->rts = 0; } switch (livr & 3) { case LIV_EXCEP: /* receive exception */ case LIV_RXDATA: /* receive interrupt */ ++c->stat->rintr; switch (c->mode) { case M_ASYNC: eoi = cxrinta (c); break; case M_HDLC: cxrinth (c); break; default:; /* No bisync and X.21 yet */ } break; case LIV_TXDATA: /* transmit interrupt */ ++c->stat->tintr; eoiport = TEOIR(port); switch (c->mode) { case M_ASYNC: cxtinta (c); break; case M_HDLC: eoi = cxtinth (c); break; default:; /* No bisync and X.21 yet */ } break; case LIV_MODEM: /* modem/timer interrupt */ ++c->stat->mintr; eoiport = MEOIR(port); cxmint (c); break; } /* Raise RTS for this channel if and only if * both receive buffers are empty. */ if (! c->sopt.norts && (inb (CSR(port)) & CSRA_RXEN) && (inb (ARBSTS(port)) & BSTS_OWN24) && (inb (BRBSTS(port)) & BSTS_OWN24)) { outb (MSVR_RTS(port), MSV_RTS); c->rts = 1; } /* Exit from interrupt context. */ outb (eoiport, eoi); /* Master channel - start output on all idle subchannels. */ if (c->master == c->ifp && c->slaveq && (livr & 3) == LIV_TXDATA && c->mode == M_HDLC && ! sppp_isempty (c->ifp)) { cx_chan_t *q; for (q=c->slaveq; q; q=q->slaveq) if ((q->ifp->if_flags & IFF_RUNNING) && ! (q->ifp->if_flags & IFF_OACTIVE)) cxsend (q); } }}/* * Process the received packet. */static void cxinput (cx_chan_t *c, void *buf, unsigned len){ /* Make an mbuf. */ struct mbuf *m = makembuf (buf, len); if (! m) { if (c->ifp->if_flags & IFF_DEBUG) printf ("cx%d.%d: no memory for packet\n", c->board->num, c->num); ++c->ifp->if_iqdrops; return; } m->m_pkthdr.rcvif = c->master;#ifdef DEBUG if (c->ifp->if_flags & IFF_DEBUG) printmbuf (m);#endif#if NBPFILTER > 0 /* * Check if there's a BPF listener on this interface. * If so, hand off the raw packet to bpf. */ if (c->ifp->if_bpf) bpf_tap (c->ifp, buf, len);#endif /* Count the received bytes to the subchannel, not the master. */ c->master->if_ibytes -= len + 3; c->ifp->if_ibytes += len + 3; sppp_input (c->master, m);}void cxswitch (cx_chan_t *c, cx_soft_opt_t new){ new.ext = 0; if (! new.ext) { struct sppp *sp = (struct sppp*) c->ifp; if (new.cisco) sp->pp_flags |= PP_CISCO; else sp->pp_flags &= ~PP_CISCO; if (new.keepalive) sp->pp_flags |= PP_KEEPALIVE; else sp->pp_flags &= ~PP_KEEPALIVE; } c->sopt = new;}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -