/* Intel EtherExpress 16 device driver for Linux * * Written by John Sullivan, 1995 * based on original code by Donald Becker, with changes by * Alan Cox and Pauline Middelink. * * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu> * * Many modifications, and currently maintained, by * Philip Blundell <philb@gnu.org> * Added the Compaq LTE Alan Cox <alan@redhat.com> * Added MCA support Adam Fritzler <mid@auk.cx> * * Note - this driver is experimental still - it has problems on faster * machines. Someone needs to sit down and go through it line by line with * a databook... */ /* The EtherExpress 16 is a fairly simple card, based on a shared-memory * design using the i82586 Ethernet coprocessor. It bears no relationship, * as far as I know, to the similarly-named "EtherExpress Pro" range. * * Historically, Linux support for these cards has been very bad. However, * things seem to be getting better slowly. */ /* If your card is confused about what sort of interface it has (eg it * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART' * or 'SOFTSET /LISA' from DOS seems to help. */ /* Here's the scoop on memory mapping. * * There are three ways to access EtherExpress card memory: either using the * shared-memory mapping, or using PIO through the dataport, or using PIO * through the "shadow memory" ports. * * The shadow memory system works by having the card map some of its memory * as follows: * * (the low five bits of the SMPTR are ignored) * * base+0x4000..400f memory at SMPTR+0..15 * base+0x8000..800f memory at SMPTR+16..31 * base+0xc000..c007 dubious stuff (memory at SMPTR+16..23 apparently) * base+0xc008..c00f memory at 0x0008..0x000f * * This last set (the one at c008) is particularly handy because the SCB * lives at 0x0008. So that set of ports gives us easy random access to data * in the SCB without having to mess around setting up pointers and the like. * We always use this method to access the SCB (via the scb_xx() functions). * * Dataport access works by aiming the appropriate (read or write) pointer * at the first address you're interested in, and then reading or writing from * the dataport. The pointers auto-increment after each transfer. We use * this for data transfer. * * We don't use the shared-memory system because it allegedly doesn't work on * all cards, and because it's a bit more prone to go wrong (it's one more * thing to configure...). */ /* Known bugs: * * - The card seems to want to give us two interrupts every time something * happens, where just one would be better. */ /* * * Note by Zoltan Szilagyi 10-12-96: * * I've succeeded in eliminating the "CU wedged" messages, and hence the * lockups, which were only occurring with cards running in 8-bit mode ("force * 8-bit operation" in Intel's SoftSet utility). This version of the driver * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the * CU before submitting a packet for transmission, and then restarts it as soon * as the process of handing the packet is complete. This is definitely an * unnecessary slowdown if the card is running in 16-bit mode; therefore one * should detect 16-bit vs 8-bit mode from the EEPROM settings and act * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for * ftp's, which is significantly better than I get in DOS, so the overhead of * stopping and restarting the CU with each transmit is not prohibitive in * practice. * * Update by David Woodhouse 11/5/99: * * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture. * I assume that this is because 16-bit accesses are actually handled as two * 8-bit accesses. */ #ifdef __alpha__#define LOCKUP16 1#endif#ifndef LOCKUP16#define LOCKUP16 0#endif #include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/string.h>#include <linux/in.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/slab.h>#include <linux/mca-legacy.h>#include <linux/spinlock.h>#include <linux/bitops.h> #include <asm/system.h>#include <asm/io.h>#include <asm/irq.h> #ifndef NET_DEBUG#define NET_DEBUG 4#endif #include "eexpress.h" #define EEXP_IO_EXTENT 16 /* * Private data declarations */ struct net_local{ struct net_device_stats stats; unsigned long last_tx; /* jiffies when last transmit started */ unsigned long init_time; /* jiffies when eexp_hw_init586 called */ unsigned short rx_first; /* first rx buf, same as RX_BUF_START */ unsigned short rx_last; /* last rx buf */ unsigned short rx_ptr; /* first rx buf to look at */ unsigned short tx_head; /* next free tx buf */ unsigned short tx_reap; /* first in-use tx buf */ unsigned short tx_tail; /* previous tx buf to tx_head */ unsigned short tx_link; /* last known-executing tx buf */ unsigned short last_tx_restart; /* set to tx_link when we restart the CU */ unsigned char started; unsigned short rx_buf_start; unsigned short rx_buf_end; unsigned short num_tx_bufs; unsigned short num_rx_bufs; unsigned char width; /* 0 for 16bit, 1 for 8bit */ unsigned char was_promisc; unsigned char old_mc_count; spinlock_t lock;}; /* This is the code and data that is downloaded to the EtherExpress card's * memory at boot time. */ static unsigned short start_code[] = {/* 0x0000 */ 0x0001, /* ISCP: busy - cleared after reset */ 0x0008,0x0000,0x0000, /* offset,address (lo,hi) of SCB */ 0x0000,0x0000, /* SCB: status, commands */ 0x0000,0x0000, /* links to first command block, first receive descriptor */ 0x0000,0x0000, /* CRC error, alignment error counts */ 0x0000,0x0000, /* out of resources, overrun error counts */ 0x0000,0x0000, /* pad */ 0x0000,0x0000, /* 0x20 -- start of 82586 CU program */#define CONF_LINK 0x20 0x0000,Cmd_Config, 0x0032, /* link to next command */ 0x080c, /* 12 bytes follow : fifo threshold=8 */ 0x2e40, /* don't rx bad frames * SRDY/ARDY => ext. sync. : preamble len=8 * take addresses from data buffers * 6 bytes/address */ 0x6000, /* default backoff method & priority * interframe spacing = 0x60 */ 0xf200, /* slot time=0x200 * max collision retry = 0xf */#define CONF_PROMISC 0x2e 0x0000, /* no HDLC : normal CRC : enable broadcast * disable promiscuous/multicast modes */ 0x003c, /* minimum frame length = 60 octets) */ 0x0000,Cmd_SetAddr, 0x003e, /* link to next command */#define CONF_HWADDR 0x38 0x0000,0x0000,0x0000, /* hardware address placed here */ 0x0000,Cmd_MCast, 0x0076, /* link to next command */#define CONF_NR_MULTICAST 0x44 0x0000, /* number of multicast addresses */#define CONF_MULTICAST 0x46 0x0000, 0x0000, 0x0000, /* some addresses */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, #define CONF_DIAG_RESULT 0x76 0x0000, Cmd_Diag, 0x007c, /* link to next command */ 0x0000,Cmd_TDR|Cmd_INT, 0x0084,#define CONF_TDR_RESULT 0x82 0x0000, 0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */ 0x0084 /* dummy link */}; /* maps irq number to EtherExpress magic value */static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 }; #ifdef CONFIG_MCA_LEGACY/* mapping of the first four bits of the second POS register */static unsigned short mca_iomap[] = { 0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200, 0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300};/* bits 5-7 of the second POS register */static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };#endif /* * Prototypes for Linux interface */ static int eexp_open(struct net_device *dev);static int eexp_close(struct net_device *dev);static void eexp_timeout(struct net_device *dev);static struct net_device_stats *eexp_stats(struct net_device *dev);static int eexp_xmit(struct sk_buff *buf, struct net_device *dev); static irqreturn_t eexp_irq(int irq, void *dev_addr);static void eexp_set_multicast(struct net_device *dev); /* * Prototypes for hardware access functions */ static void eexp_hw_rx_pio(struct net_device *dev);static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, unsigned short len);static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location); static unsigned short eexp_hw_lasttxstat(struct net_device *dev);static void eexp_hw_txrestart(struct net_device *dev); static void eexp_hw_txinit (struct net_device *dev);static void eexp_hw_rxinit (struct net_device *dev); static void eexp_hw_init586 (struct net_device *dev);static void eexp_setup_filter (struct net_device *dev); static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};enum eexp_iftype {AUI=0, BNC=1, TPE=2}; #define STARTED_RU 2#define STARTED_CU 1 /* * Primitive hardware access functions. */ static inline unsigned short scb_status(struct net_device *dev){ return inw(dev->base_addr + 0xc008);} static inline unsigned short scb_rdcmd(struct net_device *dev){ return inw(dev->base_addr + 0xc00a);} static inline void scb_command(struct net_device *dev, unsigned short cmd){ outw(cmd, dev->base_addr + 0xc00a);} static inline void scb_wrcbl(struct net_device *dev, unsigned short val){ outw(val, dev->base_addr + 0xc00c);} static inline void scb_wrrfa(struct net_device *dev, unsigned short val){ outw(val, dev->base_addr + 0xc00e);} static inline void set_loopback(struct net_device *dev){ outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);} static inline void clear_loopback(struct net_device *dev){ outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);} static inline unsigned short int SHADOW(short int addr){ addr &= 0x1f; if (addr > 0xf) addr += 0x3ff0; return addr + 0x4000;} /* * Linux interface */ /* * checks for presence of EtherExpress card */ static int __init do_express_probe(struct net_device *dev){ unsigned short *port; static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 }; unsigned short ioaddr = dev->base_addr; int dev_irq = dev->irq; int err; SET_MODULE_OWNER(dev); dev->if_port = 0xff; /* not set */ #ifdef CONFIG_MCA_LEGACY if (MCA_bus) { int slot = 0; /* * Only find one card at a time. Subsequent calls * will find others, however, proper multicard MCA * probing and setup can't be done with the * old-style Space.c init routines. -- ASF */ while (slot != MCA_NOTFOUND) { int pos0, pos1; slot = mca_find_unused_adapter(0x628B, slot); if (slot == MCA_NOTFOUND) break; pos0 = mca_read_stored_pos(slot, 2); pos1 = mca_read_stored_pos(slot, 3); ioaddr = mca_iomap[pos1&0xf]; dev->irq = mca_irqmap[(pos1>>4)&0x7]; /* * XXX: Transciever selection is done * differently on the MCA version. * How to get it to select something * other than external/AUI is currently * unknown. This code is just for looks. -- ASF */ if ((pos0 & 0x7) == 0x1) dev->if_port = AUI; else if ((pos0 & 0x7) == 0x5) { if (pos1 & 0x80) dev->if_port = BNC; else dev->if_port = TPE; } mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA"); mca_set_adapter_procfn(slot, NULL, dev); mca_mark_as_used(slot); break; } }#endif if (ioaddr&0xfe00) { if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) return -EBUSY; err = eexp_hw_probe(dev,ioaddr); release_region(ioaddr, EEXP_IO_EXTENT); return err; } else if (ioaddr) return -ENXIO; for (port=&ports[0] ; *port ; port++ ) { unsigned short sum = 0; int i; if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress")) continue; for ( i=0 ; i<4 ; i++ ) { unsigned short t; t = inb(*port + ID_PORT); sum |= (t>>4) << ((t & 0x03)<<2); } if (sum==0xbaba && !eexp_hw_probe(dev,*port)) { release_region(*port, EEXP_IO_EXTENT); return 0; } release_region(*port, EEXP_IO_EXTENT); dev->irq = dev_irq; } return -ENODEV;} #ifndef MODULEstruct net_device * __init express_probe(int unit){ struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); int err; if (!dev) return ERR_PTR(-ENOMEM); sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); err = do_express_probe(dev); if (!err) return dev; free_netdev(dev); return ERR_PTR(err);}#endif /* * open and initialize the adapter, ready for use */ static int eexp_open(struct net_device *dev){ int ret; unsigned short ioaddr = dev->base_addr; struct net_local *lp = netdev_priv(dev); #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);#endif if (!dev->irq || !irqrmap[dev->irq]) return -ENXIO; ret = request_irq(dev->irq,&eexp_irq,0,dev->name,dev); if (ret) return ret; if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr); goto err_out1; } if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr+0x4000); goto err_out2; } if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr+0x8000); goto err_out3; } if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr+0xc000); goto err_out4; } if (lp->width) { printk("%s: forcing ASIC to 8-bit mode\n", dev->name); outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config); } eexp_hw_init586(dev); netif_start_queue(dev);#if NET_DEBUG > 6 printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);#endif return 0; err_out4: release_region(ioaddr+0x8000, EEXP_IO_EXTENT); err_out3:Lines 1–500 of 1734. Load more
/* Intel EtherExpress 16 device driver for Linux * * Written by John Sullivan, 1995 * based on original code by Donald Becker, with changes by * Alan Cox and Pauline Middelink. * * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu> * * Many modifications, and currently maintained, by * Philip Blundell <philb@gnu.org> * Added the Compaq LTE Alan Cox <alan@redhat.com> * Added MCA support Adam Fritzler <mid@auk.cx> * * Note - this driver is experimental still - it has problems on faster * machines. Someone needs to sit down and go through it line by line with * a databook... */ /* The EtherExpress 16 is a fairly simple card, based on a shared-memory * design using the i82586 Ethernet coprocessor. It bears no relationship, * as far as I know, to the similarly-named "EtherExpress Pro" range. * * Historically, Linux support for these cards has been very bad. However, * things seem to be getting better slowly. */ /* If your card is confused about what sort of interface it has (eg it * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART' * or 'SOFTSET /LISA' from DOS seems to help. */ /* Here's the scoop on memory mapping. * * There are three ways to access EtherExpress card memory: either using the * shared-memory mapping, or using PIO through the dataport, or using PIO * through the "shadow memory" ports. * * The shadow memory system works by having the card map some of its memory * as follows: * * (the low five bits of the SMPTR are ignored) * * base+0x4000..400f memory at SMPTR+0..15 * base+0x8000..800f memory at SMPTR+16..31 * base+0xc000..c007 dubious stuff (memory at SMPTR+16..23 apparently) * base+0xc008..c00f memory at 0x0008..0x000f * * This last set (the one at c008) is particularly handy because the SCB * lives at 0x0008. So that set of ports gives us easy random access to data * in the SCB without having to mess around setting up pointers and the like. * We always use this method to access the SCB (via the scb_xx() functions). * * Dataport access works by aiming the appropriate (read or write) pointer * at the first address you're interested in, and then reading or writing from * the dataport. The pointers auto-increment after each transfer. We use * this for data transfer. * * We don't use the shared-memory system because it allegedly doesn't work on * all cards, and because it's a bit more prone to go wrong (it's one more * thing to configure...). */ /* Known bugs: * * - The card seems to want to give us two interrupts every time something * happens, where just one would be better. */ /* * * Note by Zoltan Szilagyi 10-12-96: * * I've succeeded in eliminating the "CU wedged" messages, and hence the * lockups, which were only occurring with cards running in 8-bit mode ("force * 8-bit operation" in Intel's SoftSet utility). This version of the driver * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the * CU before submitting a packet for transmission, and then restarts it as soon * as the process of handing the packet is complete. This is definitely an * unnecessary slowdown if the card is running in 16-bit mode; therefore one * should detect 16-bit vs 8-bit mode from the EEPROM settings and act * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for * ftp's, which is significantly better than I get in DOS, so the overhead of * stopping and restarting the CU with each transmit is not prohibitive in * practice. * * Update by David Woodhouse 11/5/99: * * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture. * I assume that this is because 16-bit accesses are actually handled as two * 8-bit accesses. */ #ifdef __alpha__ #define LOCKUP16 1 #endif #ifndef LOCKUP16 #define LOCKUP16 0 #endif #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/string.h> #include <linux/in.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <linux/mca-legacy.h> #include <linux/spinlock.h> #include <linux/bitops.h> #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> #ifndef NET_DEBUG #define NET_DEBUG 4 #endif #include "eexpress.h" #define EEXP_IO_EXTENT 16 /* * Private data declarations */ struct net_local { struct net_device_stats stats; unsigned long last_tx; /* jiffies when last transmit started */ unsigned long init_time; /* jiffies when eexp_hw_init586 called */ unsigned short rx_first; /* first rx buf, same as RX_BUF_START */ unsigned short rx_last; /* last rx buf */ unsigned short rx_ptr; /* first rx buf to look at */ unsigned short tx_head; /* next free tx buf */ unsigned short tx_reap; /* first in-use tx buf */ unsigned short tx_tail; /* previous tx buf to tx_head */ unsigned short tx_link; /* last known-executing tx buf */ unsigned short last_tx_restart; /* set to tx_link when we restart the CU */ unsigned char started; unsigned short rx_buf_start; unsigned short rx_buf_end; unsigned short num_tx_bufs; unsigned short num_rx_bufs; unsigned char width; /* 0 for 16bit, 1 for 8bit */ unsigned char was_promisc; unsigned char old_mc_count; spinlock_t lock; }; /* This is the code and data that is downloaded to the EtherExpress card's * memory at boot time. */ static unsigned short start_code[] = { /* 0x0000 */ 0x0001, /* ISCP: busy - cleared after reset */ 0x0008,0x0000,0x0000, /* offset,address (lo,hi) of SCB */ 0x0000,0x0000, /* SCB: status, commands */ 0x0000,0x0000, /* links to first command block, first receive descriptor */ 0x0000,0x0000, /* CRC error, alignment error counts */ 0x0000,0x0000, /* out of resources, overrun error counts */ 0x0000,0x0000, /* pad */ 0x0000,0x0000, /* 0x20 -- start of 82586 CU program */ #define CONF_LINK 0x20 0x0000,Cmd_Config, 0x0032, /* link to next command */ 0x080c, /* 12 bytes follow : fifo threshold=8 */ 0x2e40, /* don't rx bad frames * SRDY/ARDY => ext. sync. : preamble len=8 * take addresses from data buffers * 6 bytes/address */ 0x6000, /* default backoff method & priority * interframe spacing = 0x60 */ 0xf200, /* slot time=0x200 * max collision retry = 0xf */ #define CONF_PROMISC 0x2e 0x0000, /* no HDLC : normal CRC : enable broadcast * disable promiscuous/multicast modes */ 0x003c, /* minimum frame length = 60 octets) */ 0x0000,Cmd_SetAddr, 0x003e, /* link to next command */ #define CONF_HWADDR 0x38 0x0000,0x0000,0x0000, /* hardware address placed here */ 0x0000,Cmd_MCast, 0x0076, /* link to next command */ #define CONF_NR_MULTICAST 0x44 0x0000, /* number of multicast addresses */ #define CONF_MULTICAST 0x46 0x0000, 0x0000, 0x0000, /* some addresses */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, #define CONF_DIAG_RESULT 0x76 0x0000, Cmd_Diag, 0x007c, /* link to next command */ 0x0000,Cmd_TDR|Cmd_INT, 0x0084, #define CONF_TDR_RESULT 0x82 0x0000, 0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */ 0x0084 /* dummy link */ }; /* maps irq number to EtherExpress magic value */ static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 }; #ifdef CONFIG_MCA_LEGACY /* mapping of the first four bits of the second POS register */ static unsigned short mca_iomap[] = { 0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200, 0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300 }; /* bits 5-7 of the second POS register */ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 }; #endif /* * Prototypes for Linux interface */ static int eexp_open(struct net_device *dev); static int eexp_close(struct net_device *dev); static void eexp_timeout(struct net_device *dev); static struct net_device_stats *eexp_stats(struct net_device *dev); static int eexp_xmit(struct sk_buff *buf, struct net_device *dev); static irqreturn_t eexp_irq(int irq, void *dev_addr); static void eexp_set_multicast(struct net_device *dev); /* * Prototypes for hardware access functions */ static void eexp_hw_rx_pio(struct net_device *dev); static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, unsigned short len); static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr); static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location); static unsigned short eexp_hw_lasttxstat(struct net_device *dev); static void eexp_hw_txrestart(struct net_device *dev); static void eexp_hw_txinit (struct net_device *dev); static void eexp_hw_rxinit (struct net_device *dev); static void eexp_hw_init586 (struct net_device *dev); static void eexp_setup_filter (struct net_device *dev); static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"}; enum eexp_iftype {AUI=0, BNC=1, TPE=2}; #define STARTED_RU 2 #define STARTED_CU 1 /* * Primitive hardware access functions. */ static inline unsigned short scb_status(struct net_device *dev) { return inw(dev->base_addr + 0xc008); } static inline unsigned short scb_rdcmd(struct net_device *dev) { return inw(dev->base_addr + 0xc00a); } static inline void scb_command(struct net_device *dev, unsigned short cmd) { outw(cmd, dev->base_addr + 0xc00a); } static inline void scb_wrcbl(struct net_device *dev, unsigned short val) { outw(val, dev->base_addr + 0xc00c); } static inline void scb_wrrfa(struct net_device *dev, unsigned short val) { outw(val, dev->base_addr + 0xc00e); } static inline void set_loopback(struct net_device *dev) { outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config); } static inline void clear_loopback(struct net_device *dev) { outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config); } static inline unsigned short int SHADOW(short int addr) { addr &= 0x1f; if (addr > 0xf) addr += 0x3ff0; return addr + 0x4000; } /* * Linux interface */ /* * checks for presence of EtherExpress card */ static int __init do_express_probe(struct net_device *dev) { unsigned short *port; static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 }; unsigned short ioaddr = dev->base_addr; int dev_irq = dev->irq; int err; SET_MODULE_OWNER(dev); dev->if_port = 0xff; /* not set */ #ifdef CONFIG_MCA_LEGACY if (MCA_bus) { int slot = 0; /* * Only find one card at a time. Subsequent calls * will find others, however, proper multicard MCA * probing and setup can't be done with the * old-style Space.c init routines. -- ASF */ while (slot != MCA_NOTFOUND) { int pos0, pos1; slot = mca_find_unused_adapter(0x628B, slot); if (slot == MCA_NOTFOUND) break; pos0 = mca_read_stored_pos(slot, 2); pos1 = mca_read_stored_pos(slot, 3); ioaddr = mca_iomap[pos1&0xf]; dev->irq = mca_irqmap[(pos1>>4)&0x7]; /* * XXX: Transciever selection is done * differently on the MCA version. * How to get it to select something * other than external/AUI is currently * unknown. This code is just for looks. -- ASF */ if ((pos0 & 0x7) == 0x1) dev->if_port = AUI; else if ((pos0 & 0x7) == 0x5) { if (pos1 & 0x80) dev->if_port = BNC; else dev->if_port = TPE; } mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA"); mca_set_adapter_procfn(slot, NULL, dev); mca_mark_as_used(slot); break; } } #endif if (ioaddr&0xfe00) { if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) return -EBUSY; err = eexp_hw_probe(dev,ioaddr); release_region(ioaddr, EEXP_IO_EXTENT); return err; } else if (ioaddr) return -ENXIO; for (port=&ports[0] ; *port ; port++ ) { unsigned short sum = 0; int i; if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress")) continue; for ( i=0 ; i<4 ; i++ ) { unsigned short t; t = inb(*port + ID_PORT); sum |= (t>>4) << ((t & 0x03)<<2); } if (sum==0xbaba && !eexp_hw_probe(dev,*port)) { release_region(*port, EEXP_IO_EXTENT); return 0; } release_region(*port, EEXP_IO_EXTENT); dev->irq = dev_irq; } return -ENODEV; } #ifndef MODULE struct net_device * __init express_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); int err; if (!dev) return ERR_PTR(-ENOMEM); sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); err = do_express_probe(dev); if (!err) return dev; free_netdev(dev); return ERR_PTR(err); } #endif /* * open and initialize the adapter, ready for use */ static int eexp_open(struct net_device *dev) { int ret; unsigned short ioaddr = dev->base_addr; struct net_local *lp = netdev_priv(dev); #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_open()\n", dev->name); #endif if (!dev->irq || !irqrmap[dev->irq]) return -ENXIO; ret = request_irq(dev->irq,&eexp_irq,0,dev->name,dev); if (ret) return ret; if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr); goto err_out1; } if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr+0x4000); goto err_out2; } if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr+0x8000); goto err_out3; } if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" , ioaddr+0xc000); goto err_out4; } if (lp->width) { printk("%s: forcing ASIC to 8-bit mode\n", dev->name); outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config); } eexp_hw_init586(dev); netif_start_queue(dev); #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name); #endif return 0; err_out4: release_region(ioaddr+0x8000, EEXP_IO_EXTENT); err_out3: