📄 pt.c
字号:
{ if (request_dma(dev->dma, "pt")) { free_irq(dev->irq, dev); return -EAGAIN; } } /* Reset hardware */ chipset_init(dev); } lp->tstate = IDLE; if (dev->base_addr & CHANA) { scc_init(dev); scc_init(dev->next); } /* Save a copy of register RR0 for comparing with later on */ /* We always put 0 in zero count */ lp->saved_RR0 = rdscc(lp->cardbase, lp->base + CTL, R0) & ~ZCOUNT; /* master interrupt enable */ save_flags(flags); cli(); wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | NV); outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG); restore_flags(flags); lp->open_time = jiffies; dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; first_time = 0; MOD_INC_USE_COUNT; return 0;} /* pt_open() */static int pt_send_packet(struct sk_buff *skb, struct device *dev){ struct pt_local *lp = (struct pt_local *) dev->priv;#ifdef PT_DEBUG printk(KERN_DEBUG "PT: pt_send_packet(): (%d)\n", lp->base & CHANA);#endif hardware_send_packet(lp, skb); dev->trans_start = jiffies; return 0;}/* The inverse routine to pt_open() */static int pt_close(struct device *dev){ unsigned long flags; struct pt_local *lp = dev->priv; struct sk_buff *ptr = NULL; int cmd; cmd = lp->base + CTL; save_flags(flags); cli(); /* Reset SCC or channel */ chipset_init(dev); disable_dma(lp->dmachan); lp->open_time = 0; dev->tbusy = 1; dev->start = 0; /* Free any buffers left in the hardware transmit queue */ while ((ptr = skb_dequeue(&lp->sndq)) != NULL) kfree_skb(ptr); restore_flags(flags);#ifdef PT_DEBUG printk(KERN_DEBUG "PT: pt_close(): Closing down channel (%d).\n", lp->base & CHANA);#endif MOD_DEC_USE_COUNT; return 0;} /* pt_close() */static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd){ unsigned long flags; struct pt_req rq; struct pt_local *lp = (struct pt_local *) dev->priv; int ret = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct pt_req)); if (ret) return ret; if (cmd != SIOCDEVPRIVATE) return -EINVAL; copy_from_user(&rq, ifr->ifr_data, sizeof(struct pt_req)); switch (rq.cmd) { case SIOCSPIPARAM: if (!suser()) return -EPERM; save_flags(flags); cli(); lp->txdelay = rq.txdelay; lp->persist = rq.persist; lp->slotime = rq.slotime; lp->squeldelay = rq.squeldelay; lp->clockmode = rq.clockmode; lp->speed = rq.speed; pt_open(&pt0a); restore_flags(flags); ret = 0; break; case SIOCSPIDMA: if (!suser()) return -EPERM; ret = 0; if (dev->base_addr & CHANA) { /* if A channel */ if (rq.dmachan < 1 || rq.dmachan > 3) return -EINVAL; save_flags(flags); cli(); pt_close(dev); free_dma(lp->dmachan); dev->dma = lp->dmachan = rq.dmachan; if (request_dma(lp->dmachan,"pt")) ret = -EAGAIN; pt_open(dev); restore_flags(flags); } break; case SIOCSPIIRQ: ret = -EINVAL; /* add this later */ break; case SIOCGPIPARAM: case SIOCGPIDMA: case SIOCGPIIRQ: rq.speed = lp->speed; rq.txdelay = lp->txdelay; rq.persist = lp->persist; rq.slotime = lp->slotime; rq.squeldelay = lp->squeldelay; rq.clockmode = lp->clockmode; rq.dmachan = lp->dmachan; rq.irq = dev->irq; copy_to_user(ifr->ifr_data, &rq, sizeof(struct pt_req)); ret = 0; break; default: ret = -EINVAL; } return ret;}/* * Get the current statistics. * This may be called with the card open or closed. */ static struct net_device_stats *pt_get_stats(struct device *dev){ struct pt_local *lp = (struct pt_local *) dev->priv; return &lp->stats;}/* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c" * version-control: t * kept-new-versions: 5 * tab-width: 4 * End: */static void tdelay(struct pt_local *lp, int time){ /* For some reason, we turn off the Tx interrupts here! */ if (!lp->dmachan) wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB); if (lp->base & CHANA) { outb_p(time & 0xff, lp->cardbase + TMR1); outb_p((time >> 8)&0xff, lp->cardbase + TMR1); } else { outb_p(time & 0xff, lp->cardbase + TMR2); outb_p((time >> 8)&0xff, lp->cardbase + TMR2); }} /* tdelay */static void pt_txisr(struct pt_local *lp){ unsigned long flags; int cmd; unsigned char c; save_flags(flags); cli(); cmd = lp->base + CTL;#ifdef PT_DEBUG printk(KERN_DEBUG "PT: pt_txisr(): tstate = %d (%d).\n", lp->tstate, lp->base & CHANA);#endif 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 */ pt_rts(lp, OFF); restore_flags(flags); return; } if (!lp->dmachan) { lp->txptr = lp->sndbuf->data; lp->txptr++; /* Ignore KISS control byte */ lp->txcnt = (int) lp->sndbuf->len - 1; } /* If a buffer to send, drop though here */ case DEFER: /* 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, DCDIE); restore_flags(flags); return; } if (random() > lp->persist) { lp->tstate = DEFER; tdelay(lp, lp->slotime); restore_flags(flags); return; } pt_rts(lp, ON); /* Tx on */ if (lp->dmachan) wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8); lp->tstate = ST_TXDELAY; tdelay(lp, lp->txdelay); restore_flags(flags); return; case ACTIVE: /* Here we are actively sending a frame */ if (lp->txcnt--) { /* XLZ - checkout Gracilis PT code to see if the while * loop is better or not. */ 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) & TxEOM)) { /* Did we 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; /* Send flags on underrun */ if (lp->nrzi) { wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI); } else { wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZ); } /* Reset Tx interrupt pending */ wrtscc(lp->cardbase, cmd, R0, RES_Tx_P); } restore_flags(flags); return; default: printk(KERN_ERR "PT: pt_txisr(): Invalid tstate (%d) for chan %s.\n", lp->tstate, (cmd & CHANA? "A": "B") ); pt_rts(lp, OFF); lp->tstate = IDLE; break; } /*switch */ restore_flags(flags);}static void pt_rxisr(struct device *dev){ struct pt_local *lp = (struct pt_local*) dev->priv; int cmd = lp->base + CTL; int bytecount; unsigned long flags; char rse; struct sk_buff *skb; int sksize, pkt_len; struct mbuf *cur_buf = NULL; unsigned char *cfix; save_flags(flags); cli(); /* Get status byte from R1 */ rse = rdscc(lp->cardbase, cmd, R1);#ifdef PT_DEBUG printk(KERN_DEBUG "PT: pt_rxisr(): R1 = %#3x. (%d)\n", rse, lp->base & CHANA);#endif if (lp->dmachan && (rse & Rx_OVR)) lp->rstate = RXERROR; if (rdscc(lp->cardbase, cmd, R0) & Rx_CH_AV && !lp->dmachan) { /* There is a char to be stored * Read special condition bits before reading the data char */ if (rse & Rx_OVR) { /* Rx overrun - toss buffer */ /* wind back the pointers */ lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; lp->rstate = RXERROR; lp->stats.rx_errors++; lp->stats.rx_fifo_errors++; } else if (lp->rcvbuf->cnt >= lp->bufsiz) { /* Too large packet * wind back Rx buffer pointers */ lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; lp->rstate = TOOBIG; } /* ok, we can store the Rx char if no errors */ if (lp->rstate == ACTIVE) { *lp->rcp++ = rdscc(lp->cardbase, cmd, R8); lp->rcvbuf->cnt++; } else { /* we got an error, dump the FIFO */ (void) rdscc(lp->cardbase, cmd, R8); (void) rdscc(lp->cardbase, cmd, R8); (void) rdscc(lp->cardbase, cmd, R8); /* Reset error latch */ wrtscc(lp->cardbase, cmd, R0, ERR_RES); lp->rstate = ACTIVE; /* Resync the SCC */ wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); } } if (rse & END_FR) {#ifdef PT_DEBUG printk(KERN_DEBUG "PT: pt_rxisr() Got end of a %u byte frame.\n", lp->rcvbuf->cnt);#endif if (lp->dmachan) { clear_dma_ff(lp->dmachan); bytecount = lp->bufsiz - get_dma_residue(lp->dmachan); } else { bytecount = lp->rcvbuf->cnt; } /* END OF FRAME - Make sure Rx was active */ if (lp->rcvbuf->cnt > 0 || lp->dmachan) { if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (bytecount < 10)) { if ((bytecount >= 10) && (rse & CRC_ERR)) { lp->stats.rx_crc_errors++; } if (lp->dmachan) { if (lp->rstate == RXERROR) { lp->stats.rx_errors++; lp->stats.rx_over_errors++; } lp->rstate = ACTIVE; setup_rx_dma(lp); } else { /* wind back Rx buffer pointers */ lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; /* Re-sync the SCC */ wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8); }#ifdef PT_DEBUG printk(KERN_DEBUG "PT: pt_rxisr() %s error.\n", (rse & CRC_ERR)? "CRC" : "state");#endif } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -