ibmlana.c
来自「linux 内核源代码」· C语言 代码 · 共 1,069 行 · 第 1/2 页
C
1,069 行
priv->currtxdescr = descr; outw(CMDREG_TXP, dev->base_addr + SONIC_CMDREG);}/* ------------------------------------------------------------------------ * interrupt handler(s) * ------------------------------------------------------------------------ *//* receive buffer area exhausted */static void irqrbe_handler(struct net_device *dev){ ibmlana_priv *priv = netdev_priv(dev); /* point the SONIC back to the RRA start */ outw(priv->rrastart, dev->base_addr + SONIC_RRP); outw(priv->rrastart, dev->base_addr + SONIC_RWP);}/* receive interrupt */static void irqrx_handler(struct net_device *dev){ ibmlana_priv *priv = netdev_priv(dev); rda_t rda; u32 rdaaddr, lrdaaddr; /* loop until ... */ while (1) { /* read descriptor that was next to be filled by SONIC */ rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t)); lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t)); memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t)); /* iron out upper word halves of fields we use - SONIC will duplicate bits 0..15 to 16..31 */ rda.status &= 0xffff; rda.length &= 0xffff; rda.startlo &= 0xffff; /* stop if the SONIC still owns it, i.e. there is no data for us */ if (rda.inuse) break; /* good packet? */ else if (rda.status & RCREG_PRX) { struct sk_buff *skb; /* fetch buffer */ skb = dev_alloc_skb(rda.length + 2); if (skb == NULL) dev->stats.rx_dropped++; else { /* copy out data */ memcpy_fromio(skb_put(skb, rda.length), priv->base + rda.startlo, rda.length); /* set up skb fields */ skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; /* bookkeeping */ dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += rda.length; /* pass to the upper layers */ netif_rx(skb); } } /* otherwise check error status bits and increase statistics */ else { dev->stats.rx_errors++; if (rda.status & RCREG_FAER) dev->stats.rx_frame_errors++; if (rda.status & RCREG_CRCR) dev->stats.rx_crc_errors++; } /* descriptor processed, will become new last descriptor in queue */ rda.link = 1; rda.inuse = 1; memcpy_toio(priv->base + 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. */ memcpy_toio(priv->base + 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 net_device *dev){ ibmlana_priv *priv = netdev_priv(dev); tda_t tda; /* fetch descriptor (we forgot the size ;-) */ memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ dev->stats.tx_packets++; dev->stats.tx_bytes += tda.length; /* 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 */ netif_wake_queue(dev);}static void irqtxerr_handler(struct net_device *dev){ ibmlana_priv *priv = netdev_priv(dev); tda_t tda; /* fetch descriptor to check status */ memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ dev->stats.tx_errors++; if (tda.status & (TCREG_NCRS | TCREG_CRSL)) dev->stats.tx_carrier_errors++; if (tda.status & TCREG_EXC) dev->stats.tx_aborted_errors++; if (tda.status & TCREG_OWC) dev->stats.tx_window_errors++; if (tda.status & TCREG_FU) dev->stats.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 */ netif_wake_queue(dev);}/* general interrupt entry */static irqreturn_t irq_handler(int irq, void *device){ struct net_device *dev = (struct net_device *) device; u16 ival; /* in case we're not meant... */ if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND)) return IRQ_NONE; /* 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; } return IRQ_HANDLED;}/* ------------------------------------------------------------------------ * driver methods * ------------------------------------------------------------------------ *//* MCA info */static int ibmlana_getinfo(char *buf, int slot, void *d){ int len = 0, i; struct net_device *dev = (struct net_device *) d; ibmlana_priv *priv; /* can't say anything about an uninitialized device... */ if (dev == NULL) return len; priv = netdev_priv(dev); /* 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 net_device *dev){ int result; ibmlana_priv *priv = netdev_priv(dev); /* register resources - only necessary for IRQ */ result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); if (result != 0) { printk(KERN_ERR "%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 */ netif_start_queue(dev); return 0;}/* close driver. Shut down board and free allocated resources */static int ibmlana_close(struct net_device *dev){ /* turn off board */ /* release resources */ if (dev->irq != 0) free_irq(dev->irq, dev); dev->irq = 0; return 0;}/* transmit a block. */static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev){ ibmlana_priv *priv = netdev_priv(dev); int retval = 0, tmplen, addr; unsigned long flags; tda_t tda; int baddr; /* 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; dev->stats.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); memcpy_toio(priv->base + 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) { memcpy_toio(priv->base + baddr + destoffs, fill, l); destoffs += l; } } /* set up the new frame descriptor */ addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t)); memcpy_fromio(&tda, priv->base + addr, sizeof(tda_t)); tda.length = tda.fraglength = tmplen; memcpy_toio(priv->base + addr, &tda, sizeof(tda_t)); /* if there were no active descriptors, trigger the SONIC */ spin_lock_irqsave(&priv->lock, flags); priv->txusedcnt++; priv->txused[priv->nexttxdescr] = 1; /* are all transmission slots used up ? */ if (priv->txusedcnt >= TXBUFCNT) netif_stop_queue(dev); if (priv->txusedcnt == 1) StartTx(dev, priv->nexttxdescr); priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT; spin_unlock_irqrestore(&priv->lock, flags);tx_done: dev_kfree_skb(skb); return retval;}/* switch receiver mode. */static void ibmlana_set_multicast_list(struct net_device *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 */static int ibmlana_probe(struct net_device *dev){ int slot, z; int base = 0, irq = 0, iobase = 0, memlen = 0; ibmlana_priv *priv; ibmlana_medium medium; DECLARE_MAC_BUF(mac); /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) return -ENODEV; base = dev->mem_start; irq = dev->irq; for (slot = startslot; (slot = mca_find_adapter(IBM_LANA_ID, slot)) != -1; slot++) { /* deduce card addresses */ getaddrs(slot, &base, &memlen, &iobase, &irq, &medium); /* slot already in use ? */ if (mca_is_adapter_used(slot)) continue; /* were we looking for something different ? */ if (dev->irq && dev->irq != irq) continue; if (dev->mem_start && dev->mem_start != base) continue; /* found something that matches */ break; } /* nothing found ? */ if (slot == -1) return (base != 0 || irq != 0) ? -ENXIO : -ENODEV; /* announce success */ printk(KERN_INFO "%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, DRV_NAME)) { printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase); startslot = slot + 1; return -EBUSY; } priv = netdev_priv(dev); priv->slot = slot; priv->realirq = irq; priv->medium = medium; spin_lock_init(&priv->lock); /* 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; priv->base = ioremap(base, memlen); if (!priv->base) { printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME); startslot = slot + 1; release_region(iobase, IBM_LANA_IORANGE); return -EBUSY; } /* make procfs entries */ mca_set_adapter_name(slot, "IBM LAN Adapter/A"); mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev); mca_mark_as_used(slot); /* set methods */ dev->open = ibmlana_open; dev->stop = ibmlana_close; dev->hard_start_xmit = ibmlana_tx; dev->do_ioctl = NULL; dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; /* 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(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, " "MAC address %s.\n", dev->name, priv->realirq, dev->base_addr, dev->mem_start, dev->mem_end - 1, print_mac(mac, dev->dev_addr)); printk(KERN_INFO "%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 net_device *moddevs[DEVMAX];static int irq;static int io;module_param(irq, int, 0);module_param(io, int, 0);MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");MODULE_LICENSE("GPL");int init_module(void){ int z; startslot = 0; for (z = 0; z < DEVMAX; z++) { struct net_device *dev = alloc_etherdev(sizeof(ibmlana_priv)); if (!dev) break; dev->irq = irq; dev->base_addr = io; if (ibmlana_probe(dev)) { free_netdev(dev); break; } if (register_netdev(dev)) { ibmlana_priv *priv = netdev_priv(dev); release_region(dev->base_addr, IBM_LANA_IORANGE); mca_mark_as_unused(priv->slot); mca_set_adapter_name(priv->slot, ""); mca_set_adapter_procfn(priv->slot, NULL, NULL); iounmap(priv->base); free_netdev(dev); break; } moddevs[z] = dev; } return (z > 0) ? 0 : -EIO;}void cleanup_module(void){ int z; for (z = 0; z < DEVMAX; z++) { struct net_device *dev = moddevs[z]; if (dev) { ibmlana_priv *priv = netdev_priv(dev); unregister_netdev(dev); /*DeinitBoard(dev); */ release_region(dev->base_addr, IBM_LANA_IORANGE); mca_mark_as_unused(priv->slot); mca_set_adapter_name(priv->slot, ""); mca_set_adapter_procfn(priv->slot, NULL, NULL); iounmap(priv->base); free_netdev(dev); } }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?