📄 eepro.c
字号:
if (inb(ioaddr + STATUS_REG) & 0x08) { i = inb(ioaddr); outb(0x08, ioaddr + STATUS_REG); if (i & 0x20) { /* command ABORTed */ printk(KERN_NOTICE "%s: multicast setup failed.\n", dev->name); break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n", dev->name, dev->mc_count, dev->mc_count > 1 ? "es":""); break; } } } while (++boguscount < 100); /* Re-enable RX and TX interrupts */ eepro_en_int(ioaddr); } if (lp->eepro == LAN595FX_10ISA) { eepro_complete_selreset(ioaddr); } else eepro_en_rx(ioaddr);}/* The horrible routine to read a word from the serial EEPROM. *//* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read *//* The delay between EEPROM clock transitions. */#define eeprom_delay() { udelay(40); }#define EE_READ_CMD (6 << 6)intread_eeprom(int ioaddr, int location, struct net_device *dev){ int i; unsigned short retval = 0; struct eepro_local *lp = netdev_priv(dev); short ee_addr = ioaddr + lp->eeprom_reg; int read_cmd = location | EE_READ_CMD; short ctrl_val = EECS ; /* XXXX - black magic */ eepro_sw2bank1(ioaddr); outb(0x00, ioaddr + STATUS_REG); /* XXXX - black magic */ eepro_sw2bank2(ioaddr); outb(ctrl_val, ee_addr); /* Shift the read command bits out. */ for (i = 8; i >= 0; i--) { short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val; outb(outval, ee_addr); outb(outval | EESK, ee_addr); /* EEPROM clock tick. */ eeprom_delay(); outb(outval, ee_addr); /* Finish EEPROM a clock tick. */ eeprom_delay(); } outb(ctrl_val, ee_addr); for (i = 16; i > 0; i--) { outb(ctrl_val | EESK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); outb(ctrl_val, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ ctrl_val &= ~EECS; outb(ctrl_val | EESK, ee_addr); eeprom_delay(); outb(ctrl_val, ee_addr); eeprom_delay(); eepro_sw2bank0(ioaddr); return retval;}static inthardware_send_packet(struct net_device *dev, void *buf, short length){ struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned status, tx_available, last, end; if (net_debug > 5) printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name); /* determine how much of the transmit buffer space is available */ if (lp->tx_end > lp->tx_start) tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start); else if (lp->tx_end < lp->tx_start) tx_available = lp->tx_start - lp->tx_end; else tx_available = lp->xmt_ram; if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) { /* No space available ??? */ return 1; } last = lp->tx_end; end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */ if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) { /* Arrrr!!!, must keep the xmt header together, several days were lost to chase this one down. */ last = lp->xmt_lower_limit; end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; } else end = lp->xmt_lower_limit + (end - lp->xmt_upper_limit + 2); } outw(last, ioaddr + HOST_ADDRESS_REG); outw(XMT_CMD, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(end, ioaddr + IO_PORT); outw(length, ioaddr + IO_PORT); if (lp->version == LAN595) outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1); else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */ unsigned short temp = inb(ioaddr + INT_MASK_REG); outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG); outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2); outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG); } /* A dummy read to flush the DRAM write pipeline */ status = inw(ioaddr + IO_PORT); if (lp->tx_start == lp->tx_end) { outw(last, ioaddr + lp->xmt_bar); outb(XMT_CMD, ioaddr); lp->tx_start = last; /* I don't like to change tx_start here */ } else { /* update the next address and the chain bit in the last packet */ if (lp->tx_end != last) { outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); outw(last, ioaddr + IO_PORT); } outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG); status = inw(ioaddr + IO_PORT); outw(status | CHAIN_BIT, ioaddr + IO_PORT); /* Continue the transmit command */ outb(RESUME_XMT_CMD, ioaddr); } lp->tx_last = last; lp->tx_end = end; if (net_debug > 5) printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); return 0;}static voideepro_rx(struct net_device *dev){ struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; short boguscount = 20; short rcv_car = lp->rx_start; unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size; if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name); /* Set the read pointer to the start of the RCV */ outw(rcv_car, ioaddr + HOST_ADDRESS_REG); rcv_event = inw(ioaddr + IO_PORT); while (rcv_event == RCV_DONE) { rcv_status = inw(ioaddr + IO_PORT); rcv_next_frame = inw(ioaddr + IO_PORT); rcv_size = inw(ioaddr + IO_PORT); if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) { /* Malloc up new buffer. */ struct sk_buff *skb; dev->stats.rx_bytes+=rcv_size; rcv_size &= 0x3fff; skb = dev_alloc_skb(rcv_size+5); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; rcv_car = lp->rx_start + RCV_HEADER + rcv_size; lp->rx_start = rcv_next_frame; outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); break; } skb_reserve(skb,2); if (lp->version == LAN595) insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1); else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */ unsigned short temp = inb(ioaddr + INT_MASK_REG); outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG); insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), (rcv_size + 3) >> 2); outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG); } skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; dev->stats.rx_packets++; } else { /* Not sure will ever reach here, I set the 595 to discard bad received frames */ dev->stats.rx_errors++; if (rcv_status & 0x0100) dev->stats.rx_over_errors++; else if (rcv_status & 0x0400) dev->stats.rx_frame_errors++; else if (rcv_status & 0x0800) dev->stats.rx_crc_errors++; printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n", dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); } if (rcv_status & 0x1000) dev->stats.rx_length_errors++; rcv_car = lp->rx_start + RCV_HEADER + rcv_size; lp->rx_start = rcv_next_frame; if (--boguscount == 0) break; outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); rcv_event = inw(ioaddr + IO_PORT); } if (rcv_car == 0) rcv_car = lp->rcv_upper_limit | 0xff; outw(rcv_car - 1, ioaddr + RCV_STOP); if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);}static voideepro_transmit_interrupt(struct net_device *dev){ struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; short boguscount = 25; short xmt_status; while ((lp->tx_start != lp->tx_end) && boguscount--) { outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); xmt_status = inw(ioaddr+IO_PORT); if (!(xmt_status & TX_DONE_BIT)) break; xmt_status = inw(ioaddr+IO_PORT); lp->tx_start = inw(ioaddr+IO_PORT); netif_wake_queue (dev); if (xmt_status & TX_OK) dev->stats.tx_packets++; else { dev->stats.tx_errors++; if (xmt_status & 0x0400) { dev->stats.tx_carrier_errors++; printk(KERN_DEBUG "%s: carrier error\n", dev->name); printk(KERN_DEBUG "%s: XMT status = %#x\n", dev->name, xmt_status); } else { printk(KERN_DEBUG "%s: XMT status = %#x\n", dev->name, xmt_status); printk(KERN_DEBUG "%s: XMT status = %#x\n", dev->name, xmt_status); } } if (xmt_status & 0x000f) { dev->stats.collisions += (xmt_status & 0x000f); } if ((xmt_status & 0x0040) == 0x0) { dev->stats.tx_heartbeat_errors++; } }}static int eepro_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct eepro_local *lp = (struct eepro_local *)dev->priv; cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_Autoneg; cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_Autoneg; if (GetBit(lp->word[5], ee_PortTPE)) { cmd->supported |= SUPPORTED_TP; cmd->advertising |= ADVERTISED_TP; } if (GetBit(lp->word[5], ee_PortBNC)) { cmd->supported |= SUPPORTED_BNC; cmd->advertising |= ADVERTISED_BNC; } if (GetBit(lp->word[5], ee_PortAUI)) { cmd->supported |= SUPPORTED_AUI; cmd->advertising |= ADVERTISED_AUI; } cmd->speed = SPEED_10; if (dev->if_port == TPE && lp->word[1] & ee_Duplex) { cmd->duplex = DUPLEX_FULL; } else { cmd->duplex = DUPLEX_HALF; } cmd->port = dev->if_port; cmd->phy_address = dev->base_addr; cmd->transceiver = XCVR_INTERNAL; if (lp->word[0] & ee_AutoNeg) { cmd->autoneg = 1; } return 0;}static void eepro_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo){ strcpy(drvinfo->driver, DRV_NAME); strcpy(drvinfo->version, DRV_VERSION); sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);}static const struct ethtool_ops eepro_ethtool_ops = { .get_settings = eepro_ethtool_get_settings, .get_drvinfo = eepro_ethtool_get_drvinfo,};#ifdef MODULE#define MAX_EEPRO 8static struct net_device *dev_eepro[MAX_EEPRO];static int io[MAX_EEPRO] = { [0 ... MAX_EEPRO-1] = -1};static int irq[MAX_EEPRO];static int mem[MAX_EEPRO] = { /* Size of the rx buffer in KB */ [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024};static int autodetect;static int n_eepro;/* For linux 2.1.xx */MODULE_AUTHOR("Pascal Dupuis and others");MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");MODULE_LICENSE("GPL");module_param_array(io, int, NULL, 0);module_param_array(irq, int, NULL, 0);module_param_array(mem, int, NULL, 0);module_param(autodetect, int, 0);MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)");MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");int __init init_module(void){ struct net_device *dev; int i; if (io[0] == -1 && autodetect == 0) { printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n"); printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n"); return -ENODEV; } else if (autodetect) { /* if autodetect is set then we must force detection */ for (i = 0; i < MAX_EEPRO; i++) { io[i] = 0; } printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n"); } for (i = 0; io[i] != -1 && i < MAX_EEPRO; i++) { dev = alloc_etherdev(sizeof(struct eepro_local)); if (!dev) break; dev->mem_end = mem[i]; dev->base_addr = io[i]; dev->irq = irq[i]; if (do_eepro_probe(dev) == 0) { dev_eepro[n_eepro++] = dev; continue; } free_netdev(dev); break; } if (n_eepro) printk(KERN_INFO "%s", version); return n_eepro ? 0 : -ENODEV;}void __exitcleanup_module(void){ int i; for (i=0; i<n_eepro; i++) { struct net_device *dev = dev_eepro[i]; unregister_netdev(dev); release_region(dev->base_addr, EEPRO_IO_EXTENT); free_netdev(dev); }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -