📄 eexpress.c
字号:
outb(wval,ioaddr+EEPROM_Ctrl); outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl); eeprom_delay(); outb(wval,ioaddr+EEPROM_Ctrl); eeprom_delay(); } wval &= ~EC_Wr; outb(wval,ioaddr+EEPROM_Ctrl); for (i=0x8000 ; i ; i>>=1 ) { outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl); eeprom_delay(); if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd) rval |= i; outb(wval,ioaddr+EEPROM_Ctrl); eeprom_delay(); } wval &= ~EC_CS; outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl); eeprom_delay(); outb(wval,ioaddr+EEPROM_Ctrl); eeprom_delay(); return rval;}/* * Reap tx buffers and return last transmit status. * if ==0 then either: * a) we're not transmitting anything, so why are we here? * b) we've died. * otherwise, Stat_Busy(return) means we've still got some packets * to transmit, Stat_Done(return) means our buffers should be empty * again */static unsigned short eexp_hw_lasttxstat(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short tx_block = lp->tx_reap; unsigned short status; if ((!dev->tbusy) && lp->tx_head==lp->tx_reap) return 0x0000; do { outw(tx_block & ~31, dev->base_addr + SM_PTR); status = inw(dev->base_addr + SHADOW(tx_block)); if (!Stat_Done(status)) { lp->tx_link = tx_block; return status; } else { lp->last_tx_restart = 0; lp->stats.collisions += Stat_NoColl(status); if (!Stat_OK(status)) { char *whatsup = NULL; lp->stats.tx_errors++; if (Stat_Abort(status)) lp->stats.tx_aborted_errors++; if (Stat_TNoCar(status)) { whatsup = "aborted, no carrier"; lp->stats.tx_carrier_errors++; } if (Stat_TNoCTS(status)) { whatsup = "aborted, lost CTS"; lp->stats.tx_carrier_errors++; } if (Stat_TNoDMA(status)) { whatsup = "FIFO underran"; lp->stats.tx_fifo_errors++; } if (Stat_TXColl(status)) { whatsup = "aborted, too many collisions"; lp->stats.tx_aborted_errors++; } if (whatsup) printk(KERN_INFO "%s: transmit %s\n", dev->name, whatsup); } 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; return status;}/* * This should never happen. It is called when some higher routine detects * that 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; scb_wrcbl(dev, lp->tx_link); scb_command(dev, SCB_CUstart); outb(0,ioaddr+SIGNAL_CA); { unsigned short boguscount=50,failcount=5; while (!scb_status(dev)) { if (!--boguscount) { if (--failcount) { printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev)); scb_wrcbl(dev, lp->tx_link); scb_command(dev, SCB_CUstart); 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. Each * entry consists of an 82586 transmit command, followed by a jump * pointing to itself. When we want to transmit a packet, we write * the data into the appropriate transmit buffer and then modify the * preceding jump to point at the new transmit command. This means that * the 586 command unit is continuously active. */static void eexp_hw_txinit(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short tx_block = TX_BUF_START; unsigned short curtbuf; unsigned short ioaddr = dev->base_addr; for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ ) { outw(tx_block, ioaddr + WRITE_PTR); outw(0x0000, ioaddr + DATAPORT); outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT); outw(tx_block+0x08, ioaddr + DATAPORT); outw(tx_block+0x0e, ioaddr + DATAPORT); outw(0x0000, ioaddr + DATAPORT); outw(0x0000, ioaddr + DATAPORT); outw(tx_block+0x08, ioaddr + DATAPORT); outw(0x8000, ioaddr + DATAPORT); outw(-1, ioaddr + DATAPORT); outw(tx_block+0x16, ioaddr + DATAPORT); outw(0x0000, ioaddr + DATAPORT); 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;}/* * Write the circular list of receive buffer descriptors to card memory. * The end of the list isn't marked, which means that the 82586 receive * unit will loop until buffers become available (this avoids it giving us * "out of resources" messages). */static void eexp_hw_rxinit(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short rx_block = lp->rx_buf_start; unsigned short ioaddr = dev->base_addr; lp->num_rx_bufs = 0; lp->rx_first = lp->rx_ptr = rx_block; do { lp->num_rx_bufs++; outw(rx_block, ioaddr + WRITE_PTR); outw(0, ioaddr + DATAPORT); outw(0, ioaddr+DATAPORT); outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT); outw(0xffff, ioaddr+DATAPORT); outw(0x0000, ioaddr+DATAPORT); outw(0xdead, ioaddr+DATAPORT); outw(0xdead, ioaddr+DATAPORT); outw(0xdead, ioaddr+DATAPORT); outw(0xdead, ioaddr+DATAPORT); outw(0xdead, ioaddr+DATAPORT); outw(0xdead, ioaddr+DATAPORT); outw(0x0000, ioaddr+DATAPORT); outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT); outw(rx_block + 0x20, ioaddr+DATAPORT); outw(0, ioaddr+DATAPORT); outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT); lp->rx_last = rx_block; rx_block += RX_BUF_SIZE; } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE); /* Make first Rx frame descriptor point to first Rx buffer descriptor */ outw(lp->rx_first + 6, ioaddr+WRITE_PTR); outw(lp->rx_first + 0x16, ioaddr+DATAPORT); /* Close Rx frame descriptor ring */ outw(lp->rx_last + 4, ioaddr+WRITE_PTR); outw(lp->rx_first, ioaddr+DATAPORT); /* Close Rx buffer descriptor ring */ outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR); outw(lp->rx_first + 0x16, ioaddr+DATAPORT); }/* * Un-reset the 586, 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; int i;#if NET_DEBUG > 6 printk("%s: eexp_hw_init586()\n", dev->name);#endif lp->started = 0; set_loopback(dev); outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); /* Download the startup code */ outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR); outw(lp->width?0x0001:0x0000, ioaddr + 0x8006); outw(0x0000, ioaddr + 0x8008); outw(0x0000, ioaddr + 0x800a); outw(0x0000, ioaddr + 0x800c); outw(0x0000, ioaddr + 0x800e); for (i = 0; i < (sizeof(start_code)); i+=32) { int j; outw(i, ioaddr + SM_PTR); for (j = 0; j < 16; j+=2) outw(start_code[(i+j)/2], ioaddr+0x4000+j); for (j = 0; j < 16; j+=2) outw(start_code[(i+j+16)/2], ioaddr+0x8000+j); } /* Do we want promiscuous mode or multicast? */ outw(CONF_PROMISC & ~31, ioaddr+SM_PTR); i = inw(ioaddr+SHADOW(CONF_PROMISC)); outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1), ioaddr+SHADOW(CONF_PROMISC)); lp->was_promisc = dev->flags & IFF_PROMISC;#if 0 eexp_setup_filter(dev);#endif /* Write our hardware address */ outw(CONF_HWADDR & ~31, ioaddr+SM_PTR); outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR)); outw(((unsigned short *)dev->dev_addr)[1], ioaddr+SHADOW(CONF_HWADDR+2)); outw(((unsigned short *)dev->dev_addr)[2], ioaddr+SHADOW(CONF_HWADDR+4)); eexp_hw_txinit(dev); eexp_hw_rxinit(dev); outb(0,ioaddr+EEPROM_Ctrl); mdelay(5); scb_command(dev, 0xf000); outb(0,ioaddr+SIGNAL_CA); outw(0, ioaddr+SM_PTR); { unsigned short rboguscount=50,rfailcount=5; while (inw(ioaddr+0x4000)) { if (!--rboguscount) { printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n", dev->name); scb_command(dev, 0); outb(0,ioaddr+SIGNAL_CA); rboguscount = 100; if (!--rfailcount) { printk(KERN_WARNING "%s: i82586 not responding, giving up.\n", dev->name); return; } } } } scb_wrcbl(dev, CONF_LINK); scb_command(dev, 0xf000|SCB_CUstart); outb(0,ioaddr+SIGNAL_CA); { unsigned short iboguscount=50,ifailcount=5; while (!scb_status(dev)) { if (!--iboguscount) { if (--ifailcount) { printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev)); scb_wrcbl(dev, CONF_LINK); scb_command(dev, 0xf000|SCB_CUstart); outb(0,ioaddr+SIGNAL_CA); iboguscount = 100; } else { printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name); return; } } } } clear_loopback(dev); outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ); lp->init_time = jiffies;#if NET_DEBUG > 6 printk("%s: leaving eexp_hw_init586()\n", dev->name);#endif return;}static void eexp_setup_filter(struct device *dev){ struct dev_mc_list *dmi = dev->mc_list; unsigned short ioaddr = dev->base_addr; int count = dev->mc_count; int i; if (count > 8) { printk(KERN_INFO "%s: too many multicast addresses (%d)\n", dev->name, count); count = 8; } outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR); outw(count, ioaddr+SHADOW(CONF_NR_MULTICAST)); for (i = 0; i < count; i++) { unsigned short *data = (unsigned short *)dmi->dmi_addr; if (!dmi) { printk(KERN_INFO "%s: too few multicast addresses\n", dev->name); break; } if (dmi->dmi_addrlen != ETH_ALEN) { printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name); continue; } outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR); outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i))); outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR); outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2)); outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR); outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4)); }}/* * Set or clear the multicast filter for this adaptor. */static voideexp_set_multicast(struct device *dev){ unsigned short ioaddr = dev->base_addr; struct net_local *lp = (struct net_local *)dev->priv; int kick = 0, i; if ((dev->flags & IFF_PROMISC) != lp->was_promisc) { outw(CONF_PROMISC & ~31, ioaddr+SM_PTR); i = inw(ioaddr+SHADOW(CONF_PROMISC)); outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1), ioaddr+SHADOW(CONF_PROMISC)); lp->was_promisc = dev->flags & IFF_PROMISC; kick = 1; } if (!(dev->flags & IFF_PROMISC)) { eexp_setup_filter(dev); if (lp->old_mc_count != dev->mc_count) { kick = 1; lp->old_mc_count = dev->mc_count; } } if (kick) { unsigned long oj; scb_command(dev, SCB_CUsuspend); outb(0, ioaddr+SIGNAL_CA); outb(0, ioaddr+SIGNAL_CA);#if 0 printk("%s: waiting for CU to go suspended\n", dev->name);#endif oj = jiffies; while ((SCB_CUstat(scb_status(dev)) == 2) && ((jiffies-oj) < 2000)); if (SCB_CUstat(scb_status(dev)) == 2) printk("%s: warning, CU didn't stop\n", dev->name); lp->started &= ~(STARTED_CU); scb_wrcbl(dev, CONF_LINK); scb_command(dev, SCB_CUstart); outb(0, ioaddr+SIGNAL_CA); }}/* * 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 },};static int irq[EEXP_MAX_CARDS] = {0, };static int io[EEXP_MAX_CARDS] = {0, };MODULE_PARM(io, "1-" __MODULE_STRING(EEXP_MAX_CARDS) "i");MODULE_PARM(irq, "1-" __MODULE_STRING(EEXP_MAX_CARDS) "i");/* 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) { unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, EEXP_IO_EXTENT); } }}#endif/* * Local Variables: * c-file-style: "linux" * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -