📄 sk_mca.c
字号:
} dev->irq = priv->realirq; /* set up the card and LANCE */ InitBoard(dev); /* set up flags */#if (LINUX_VERSION_CODE >= 0x02032a) netif_start_queue(dev);#else dev->interrupt = 0; dev->tbusy = 0; dev->start = 0; MOD_INC_USE_COUNT;#endif return 0;}/* close driver. Shut down board and free allocated resources */static int skmca_close(struct SKMCA_NETDEV *dev){ /* turn off board */ DeinitBoard(dev); /* 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 skmca_tx(struct sk_buff *skb, struct SKMCA_NETDEV *dev){ skmca_priv *priv = (skmca_priv *) dev->priv; LANCE_TxDescr descr; unsigned int address; int tmplen, retval = 0; unsigned long flags; /* 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) { DeinitBoard(dev); InitBoard(dev); return 0; /* don't try to free the block here ;-) */ } /* is there space in the Tx queue ? If no, the upper layer gave us a packet in spite of us not being ready and is really in trouble. We'll do the dropping for him: */ if (priv->txbusy >= TXCOUNT) { priv->stat.tx_dropped++; retval = -EIO; goto tx_done; } /* get TX descriptor */ address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr)); SKMCA_FROMIO(&descr, dev->mem_start + address, sizeof(LANCE_TxDescr)); /* enter packet length as 2s complement - assure minimum length */ tmplen = skb->len; if (tmplen < 60) tmplen = 60; descr.Len = 65536 - tmplen; /* 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... */ if (tmplen > skb->len) { char *fill = "NetBSD is a nice OS too! "; unsigned int destoffs = 0, l = strlen(fill); while (destoffs < tmplen) { SKMCA_TOIO(dev->mem_start + descr.LowAddr + destoffs, fill, l); destoffs += l; } } /* do the real data copying */ SKMCA_TOIO(dev->mem_start + descr.LowAddr, skb->data, skb->len); /* hand descriptor over to LANCE - this is the first and last chunk */ descr.Flags = TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;#ifdef DEBUG PrTime(); printk("Send packet on descr %d len %d\n", priv->nexttxput, skb->len);#endif /* one more descriptor busy */ save_flags(flags); cli(); priv->nexttxput++; if (priv->nexttxput >= TXCOUNT) priv->nexttxput = 0; priv->txbusy++; /* are we saturated ? */ if (priv->txbusy >= TXCOUNT)#if (LINUX_VERSION_CODE >= 0x02032a) netif_stop_queue(dev);#else dev->tbusy = 1;#endif /* write descriptor back to RAM */ SKMCA_TOIO(dev->mem_start + address, &descr, sizeof(LANCE_TxDescr)); /* if no descriptors were active, give the LANCE a hint to read it immediately */ if (priv->txbusy == 0) SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD); restore_flags(flags); tx_done: /* When did that change exactly ? */#if LINUX_VERSION_CODE >= 0x020200 dev_kfree_skb(skb);#else dev_kfree_skb(skb, FREE_WRITE);#endif return retval;}/* return pointer to Ethernet statistics */static struct net_device_stats *skmca_stats(struct SKMCA_NETDEV *dev){ skmca_priv *priv = (skmca_priv *) dev->priv; return &(priv->stat);}/* we don't support runtime reconfiguration, since an MCA card can be unambigously identified by its POS registers. */static int skmca_config(struct SKMCA_NETDEV *dev, struct ifmap *map){ return 0;}/* switch receiver mode. We use the LANCE's multicast filter to prefilter multicast addresses. */static void skmca_set_multicast_list(struct SKMCA_NETDEV *dev){ LANCE_InitBlock block; /* first stop the LANCE... */ StopLANCE(dev); /* ...then modify the initialization block... */ SKMCA_FROMIO(&block, dev->mem_start + RAM_INITBASE, sizeof(block)); if (dev->flags & IFF_PROMISC) block.Mode |= LANCE_INIT_PROM; else block.Mode &= ~LANCE_INIT_PROM; if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */ memset(block.LAdrF, 8, 0xff); } else { /* get selected/no multicasts */ struct dev_mc_list *mptr; int code; memset(block.LAdrF, 8, 0x00); for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) { code = GetHash(mptr->dmi_addr); block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7); } } SKMCA_TOIO(dev->mem_start + RAM_INITBASE, &block, sizeof(block)); /* ...then reinit LANCE with the correct flags */ InitLANCE(dev);}/* ------------------------------------------------------------------------ * hardware check * ------------------------------------------------------------------------ */static int startslot; /* counts through slots when probing multiple devices */int skmca_probe(struct SKMCA_NETDEV *dev){ int force_detect = 0; int junior, slot, i; int base = 0, irq = 0; skmca_priv *priv; skmca_medium medium; /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) return -ENODEV; SET_MODULE_OWNER(dev); /* 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 = dofind(&junior, startslot); while (slot != -1) { /* deduce card addresses */ getaddrs(slot, junior, &base, &irq, &medium);#if LINUX_VERSION_CODE >= 0x020300 /* slot already in use ? */ if (mca_is_adapter_used(slot)) { slot = dofind(&junior, 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 = dofind(&junior, slot + 1); continue; } if ((dev->mem_start != 0) && (dev->mem_start != base)) { slot = dofind(&junior, slot + 1); continue; } } /* found something that matches */ break; } /* nothing found ? */ if (slot == -1) return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV; /* make procfs entries */ if (junior) mca_set_adapter_name(slot, "SKNET junior MC2 Ethernet Adapter"); else mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter"); mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);#if LINUX_VERSION_CODE >= 0x020200 mca_mark_as_used(slot);#endif /* announce success */ printk("%s: SKNet %s adapter found in slot %d\n", dev->name, junior ? "Junior MC2" : "MC2+", slot + 1); /* allocate structure */ priv = dev->priv = (skmca_priv *) kmalloc(sizeof(skmca_priv), GFP_KERNEL); priv->slot = slot; priv->macbase = base + 0x3fc0; priv->ioregaddr = base + 0x3ff0; priv->ctrladdr = base + 0x3ff2; priv->cmdaddr = base + 0x3ff3; 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 + 0x4000; /* autoprobe ? */ if (irq < 0) { int nirq; printk ("%s: ambigous POS bit combination, must probe for IRQ...\n", dev->name); nirq = ProbeIRQ(dev); if (nirq <= 0) printk("%s: IRQ probe failed, assuming IRQ %d", dev->name, priv->realirq = -irq); else priv->realirq = nirq; } else priv->realirq = irq; /* set methods */ dev->open = skmca_open; dev->stop = skmca_close; dev->set_config = skmca_config; dev->hard_start_xmit = skmca_tx; dev->do_ioctl = NULL; dev->get_stats = skmca_stats; dev->set_multicast_list = skmca_set_multicast_list; dev->flags |= IFF_MULTICAST; /* generic setup */ ether_setup(dev); /* copy out MAC address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1)); /* print config */ printk("%s: IRQ %d, memory %#lx-%#lx, " "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n", dev->name, priv->realirq, 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); startslot = slot + 1; return 0;}/* ------------------------------------------------------------------------ * modularization support * ------------------------------------------------------------------------ */#ifdef MODULE#define DEVMAX 5#if (LINUX_VERSION_CODE >= 0x020369)static struct SKMCA_NETDEV moddevs[DEVMAX] = { {" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}};#elsestatic char NameSpace[8 * DEVMAX];static struct SKMCA_NETDEV moddevs[DEVMAX] = { {NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},{NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}};#endifint irq = 0;int io = 0;int init_module(void){ int z, res; startslot = 0; for (z = 0; z < DEVMAX; z++) { strcpy(moddevs[z].name, " "); res = register_netdev(moddevs + z); if (res != 0) return (z > 0) ? 0 : -EIO; } return 0;}void cleanup_module(void){ struct SKMCA_NETDEV *dev; skmca_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 = (skmca_priv *) dev->priv; DeinitBoard(dev); if (dev->irq != 0) free_irq(dev->irq, dev); dev->irq = 0; unregister_netdev(dev);#if LINUX_VERSION_CODE >= 0x020200 mca_mark_as_unused(priv->slot);#endif 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 + -