📄 ne2.c
字号:
ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; ei_status.word16 = (2 == 2); ei_status.rx_start_page = start_page + TX_PAGES;#ifdef PACKETBUF_MEMSIZE /* Allow the packet buffer size to be overridden by know-it-alls. */ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;#endif ei_status.reset_8390 = &ne_reset_8390; ei_status.block_input = &ne_block_input; ei_status.block_output = &ne_block_output; ei_status.get_8390_hdr = &ne_get_8390_hdr; ei_status.priv = slot; dev->open = &ne_open; dev->stop = &ne_close; NS8390_init(dev, 0); return 0;}static int ne_open(struct device *dev){ ei_open(dev); MOD_INC_USE_COUNT; return 0;}static int ne_close(struct device *dev){ if (ei_debug > 1) printk("%s: Shutting down ethercard.\n", dev->name); ei_close(dev); MOD_DEC_USE_COUNT; return 0;}/* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */static void ne_reset_8390(struct device *dev){ unsigned long reset_start_time = jiffies; if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies); /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); ei_status.txing = 0; ei_status.dmaing = 0; /* This check _should_not_ be necessary, omit eventually. */ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { printk("%s: ne_reset_8390() did not complete.\n", dev->name); break; } outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */}/* Grab the 8390 specific header. Similar to the block_input routine, but we don't need to be concerned with ring wrap as the header will be at the start of a page, so we optimize accordingly. */static void ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page){ int nic_base = dev->base_addr; /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne_get_8390_hdr " "[DMAstat:%d][irqlock:%d][intr:%ld].\n", dev->name, ei_status.dmaing, ei_status.irqlock, dev->interrupt); return; } ei_status.dmaing |= 0x01; outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); outb_p(0, nic_base + EN0_RCNTHI); outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ outb_p(ring_page, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); if (ei_status.word16) insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); else insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01;}/* Block input and output, similar to the Crynwr packet driver. If you are porting to a new ethercard, look at the packet driver source for hints. The NEx000 doesn't share the on-board packet memory -- you have to put the packet out through the "remote DMA" dataport using outb. */static void ne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset){#ifdef NE_SANITY_CHECK int xfer_count = count;#endif int nic_base = dev->base_addr; char *buf = skb->data; /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne_block_input " "[DMAstat:%d][irqlock:%d][intr:%ld].\n", dev->name, ei_status.dmaing, ei_status.irqlock, dev->interrupt); return; } ei_status.dmaing |= 0x01; outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); outb_p(count & 0xff, nic_base + EN0_RCNTLO); outb_p(count >> 8, nic_base + EN0_RCNTHI); outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { insw(NE_BASE + NE_DATAPORT,buf,count>>1); if (count & 0x01) { buf[count-1] = inb(NE_BASE + NE_DATAPORT);#ifdef NE_SANITY_CHECK xfer_count++;#endif } } else { insb(NE_BASE + NE_DATAPORT, buf, count); }#ifdef NE_SANITY_CHECK /* This was for the ALPHA version only, but enough people have been encountering problems so it is still here. If you see this message you either 1) have a slightly incompatible clone or 2) have noise/speed problems with your bus. */ if (ei_debug > 1) { /* DMA termination address check... */ int addr, tries = 20; do { /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken for Rx on some cards! */ int high = inb_p(nic_base + EN0_RSARHI); int low = inb_p(nic_base + EN0_RSARLO); addr = (high << 8) + low; if (((ring_offset + xfer_count) & 0xff) == low) break; } while (--tries > 0); if (tries <= 0) printk("%s: RX transfer address mismatch," "%#4.4x (expected) vs. %#4.4x (actual).\n", dev->name, ring_offset + xfer_count, addr); }#endif outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01;}static void ne_block_output(struct device *dev, int count, const unsigned char *buf, const int start_page){ int nic_base = NE_BASE; unsigned long dma_start;#ifdef NE_SANITY_CHECK int retries = 0;#endif /* Round the count up for word writes. Do we need to do this? What effect will an odd byte count have on the 8390? I should check someday. */ if (ei_status.word16 && (count & 0x01)) count++; /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne_block_output." "[DMAstat:%d][irqlock:%d][intr:%ld]\n", dev->name, ei_status.dmaing, ei_status.irqlock, dev->interrupt); return; } ei_status.dmaing |= 0x01; /* We should already be in page 0, but to be safe... */ outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);#ifdef NE_SANITY_CHECKretry:#endif#ifdef NE8390_RW_BUGFIX /* Handle the read-before-write bug the same way as the Crynwr packet driver -- the NatSemi method doesn't work. Actually this doesn't always work either, but if you have problems with your NEx000 this is better than nothing! */ outb_p(0x42, nic_base + EN0_RCNTLO); outb_p(0x00, nic_base + EN0_RCNTHI); outb_p(0x42, nic_base + EN0_RSARLO); outb_p(0x00, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); /* Make certain that the dummy read has occurred. */ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO;#endif outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Now the normal output. */ outb_p(count & 0xff, nic_base + EN0_RCNTLO); outb_p(count >> 8, nic_base + EN0_RCNTHI); outb_p(0x00, nic_base + EN0_RSARLO); outb_p(start_page, nic_base + EN0_RSARHI); outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { outsw(NE_BASE + NE_DATAPORT, buf, count>>1); } else { outsb(NE_BASE + NE_DATAPORT, buf, count); } dma_start = jiffies;#ifdef NE_SANITY_CHECK /* This was for the ALPHA version only, but enough people have been encountering problems so it is still here. */ if (ei_debug > 1) { /* DMA termination address check... */ int addr, tries = 20; do { int high = inb_p(nic_base + EN0_RSARHI); int low = inb_p(nic_base + EN0_RSARLO); addr = (high << 8) + low; if ((start_page << 8) + count == addr) break; } while (--tries > 0); if (tries <= 0) { printk("%s: Tx packet transfer address mismatch," "%#4.4x (expected) vs. %#4.4x (actual).\n", dev->name, (start_page << 8) + count, addr); if (retries++ == 0) goto retry; } }#endif while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ printk("%s: timeout waiting for Tx RDC.\n", dev->name); ne_reset_8390(dev); NS8390_init(dev,1); break; } outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; return;}#ifdef MODULE#define MAX_NE_CARDS 4 /* Max number of NE cards per module */#define NAMELEN 8 /* # of chars for storing dev->name */static char namelist[NAMELEN * MAX_NE_CARDS] = { 0, };static struct device dev_ne[MAX_NE_CARDS] = { { NULL, /* assign a chunk of namelist[] below */ 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL },};static int io[MAX_NE_CARDS] = { 0, };static int irq[MAX_NE_CARDS] = { 0, };static int bad[MAX_NE_CARDS] = { 0, }; /* 0xbad = bad sig or no reset ack */#ifdef MODULE_PARMMODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");#endif/* Module code fixed by David Weinehall */int init_module(void){ int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { struct device *dev = &dev_ne[this_dev]; dev->name = namelist+(NAMELEN*this_dev); dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; dev->init = ne2_probe; if (register_netdev(dev) != 0) { if (found != 0) return 0; /* Got at least one. */ printk(KERN_WARNING "ne2.c: No NE/2 card found.\n"); return -ENXIO; } found++; } return 0;}void cleanup_module(void){ int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { struct device *dev = &dev_ne[this_dev]; if (dev->priv != NULL) { mca_mark_as_unused(ei_status.priv); mca_set_adapter_procfn( ei_status.priv, NULL, NULL); kfree(dev->priv); free_irq(dev->irq, dev); release_region(dev->base_addr, NE_IO_EXTENT); unregister_netdev(dev); } }}#endif /* MODULE *//* * Local variables: * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne2.c" * version-control: t * kept-new-versions: 5 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -