📄 fmv18x.c
字号:
/* fmv18x.c: A network device driver for the Fujitsu FMV-181/182/183/184. Original: at1700.c (1993-94 by Donald Becker). Copyright 1993 United States Government as represented by the Director, National Security Agency. The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 Modified by Yutaka TAMIYA (tamy@flab.fujitsu.co.jp) Copyright 1994 Fujitsu Laboratories Ltd. Special thanks to: Masayoshi UTAKA (utaka@ace.yk.fujitsu.co.jp) for testing this driver. H. NEGISHI (agy, negishi@sun45.psd.cs.fujitsu.co.jp) for suggestion of some program modification. Masahiro SEKIGUCHI <seki@sysrap.cs.fujitsu.co.jp> for suggestion of some program modification. Kazutoshi MORIOKA (morioka@aurora.oaks.cs.fujitsu.co.jp) for testing this driver. 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 Fujitsu FMV-181/182/183/184, which is a straight-forward Fujitsu MB86965 implementation. Sources: at1700.c The Fujitsu MB86965 datasheet. The Fujitsu FMV-181/182 user's guide*/static const char *version = "fmv18x.c:v1.3.71e 03/04/96 Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)\n";#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>static int fmv18x_probe_list[] ={0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};/* use 0 for production, 1 for verification, >2 for debug */#ifndef NET_DEBUG#define NET_DEBUG 1#endifstatic unsigned int net_debug = NET_DEBUG;typedef unsigned char uchar;/* Information that need to be kept for each board. */struct net_local { struct enet_statistics 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. */};/* 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/* 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#define FMV18X_IO_EXTENT 32/* Index to functions, as function prototypes. */extern int fmv18x_probe(struct device *dev);static int fmv18x_probe1(struct device *dev, short ioaddr);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 enet_statistics *net_get_stats(struct device *dev);static void set_multicast_list(struct device *dev);/* 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 a alternate probe manager, which will eliminate the boilerplate below. */struct netdev_entry fmv18x_drv ={"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list};#elseintfmv18x_probe(struct device *dev){ int i; int base_addr = dev ? dev->base_addr : 0; if (base_addr > 0x1ff) /* Check a single specified location. */ return fmv18x_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ return ENXIO; for (i = 0; fmv18x_probe_list[i]; i++) { int ioaddr = fmv18x_probe_list[i]; if (check_region(ioaddr, FMV18X_IO_EXTENT)) continue; if (fmv18x_probe1(dev, ioaddr) == 0) 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. */int fmv18x_probe1(struct device *dev, short ioaddr){ char irqmap[4] = {3, 7, 10, 15}; unsigned int i, irq; /* 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, FMV18X_IO_EXTENT, "fmv18x"); printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name, ioaddr, irq); dev->base_addr = ioaddr; dev->irq = irq; irq2dev_map[irq] = dev; 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(0x00, ioaddr + FJ_CONFIG1); /* Disable 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(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;}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, and two 4K Tx, enable the Rx and Tx. */ 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 the IRQ of the LAN Card */ outb(0x80, ioaddr + FJ_CONFIG1); /* Enable both Tx and Rx interrupts */ outw(0x8182, ioaddr+TX_INTR); MOD_INC_USE_COUNT; return 0;}static intnet_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))); printk("eth card: %04x %04x\n", htons(inw(ioaddr+FJ_STATUS0)), htons(inw(ioaddr+FJ_CONFIG0)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -