📄 eexpress.c
字号:
static unsigned short eexp_hw_lasttxstat(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; unsigned short old_rp = inw(ioaddr+READ_PTR); unsigned short old_wp = inw(ioaddr+WRITE_PTR); unsigned short tx_block = lp->tx_reap; unsigned short status; if (!test_bit(0,(void *)&dev->tbusy) && lp->tx_head==lp->tx_reap) return 0x0000; do { outw(tx_block,ioaddr+READ_PTR); status = inw(ioaddr); if (!Stat_Done(status)) { lp->tx_link = tx_block; outw(old_rp,ioaddr+READ_PTR); outw(old_wp,ioaddr+WRITE_PTR); return status; } else { lp->last_tx_restart = 0; lp->stats.collisions += Stat_NoColl(status); if (!Stat_OK(status)) { if (Stat_Abort(status)) lp->stats.tx_aborted_errors++; if (Stat_TNoCar(status) || Stat_TNoCTS(status)) lp->stats.tx_carrier_errors++; if (Stat_TNoDMA(status)) lp->stats.tx_fifo_errors++; } else lp->stats.tx_packets++; } if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) lp->tx_reap = tx_block = TX_BUF_START; else lp->tx_reap = tx_block += TX_BUF_SIZE; dev->tbusy = 0; mark_bh(NET_BH); } while (lp->tx_reap != lp->tx_head); lp->tx_link = lp->tx_tail + 0x08; outw(old_rp,ioaddr+READ_PTR); outw(old_wp,ioaddr+WRITE_PTR); return status;}/* * This should never happen. It is called when some higher * routine detects the CU has stopped, to try to restart * it from the last packet we knew we were working on, * or the idle loop if we had finished for the time. */static void eexp_hw_txrestart(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; lp->last_tx_restart = lp->tx_link; outw(lp->tx_link,ioaddr+SCB_CBL); outw(SCB_CUstart,ioaddr+SCB_CMD); outw(0,ioaddr+SCB_STATUS); outb(0,ioaddr+SIGNAL_CA); { unsigned short boguscount=50,failcount=5; while (!inw(ioaddr+SCB_STATUS)) { if (!--boguscount) { if (--failcount) { printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD)); outw(lp->tx_link,ioaddr+SCB_CBL); outw(0,ioaddr+SCB_STATUS); outw(SCB_CUstart,ioaddr+SCB_CMD); outb(0,ioaddr+SIGNAL_CA); boguscount = 100; } else { printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name); eexp_hw_init586(dev); dev->tbusy = 0; mark_bh(NET_BH); return; } } } }}/* * Writes down the list of transmit buffers into card * memory. Initial separate, repeated transmits link * them into a circular list, such that the CU can * be constantly active, and unlink them as we reap * transmitted packet buffers, so the CU doesn't loop * and endlessly transmit packets. (Try hacking the driver * to send continuous broadcast messages, say ARP requests * on a subnet with Windows boxes running on Novell and * LAN Workplace with EMM386. Amusing to watch them all die * horribly leaving the Linux boxes up!) */static void eexp_hw_txinit(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; unsigned short old_wp = inw(ioaddr+WRITE_PTR); unsigned short tx_block = TX_BUF_START; unsigned short curtbuf; for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ ) { outw(tx_block,ioaddr+WRITE_PTR); outw(0x0000,ioaddr); outw(Cmd_INT|Cmd_Xmit,ioaddr); outw(tx_block+0x08,ioaddr); outw(tx_block+0x0e,ioaddr); outw(0x0000,ioaddr); outw(0x0000,ioaddr); outw(tx_block+0x08,ioaddr); outw(0x8000,ioaddr); outw(-1,ioaddr); outw(tx_block+0x16,ioaddr); outw(0x0000,ioaddr); tx_block += TX_BUF_SIZE; } lp->tx_head = TX_BUF_START; lp->tx_reap = TX_BUF_START; lp->tx_tail = tx_block - TX_BUF_SIZE; lp->tx_link = lp->tx_tail + 0x08; lp->rx_buf_start = tx_block; outw(old_wp,ioaddr+WRITE_PTR);}/* is this a standard test pattern, or dbecker randomness? */unsigned short rx_words[] = { 0xfeed,0xf00d,0xf001,0x0505,0x2424,0x6565,0xdeaf};/* * Write the circular list of receive buffer descriptors to * card memory. Note, we no longer mark the end of the list, * so if all the buffers fill up, the 82586 will loop until * we free one. This may sound dodgy, but it works, and * it makes the error detection in the interrupt handler * a lot simpler. */static void eexp_hw_rxinit(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; unsigned short old_wp = inw(ioaddr+WRITE_PTR); unsigned short rx_block = lp->rx_buf_start; lp->num_rx_bufs = 0; lp->rx_first = rx_block; do { lp->num_rx_bufs++; outw(rx_block,ioaddr+WRITE_PTR); outw(0x0000,ioaddr); outw(0x0000,ioaddr); outw(rx_block+RX_BUF_SIZE,ioaddr); outw(rx_block+0x16,ioaddr); outsw(ioaddr, rx_words, sizeof(rx_words)>>1); outw(0x8000,ioaddr); outw(-1,ioaddr); outw(rx_block+0x20,ioaddr); outw(0x0000,ioaddr); outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr); lp->rx_last = rx_block; rx_block += RX_BUF_SIZE; } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE); outw(lp->rx_last+4,ioaddr+WRITE_PTR); outw(lp->rx_first,ioaddr); outw(old_wp,ioaddr+WRITE_PTR);}/* * Reset the 586, fill memory (including calls to * eexp_hw_[(rx)(tx)]init()) unreset, and start * the configuration sequence. We don't wait for this * to finish, but allow the interrupt handler to start * the CU and RU for us. We can't start the receive/ * transmission system up before we know that the * hardware is configured correctly */static void eexp_hw_init586(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr;#if NET_DEBUG > 6 printk("%s: eexp_hw_init586()\n", dev->name);#endif lp->started = 0; set_loopback; outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); outb_p(i586_RST,ioaddr+EEPROM_Ctrl); udelay(2000); /* delay 20ms */ { unsigned long ofs; for (ofs = 0; ofs < lp->rx_buf_end; ofs += 32) { unsigned long i; outw_p(ofs, ioaddr+SM_PTR); for (i = 0; i < 16; i++) { outw_p(0, ioaddr+SM_ADDR(i<<1)); } } } outw_p(lp->rx_buf_end,ioaddr+WRITE_PTR); start_code[28] = (dev->flags & IFF_PROMISC)?(start_code[28] | 1):(start_code[28] & ~1); lp->promisc = dev->flags & IFF_PROMISC; /* We may die here */ outsw(ioaddr, start_code, sizeof(start_code)>>1); outw(CONF_HW_ADDR,ioaddr+WRITE_PTR); outsw(ioaddr,dev->dev_addr,3); eexp_hw_txinit(dev); eexp_hw_rxinit(dev); outw(0,ioaddr+WRITE_PTR); outw(1,ioaddr); outb(0,ioaddr+EEPROM_Ctrl); outw(0,ioaddr+SCB_CMD); outb(0,ioaddr+SIGNAL_CA); { unsigned short rboguscount=50,rfailcount=5; while (outw(0,ioaddr+READ_PTR),inw(ioaddr)) { if (!--rboguscount) { printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n", dev->name); outw(0,ioaddr+SCB_CMD); outb(0,ioaddr+SIGNAL_CA); rboguscount = 100; if (!--rfailcount) { printk(KERN_WARNING "%s: i82586 not responding, giving up.\n", dev->name); return; } } } } outw(CONF_LINK,ioaddr+SCB_CBL); outw(0,ioaddr+SCB_STATUS); outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD); outb(0,ioaddr+SIGNAL_CA); { unsigned short iboguscount=50,ifailcount=5; while (!inw(ioaddr+SCB_STATUS)) { if (!--iboguscount) { if (--ifailcount) { printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n", dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD)); outw(CONF_LINK,ioaddr+SCB_CBL); outw(0,ioaddr+SCB_STATUS); outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD); outb(0,ioaddr+SIGNAL_CA); iboguscount = 100; } else { printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name); return; } } } } outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ); clear_loopback; lp->init_time = jiffies;#if NET_DEBUG > 6 printk("%s: leaving eexp_hw_init586()\n", dev->name);#endif return;}/* * completely reset the EtherExpress hardware. We will most likely get * an interrupt during this whether we want one or not. It is best, * therefore, to call this while we don't have a request_irq() on. */static void eexp_hw_ASICrst(struct device *dev){ unsigned short ioaddr = dev->base_addr; unsigned short wrval = 0x0001,succount=0,boguscount=500; outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); PRIV(dev)->started = 0; outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl); while (succount<20) { if (wrval == 0xffff) wrval = 0x0001; outw(0,ioaddr+WRITE_PTR); outw(wrval,ioaddr); outw(0,ioaddr+READ_PTR); if (wrval++ == inw(ioaddr)) succount++; else { succount = 0; if (!boguscount--) { boguscount = 500; printk("%s: Having problems resetting EtherExpress ASIC, continuing...\n", dev->name); wrval = 0x0001; outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl); } } } outb(i586_RST,ioaddr+EEPROM_Ctrl);}/* * Set or clear the multicast filter for this adaptor. * We have to do a complete 586 restart for this to take effect. * At the moment only promiscuous mode is supported. */static voideexp_set_multicast(struct device *dev){ if ((dev->flags & IFF_PROMISC) != PRIV(dev)->promisc) eexp_hw_init586(dev);}/* * MODULE stuff */#ifdef MODULE#define EEXP_MAX_CARDS 4 /* max number of cards to support */#define NAMELEN 8 /* max length of dev->name (inc null) */static char namelist[NAMELEN * EEXP_MAX_CARDS] = { 0, };static struct device dev_eexp[EEXP_MAX_CARDS] = { { NULL, /* will allocate dynamically */ 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe }, };int irq[EEXP_MAX_CARDS] = {0, };int io[EEXP_MAX_CARDS] = {0, };/* Ideally the user would give us io=, irq= for every card. If any parameters * are specified, we verify and then use them. If no parameters are given, we * autoprobe for one card only. */int init_module(void){ int this_dev, found = 0; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { struct device *dev = &dev_eexp[this_dev]; dev->name = namelist + (NAMELEN*this_dev); dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; if (io[this_dev] == 0) { if (this_dev) break; printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n"); } if (register_netdev(dev) != 0) { printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]); if (found != 0) return 0; return -ENXIO; } found++; } return 0;}void cleanup_module(void){ int this_dev; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { struct device *dev = &dev_eexp[this_dev]; if (dev->priv != NULL) { kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, EEXP_IO_EXTENT); unregister_netdev(dev); } }}#endif/* * Local Variables: * c-file-style: "linux" * tab-width: 8 * compile-command: "gcc -D__KERNEL__ -I/discs/bibble/src/linux-1.3.69/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -c 3c505.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -