📄 pi2.c
字号:
restore_flags(flags); return; } /* NOTE - fall through if more to send */ case ST_TXDELAY: /* Disable DMA chan */ disable_dma(lp->dmachan); /* Set up for TX dma */ wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); /* Get all chars */ /* Strip KISS control byte */ length = lp->sndbuf->len - 1; memcpy(lp->txdmabuf, &lp->sndbuf->data[1], length); /* Setup DMA controller for tx */ setup_tx_dma(lp, length); /* select transmit interrupts to enable */ /* Allow DMA on chan */ enable_dma(lp->dmachan); /* reset CRC, Txint pend*/ wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC | RES_Tx_P); /* allow Underrun int only */ wrtscc(lp->cardbase, cmd, R15, TxUIE); /* Enable TX DMA */ wrtscc(lp->cardbase, cmd, R1, WT_RDY_ENAB | WT_FN_RDYFN | EXT_INT_ENAB); /* Send CRC on underrun */ wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); /* packet going out now */ lp->tstate = ACTIVE; break; case DEFER: /* we have deferred prev xmit attempt * See Intel Microcommunications Handbook, p2-308 */ wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { lp->tstate = DEFER; tdelay(lp, 100); /* Defer until dcd transition or 100mS timeout */ wrtscc(lp->cardbase, CTL + lp->base, R15, CTSIE | DCDIE); restore_flags(flags); return; } if (random() > lp->persist) { lp->tstate = DEFER; tdelay(lp, lp->slotime); restore_flags(flags); return; } /* Assert RTS early minimize collision window */ wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); rts(lp, ON); /* Transmitter on */ lp->tstate = ST_TXDELAY; tdelay(lp, lp->txdelay); restore_flags(flags); return; } /* switch(lp->tstate) */ restore_flags(flags);} /* a_exint() *//* Receive interrupt handler for the A channel */static void a_rxint(struct device *dev, struct pi_local *lp){ unsigned long flags; int cmd; int bytecount; char rse; struct sk_buff *skb; int sksize, pkt_len; struct mbuf *cur_buf; unsigned char *cfix; save_flags(flags); cli(); /* disable interrupts */ cmd = lp->base + CTL; rse = rdscc(lp->cardbase, cmd, R1); /* Get special condition bits from R1 */ if (rse & Rx_OVR) lp->rstate = RXERROR; if (rse & END_FR) { /* If end of frame */ /* figure length of frame from 8237 */ clear_dma_ff(lp->dmachan); bytecount = lp->bufsiz - get_dma_residue(lp->dmachan); if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (bytecount < 10)) { if ((bytecount >= 10) && (rse & CRC_ERR)) { lp->stats.rx_crc_errors++; } if (lp->rstate == RXERROR) { lp->stats.rx_errors++; lp->stats.rx_over_errors++; } /* Reset buffer pointers */ lp->rstate = ACTIVE; setup_rx_dma(lp); } else { /* Here we have a valid frame */ /* Toss 2 crc bytes , add one for KISS */ pkt_len = lp->rcvbuf->cnt = bytecount - 2 + 1; /* Get buffer for next frame */ cur_buf = lp->rcvbuf; switchbuffers(lp); setup_rx_dma(lp); /* Malloc up new buffer. */ sksize = pkt_len; skb = dev_alloc_skb(sksize); if (skb == NULL) { printk(KERN_ERR "PI: %s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; restore_flags(flags); return; } skb->dev = dev; /* KISS kludge - prefix with a 0 byte */ cfix=skb_put(skb,pkt_len); *cfix++=0; /* 'skb->data' points to the start of sk_buff data area. */ memcpy(cfix, (char *) cur_buf->data, pkt_len - 1); skb->protocol=htons(ETH_P_AX25); skb->mac.raw=skb->data; netif_rx(skb); lp->stats.rx_packets++; } /* end good frame */ } /* end EOF check */ wrtscc(lp->cardbase, lp->base + CTL, R0, ERR_RES); /* error reset */ restore_flags(flags);}static void b_rxint(struct device *dev, struct pi_local *lp){ unsigned long flags; int cmd; char rse; struct sk_buff *skb; int sksize; int pkt_len; unsigned char *cfix; save_flags(flags); cli(); /* disable interrupts */ cmd = CTL + lp->base; rse = rdscc(lp->cardbase, cmd, R1); /* get status byte from R1 */ if ((rdscc(lp->cardbase, cmd, R0)) & Rx_CH_AV) { /* there is a char to be stored * read special condition bits before reading the data char */ if (rse & Rx_OVR) { /* Rx overrun - toss buffer */ /* reset buffer pointers */ lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; lp->rstate = RXERROR; /* set error flag */ lp->stats.rx_errors++; lp->stats.rx_over_errors++; } else if (lp->rcvbuf->cnt >= lp->bufsiz) { /* Too large -- toss buffer */ /* reset buffer pointers */ lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; lp->rstate = TOOBIG;/* when set, chars are not stored */ } /* ok, we can store the received character now */ if (lp->rstate == ACTIVE) { /* If no errors... */ *lp->rcp++ = rdscc(lp->cardbase, cmd, R8); /* char to rcv buff */ lp->rcvbuf->cnt++; /* bump count */ } else { /* got to empty FIFO */ (void) rdscc(lp->cardbase, cmd, R8); wrtscc(lp->cardbase, cmd, R0, ERR_RES); /* reset err latch */ lp->rstate = ACTIVE; } } if (rse & END_FR) { /* END OF FRAME -- Make sure Rx was active */ if (lp->rcvbuf->cnt > 0) { if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (lp->rcvbuf->cnt < 10)) { if ((lp->rcvbuf->cnt >= 10) && (rse & CRC_ERR)) { lp->stats.rx_crc_errors++; } lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; } else { /* Here we have a valid frame */ pkt_len = lp->rcvbuf->cnt -= 2; /* Toss 2 crc bytes */ pkt_len += 1; /* Make room for KISS control byte */ /* Malloc up new buffer. */ sksize = pkt_len; skb = dev_alloc_skb(sksize); if (skb == NULL) { printk(KERN_ERR "PI: %s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; restore_flags(flags); return; } skb->dev = dev; /* KISS kludge - prefix with a 0 byte */ cfix=skb_put(skb,pkt_len); *cfix++=0; /* 'skb->data' points to the start of sk_buff data area. */ memcpy(cfix, lp->rcvbuf->data, pkt_len - 1); skb->protocol=ntohs(ETH_P_AX25); skb->mac.raw=skb->data; netif_rx(skb); lp->stats.rx_packets++; /* packet queued - initialize buffer for next frame */ lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; } /* end good frame queued */ } /* end check for active receive upon EOF */ lp->rstate = ACTIVE; /* and clear error status */ } /* end EOF check */ restore_flags(flags);}static void b_txint(struct pi_local *lp){ unsigned long flags; int cmd; unsigned char c; save_flags(flags); cli(); cmd = CTL + lp->base; switch (lp->tstate) { case CRCOUT: lp->tstate = FLAGOUT; tdelay(lp, lp->squeldelay); restore_flags(flags); return; case IDLE: /* Transmitter idle. Find a frame for transmission */ if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { /* Nothing to send - return to receive mode * Tx OFF now - flag should have gone */ rts(lp, OFF); restore_flags(flags); return; } lp->txptr = lp->sndbuf->data; lp->txptr++; /* Ignore KISS control byte */ lp->txcnt = (int) lp->sndbuf->len - 1; /* If a buffer to send, we drop thru here */ case DEFER: /* we may have deferred prev xmit attempt */ /* Check DCD - debounce it */ /* See Intel Microcommunications Handbook, p2-308 */ wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0) { lp->tstate = DEFER; tdelay(lp, 100); /* defer until DCD transition or timeout */ wrtscc(lp->cardbase, cmd, R15, CTSIE | DCDIE); restore_flags(flags); return; } if (random() > lp->persist) { lp->tstate = DEFER; tdelay(lp, lp->slotime); restore_flags(flags); return; } rts(lp, ON); /* Transmitter on */ lp->tstate = ST_TXDELAY; tdelay(lp, lp->txdelay); restore_flags(flags); return; case ACTIVE: /* Here we are actively sending a frame */ if (lp->txcnt--) { c = *lp->txptr++; /* next char is gone */ wrtscc(lp->cardbase, cmd, R8, c); /* stuffing a char satisfies Interrupt condition */ } else { /* No more to send */ kfree_skb(lp->sndbuf); lp->sndbuf = NULL; if ((rdscc(lp->cardbase, cmd, R0) & 0x40)) { /* Did we underrun? */ /* unexpected underrun */ lp->stats.tx_errors++; lp->stats.tx_fifo_errors++; wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); lp->tstate = FLAGOUT; tdelay(lp, lp->squeldelay); restore_flags(flags); return; } lp->tstate = UNDERRUN; /* Now we expect to underrun */ /* Send flags on underrun */ if (lp->speed) { /* If internally clocked */ wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); } else { wrtscc(lp->cardbase, cmd, R10, CRCPS); } wrtscc(lp->cardbase, cmd, R0, RES_Tx_P); /* reset Tx Int Pend */ } restore_flags(flags); return; /* back to wait for interrupt */ } /* end switch */ restore_flags(flags);}/* Pi SIO External/Status interrupts (for the B channel) * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM. * Receiver automatically goes to Hunt on an abort. * * If the Tx Underrun interrupt hits, change state and * issue a reset command for it, and return. */static void b_exint(struct pi_local *lp){ unsigned long flags; char st; int cmd; char c; cmd = CTL + lp->base; save_flags(flags); cli(); /* disable interrupts */ st = rdscc(lp->cardbase, cmd, R0); /* Fetch status */ /* reset external status latch */ wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); switch (lp->tstate) { case ACTIVE: /* Unexpected underrun */ kfree_skb(lp->sndbuf); lp->sndbuf = NULL; wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); lp->tstate = FLAGOUT; lp->stats.tx_errors++; lp->stats.tx_fifo_errors++; tdelay(lp, lp->squeldelay); restore_flags(flags); return; case UNDERRUN: lp->tstate = CRCOUT; restore_flags(flags); return; case FLAGOUT: /* Find a frame for transmission */ if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL) { /* Nothing to send - return to receive mode * Tx OFF now - flag should have gone */ rts(lp, OFF); lp->tstate = IDLE; restore_flags(flags); return; } lp->txptr = lp->sndbuf->data; lp->txptr++; /* Ignore KISS control byte */ lp->txcnt = (int) lp->sndbuf->len - 1; /* Get first char to send */ lp->txcnt--; c = *lp->txptr++; wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC); /* reset for next frame */ /* Send abort on underrun */ if (lp->speed) { /* If internally clocked */ wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER); } else { wrtscc(lp->cardbase, cmd, R10, CRCPS | ABUNDER); } wrtscc(lp->cardbase, cmd, R8, c); /* First char out now */ wrtscc(lp->cardbase, cmd, R0, RES_EOM_L); /* Reset end of message latch */#ifdef STUFF2 /* stuff an extra one if we can */ if (lp->txcnt) { lp->txcnt--; c = *lp->txptr++; /* Wait for tx buffer empty */ while((rdscc(lp->cardbase, cmd, R0) & 0x04) == 0) ; wrtscc(lp->cardbase, cmd, R8, c); }#endif /* select transmit interrupts to enable */ wrtscc(lp->cardbase, cmd, R15, TxUIE); /* allow Underrun int only */ wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT); wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB); /* Tx/Ext ints */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -