📄 ni65.c
字号:
}/* * free buffers and private struct */static void ni65_free_buffer(struct priv *p){ int i; if(!p) return; for(i=0;i<TMDNUM;i++) { if(p->tmdbounce[i]) kfree(p->tmdbounce[i]);#ifdef XMT_VIA_SKB if(p->tmd_skb[i]) dev_kfree_skb(p->tmd_skb[i]);#endif } for(i=0;i<RMDNUM;i++) {#ifdef RCV_VIA_SKB if(p->recv_skb[i]) dev_kfree_skb(p->recv_skb[i]);#else if(p->recvbounce[i]) kfree(p->recvbounce[i]);#endif } if(p->self) kfree(p->self);}/* * stop and (re)start lance .. e.g after an error */static void ni65_stop_start(struct device *dev,struct priv *p){ int csr0 = CSR0_INEA; writedatareg(CSR0_STOP); if(debuglevel > 1) printk("ni65_stop_start\n"); if(p->features & INIT_RING_BEFORE_START) { int i;#ifdef XMT_VIA_SKB struct sk_buff *skb_save[TMDNUM];#endif unsigned long buffer[TMDNUM]; short blen[TMDNUM]; if(p->xmit_queued) { while(1) { if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN)) break; p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1); if(p->tmdlast == p->tmdnum) break; } } for(i=0;i<TMDNUM;i++) { struct tmd *tmdp = p->tmdhead + i;#ifdef XMT_VIA_SKB skb_save[i] = p->tmd_skb[i];#endif buffer[i] = (u32) bus_to_virt(tmdp->u.buffer); blen[i] = tmdp->blen; tmdp->u.s.status = 0x0; } for(i=0;i<RMDNUM;i++) { struct rmd *rmdp = p->rmdhead + i; rmdp->u.s.status = RCV_OWN; } p->tmdnum = p->xmit_queued = 0; writedatareg(CSR0_STRT | csr0); for(i=0;i<TMDNUM;i++) { int num = (i + p->tmdlast) & (TMDNUM-1); p->tmdhead[i].u.buffer = (u32) virt_to_bus((char *)buffer[num]); /* status is part of buffer field */ p->tmdhead[i].blen = blen[num]; if(p->tmdhead[i].u.s.status & XMIT_OWN) { p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1); p->xmit_queued = 1; writedatareg(CSR0_TDMD | CSR0_INEA | csr0); }#ifdef XMT_VIA_SKB p->tmd_skb[i] = skb_save[num];#endif } p->rmdnum = p->tmdlast = 0; if(!p->lock) dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1; dev->trans_start = jiffies; } else writedatareg(CSR0_STRT | csr0);}/* * init lance (write init-values .. init-buffers) (open-helper) */static int ni65_lance_reinit(struct device *dev){ int i; struct priv *p = (struct priv *) dev->priv; unsigned long flags; p->lock = 0; p->xmit_queued = 0; flags=claim_dma_lock(); disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */ set_dma_mode(dev->dma,DMA_MODE_CASCADE); enable_dma(dev->dma); release_dma_lock(flags); outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */ if( (i=readreg(CSR0) ) != 0x4) { printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name, cards[p->cardno].cardname,(int) i); flags=claim_dma_lock(); disable_dma(dev->dma); release_dma_lock(flags); return 0; } p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0; for(i=0;i<TMDNUM;i++) { struct tmd *tmdp = p->tmdhead + i;#ifdef XMT_VIA_SKB if(p->tmd_skb[i]) { dev_kfree_skb(p->tmd_skb[i]); p->tmd_skb[i] = NULL; }#endif tmdp->u.buffer = 0x0; tmdp->u.s.status = XMIT_START | XMIT_END; tmdp->blen = tmdp->status2 = 0; } for(i=0;i<RMDNUM;i++) { struct rmd *rmdp = p->rmdhead + i;#ifdef RCV_VIA_SKB rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data);#else rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]);#endif rmdp->blen = -(R_BUF_SIZE-8); rmdp->mlen = 0; rmdp->u.s.status = RCV_OWN; } if(dev->flags & IFF_PROMISC) ni65_init_lance(p,dev->dev_addr,0x00,M_PROM); else if(dev->mc_count || dev->flags & IFF_ALLMULTI) ni65_init_lance(p,dev->dev_addr,0xff,0x0); else ni65_init_lance(p,dev->dev_addr,0x00,0x00); /* * ni65_set_lance_mem() sets L_ADDRREG to CSR0 * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED */ if(inw(PORT+L_DATAREG) & CSR0_IDON) { ni65_set_performance(p); /* init OK: start lance , enable interrupts */ writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); return 1; /* ->OK */ } printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); flags=claim_dma_lock(); disable_dma(dev->dma); release_dma_lock(flags); return 0; /* ->Error */}/* * interrupt handler */static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs){ int csr0; struct device *dev = dev_id; struct priv *p; int bcnt = 32; if (dev == NULL) { printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq); return; } if(test_and_set_bit(0,(int *) &dev->interrupt)) { printk("ni65: oops .. interrupt while proceeding interrupt\n"); return; } p = (struct priv *) dev->priv; while(--bcnt) { csr0 = inw(PORT+L_DATAREG);#if 0 writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */#else writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */#endif if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT))) break; if(csr0 & CSR0_RINT) /* RECV-int? */ ni65_recv_intr(dev,csr0); if(csr0 & CSR0_TINT) /* XMIT-int? */ ni65_xmit_intr(dev,csr0); if(csr0 & CSR0_ERR) { struct priv *p = (struct priv *) dev->priv; if(debuglevel > 1) printk("%s: general error: %04x.\n",dev->name,csr0); if(csr0 & CSR0_BABL) p->stats.tx_errors++; if(csr0 & CSR0_MISS) { int i; for(i=0;i<RMDNUM;i++) printk("%02x ",p->rmdhead[i].u.s.status); printk("\n"); p->stats.rx_errors++; } if(csr0 & CSR0_MERR) { if(debuglevel > 1) printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0); ni65_stop_start(dev,p); } } }#ifdef RCV_PARANOIA_CHECK{ int j; for(j=0;j<RMDNUM;j++) { struct priv *p = (struct priv *) dev->priv; int i,k,num1,num2; for(i=RMDNUM-1;i>0;i--) { num2 = (p->rmdnum + i) & (RMDNUM-1); if(!(p->rmdhead[num2].u.s.status & RCV_OWN)) break; } if(i) { for(k=0;k<RMDNUM;k++) { num1 = (p->rmdnum + k) & (RMDNUM-1); if(!(p->rmdhead[num1].u.s.status & RCV_OWN)) break; } if(!k) break; if(debuglevel > 0) { char buf[256],*buf1; int k; buf1 = buf; for(k=0;k<RMDNUM;k++) { sprintf(buf1,"%02x ",(p->rmdhead[k].u.s.status)); /* & RCV_OWN) ); */ buf1 += 3; } *buf1 = 0; printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf); } p->rmdnum = num1; ni65_recv_intr(dev,csr0); if((p->rmdhead[num2].u.s.status & RCV_OWN)) break; /* ok, we are 'in sync' again */ } else break; }}#endif if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) { printk("%s: RX or TX was offline -> restart\n",dev->name); ni65_stop_start(dev,p); } else writedatareg(CSR0_INEA); dev->interrupt = 0; return;}/* * We have received an Xmit-Interrupt .. * send a new packet if necessary */static void ni65_xmit_intr(struct device *dev,int csr0){ struct priv *p = (struct priv *) dev->priv; while(p->xmit_queued) { struct tmd *tmdp = p->tmdhead + p->tmdlast; int tmdstat = tmdp->u.s.status; if(tmdstat & XMIT_OWN) break; if(tmdstat & XMIT_ERR) {#if 0 if(tmdp->status2 & XMIT_TDRMASK && debuglevel > 3) printk(KERN_ERR "%s: tdr-problems (e.g. no resistor)\n",dev->name);#endif /* checking some errors */ if(tmdp->status2 & XMIT_RTRY) p->stats.tx_aborted_errors++; if(tmdp->status2 & XMIT_LCAR) p->stats.tx_carrier_errors++; if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) { /* this stops the xmitter */ p->stats.tx_fifo_errors++; if(debuglevel > 0) printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name); if(p->features & INIT_RING_BEFORE_START) { tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END; /* test: resend this frame */ ni65_stop_start(dev,p); break; /* no more Xmit processing .. */ } else ni65_stop_start(dev,p); } if(debuglevel > 2) printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2); if(!(csr0 & CSR0_BABL)) /* don't count errors twice */ p->stats.tx_errors++; tmdp->status2 = 0; } else p->stats.tx_packets++;#ifdef XMT_VIA_SKB if(p->tmd_skb[p->tmdlast]) { dev_kfree_skb(p->tmd_skb[p->tmdlast]); p->tmd_skb[p->tmdlast] = NULL; }#endif p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1); if(p->tmdlast == p->tmdnum) p->xmit_queued = 0; } dev->tbusy = 0; mark_bh(NET_BH);}/* * We have received a packet */static void ni65_recv_intr(struct device *dev,int csr0){ struct rmd *rmdp; int rmdstat,len; int cnt=0; struct priv *p = (struct priv *) dev->priv; rmdp = p->rmdhead + p->rmdnum; while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN)) { cnt++; if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */ { if(!(rmdstat & RCV_ERR)) { if(rmdstat & RCV_START) { p->stats.rx_length_errors++; printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff); } } else { if(debuglevel > 2) printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n", dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) ); if(rmdstat & RCV_FRAM) p->stats.rx_frame_errors++; if(rmdstat & RCV_OFLO) p->stats.rx_over_errors++; if(rmdstat & RCV_CRC) p->stats.rx_crc_errors++; if(rmdstat & RCV_BUF_ERR) p->stats.rx_fifo_errors++; } if(!(csr0 & CSR0_MISS)) /* don't count errors twice */ p->stats.rx_errors++; } else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60) {#ifdef RCV_VIA_SKB struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC); if (skb) skb_reserve(skb,16);#else struct sk_buff *skb = dev_alloc_skb(len+2);#endif if(skb) { skb_reserve(skb,2); skb->dev = dev;#ifdef RCV_VIA_SKB if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) { skb_put(skb,len); eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0); } else { struct sk_buff *skb1 = p->recv_skb[p->rmdnum]; skb_put(skb,R_BUF_SIZE); p->recv_skb[p->rmdnum] = skb; rmdp->u.buffer = (u32) virt_to_bus(skb->data); skb = skb1; skb_trim(skb,len); }#else skb_put(skb,len); eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);#endif p->stats.rx_packets++; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } else { printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name); p->stats.rx_dropped++; } } else { printk(KERN_INFO "%s: received runt packet\n",dev->name); p->stats.rx_errors++; } rmdp->blen = -(R_BUF_SIZE-8); rmdp->mlen = 0; rmdp->u.s.status = RCV_OWN; /* change owner */ p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1); rmdp = p->rmdhead + p->rmdnum; }}/* * kick xmitter .. */static int ni65_send_packet(struct sk_buff *skb, struct device *dev){ struct priv *p = (struct priv *) dev->priv; if(dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 50) return 1; printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); { int i; for(i=0;i<TMDNUM;i++) printk("%02x ",p->tmdhead[i].u.s.status); printk("\n"); } ni65_lance_reinit(dev); dev->tbusy=0; dev->trans_start = jiffies; } if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); return 1; } if (test_and_set_bit(0, (void*)&p->lock)) { printk(KERN_ERR "%s: Queue was locked.\n", dev->name); return 1; } { short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; struct tmd *tmdp; long flags;#ifdef XMT_VIA_SKB if( (unsigned long) (skb->data + skb->len) > 0x1000000) {#endif memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data, (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len); dev_kfree_skb (skb); save_flags(flags); cli(); tmdp = p->tmdhead + p->tmdnum; tmdp->u.buffer = (u32) virt_to_bus(p->tmdbounce[p->tmdbouncenum]); p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1);#ifdef XMT_VIA_SKB } else { save_flags(flags); cli(); tmdp = p->tmdhead + p->tmdnum; tmdp->u.buffer = (u32) virt_to_bus(skb->data); p->tmd_skb[p->tmdnum] = skb; }#endif tmdp->blen = -len; tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END; writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */ p->xmit_queued = 1; p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1); dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0; p->lock = 0; dev->trans_start = jiffies; restore_flags(flags); } return 0;}static struct net_device_stats *ni65_get_stats(struct device *dev){#if 0 int i; struct priv *p = (struct priv *) dev->priv; for(i=0;i<RMDNUM;i++) { struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1)); printk("%02x ",rmdp->u.s.status); } printk("\n");#endif return &((struct priv *) dev->priv)->stats;}static void set_multicast_list(struct device *dev){ if(!ni65_lance_reinit(dev)) printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name); dev->tbusy = 0;}#ifdef MODULEstatic char devicename[9] = { 0, };static struct device dev_ni65 = { devicename, /* "ni6510": device name inserted by net_init.c */ 0, 0, 0, 0, 0x360, 9, /* I/O address, IRQ */ 0, 0, 0, NULL, ni65_probe };/* set: io,irq,dma or set it when calling insmod */static int irq=0;static int io=0;static int dma=0;MODULE_PARM(irq, "i");MODULE_PARM(io, "i");MODULE_PARM(dma, "i");int init_module(void){ dev_ni65.irq = irq; dev_ni65.dma = dma; dev_ni65.base_addr = io; if (register_netdev(&dev_ni65) != 0) return -EIO; return 0;}void cleanup_module(void){ struct priv *p; p = (struct priv *) dev_ni65.priv; if(!p) { printk("Ooops .. no private struct\n"); return; } disable_dma(dev_ni65.dma); free_dma(dev_ni65.dma); unregister_netdev(&dev_ni65); release_region(dev_ni65.base_addr,cards[p->cardno].total_size); ni65_free_buffer(p); dev_ni65.priv = NULL;}#endif /* MODULE *//* * END of ni65.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -