/* at1700.c (tentative name): A network device driver for the FMV-181/182/183/184 and the AT1700/RE2000 series. Original: fmv18x.c (1994 by Yutaka TAMIYA). Modified by Hiroaki Nagoya (nagoya@is.titech.ac.jp) This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. This is a device driver for the AT1700/RE2000 series and the FMV-18x series, which is a straight-forward Fujitsu MB86965 implementation. Sources: at1700.c (by D. Becker) fmv18x.c (by Y. Tamiya) if_fe.c (by M. Seki, in FreeBSD kernel source) The Fujitsu MB86965 datasheet History: 97/03/25 1st release (based on fmv18x.c) 97/11/22 Fixed 16collision problem (I`m not sure ...) 97/11/22 Merged with fmv18x driver 97/11/25 Fixed missing IRQ enabler for FMV-18x (by Y. TAMIYA) 97/12/04 Fixed bug of interface recognition 98/01/28 Fixed bug of IRQ selection for AT1700 (by T. Nakamura) 98/04/12 Supported kernel version 2.1.84 */ #include #if (LINUX_VERSION_CODE < 0x200ff) /* for v2.0.x */ #define KERNEL_MAJOR_VERSION 20 #elif (LINUX_VERSION_CODE < 0x201ff) /* for v2.1.x */ #define KERNEL_MAJOR_VERSION 21 #endif static const char version[] = "at1700.c:v$Revision: 0.9.2.4 $ $Date: 1998/04/14 04:11:51 $ $Author: nagoya $"; #include #include #include #include #include #include #include #include #include #include #include #if (KERNEL_MAJOR_VERSION == 21) #include #endif #include #include #include #include #include #include #include #include #include /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG #define NET_DEBUG 1 #endif /* use check for probe functions (NAGOYA) */ #define MB86965_DEBUG /* for test (NAGOYA) */ #define mb86965_probe at1700_probe /* If at1700.c replace by this */ //#define mb86965_probe fmv18x_probe /* If fmv18x.c replace by this */ #if (KERNEL_MAJOR_VERSION == 20) #define __initdata #define net_device_stats enet_statistics #define __initfunc(func) func #define test_and_set_bit(a,b) set_bit(a,b) #endif static unsigned int net_debug = NET_DEBUG; typedef unsigned char uchar; /* Information that need to be kept for each board. */ struct net_local { struct net_device_stats stats; long open_time; /* Useless example local info. */ uint tx_started:1; /* Number of packet on the Tx queue. */ uchar tx_queue; /* Number of packet on the Tx queue. */ ushort tx_queue_len; /* Current length of the Tx queue. */ const char *cardtype; /* Assign card type (NAGOYA) */ }; /* Offsets from the base address. */ #define STATUS 0 #define TX_STATUS 0 #define RX_STATUS 1 #define TX_INTR 2 /* Bit-mapped interrupt enable registers. */ #define RX_INTR 3 #define TX_MODE 4 #define RX_MODE 5 #define CONFIG_0 6 /* Misc. configuration settings. */ #define CONFIG_1 7 /* Run-time register bank 2 definitions. */ #define DATAPORT 8 /* Word-wide DMA or programmed-I/O dataport. */ #define TX_START 10 #define COL16CNTL 11 #define MODE13 13 #define EEPROM_Ctrl 16 #define EEPROM_Data 17 #define IOCONFIG 19 #define RESET 31 /* Write to reset some parts of the chip. */ #define MB86965_IO_EXTENT 32 /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x40 /* EEPROM shift clock, in reg. 16. */ #define EE_CS 0x20 /* EEPROM chip select, in reg. 16. */ #define EE_DATA_WRITE 0x80 /* EEPROM chip data in, in reg. 17. */ #define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */ /* Delay between EEPROM clock transitions. */ #define eeprom_delay() \ do { int _i = 40; while (--_i > 0) { inb(0x80); }} while (0) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << 6) #define EE_READ_CMD (6 << 6) #define EE_ERASE_CMD (7 << 6) #define MB86965_BMPR19 19 #define MB86965_B19_IRQ 0xC0 #define MB86965_B19_IRQ_SHIFT 6 /* EEPROM allocation (offsets) of AT1700/RE2000. */ #define MB86965_ATI_EEP_ADDR 0x08 /* Station address. (8-13) */ #define MB86965_ATI_EEP_MEDIA 0x18 /* Media type. */ #define MB86965_ATI_EEP_MAGIC 0x19 /* XXX Magic. */ #define MB86965_ATI_EEP_MODEL 0x1e /* Hardware type. */ #define MB86965_ATI_EEP_REVISION 0x1f /* Hardware revision. */ #define MB86965_ATI_MODEL_AT1700T 00 #define MB86965_ATI_MODEL_AT1700BT 01 #define MB86965_ATI_MODEL_AT1700FT 02 #define MB86965_ATI_MODEL_AT1700AT 03 /* Fujitsu FMV-18x Card Configuration */ #define FJ_STATUS0 0x10 #define FJ_STATUS1 0x11 #define FJ_CONFIG0 0x12 #define FJ_CONFIG1 0x13 #define FJ_MACADDR 0x14 /* 0x14 - 0x19 */ #define FJ_BUFCNTL 0x1A #define FJ_BUFDATA 0x1C /* Index to functions, as function prototypes. */ extern int mb86965_probe(struct device *dev); static int at1700_probe1(struct device *dev, short ioaddr); static int fmv18x_probe1(struct device *dev, short ioaddr); static int read_eeprom(int ioaddr, int location); static int net_open(struct device *dev); static int net_send_packet(struct sk_buff *skb, struct device *dev); static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void net_rx(struct device *dev); static int net_close(struct device *dev); static struct net_device_stats *net_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); static int at1700_probe_list[] __initdata = {0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0}; static int fmv18x_probe_list[] __initdata = {0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0}; struct probe_list { const char *cardtype; int (*probe)(struct device *dev, short ioaddr); int *addresses; }; static const struct probe_list probe_list[] = { /* { , } */ {"fmv18x", fmv18x_probe1, fmv18x_probe_list}, {"at1700", at1700_probe1, at1700_probe_list}, {NULL, NULL} }; /* Check for a network adaptor of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. If dev->base_addr == 1, always return failure. If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ #ifdef HAVE_DEVLIST /* Support for an alternate probe manager, which will eliminate the boilerplate below. */ /* I don't understand this section, so eliminated this. (NAGOYA)*/ #else /* Wrapper probe function (NAGOYA) */ __initfunc(int mb86965_probe(struct device *dev)) { const struct probe_list *list; int i; int base_addr = dev ? dev->base_addr : 0; #ifdef MB86965_DEBUG printk("%s\n", version); #endif if (base_addr > 0x1ff) { /* Check a single specified location. */ for (list = probe_list; list->probe != NULL; list++) { int retval; if ((retval = list->probe(dev, base_addr)) == 0) { ((struct net_local *)dev->priv)->cardtype = list->cardtype; return 0; } } return -ENODEV; } else if (base_addr != 0) { /* Don't probe at all. */ return ENXIO; } for (list = probe_list; list->probe != NULL; list++) { for (i = 0; list->addresses[i]; i++) { int ioaddr = list->addresses[i]; if (check_region(ioaddr, MB86965_IO_EXTENT)) continue; if (list->probe(dev, ioaddr) == 0) { ((struct net_local *)dev->priv)->cardtype = list->cardtype; return 0; } } } return ENODEV; } #endif /* The Fujitsu datasheet suggests that the NIC be probed for by checking its "signature", the default bit pattern after a reset. This *doesn't* work -- there is no way to reset the bus interface without a complete power-cycle! It turns out that ATI came to the same conclusion I did: the only thing that can be done is checking a few bits and then diving right into MAC address check. */ /* Stole from at1700.c (NAGOYA) */ __initfunc(int at1700_probe1(struct device *dev, short ioaddr)) { char irqmap[][4] = { {3, 4, 5, 9}, {10, 11, 14, 15}, {3,11,5,15}, {10,11,14,15}}; int n; char *model; unsigned int i, irq; #ifdef MB86965_DEBUG printk("at1700_probe1(%#x)\n", ioaddr); #endif /* Resetting the chip doesn't reset the ISA interface, so don't bother. That means we have to be careful with the register values we probe for. */ /* Check I/O address configuration */ if (at1700_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr || read_eeprom(ioaddr,4) != 0x0000 || (read_eeprom(ioaddr,5) & 0xff00) != 0xf400) return -ENODEV; /* Reset the internal state machines. */ outb(0, ioaddr + RESET); /* * Try to determine IRQ settings. * Different models use different ranges of IRQs. */ n = (inb(ioaddr + IOCONFIG) & MB86965_B19_IRQ) >> MB86965_B19_IRQ_SHIFT; switch ((read_eeprom(ioaddr, 15) & 0x00f0)) { case 0x30: irq = irqmap[3][n]; break; case 0x10: case 0x50: irq = irqmap[2][n]; break; case 0x40: case 0x60: if ((read_eeprom(ioaddr, 12) & 0x04)) { irq = irqmap[1][n]; } else { irq = irqmap[0][n]; } break; default: irq = irqmap[0][n]; break; } /* Snarf the interrupt vector now. */ if (request_irq(irq, &net_interrupt, 0, "at1700", dev)) { printk ("AT1700 found at %#3x, but it's unusable due to a conflict on" "IRQ %d.\n", ioaddr, irq); return EAGAIN; } /* Allocate a new 'dev' if needed. */ if (dev == NULL) dev = init_etherdev(0, sizeof(struct net_local)); /* Grab the region so that we can find another board if the IRQ request fails. */ request_region(ioaddr, MB86965_IO_EXTENT, "at1700"); /* Determine the card type. */ switch ((read_eeprom(ioaddr, 15)>>8) & 0x07) { case MB86965_ATI_MODEL_AT1700T: model = "AT1700T/RE2001"; break; case MB86965_ATI_MODEL_AT1700BT: model = "AT1700BT/RE2003"; break; case MB86965_ATI_MODEL_AT1700FT: model = "AT1700FT/RE2009"; break; case MB86965_ATI_MODEL_AT1700AT: model = "AT1700AT/RE2005"; break; default: model = "unknown AT1700/RE2000 ?"; break; } printk("%s: %s found at %#3x, IRQ %d, address ", dev->name, model, ioaddr, irq); dev->base_addr = ioaddr; dev->irq = irq; #if (KERNEL_MAJOR_VERSION == 20) irq2dev_map[irq] = dev; #endif for(i = 0; i < 3; i++) { unsigned short eeprom_val = read_eeprom(ioaddr, 4+i); printk("%04x", eeprom_val); ((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val); } /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals, rather than 150 ohm shielded twisted pair compensation. 0x0000 == auto-sense the interface 0x0800 == use TP interface 0x1800 == use coax interface */ { const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2/5"}; ushort setup_value = read_eeprom(ioaddr, 12); dev->if_port = setup_value >> 8; printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]); } /* Initialize LAN Controller and LAN Card */ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */ outb(0x00, ioaddr + CONFIG_1); /* Stand by mode */ /* wait for a while */ udelay(200); /* Set the station address in bank zero. */ outb(0xe0, ioaddr + CONFIG_1); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + 8 + i); /* Switch to bank 1 and set the multicast table to accept none. */ outb(0xe4, ioaddr + CONFIG_1); for (i = 0; i < 8; i++) outb(0x00, ioaddr + 8 + i); /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit bus access, two 4K Tx queues, and disabeld Tx and Rx. */ outb(0xda, ioaddr + CONFIG_0); /* Switch to bank 2 and lock our I/O address. */ outb(0xe8, ioaddr + CONFIG_1); outb(dev->if_port, ioaddr + MODE13); if (net_debug) printk("%s\n", version); /* Initialize the device structure. */ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats; dev->set_multicast_list = &set_multicast_list; /* Fill in the fields of 'dev' with ethernet-generic values. */ ether_setup(dev); return 0; } /* Stole from fmv18x.c (NAGOYA) */ __initfunc(int fmv18x_probe1(struct device *dev, short ioaddr)) { char irqmap[4] = {3, 7, 10, 15}; unsigned int i, irq; #ifdef MB86965_DEBUG printk("fmv18x_probe1(%#x)\n", ioaddr); #endif /* Resetting the chip doesn't reset the ISA interface, so don't bother. That means we have to be careful with the register values we probe for. */ /* Check I/O address configuration and Fujitsu vendor code */ if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr || inb(ioaddr+FJ_MACADDR ) != 0x00 || inb(ioaddr+FJ_MACADDR+1) != 0x00 || inb(ioaddr+FJ_MACADDR+2) != 0x0e) return -ENODEV; irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; /* Snarf the interrupt vector now. */ if (request_irq(irq, &net_interrupt, 0, "fmv18x", NULL)) { printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on" "IRQ %d.\n", ioaddr, irq); return EAGAIN; } /* Allocate a new 'dev' if needed. */ if (dev == NULL) dev = init_etherdev(0, sizeof(struct net_local)); /* Grab the region so that we can find another board if the IRQ request fails. */ request_region(ioaddr, MB86965_IO_EXTENT, "fmv18x"); printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name, ioaddr, irq); dev->base_addr = ioaddr; dev->irq = irq; #if (KERNEL_MAJOR_VERSION == 20) irq2dev_map[irq] = dev; #endif for(i = 0; i < 6; i++) { unsigned char val = inb(ioaddr + FJ_MACADDR + i); printk("%02x", val); dev->dev_addr[i] = val; } /* "FJ_STATUS0" 12 bit 0x0400 means use regular 100 ohm 10baseT signals, rather than 150 ohm shielded twisted pair compensation. 0x0000 == auto-sense the interface 0x0800 == use TP interface 0x1800 == use coax interface */ { const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2/5"}; ushort setup_value = inb(ioaddr + FJ_STATUS0); switch( setup_value & 0x07 ){ case 0x01 /* 10base5 */: case 0x02 /* 10base2 */: dev->if_port = 0x18; break; case 0x04 /* 10baseT */: dev->if_port = 0x08; break; default /* auto-sense*/: dev->if_port = 0x00; break; } printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]); } /* Initialize LAN Controller and LAN Card */ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */ outb(0x00, ioaddr + CONFIG_1); /* Stand by mode */ outb(0x80, ioaddr + FJ_CONFIG1); /* Enable IRQ of LAN Card */ outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure (TAMIYA) */ /* wait for a while */ udelay(200); /* Set the station address in bank zero. */ outb(0x00, ioaddr + CONFIG_1); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + 8 + i); /* Switch to bank 1 and set the multicast table to accept none. */ outb(0x04, ioaddr + CONFIG_1); for (i = 0; i < 8; i++) outb(0x00, ioaddr + 8 + i); /* Switch to bank 2 and lock our I/O address. */ outb(0x08, ioaddr + CONFIG_1); outb(dev->if_port, ioaddr + MODE13); if (net_debug) printk("%s\n", version); /* Initialize the device structure. */ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats; dev->set_multicast_list = &set_multicast_list; /* Fill in the fields of 'dev' with ethernet-generic values. */ ether_setup(dev); return 0; } /* Stole from at1700.c (NAGOYA) */ static int read_eeprom(int ioaddr, int location) { int i; unsigned short retval = 0; short ee_addr = ioaddr + EEPROM_Ctrl; short ee_daddr = ioaddr + EEPROM_Data; int read_cmd = location | EE_READ_CMD; short ctrl_val = EE_CS; outb(ctrl_val, ee_addr); /* Shift the read command bits out. */ for (i = 9; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outb(dataval, ee_daddr); outb(EE_CS | EE_SHIFT_CLK, ee_addr); /* EEPROM clock tick. */ eeprom_delay(); outb(EE_CS, ee_addr); /* Finish EEPROM a clock tick. */ eeprom_delay(); } outb(EE_CS, ee_addr); for (i = 16; i > 0; i--) { outb(EE_CS | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0); outb(EE_CS, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ ctrl_val &= ~EE_CS; outb(ctrl_val | EE_SHIFT_CLK, ee_addr); eeprom_delay(); outb(ctrl_val, ee_addr); eeprom_delay(); return retval; } static int net_open(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit bus access, two 4K Tx queues, and disabeld Tx and Rx. */ outb(0x5a, ioaddr + CONFIG_0); /* Powerup and switch to register bank 2 for the run-time registers. */ outb(0xe8, ioaddr + CONFIG_1); lp->tx_started = 0; lp->tx_queue = 0; lp->tx_queue_len = 0; /* Clear Tx and Rx Status */ outb(0xff, ioaddr + TX_STATUS); outb(0xff, ioaddr + RX_STATUS); lp->open_time = jiffies; dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; /* Enable both Tx and Rx interrupts */ outw(0x8182, ioaddr+TX_INTR); MOD_INC_USE_COUNT; return 0; } static int net_send_packet(struct sk_buff *skb, struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 10) return 1; printk("%s: transmit timed out with status %04x, %s?\n", dev->name, htons(inw(ioaddr + TX_STATUS)), inb(ioaddr + TX_STATUS) & 0x80 ? "IRQ conflict" : "network cable problem"); printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n", dev->name, htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)), htons(inw(ioaddr +10)), htons(inw(ioaddr +12)), htons(inw(ioaddr +14))); lp->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ cli(); /* Initialize LAN Controller and LAN Card */ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */ outb(0x00, ioaddr + CONFIG_1); /* Stand by mode */ net_open(dev); sti(); } #if (KERNEL_MAJOR_VERSION == 20) /* If some higher layer thinks we've missed an tx-done interrupt we are passed NULL. Caution: dev_tint() handles the cli()/sti() itself. */ if (skb == NULL) { dev_tint(dev); return 0; } #endif /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; if (length > ETH_FRAME_LEN) { if (net_debug) printk("%s: Attempting to send a large packet (%d bytes).\n", dev->name, length); return 1; } if (net_debug > 4) printk("%s: Transmitting a packet of length %lu.\n", dev->name, (unsigned long)skb->len); /* Disable both interrupts. */ outw(0x0000, ioaddr + TX_INTR); outw(length, ioaddr + DATAPORT); outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); lp->tx_queue++; lp->tx_queue_len += length + 2; if (lp->tx_started == 0) { /* If the Tx is idle, always trigger a transmit. */ outb(0x80 | lp->tx_queue, ioaddr + TX_START); lp->tx_queue = 0; lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; dev->tbusy = 0; } else if (lp->tx_queue_len < 4096 - 1502) /* Yes, there is room for one more packet. */ dev->tbusy = 0; /* Re-enable interrupts */ outw(0x8182, ioaddr + TX_INTR); } dev_kfree_skb (skb, FREE_WRITE); return 0; } /* The typical workload of the driver: Handle the network interface interrupts. */ static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs) { #if (KERNEL_MAJOR_VERSION == 20) struct device *dev = (struct device *)(irq2dev_map[irq]); #elif (KERNEL_MAJOR_VERSION == 21) struct device *dev = dev_id; #endif struct net_local *lp = (struct net_local *)dev->priv; int ioaddr, status; if (dev == NULL) { printk ("%s_interrupt(): irq %d for unknown device.\n", lp->cardtype, irq); return; } dev->interrupt = 1; ioaddr = dev->base_addr; /* Avoid multiple interrupts. */ outw(0x0000, ioaddr + TX_INTR); status = inw(ioaddr + TX_STATUS); outw(status, ioaddr + TX_STATUS); if (net_debug > 4) printk("%s: Interrupt with status %04x.\n", dev->name, status); if (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0) { /* Got a packet(s). */ net_rx(dev); } if (status & 0x00ff) { if (status & 0x80) { lp->stats.tx_packets++; if (lp->tx_queue) { outb(0x80 | lp->tx_queue, ioaddr + TX_START); lp->tx_queue = 0; lp->tx_queue_len = 0; dev->trans_start = jiffies; dev->tbusy = 0; mark_bh(NET_BH); /* Inform upper layers. */ } else { lp->tx_started = 0; dev->tbusy = 0; mark_bh(NET_BH); /* Inform upper layers. */ } } if (status & 0x02 ) { /* Stole from if_fe.c (NAGOYA) */ #ifdef MB86965_DEBUG /* Find how many packets (including this collided one) are left unsent in transmission buffer. */ int left = inb(ioaddr + TX_START); printk("%s: excessive collision (%d)\n", dev->name, left); #endif if (net_debug > 4) printk("%s: 16 Collision occur during Txing.\n", dev->name); /* Clear the collision flag (in 86960) here to avoid confusing statistics. */ outb(0x04, ioaddr + TX_STATUS); /* Restart Transmitter, skipping the collided packet. We *must* skip the packet to keep network running properly. Excessive collision error is an indication of the network overload. If we tried sending the same packet after excessive collision, the network would be filled with out-of-time packets. Packets belonging to reliable transport (such as TCP) are resent by some upper layer. */ outb(0x03, ioaddr + COL16CNTL); /* Update statistics */ lp->stats.collisions++; } } dev->interrupt = 0; outw(0x8182, ioaddr + TX_INTR); return; } /* We have a good packet(s), get it/them out of the buffers. */ static void net_rx(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; int boguscount = 10; /* 5 -> 10: by agy 19940922 */ while ((inb(ioaddr + RX_MODE) & 0x40) == 0) { /* Clear PKT_RDY bit: by agy 19940922 */ /* outb(0x80, ioaddr + RX_STATUS); */ ushort status = inw(ioaddr + DATAPORT); if (net_debug > 4) printk("%s: Rxing packet mode %02x status %04x.\n", dev->name, inb(ioaddr + RX_MODE), status); #ifndef final_version if (status == 0) { outb(0x05, ioaddr + 14); break; } #endif if ((status & 0xF0) != 0x20) { /* There was an error. */ lp->stats.rx_errors++; if (status & 0x08) lp->stats.rx_length_errors++; if (status & 0x04) lp->stats.rx_frame_errors++; if (status & 0x02) lp->stats.rx_crc_errors++; if (status & 0x01) lp->stats.rx_over_errors++; } else { ushort pkt_len = inw(ioaddr + DATAPORT); /* Malloc up new buffer. */ struct sk_buff *skb; if (pkt_len > 1550) { printk("%s: The fe claimed a very large packet, size %d.\n", dev->name, pkt_len); outb(0x05, ioaddr + 14); lp->stats.rx_errors++; break; } skb = dev_alloc_skb(pkt_len+3); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet (len %d).\n", dev->name, pkt_len); outb(0x05, ioaddr + 14); lp->stats.rx_dropped++; break; } skb->dev = dev; skb_reserve(skb,2); insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1); if (net_debug > 5) { int i; printk("%s: Rxed packet of length %d: ", dev->name, pkt_len); for (i = 0; i < 14; i++) printk(" %02x", skb->data[i]); printk(".\n"); } skb->protocol=eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; } if (--boguscount <= 0) break; } /* If any worth-while packets have been received, dev_rint() has done a mark_bh(NET_BH) for us and will work on them when we get to the bottom-half routine. */ { int i; for (i = 0; i < 20; i++) { if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40) break; (void)inw(ioaddr + DATAPORT); /* dummy status read */ outb(0x05, ioaddr + 14); } if (net_debug > 5 && i > 0) printk("%s: Exint Rx packet with mode %02x after %d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); } return; } /* The inverse routine to net_open(). */ static int net_close(struct device *dev) { int ioaddr = dev->base_addr; ((struct net_local *)dev->priv)->open_time = 0; dev->tbusy = 1; dev->start = 0; /* Set configuration register 0 to disable Tx and Rx. */ outb(0xda, ioaddr + CONFIG_0); /* Update the statistics -- ToDo. */ /* Power-down the chip. Green, green, green! */ outb(0x00, ioaddr + CONFIG_1); MOD_DEC_USE_COUNT; return 0; } /* Get the current statistics. This may be called with the card open or closed. */ static struct net_device_stats * net_get_stats(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; cli(); /* ToDo: Update the statistics from the device registers. */ sti(); return &lp->stats; } /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list num_addrs > 0 Multicast mode, receive normal and MC packets, and do best-effort filtering. */ static void set_multicast_list(struct device *dev) { short ioaddr = dev->base_addr; if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) { /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on * the cable. - AC */ dev->flags|=IFF_PROMISC; outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ } else outb(2, ioaddr + RX_MODE); /* Disable promiscuous, use normal mode */ } #ifdef MODULE static char devicename[9] = { 0, }; static struct device dev_mb86965 = { devicename, /* device name is inserted by linux/drivers/net/net_init.c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, mb86965_probe }; static int io = 0x260; static int irq = 0; static char module_name[] = "fmv18x/at1700"; #if (KERNEL_MAJOR_VERSION == 21) MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); #endif int init_module(void) { if (io == 0) printk("%s: You should not use auto-probing with insmod!\n", module_name); dev_mb86965.base_addr = io; dev_mb86965.irq = irq; if (register_netdev(&dev_mb86965) != 0) { printk("%s: register_netdev() returned non-zero.\n", module_name); return -EIO; } return 0; } void cleanup_module(void) { unregister_netdev(&dev_mb86965); kfree(dev_mb86965.priv); dev_mb86965.priv = NULL; /* If we don't do this, we can't re-insmod it later. */ #if (KERNEL_MAJOR_VERSION == 20) free_irq(dev_mb86965.irq, NULL); irq2dev_map[dev_mb86965.irq] = NULL; #elif (KERNEL_MAJOR_VERSION == 21) free_irq(dev_mb86965.irq, &dev_mb86965); #endif release_region(dev_mb86965.base_addr, MB86965_IO_EXTENT); } #endif /* MODULE */ /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c at1700.c" * version-control: t * kept-new-versions: 5 * tab-width: 4 * c-indent-level: 4 * End: */