📄 ibmlana.c
字号:
priv->stat.rx_bytes += rda.length;#endif /* pass to the upper layers */ netif_rx(skb); } } /* otherwise check error status bits and increase statistics */ else { priv->stat.rx_errors++; if (rda.status & RCREG_FAER) priv->stat.rx_frame_errors++; if (rda.status & RCREG_CRCR) priv->stat.rx_crc_errors++; } /* descriptor processed, will become new last descriptor in queue */ rda.link = 1; rda.inuse = 1; IBMLANA_TOIO(dev->mem_start + rdaaddr, &rda, sizeof(rda_t)); /* set up link and EOL = 0 in currently last descriptor. Only write the link field since the SONIC may currently already access the other fields. */ IBMLANA_TOIO(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4); /* advance indices */ priv->lastrxdescr = priv->nextrxdescr; if ((++priv->nextrxdescr) >= priv->rxbufcnt) priv->nextrxdescr = 0; }}/* transmit interrupt */static void irqtx_handler(struct IBMLANA_NETDEV *dev){ ibmlana_priv *priv = (ibmlana_priv *) dev->priv; tda_t tda; /* fetch descriptor (we forgot the size ;-) */ IBMLANA_FROMIO(&tda, dev->mem_start + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ priv->stat.tx_packets++;#if (LINUX_VERSION_CODE >= 0x020119) priv->stat.tx_bytes += tda.length;#endif /* update our pointers */ priv->txused[priv->currtxdescr] = 0; priv->txusedcnt--; /* if there are more descriptors present in RAM, start them */ if (priv->txusedcnt > 0) StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT); /* tell the upper layer we can go on transmitting */#if LINUX_VERSION_CODE >= 0x02032a netif_wake_queue(dev);#else dev->tbusy = 0; mark_bh(NET_BH);#endif}static void irqtxerr_handler(struct IBMLANA_NETDEV *dev){ ibmlana_priv *priv = (ibmlana_priv *) dev->priv; tda_t tda; /* fetch descriptor to check status */ IBMLANA_FROMIO(&tda, dev->mem_start + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ priv->stat.tx_errors++; if (tda.status & (TCREG_NCRS | TCREG_CRSL)) priv->stat.tx_carrier_errors++; if (tda.status & TCREG_EXC) priv->stat.tx_aborted_errors++; if (tda.status & TCREG_OWC) priv->stat.tx_window_errors++; if (tda.status & TCREG_FU) priv->stat.tx_fifo_errors++; /* update our pointers */ priv->txused[priv->currtxdescr] = 0; priv->txusedcnt--; /* if there are more descriptors present in RAM, start them */ if (priv->txusedcnt > 0) StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT); /* tell the upper layer we can go on transmitting */#if LINUX_VERSION_CODE >= 0x02032a netif_wake_queue(dev);#else dev->tbusy = 0; mark_bh(NET_BH);#endif}/* general interrupt entry */static void irq_handler(int irq, void *device, struct pt_regs *regs){ struct IBMLANA_NETDEV *dev = (struct IBMLANA_NETDEV *) device; u16 ival; /* in case we're not meant... */ if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND)) return;#if (LINUX_VERSION_CODE >= 0x02032a)#if 0 set_bit(LINK_STATE_RXSEM, &dev->state);#endif#else dev->interrupt = 1;#endif /* loop through the interrupt bits until everything is clear */ while (1) { ival = inw(dev->base_addr + SONIC_ISREG); if (ival & ISREG_RBE) { irqrbe_handler(dev); outw(ISREG_RBE, dev->base_addr + SONIC_ISREG); } if (ival & ISREG_PKTRX) { irqrx_handler(dev); outw(ISREG_PKTRX, dev->base_addr + SONIC_ISREG); } if (ival & ISREG_TXDN) { irqtx_handler(dev); outw(ISREG_TXDN, dev->base_addr + SONIC_ISREG); } if (ival & ISREG_TXER) { irqtxerr_handler(dev); outw(ISREG_TXER, dev->base_addr + SONIC_ISREG); } break; }#if (LINUX_VERSION_CODE >= 0x02032a)#if 0 clear_bit(LINK_STATE_RXSEM, &dev->state);#endif#else dev->interrupt = 0;#endif}/* ------------------------------------------------------------------------ * driver methods * ------------------------------------------------------------------------ *//* MCA info */static int ibmlana_getinfo(char *buf, int slot, void *d){ int len = 0, i; struct IBMLANA_NETDEV *dev = (struct IBMLANA_NETDEV *) d; ibmlana_priv *priv; /* can't say anything about an uninitialized device... */ if (dev == NULL) return len; if (dev->priv == NULL) return len; priv = (ibmlana_priv *) dev->priv; /* print info */ len += sprintf(buf + len, "IRQ: %d\n", priv->realirq); len += sprintf(buf + len, "I/O: %#lx\n", dev->base_addr); len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, dev->mem_end - 1); len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]); len += sprintf(buf + len, "Device: %s\n", dev->name); len += sprintf(buf + len, "MAC address:"); for (i = 0; i < 6; i++) len += sprintf(buf + len, " %02x", dev->dev_addr[i]); buf[len++] = '\n'; buf[len] = 0; return len;}/* open driver. Means also initialization and start of LANCE */static int ibmlana_open(struct IBMLANA_NETDEV *dev){ int result; ibmlana_priv *priv = (ibmlana_priv *) dev->priv; /* register resources - only necessary for IRQ */ result = request_irq(priv->realirq, irq_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); if (result != 0) { printk("%s: failed to register irq %d\n", dev->name, dev->irq); return result; } dev->irq = priv->realirq; /* set up the card and SONIC */ InitBoard(dev); /* initialize operational flags */#if (LINUX_VERSION_CODE >= 0x02032a) netif_start_queue(dev);#else dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; MOD_INC_USE_COUNT;#endif return 0;}/* close driver. Shut down board and free allocated resources */static int ibmlana_close(struct IBMLANA_NETDEV *dev){ /* turn off board */ /* release resources */ if (dev->irq != 0) free_irq(dev->irq, dev); dev->irq = 0;#if (LINUX_VERSION_CODE < 0x02032a) MOD_DEC_USE_COUNT;#endif return 0;}/* transmit a block. */static int ibmlana_tx(struct sk_buff *skb, struct IBMLANA_NETDEV *dev){ ibmlana_priv *priv = (ibmlana_priv *) dev->priv; int retval = 0, tmplen, addr; unsigned long flags; tda_t tda; int baddr; /* if we get called with a NULL descriptor, the Ethernet layer thinks our card is stuck an we should reset it. We'll do this completely: */ if (skb == NULL) { printk("%s: Resetting SONIC\n", dev->name); StopSONIC(dev); InitBoard(dev); return 0; /* don't try to free the block here ;-) */ } /* find out if there are free slots for a frame to transmit. If not, the upper layer is in deep desperation and we simply ignore the frame. */ if (priv->txusedcnt >= TXBUFCNT) { retval = -EIO; priv->stat.tx_dropped++; goto tx_done; } /* copy the frame data into the next free transmit buffer - fillup missing */ tmplen = skb->len; if (tmplen < 60) tmplen = 60; baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE); IBMLANA_TOIO(dev->mem_start + baddr, skb->data, skb->len); /* copy filler into RAM - in case we're filling up... we're filling a bit more than necessary, but that doesn't harm since the buffer is far larger... Sorry Linus for the filler string but I couldn't resist ;-) */ if (tmplen > skb->len) { char *fill = "NetBSD is a nice OS too! "; unsigned int destoffs = skb->len, l = strlen(fill); while (destoffs < tmplen) { IBMLANA_TOIO(dev->mem_start + baddr + destoffs, fill, l); destoffs += l; } } /* set up the new frame descriptor */ addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t)); IBMLANA_FROMIO(&tda, dev->mem_start + addr, sizeof(tda_t)); tda.length = tda.fraglength = tmplen; IBMLANA_TOIO(dev->mem_start + addr, &tda, sizeof(tda_t)); /* if there were no active descriptors, trigger the SONIC */ save_flags(flags); cli(); priv->txusedcnt++; priv->txused[priv->nexttxdescr] = 1; /* are all transmission slots used up ? */ if (priv->txusedcnt >= TXBUFCNT)#if (LINUX_VERSION_CODE >= 0x02032a) netif_stop_queue(dev);#else dev->tbusy = 1;#endif if (priv->txusedcnt == 1) StartTx(dev, priv->nexttxdescr); priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT; restore_flags(flags); tx_done: /* When did that change exactly ? */#if (LINUX_VERSION_CODE >= 0x20200) dev_kfree_skb(skb);#else dev_kfree_skb(skb, FREE_WRITE);#endif return retval;}/* return pointer to Ethernet statistics */static struct net_device_stats *ibmlana_stats(struct IBMLANA_NETDEV *dev){ ibmlana_priv *priv = (ibmlana_priv *) dev->priv; return &(priv->stat);}/* we don't support runtime reconfiguration, since am MCA card can be unambigously identified by its POS registers. */static int ibmlana_config(struct IBMLANA_NETDEV *dev, struct ifmap *map){ return 0;}/* switch receiver mode. */static void ibmlana_set_multicast_list(struct IBMLANA_NETDEV *dev){ /* first stop the SONIC... */ StopSONIC(dev); /* ...then reinit it with the new flags */ InitBoard(dev);}/* ------------------------------------------------------------------------ * hardware check * ------------------------------------------------------------------------ */static int startslot; /* counts through slots when probing multiple devices */int ibmlana_probe(struct IBMLANA_NETDEV *dev){ int force_detect = 0; int slot, z; int base = 0, irq = 0, iobase = 0, memlen = 0; ibmlana_priv *priv; ibmlana_medium medium;#if (LINUX_VERSION_CODE >= 0x02032a) SET_MODULE_OWNER(dev);#endif /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) return -ENODEV; /* start address of 1 --> forced detection */ if (dev->mem_start == 1) force_detect = 1; /* search through slots */ if (dev != NULL) { base = dev->mem_start; irq = dev->irq; } slot = mca_find_adapter(IBM_LANA_ID, startslot); while (slot != -1) { /* deduce card addresses */ getaddrs(slot, &base, &memlen, &iobase, &irq, &medium);#if (LINUX_VERSION_CODE >= 0x20300) /* slot already in use ? */ if (mca_is_adapter_used(slot)) { slot = mca_find_adapter(IBM_LANA_ID, slot + 1); continue; }#endif /* were we looking for something different ? */ if ((dev->irq != 0) || (dev->mem_start != 0)) { if ((dev->irq != 0) && (dev->irq != irq)) { slot = mca_find_adapter(IBM_LANA_ID, slot + 1); continue; } if ((dev->mem_start != 0) && (dev->mem_start != base)) { slot = mca_find_adapter(IBM_LANA_ID, slot + 1); continue; } } /* found something that matches */ break; } /* nothing found ? */ if (slot == -1) return ((base != 0) || (irq != 0)) ? -ENXIO : -ENODEV; /* announce success */ printk("%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1); /* try to obtain I/O range */ if (!request_region(iobase, IBM_LANA_IORANGE, dev->name)) { printk("%s: cannot allocate I/O range at %#x!\n", dev->name, iobase); startslot = slot + 1; return -EBUSY; } /* make procfs entries */ mca_set_adapter_name(slot, "IBM LAN Adapter/A"); mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev);#if (LINUX_VERSION_CODE >= 0x20200) mca_mark_as_used(slot);#endif /* allocate structure */ priv = dev->priv = (ibmlana_priv *) kmalloc(sizeof(ibmlana_priv), GFP_KERNEL); if (!priv) { release_region(iobase, IBM_LANA_IORANGE); return -ENOMEM; } priv->slot = slot; priv->realirq = irq; priv->medium = medium; memset(&(priv->stat), 0, sizeof(struct net_device_stats)); /* set base + irq for this device (irq not allocated so far) */ dev->irq = 0; dev->mem_start = base; dev->mem_end = base + memlen; dev->base_addr = iobase; /* set methods */ dev->open = ibmlana_open; dev->stop = ibmlana_close; dev->set_config = ibmlana_config; dev->hard_start_xmit = ibmlana_tx; dev->do_ioctl = NULL; dev->get_stats = ibmlana_stats; dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; /* generic setup */ ether_setup(dev); /* copy out MAC address */ for (z = 0; z < sizeof(dev->dev_addr); z++) dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z); /* print config */ printk("%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, " "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n", dev->name, priv->realirq, dev->base_addr, dev->mem_start, dev->mem_end - 1, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]); /* reset board */ ResetBoard(dev); /* next probe will start at next slot */ startslot = slot + 1; return 0;}/* ------------------------------------------------------------------------ * modularization support * ------------------------------------------------------------------------ */#ifdef MODULE#define DEVMAX 5static struct IBMLANA_NETDEV moddevs[DEVMAX];static int irq;static int io;MODULE_PARM(irq, "i");MODULE_PARM(io, "i");int init_module(void){ int z, res; startslot = 0; for (z = 0; z < DEVMAX; z++) { moddevs[z].init = ibmlana_probe; moddevs[z].irq = irq; moddevs[z].base_addr = io; res = register_netdev(moddevs + z); if (res != 0) return (z > 0) ? 0 : -EIO; } return 0;}void cleanup_module(void){ struct IBMLANA_NETDEV *dev; ibmlana_priv *priv; int z; if (MOD_IN_USE) { printk("cannot unload, module in use\n"); return; } for (z = 0; z < DEVMAX; z++) { dev = moddevs + z; if (dev->priv != NULL) { priv = (ibmlana_priv *) dev->priv; /*DeinitBoard(dev); */ if (dev->irq != 0) free_irq(dev->irq, dev); dev->irq = 0; release_region(dev->base_addr, IBM_LANA_IORANGE); unregister_netdev(dev);#if (LINUX_VERSION_CODE >= 0x20200) mca_mark_as_unused(priv->slot);#endif mca_set_adapter_name(priv->slot, ""); mca_set_adapter_procfn(priv->slot, NULL, NULL); kfree(dev->priv); dev->priv = NULL; } }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -