forked from Minki/linux
drivers/net: delete 8390 based EISA drivers.
The NS8390 chip was essentially the 1st widespread PC ethernet chip, starting its life on 8 bit ISA cards in the late 1980s. Even with better technologies available (bus mastering etc) the 8390 managed to get used on a few rare EISA cards in the early to mid 1990s. The EISA bus in the x86 world was largely confined to systems ranging from 486 to 586 (essentially 200MHz or lower, and less than 100MB RAM) -- i.e. machines unlikely to be still in service, and even less likely to be running a 3.9+ kernel. On top of that, only one of the five really ever was considered non-experimental; the smc-ultra32 was the one -- since it was largely just an EISA version of the popular smc-ultra ISA card. All the others had such a tiny user base that they simply never could be considered anything more than experimental. Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
This commit is contained in:
parent
483f777266
commit
bca94cffab
@ -6,7 +6,7 @@ config NET_VENDOR_8390
|
||||
bool "National Semi-conductor 8390 devices"
|
||||
default y
|
||||
depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \
|
||||
ISA || EISA || MAC || M32R || MACH_TX49XX || \
|
||||
ISA || MAC || M32R || MACH_TX49XX || \
|
||||
H8300 || ARM || MIPS || ZORRO || PCMCIA || \
|
||||
EXPERIMENTAL)
|
||||
---help---
|
||||
@ -33,18 +33,6 @@ config EL2
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called 3c503.
|
||||
|
||||
config AC3200
|
||||
tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
|
||||
depends on PCI && (ISA || EISA) && EXPERIMENTAL
|
||||
select CRC32
|
||||
---help---
|
||||
If you have a network (Ethernet) card of this type, say Y and read
|
||||
the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called ac3200.
|
||||
|
||||
config PCMCIA_AXNET
|
||||
tristate "Asix AX88190 PCMCIA support"
|
||||
depends on PCMCIA
|
||||
@ -86,18 +74,6 @@ config E2100
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called e2100.
|
||||
|
||||
config ES3210
|
||||
tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
|
||||
depends on PCI && EISA && EXPERIMENTAL
|
||||
select CRC32
|
||||
---help---
|
||||
If you have a network (Ethernet) card of this type, say Y and read
|
||||
the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called es3210.
|
||||
|
||||
config HPLAN_PLUS
|
||||
tristate "HP PCLAN+ (27247B and 27252A) support"
|
||||
depends on ISA
|
||||
@ -140,18 +116,6 @@ config ARM_ETHERH
|
||||
If you have an Acorn system with one of these network cards, you
|
||||
should say Y to this option if you wish to use it with Linux.
|
||||
|
||||
config LNE390
|
||||
tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
|
||||
depends on PCI && EISA && EXPERIMENTAL
|
||||
select CRC32
|
||||
---help---
|
||||
If you have a network (Ethernet) card of this type, say Y and read
|
||||
the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called lne390.
|
||||
|
||||
config MAC8390
|
||||
bool "Macintosh NS 8390 based ethernet cards"
|
||||
depends on MAC
|
||||
@ -187,8 +151,7 @@ config NE2000
|
||||
without a specific driver are compatible with NE2000.
|
||||
|
||||
If you have a PCI NE2000 card however, say N here and Y to "PCI
|
||||
NE2000 and clone support" under "EISA, VLB, PCI and on board
|
||||
controllers" below.
|
||||
NE2000 and clone support" below.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called ne.
|
||||
@ -223,19 +186,6 @@ config APNE
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called apne.
|
||||
|
||||
config NE3210
|
||||
tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
|
||||
depends on PCI && EISA && EXPERIMENTAL
|
||||
select CRC32
|
||||
---help---
|
||||
If you have a network (Ethernet) card of this type, say Y and read
|
||||
the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>. Note that this driver
|
||||
will NOT WORK for NE3200 cards as they are completely different.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called ne3210.
|
||||
|
||||
config PCMCIA_PCNET
|
||||
tristate "NE2000 compatible PCMCIA support"
|
||||
depends on PCMCIA
|
||||
@ -285,18 +235,6 @@ config ULTRA
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called smc-ultra.
|
||||
|
||||
config ULTRA32
|
||||
tristate "SMC Ultra32 EISA support"
|
||||
depends on EISA
|
||||
select CRC32
|
||||
---help---
|
||||
If you have a network (Ethernet) card of this type, say Y and read
|
||||
the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called smc-ultra32.
|
||||
|
||||
config WD80x3
|
||||
tristate "WD80*3 support"
|
||||
depends on ISA
|
||||
|
@ -3,26 +3,21 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_MAC8390) += mac8390.o
|
||||
obj-$(CONFIG_AC3200) += ac3200.o 8390.o
|
||||
obj-$(CONFIG_APNE) += apne.o 8390.o
|
||||
obj-$(CONFIG_ARM_ETHERH) += etherh.o
|
||||
obj-$(CONFIG_AX88796) += ax88796.o
|
||||
obj-$(CONFIG_E2100) += e2100.o 8390.o
|
||||
obj-$(CONFIG_EL2) += 3c503.o 8390p.o
|
||||
obj-$(CONFIG_ES3210) += es3210.o 8390.o
|
||||
obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
|
||||
obj-$(CONFIG_HPLAN) += hp.o 8390p.o
|
||||
obj-$(CONFIG_HYDRA) += hydra.o 8390.o
|
||||
obj-$(CONFIG_LNE390) += lne390.o 8390.o
|
||||
obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o
|
||||
obj-$(CONFIG_NE2000) += ne.o 8390p.o
|
||||
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
|
||||
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
|
||||
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
|
||||
obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
|
||||
obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
|
||||
obj-$(CONFIG_STNIC) += stnic.o 8390.o
|
||||
obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
|
||||
obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
|
||||
obj-$(CONFIG_WD80x3) += wd.o 8390.o
|
||||
obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
|
||||
|
@ -1,431 +0,0 @@
|
||||
/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */
|
||||
/*
|
||||
Written 1993, 1994 by Donald Becker.
|
||||
Copyright 1993 United States Government as represented by the Director,
|
||||
National Security Agency. This software may only be used and distributed
|
||||
according to the terms of the GNU General Public License as modified by SRC,
|
||||
incorporated herein by reference.
|
||||
|
||||
The author may be reached as becker@scyld.com, or C/O
|
||||
Scyld Computing Corporation
|
||||
410 Severn Ave., Suite 210
|
||||
Annapolis MD 21403
|
||||
|
||||
This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN
|
||||
Adapter. The programming information is from the users manual, as related
|
||||
by glee@ardnassak.math.clemson.edu.
|
||||
|
||||
Changelog:
|
||||
|
||||
Paul Gortmaker 05/98 : add support for shared mem above 1MB.
|
||||
|
||||
*/
|
||||
|
||||
static const char version[] =
|
||||
"ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/eisa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "8390.h"
|
||||
|
||||
#define DRV_NAME "ac3200"
|
||||
|
||||
/* Offsets from the base address. */
|
||||
#define AC_NIC_BASE 0x00
|
||||
#define AC_SA_PROM 0x16 /* The station address PROM. */
|
||||
#define AC_ADDR0 0x00 /* Prefix station address values. */
|
||||
#define AC_ADDR1 0x40
|
||||
#define AC_ADDR2 0x90
|
||||
#define AC_ID_PORT 0xC80
|
||||
#define AC_EISA_ID 0x0110d305
|
||||
#define AC_RESET_PORT 0xC84
|
||||
#define AC_RESET 0x00
|
||||
#define AC_ENABLE 0x01
|
||||
#define AC_CONFIG 0xC90 /* The configuration port. */
|
||||
|
||||
#define AC_IO_EXTENT 0x20
|
||||
/* Actually accessed is:
|
||||
* AC_NIC_BASE (0-15)
|
||||
* AC_SA_PROM (0-5)
|
||||
* AC_ID_PORT (0-3)
|
||||
* AC_RESET_PORT
|
||||
* AC_CONFIG
|
||||
*/
|
||||
|
||||
/* Decoding of the configuration register. */
|
||||
static unsigned char config2irqmap[8] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
|
||||
static int addrmap[8] =
|
||||
{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000, 0xD0000, 0 };
|
||||
static const char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"};
|
||||
|
||||
#define config2irq(configval) config2irqmap[((configval) >> 3) & 7]
|
||||
#define config2mem(configval) addrmap[(configval) & 7]
|
||||
#define config2name(configval) port_name[((configval) >> 6) & 3]
|
||||
|
||||
/* First and last 8390 pages. */
|
||||
#define AC_START_PG 0x00 /* First page of 8390 TX buffer */
|
||||
#define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */
|
||||
|
||||
static int ac_probe1(int ioaddr, struct net_device *dev);
|
||||
|
||||
static int ac_open(struct net_device *dev);
|
||||
static void ac_reset_8390(struct net_device *dev);
|
||||
static void ac_block_input(struct net_device *dev, int count,
|
||||
struct sk_buff *skb, int ring_offset);
|
||||
static void ac_block_output(struct net_device *dev, const int count,
|
||||
const unsigned char *buf, const int start_page);
|
||||
static void ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
|
||||
int ring_page);
|
||||
|
||||
static int ac_close_card(struct net_device *dev);
|
||||
|
||||
|
||||
/* Probe for the AC3200.
|
||||
|
||||
The AC3200 can be identified by either the EISA configuration registers,
|
||||
or the unique value in the station address PROM.
|
||||
*/
|
||||
|
||||
static int __init do_ac3200_probe(struct net_device *dev)
|
||||
{
|
||||
unsigned short ioaddr = dev->base_addr;
|
||||
int irq = dev->irq;
|
||||
int mem_start = dev->mem_start;
|
||||
|
||||
if (ioaddr > 0x1ff) /* Check a single specified location. */
|
||||
return ac_probe1(ioaddr, dev);
|
||||
else if (ioaddr > 0) /* Don't probe at all. */
|
||||
return -ENXIO;
|
||||
|
||||
if ( ! EISA_bus)
|
||||
return -ENXIO;
|
||||
|
||||
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
|
||||
if (ac_probe1(ioaddr, dev) == 0)
|
||||
return 0;
|
||||
dev->irq = irq;
|
||||
dev->mem_start = mem_start;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifndef MODULE
|
||||
struct net_device * __init ac3200_probe(int unit)
|
||||
{
|
||||
struct net_device *dev = alloc_ei_netdev();
|
||||
int err;
|
||||
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sprintf(dev->name, "eth%d", unit);
|
||||
netdev_boot_setup_check(dev);
|
||||
|
||||
err = do_ac3200_probe(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
return dev;
|
||||
out:
|
||||
free_netdev(dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct net_device_ops ac_netdev_ops = {
|
||||
.ndo_open = ac_open,
|
||||
.ndo_stop = ac_close_card,
|
||||
|
||||
.ndo_start_xmit = ei_start_xmit,
|
||||
.ndo_tx_timeout = ei_tx_timeout,
|
||||
.ndo_get_stats = ei_get_stats,
|
||||
.ndo_set_rx_mode = ei_set_multicast_list,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = ei_poll,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ac_probe1(int ioaddr, struct net_device *dev)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
|
||||
return -EBUSY;
|
||||
|
||||
if (inb_p(ioaddr + AC_ID_PORT) == 0xff) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef final_version
|
||||
printk(KERN_DEBUG "AC3200 ethercard configuration register is %#02x,"
|
||||
" EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG),
|
||||
inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1),
|
||||
inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
|
||||
|
||||
printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM",
|
||||
ioaddr/0x1000, dev->dev_addr);
|
||||
#if 0
|
||||
/* Check the vendor ID/prefix. Redundant after checking the EISA ID */
|
||||
if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
|
||||
|| inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1
|
||||
|| inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) {
|
||||
printk(", not found (invalid prefix).\n");
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Assign and allocate the interrupt now. */
|
||||
if (dev->irq == 0) {
|
||||
dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
|
||||
printk(", using");
|
||||
} else {
|
||||
dev->irq = irq_canonicalize(dev->irq);
|
||||
printk(", assigning");
|
||||
}
|
||||
|
||||
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
|
||||
if (retval) {
|
||||
printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
|
||||
|
||||
dev->base_addr = ioaddr;
|
||||
|
||||
#ifdef notyet
|
||||
if (dev->mem_start) { /* Override the value from the board. */
|
||||
for (i = 0; i < 7; i++)
|
||||
if (addrmap[i] == dev->mem_start)
|
||||
break;
|
||||
if (i >= 7)
|
||||
i = 0;
|
||||
outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG);
|
||||
}
|
||||
#endif
|
||||
|
||||
dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
|
||||
dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
|
||||
|
||||
printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
|
||||
dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
|
||||
|
||||
/*
|
||||
* BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
|
||||
* the card mem within the region covered by `normal' RAM !!!
|
||||
*
|
||||
* ioremap() will fail in that case.
|
||||
*/
|
||||
ei_status.mem = ioremap(dev->mem_start, AC_STOP_PG*0x100);
|
||||
if (!ei_status.mem) {
|
||||
printk(KERN_ERR "ac3200.c: Unable to remap card memory above 1MB !!\n");
|
||||
printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n");
|
||||
printk(KERN_ERR "ac3200.c: Driver NOT installed.\n");
|
||||
retval = -EINVAL;
|
||||
goto out1;
|
||||
}
|
||||
printk("ac3200.c: remapped %dkB card memory to virtual address %p\n",
|
||||
AC_STOP_PG/4, ei_status.mem);
|
||||
|
||||
dev->mem_start = (unsigned long)ei_status.mem;
|
||||
dev->mem_end = dev->mem_start + (AC_STOP_PG - AC_START_PG)*256;
|
||||
|
||||
ei_status.name = "AC3200";
|
||||
ei_status.tx_start_page = AC_START_PG;
|
||||
ei_status.rx_start_page = AC_START_PG + TX_PAGES;
|
||||
ei_status.stop_page = AC_STOP_PG;
|
||||
ei_status.word16 = 1;
|
||||
|
||||
if (ei_debug > 0)
|
||||
printk(version);
|
||||
|
||||
ei_status.reset_8390 = &ac_reset_8390;
|
||||
ei_status.block_input = &ac_block_input;
|
||||
ei_status.block_output = &ac_block_output;
|
||||
ei_status.get_8390_hdr = &ac_get_8390_hdr;
|
||||
|
||||
dev->netdev_ops = &ac_netdev_ops;
|
||||
NS8390_init(dev, 0);
|
||||
|
||||
retval = register_netdev(dev);
|
||||
if (retval)
|
||||
goto out2;
|
||||
return 0;
|
||||
out2:
|
||||
if (ei_status.reg0)
|
||||
iounmap(ei_status.mem);
|
||||
out1:
|
||||
free_irq(dev->irq, dev);
|
||||
out:
|
||||
release_region(ioaddr, AC_IO_EXTENT);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ac_open(struct net_device *dev)
|
||||
{
|
||||
#ifdef notyet
|
||||
/* Someday we may enable the IRQ and shared memory here. */
|
||||
int ioaddr = dev->base_addr;
|
||||
#endif
|
||||
|
||||
ei_open(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ac_reset_8390(struct net_device *dev)
|
||||
{
|
||||
ushort ioaddr = dev->base_addr;
|
||||
|
||||
outb(AC_RESET, ioaddr + AC_RESET_PORT);
|
||||
if (ei_debug > 1) printk("resetting AC3200, t=%ld...", jiffies);
|
||||
|
||||
ei_status.txing = 0;
|
||||
outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
|
||||
if (ei_debug > 1) printk("reset done\n");
|
||||
}
|
||||
|
||||
/* Grab the 8390 specific header. Similar to the block_input routine, but
|
||||
we don't need to be concerned with ring wrap as the header will be at
|
||||
the start of a page, so we optimize accordingly. */
|
||||
|
||||
static void
|
||||
ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
|
||||
{
|
||||
void __iomem *hdr_start = ei_status.mem + ((ring_page - AC_START_PG)<<8);
|
||||
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
|
||||
}
|
||||
|
||||
/* Block input and output are easy on shared memory ethercards, the only
|
||||
complication is when the ring buffer wraps. */
|
||||
|
||||
static void ac_block_input(struct net_device *dev, int count, struct sk_buff *skb,
|
||||
int ring_offset)
|
||||
{
|
||||
void __iomem *start = ei_status.mem + ring_offset - AC_START_PG*256;
|
||||
|
||||
if (ring_offset + count > AC_STOP_PG*256) {
|
||||
/* We must wrap the input move. */
|
||||
int semi_count = AC_STOP_PG*256 - ring_offset;
|
||||
memcpy_fromio(skb->data, start, semi_count);
|
||||
count -= semi_count;
|
||||
memcpy_fromio(skb->data + semi_count,
|
||||
ei_status.mem + TX_PAGES*256, count);
|
||||
} else {
|
||||
memcpy_fromio(skb->data, start, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void ac_block_output(struct net_device *dev, int count,
|
||||
const unsigned char *buf, int start_page)
|
||||
{
|
||||
void __iomem *shmem = ei_status.mem + ((start_page - AC_START_PG)<<8);
|
||||
|
||||
memcpy_toio(shmem, buf, count);
|
||||
}
|
||||
|
||||
static int ac_close_card(struct net_device *dev)
|
||||
{
|
||||
if (ei_debug > 1)
|
||||
printk("%s: Shutting down ethercard.\n", dev->name);
|
||||
|
||||
#ifdef notyet
|
||||
/* We should someday disable shared memory and interrupts. */
|
||||
outb(0x00, ioaddr + 6); /* Disable interrupts. */
|
||||
free_irq(dev->irq, dev);
|
||||
#endif
|
||||
|
||||
ei_close(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
#define MAX_AC32_CARDS 4 /* Max number of AC32 cards per module */
|
||||
static struct net_device *dev_ac32[MAX_AC32_CARDS];
|
||||
static int io[MAX_AC32_CARDS];
|
||||
static int irq[MAX_AC32_CARDS];
|
||||
static int mem[MAX_AC32_CARDS];
|
||||
module_param_array(io, int, NULL, 0);
|
||||
module_param_array(irq, int, NULL, 0);
|
||||
module_param_array(mem, int, NULL, 0);
|
||||
MODULE_PARM_DESC(io, "I/O base address(es)");
|
||||
MODULE_PARM_DESC(irq, "IRQ number(s)");
|
||||
MODULE_PARM_DESC(mem, "Memory base address(es)");
|
||||
MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int __init ac3200_module_init(void)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int this_dev, found = 0;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
|
||||
if (io[this_dev] == 0 && this_dev != 0)
|
||||
break;
|
||||
dev = alloc_ei_netdev();
|
||||
if (!dev)
|
||||
break;
|
||||
dev->irq = irq[this_dev];
|
||||
dev->base_addr = io[this_dev];
|
||||
dev->mem_start = mem[this_dev]; /* Currently ignored by driver */
|
||||
if (do_ac3200_probe(dev) == 0) {
|
||||
dev_ac32[found++] = dev;
|
||||
continue;
|
||||
}
|
||||
free_netdev(dev);
|
||||
printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
return 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static void cleanup_card(struct net_device *dev)
|
||||
{
|
||||
/* Someday free_irq may be in ac_close_card() */
|
||||
free_irq(dev->irq, dev);
|
||||
release_region(dev->base_addr, AC_IO_EXTENT);
|
||||
iounmap(ei_status.mem);
|
||||
}
|
||||
|
||||
static void __exit ac3200_module_exit(void)
|
||||
{
|
||||
int this_dev;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
|
||||
struct net_device *dev = dev_ac32[this_dev];
|
||||
if (dev) {
|
||||
unregister_netdev(dev);
|
||||
cleanup_card(dev);
|
||||
free_netdev(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
module_init(ac3200_module_init);
|
||||
module_exit(ac3200_module_exit);
|
||||
#endif /* MODULE */
|
@ -1,445 +0,0 @@
|
||||
/*
|
||||
es3210.c
|
||||
|
||||
Linux driver for Racal-Interlan ES3210 EISA Network Adapter
|
||||
|
||||
Copyright (C) 1996, Paul Gortmaker.
|
||||
|
||||
This software may be used and distributed according to the terms
|
||||
of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
Information and Code Sources:
|
||||
|
||||
1) The existing myriad of Linux 8390 drivers written by Donald Becker.
|
||||
|
||||
2) Once again Russ Nelson's asm packet driver provided additional info.
|
||||
|
||||
3) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
|
||||
Too bad it doesn't work -- see below.
|
||||
|
||||
The ES3210 is an EISA shared memory NS8390 implementation. Note
|
||||
that all memory copies to/from the board must be 32bit transfers.
|
||||
Which rules out using eth_io_copy_and_sum() in this driver.
|
||||
|
||||
Apparently there are two slightly different revisions of the
|
||||
card, since there are two distinct EISA cfg files (!rii0101.cfg
|
||||
and !rii0102.cfg) One has media select in the cfg file and the
|
||||
other doesn't. Hopefully this will work with either.
|
||||
|
||||
That is about all I can tell you about it, having never actually
|
||||
even seen one of these cards. :) Try http://www.interlan.com
|
||||
if you want more info.
|
||||
|
||||
Thanks go to Mark Salazar for testing v0.02 of this driver.
|
||||
|
||||
Bugs, to-fix, etc:
|
||||
|
||||
1) The EISA cfg ports that are *supposed* to have the IRQ and shared
|
||||
mem values just read 0xff all the time. Hrrmpf. Apparently the
|
||||
same happens with the packet driver as the code for reading
|
||||
these registers is disabled there. In the meantime, boot with:
|
||||
ether=<IRQ>,0,0x<shared_mem_addr>,eth0 to override the IRQ and
|
||||
shared memory detection. (The i/o port detection is okay.)
|
||||
|
||||
2) Module support currently untested. Probably works though.
|
||||
|
||||
*/
|
||||
|
||||
static const char version[] =
|
||||
"es3210.c: Driver revision v0.03, 14/09/96\n";
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/eisa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "8390.h"
|
||||
|
||||
static int es_probe1(struct net_device *dev, int ioaddr);
|
||||
|
||||
static void es_reset_8390(struct net_device *dev);
|
||||
|
||||
static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
|
||||
static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
|
||||
static void es_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page);
|
||||
|
||||
#define ES_START_PG 0x00 /* First page of TX buffer */
|
||||
#define ES_STOP_PG 0x40 /* Last page +1 of RX ring */
|
||||
|
||||
#define ES_IO_EXTENT 0x37 /* The cfg file says 0xc90 -> 0xcc7 */
|
||||
#define ES_ID_PORT 0xc80 /* Same for all EISA cards */
|
||||
#define ES_SA_PROM 0xc90 /* Start of e'net addr. */
|
||||
#define ES_RESET_PORT 0xc84 /* From the packet driver source */
|
||||
#define ES_NIC_OFFSET 0xca0 /* Hello, the 8390 is *here* */
|
||||
|
||||
#define ES_ADDR0 0x02 /* 3 byte vendor prefix */
|
||||
#define ES_ADDR1 0x07
|
||||
#define ES_ADDR2 0x01
|
||||
|
||||
/*
|
||||
* Two card revisions. EISA ID's are always rev. minor, rev. major,, and
|
||||
* then the three vendor letters stored in 5 bits each, with an "a" = 1.
|
||||
* For eg: "rii" = 10010 01001 01001 = 0x4929, which is how the EISA
|
||||
* config utility determines automagically what config file(s) to use.
|
||||
*/
|
||||
#define ES_EISA_ID1 0x01012949 /* !rii0101.cfg */
|
||||
#define ES_EISA_ID2 0x02012949 /* !rii0102.cfg */
|
||||
|
||||
#define ES_CFG1 0xcc0 /* IOPORT(1) --> IOPORT(6) in cfg file */
|
||||
#define ES_CFG2 0xcc1
|
||||
#define ES_CFG3 0xcc2
|
||||
#define ES_CFG4 0xcc3
|
||||
#define ES_CFG5 0xcc4
|
||||
#define ES_CFG6 0xc84 /* NB: 0xc84 is also "reset" port. */
|
||||
|
||||
/*
|
||||
* You can OR any of the following bits together and assign it
|
||||
* to ES_DEBUG to get verbose driver info during operation.
|
||||
* Some of these don't do anything yet.
|
||||
*/
|
||||
|
||||
#define ES_D_PROBE 0x01
|
||||
#define ES_D_RX_PKT 0x02
|
||||
#define ES_D_TX_PKT 0x04
|
||||
#define ED_D_IRQ 0x08
|
||||
|
||||
#define ES_DEBUG 0
|
||||
|
||||
static unsigned char lo_irq_map[] __initdata = {3, 4, 5, 6, 7, 9, 10};
|
||||
static unsigned char hi_irq_map[] __initdata = {11, 12, 0, 14, 0, 0, 0, 15};
|
||||
|
||||
/*
|
||||
* Probe for the card. The best way is to read the EISA ID if it
|
||||
* is known. Then we check the prefix of the station address
|
||||
* PROM for a match against the Racal-Interlan assigned value.
|
||||
*/
|
||||
|
||||
static int __init do_es_probe(struct net_device *dev)
|
||||
{
|
||||
unsigned short ioaddr = dev->base_addr;
|
||||
int irq = dev->irq;
|
||||
int mem_start = dev->mem_start;
|
||||
|
||||
if (ioaddr > 0x1ff) /* Check a single specified location. */
|
||||
return es_probe1(dev, ioaddr);
|
||||
else if (ioaddr > 0) /* Don't probe at all. */
|
||||
return -ENXIO;
|
||||
|
||||
if (!EISA_bus) {
|
||||
#if ES_DEBUG & ES_D_PROBE
|
||||
printk("es3210.c: Not EISA bus. Not probing high ports.\n");
|
||||
#endif
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* EISA spec allows for up to 16 slots, but 8 is typical. */
|
||||
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
|
||||
if (es_probe1(dev, ioaddr) == 0)
|
||||
return 0;
|
||||
dev->irq = irq;
|
||||
dev->mem_start = mem_start;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifndef MODULE
|
||||
struct net_device * __init es_probe(int unit)
|
||||
{
|
||||
struct net_device *dev = alloc_ei_netdev();
|
||||
int err;
|
||||
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sprintf(dev->name, "eth%d", unit);
|
||||
netdev_boot_setup_check(dev);
|
||||
|
||||
err = do_es_probe(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
return dev;
|
||||
out:
|
||||
free_netdev(dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init es_probe1(struct net_device *dev, int ioaddr)
|
||||
{
|
||||
int i, retval;
|
||||
unsigned long eisa_id;
|
||||
|
||||
if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
|
||||
return -ENODEV;
|
||||
|
||||
#if ES_DEBUG & ES_D_PROBE
|
||||
printk("es3210.c: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + ES_ID_PORT));
|
||||
printk("es3210.c: config regs: %#x %#x %#x %#x %#x %#x\n",
|
||||
inb(ioaddr + ES_CFG1), inb(ioaddr + ES_CFG2), inb(ioaddr + ES_CFG3),
|
||||
inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
|
||||
#endif
|
||||
|
||||
/* Check the EISA ID of the card. */
|
||||
eisa_id = inl(ioaddr + ES_ID_PORT);
|
||||
if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ETH_ALEN ; i++)
|
||||
dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
|
||||
|
||||
/* Check the Racal vendor ID as well. */
|
||||
if (dev->dev_addr[0] != ES_ADDR0 ||
|
||||
dev->dev_addr[1] != ES_ADDR1 ||
|
||||
dev->dev_addr[2] != ES_ADDR2) {
|
||||
printk("es3210.c: card not found %pM (invalid_prefix).\n",
|
||||
dev->dev_addr);
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk("es3210.c: ES3210 rev. %ld at %#x, node %pM",
|
||||
eisa_id>>24, ioaddr, dev->dev_addr);
|
||||
|
||||
/* Snarf the interrupt now. */
|
||||
if (dev->irq == 0) {
|
||||
unsigned char hi_irq = inb(ioaddr + ES_CFG2) & 0x07;
|
||||
unsigned char lo_irq = inb(ioaddr + ES_CFG1) & 0xfe;
|
||||
|
||||
if (hi_irq != 0) {
|
||||
dev->irq = hi_irq_map[hi_irq - 1];
|
||||
} else {
|
||||
int i = 0;
|
||||
while (lo_irq > (1<<i)) i++;
|
||||
dev->irq = lo_irq_map[i];
|
||||
}
|
||||
printk(" using IRQ %d", dev->irq);
|
||||
#if ES_DEBUG & ES_D_PROBE
|
||||
printk("es3210.c: hi_irq %#x, lo_irq %#x, dev->irq = %d\n",
|
||||
hi_irq, lo_irq, dev->irq);
|
||||
#endif
|
||||
} else {
|
||||
if (dev->irq == 2)
|
||||
dev->irq = 9; /* Doh! */
|
||||
printk(" assigning IRQ %d", dev->irq);
|
||||
}
|
||||
|
||||
if (request_irq(dev->irq, ei_interrupt, 0, "es3210", dev)) {
|
||||
printk (" unable to get IRQ %d.\n", dev->irq);
|
||||
retval = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev->mem_start == 0) {
|
||||
unsigned char mem_enabled = inb(ioaddr + ES_CFG2) & 0xc0;
|
||||
unsigned char mem_bits = inb(ioaddr + ES_CFG3) & 0x07;
|
||||
|
||||
if (mem_enabled != 0x80) {
|
||||
printk(" shared mem disabled - giving up\n");
|
||||
retval = -ENXIO;
|
||||
goto out1;
|
||||
}
|
||||
dev->mem_start = 0xC0000 + mem_bits*0x4000;
|
||||
printk(" using ");
|
||||
} else {
|
||||
printk(" assigning ");
|
||||
}
|
||||
|
||||
ei_status.mem = ioremap(dev->mem_start, (ES_STOP_PG - ES_START_PG)*256);
|
||||
if (!ei_status.mem) {
|
||||
printk("ioremap failed - giving up\n");
|
||||
retval = -ENXIO;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
dev->mem_end = dev->mem_start + (ES_STOP_PG - ES_START_PG)*256;
|
||||
|
||||
printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
|
||||
|
||||
#if ES_DEBUG & ES_D_PROBE
|
||||
if (inb(ioaddr + ES_CFG5))
|
||||
printk("es3210: Warning - DMA channel enabled, but not used here.\n");
|
||||
#endif
|
||||
/* Note, point at the 8390, and not the card... */
|
||||
dev->base_addr = ioaddr + ES_NIC_OFFSET;
|
||||
|
||||
ei_status.name = "ES3210";
|
||||
ei_status.tx_start_page = ES_START_PG;
|
||||
ei_status.rx_start_page = ES_START_PG + TX_PAGES;
|
||||
ei_status.stop_page = ES_STOP_PG;
|
||||
ei_status.word16 = 1;
|
||||
|
||||
if (ei_debug > 0)
|
||||
printk(version);
|
||||
|
||||
ei_status.reset_8390 = &es_reset_8390;
|
||||
ei_status.block_input = &es_block_input;
|
||||
ei_status.block_output = &es_block_output;
|
||||
ei_status.get_8390_hdr = &es_get_8390_hdr;
|
||||
|
||||
dev->netdev_ops = &ei_netdev_ops;
|
||||
NS8390_init(dev, 0);
|
||||
|
||||
retval = register_netdev(dev);
|
||||
if (retval)
|
||||
goto out1;
|
||||
return 0;
|
||||
out1:
|
||||
free_irq(dev->irq, dev);
|
||||
out:
|
||||
release_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset as per the packet driver method. Judging by the EISA cfg
|
||||
* file, this just toggles the "Board Enable" bits (bit 2 and 0).
|
||||
*/
|
||||
|
||||
static void es_reset_8390(struct net_device *dev)
|
||||
{
|
||||
unsigned short ioaddr = dev->base_addr;
|
||||
unsigned long end;
|
||||
|
||||
outb(0x04, ioaddr + ES_RESET_PORT);
|
||||
if (ei_debug > 1) printk("%s: resetting the ES3210...", dev->name);
|
||||
|
||||
end = jiffies + 2*HZ/100;
|
||||
while ((signed)(end - jiffies) > 0) continue;
|
||||
|
||||
ei_status.txing = 0;
|
||||
outb(0x01, ioaddr + ES_RESET_PORT);
|
||||
if (ei_debug > 1) printk("reset done\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: In the following three functions is the implicit assumption
|
||||
* that the associated memcpy will only use "rep; movsl" as long as
|
||||
* we keep the counts as some multiple of doublewords. This is a
|
||||
* requirement of the hardware, and also prevents us from using
|
||||
* eth_io_copy_and_sum() since we can't guarantee it will limit
|
||||
* itself to doubleword access.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Grab the 8390 specific header. Similar to the block_input routine, but
|
||||
* we don't need to be concerned with ring wrap as the header will be at
|
||||
* the start of a page, so we optimize accordingly. (A single doubleword.)
|
||||
*/
|
||||
|
||||
static void
|
||||
es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
|
||||
{
|
||||
void __iomem *hdr_start = ei_status.mem + ((ring_page - ES_START_PG)<<8);
|
||||
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
|
||||
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Block input and output are easy on shared memory ethercards, the only
|
||||
* complication is when the ring buffer wraps. The count will already
|
||||
* be rounded up to a doubleword value via es_get_8390_hdr() above.
|
||||
*/
|
||||
|
||||
static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb,
|
||||
int ring_offset)
|
||||
{
|
||||
void __iomem *xfer_start = ei_status.mem + ring_offset - ES_START_PG*256;
|
||||
|
||||
if (ring_offset + count > ES_STOP_PG*256) {
|
||||
/* Packet wraps over end of ring buffer. */
|
||||
int semi_count = ES_STOP_PG*256 - ring_offset;
|
||||
memcpy_fromio(skb->data, xfer_start, semi_count);
|
||||
count -= semi_count;
|
||||
memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
|
||||
} else {
|
||||
/* Packet is in one chunk. */
|
||||
memcpy_fromio(skb->data, xfer_start, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void es_block_output(struct net_device *dev, int count,
|
||||
const unsigned char *buf, int start_page)
|
||||
{
|
||||
void __iomem *shmem = ei_status.mem + ((start_page - ES_START_PG)<<8);
|
||||
|
||||
count = (count + 3) & ~3; /* Round up to doubleword */
|
||||
memcpy_toio(shmem, buf, count);
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
#define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */
|
||||
#define NAMELEN 8 /* # of chars for storing dev->name */
|
||||
static struct net_device *dev_es3210[MAX_ES_CARDS];
|
||||
static int io[MAX_ES_CARDS];
|
||||
static int irq[MAX_ES_CARDS];
|
||||
static int mem[MAX_ES_CARDS];
|
||||
|
||||
module_param_array(io, int, NULL, 0);
|
||||
module_param_array(irq, int, NULL, 0);
|
||||
module_param_array(mem, int, NULL, 0);
|
||||
MODULE_PARM_DESC(io, "I/O base address(es)");
|
||||
MODULE_PARM_DESC(irq, "IRQ number(s)");
|
||||
MODULE_PARM_DESC(mem, "memory base address(es)");
|
||||
MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
int __init init_module(void)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int this_dev, found = 0;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
|
||||
if (io[this_dev] == 0 && this_dev != 0)
|
||||
break;
|
||||
dev = alloc_ei_netdev();
|
||||
if (!dev)
|
||||
break;
|
||||
dev->irq = irq[this_dev];
|
||||
dev->base_addr = io[this_dev];
|
||||
dev->mem_start = mem[this_dev];
|
||||
if (do_es_probe(dev) == 0) {
|
||||
dev_es3210[found++] = dev;
|
||||
continue;
|
||||
}
|
||||
free_netdev(dev);
|
||||
printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
return 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static void cleanup_card(struct net_device *dev)
|
||||
{
|
||||
free_irq(dev->irq, dev);
|
||||
release_region(dev->base_addr, ES_IO_EXTENT);
|
||||
iounmap(ei_status.mem);
|
||||
}
|
||||
|
||||
void __exit
|
||||
cleanup_module(void)
|
||||
{
|
||||
int this_dev;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
|
||||
struct net_device *dev = dev_es3210[this_dev];
|
||||
if (dev) {
|
||||
unregister_netdev(dev);
|
||||
cleanup_card(dev);
|
||||
free_netdev(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* MODULE */
|
||||
|
@ -1,433 +0,0 @@
|
||||
/*
|
||||
lne390.c
|
||||
|
||||
Linux driver for Mylex LNE390 EISA Network Adapter
|
||||
|
||||
Copyright (C) 1996-1998, Paul Gortmaker.
|
||||
|
||||
This software may be used and distributed according to the terms
|
||||
of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
Information and Code Sources:
|
||||
|
||||
1) Based upon framework of es3210 driver.
|
||||
2) The existing myriad of other Linux 8390 drivers by Donald Becker.
|
||||
3) Russ Nelson's asm packet driver provided additional info.
|
||||
4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
|
||||
|
||||
The LNE390 is an EISA shared memory NS8390 implementation. Note
|
||||
that all memory copies to/from the board must be 32bit transfers.
|
||||
There are two versions of the card: the lne390a and the lne390b.
|
||||
Going by the EISA cfg files, the "a" has jumpers to select between
|
||||
BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU.
|
||||
The shared memory address selection is also slightly different.
|
||||
Note that shared memory address > 1MB are supported with this driver.
|
||||
|
||||
You can try <http://www.mylex.com> if you want more info, as I've
|
||||
never even seen one of these cards. :)
|
||||
|
||||
Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/01
|
||||
- get rid of check_region
|
||||
- no need to check if dev == NULL in lne390_probe1
|
||||
*/
|
||||
|
||||
static const char *version =
|
||||
"lne390.c: Driver revision v0.99.1, 01/09/2000\n";
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/eisa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "8390.h"
|
||||
|
||||
#define DRV_NAME "lne390"
|
||||
|
||||
static int lne390_probe1(struct net_device *dev, int ioaddr);
|
||||
|
||||
static void lne390_reset_8390(struct net_device *dev);
|
||||
|
||||
static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
|
||||
static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
|
||||
static void lne390_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
|
||||
|
||||
#define LNE390_START_PG 0x00 /* First page of TX buffer */
|
||||
#define LNE390_STOP_PG 0x80 /* Last page +1 of RX ring */
|
||||
|
||||
#define LNE390_ID_PORT 0xc80 /* Same for all EISA cards */
|
||||
#define LNE390_IO_EXTENT 0x20
|
||||
#define LNE390_SA_PROM 0x16 /* Start of e'net addr. */
|
||||
#define LNE390_RESET_PORT 0xc84 /* From the pkt driver source */
|
||||
#define LNE390_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
|
||||
|
||||
#define LNE390_ADDR0 0x00 /* 3 byte vendor prefix */
|
||||
#define LNE390_ADDR1 0x80
|
||||
#define LNE390_ADDR2 0xe5
|
||||
|
||||
#define LNE390_ID0 0x10009835 /* 0x3598 = 01101 01100 11000 = mlx */
|
||||
#define LNE390_ID1 0x11009835 /* above is the 390A, this is 390B */
|
||||
|
||||
#define LNE390_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
|
||||
#define LNE390_CFG2 0xc90
|
||||
|
||||
/*
|
||||
* You can OR any of the following bits together and assign it
|
||||
* to LNE390_DEBUG to get verbose driver info during operation.
|
||||
* Currently only the probe one is implemented.
|
||||
*/
|
||||
|
||||
#define LNE390_D_PROBE 0x01
|
||||
#define LNE390_D_RX_PKT 0x02
|
||||
#define LNE390_D_TX_PKT 0x04
|
||||
#define LNE390_D_IRQ 0x08
|
||||
|
||||
#define LNE390_DEBUG 0
|
||||
|
||||
static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
|
||||
static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
|
||||
static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
|
||||
|
||||
/*
|
||||
* Probe for the card. The best way is to read the EISA ID if it
|
||||
* is known. Then we can check the prefix of the station address
|
||||
* PROM for a match against the value assigned to Mylex.
|
||||
*/
|
||||
|
||||
static int __init do_lne390_probe(struct net_device *dev)
|
||||
{
|
||||
unsigned short ioaddr = dev->base_addr;
|
||||
int irq = dev->irq;
|
||||
int mem_start = dev->mem_start;
|
||||
int ret;
|
||||
|
||||
if (ioaddr > 0x1ff) { /* Check a single specified location. */
|
||||
if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
|
||||
return -EBUSY;
|
||||
ret = lne390_probe1(dev, ioaddr);
|
||||
if (ret)
|
||||
release_region(ioaddr, LNE390_IO_EXTENT);
|
||||
return ret;
|
||||
}
|
||||
else if (ioaddr > 0) /* Don't probe at all. */
|
||||
return -ENXIO;
|
||||
|
||||
if (!EISA_bus) {
|
||||
#if LNE390_DEBUG & LNE390_D_PROBE
|
||||
printk("lne390-debug: Not an EISA bus. Not probing high ports.\n");
|
||||
#endif
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* EISA spec allows for up to 16 slots, but 8 is typical. */
|
||||
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
|
||||
if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
|
||||
continue;
|
||||
if (lne390_probe1(dev, ioaddr) == 0)
|
||||
return 0;
|
||||
release_region(ioaddr, LNE390_IO_EXTENT);
|
||||
dev->irq = irq;
|
||||
dev->mem_start = mem_start;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifndef MODULE
|
||||
struct net_device * __init lne390_probe(int unit)
|
||||
{
|
||||
struct net_device *dev = alloc_ei_netdev();
|
||||
int err;
|
||||
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sprintf(dev->name, "eth%d", unit);
|
||||
netdev_boot_setup_check(dev);
|
||||
|
||||
err = do_lne390_probe(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
return dev;
|
||||
out:
|
||||
free_netdev(dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init lne390_probe1(struct net_device *dev, int ioaddr)
|
||||
{
|
||||
int i, revision, ret;
|
||||
unsigned long eisa_id;
|
||||
|
||||
if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
|
||||
|
||||
#if LNE390_DEBUG & LNE390_D_PROBE
|
||||
printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT));
|
||||
printk("lne390-debug: config regs: %#x %#x\n",
|
||||
inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2));
|
||||
#endif
|
||||
|
||||
|
||||
/* Check the EISA ID of the card. */
|
||||
eisa_id = inl(ioaddr + LNE390_ID_PORT);
|
||||
if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */
|
||||
|
||||
#if 0
|
||||
/* Check the Mylex vendor ID as well. Not really required. */
|
||||
if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
|
||||
|| inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
|
||||
|| inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
|
||||
printk("lne390.c: card not found");
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
|
||||
printk(" (invalid prefix).\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
|
||||
printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
|
||||
0xa+revision, ioaddr/0x1000, dev->dev_addr);
|
||||
|
||||
printk("lne390.c: ");
|
||||
|
||||
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
|
||||
if (dev->irq == 0) {
|
||||
unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3;
|
||||
dev->irq = irq_map[irq_reg & 0x07];
|
||||
printk("using");
|
||||
} else {
|
||||
/* This is useless unless we reprogram the card here too */
|
||||
if (dev->irq == 2) dev->irq = 9; /* Doh! */
|
||||
printk("assigning");
|
||||
}
|
||||
printk(" IRQ %d,", dev->irq);
|
||||
|
||||
if ((ret = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) {
|
||||
printk (" unable to get IRQ %d.\n", dev->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dev->mem_start == 0) {
|
||||
unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07;
|
||||
|
||||
if (revision) /* LNE390B */
|
||||
dev->mem_start = shmem_mapB[mem_reg] * 0x10000;
|
||||
else /* LNE390A */
|
||||
dev->mem_start = shmem_mapA[mem_reg] * 0x10000;
|
||||
printk(" using ");
|
||||
} else {
|
||||
/* Should check for value in shmem_map and reprogram the card to use it */
|
||||
dev->mem_start &= 0xfff0000;
|
||||
printk(" assigning ");
|
||||
}
|
||||
|
||||
printk("%dkB memory at physical address %#lx\n",
|
||||
LNE390_STOP_PG/4, dev->mem_start);
|
||||
|
||||
/*
|
||||
BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
|
||||
the card mem within the region covered by `normal' RAM !!!
|
||||
|
||||
ioremap() will fail in that case.
|
||||
*/
|
||||
ei_status.mem = ioremap(dev->mem_start, LNE390_STOP_PG*0x100);
|
||||
if (!ei_status.mem) {
|
||||
printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n");
|
||||
printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n");
|
||||
printk(KERN_ERR "lne390.c: Driver NOT installed.\n");
|
||||
ret = -EAGAIN;
|
||||
goto cleanup;
|
||||
}
|
||||
printk("lne390.c: remapped %dkB card memory to virtual address %p\n",
|
||||
LNE390_STOP_PG/4, ei_status.mem);
|
||||
|
||||
dev->mem_start = (unsigned long)ei_status.mem;
|
||||
dev->mem_end = dev->mem_start + (LNE390_STOP_PG - LNE390_START_PG)*256;
|
||||
|
||||
/* The 8390 offset is zero for the LNE390 */
|
||||
dev->base_addr = ioaddr;
|
||||
|
||||
ei_status.name = "LNE390";
|
||||
ei_status.tx_start_page = LNE390_START_PG;
|
||||
ei_status.rx_start_page = LNE390_START_PG + TX_PAGES;
|
||||
ei_status.stop_page = LNE390_STOP_PG;
|
||||
ei_status.word16 = 1;
|
||||
|
||||
if (ei_debug > 0)
|
||||
printk(version);
|
||||
|
||||
ei_status.reset_8390 = &lne390_reset_8390;
|
||||
ei_status.block_input = &lne390_block_input;
|
||||
ei_status.block_output = &lne390_block_output;
|
||||
ei_status.get_8390_hdr = &lne390_get_8390_hdr;
|
||||
|
||||
dev->netdev_ops = &ei_netdev_ops;
|
||||
NS8390_init(dev, 0);
|
||||
|
||||
ret = register_netdev(dev);
|
||||
if (ret)
|
||||
goto unmap;
|
||||
return 0;
|
||||
unmap:
|
||||
if (ei_status.reg0)
|
||||
iounmap(ei_status.mem);
|
||||
cleanup:
|
||||
free_irq(dev->irq, dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset as per the packet driver method. Judging by the EISA cfg
|
||||
* file, this just toggles the "Board Enable" bits (bit 2 and 0).
|
||||
*/
|
||||
|
||||
static void lne390_reset_8390(struct net_device *dev)
|
||||
{
|
||||
unsigned short ioaddr = dev->base_addr;
|
||||
|
||||
outb(0x04, ioaddr + LNE390_RESET_PORT);
|
||||
if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name);
|
||||
|
||||
mdelay(2);
|
||||
|
||||
ei_status.txing = 0;
|
||||
outb(0x01, ioaddr + LNE390_RESET_PORT);
|
||||
if (ei_debug > 1) printk("reset done\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: In the following three functions is the implicit assumption
|
||||
* that the associated memcpy will only use "rep; movsl" as long as
|
||||
* we keep the counts as some multiple of doublewords. This is a
|
||||
* requirement of the hardware, and also prevents us from using
|
||||
* eth_io_copy_and_sum() since we can't guarantee it will limit
|
||||
* itself to doubleword access.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Grab the 8390 specific header. Similar to the block_input routine, but
|
||||
* we don't need to be concerned with ring wrap as the header will be at
|
||||
* the start of a page, so we optimize accordingly. (A single doubleword.)
|
||||
*/
|
||||
|
||||
static void
|
||||
lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
|
||||
{
|
||||
void __iomem *hdr_start = ei_status.mem + ((ring_page - LNE390_START_PG)<<8);
|
||||
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
|
||||
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Block input and output are easy on shared memory ethercards, the only
|
||||
* complication is when the ring buffer wraps. The count will already
|
||||
* be rounded up to a doubleword value via lne390_get_8390_hdr() above.
|
||||
*/
|
||||
|
||||
static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb,
|
||||
int ring_offset)
|
||||
{
|
||||
void __iomem *xfer_start = ei_status.mem + ring_offset - (LNE390_START_PG<<8);
|
||||
|
||||
if (ring_offset + count > (LNE390_STOP_PG<<8)) {
|
||||
/* Packet wraps over end of ring buffer. */
|
||||
int semi_count = (LNE390_STOP_PG<<8) - ring_offset;
|
||||
memcpy_fromio(skb->data, xfer_start, semi_count);
|
||||
count -= semi_count;
|
||||
memcpy_fromio(skb->data + semi_count,
|
||||
ei_status.mem + (TX_PAGES<<8), count);
|
||||
} else {
|
||||
/* Packet is in one chunk. */
|
||||
memcpy_fromio(skb->data, xfer_start, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void lne390_block_output(struct net_device *dev, int count,
|
||||
const unsigned char *buf, int start_page)
|
||||
{
|
||||
void __iomem *shmem = ei_status.mem + ((start_page - LNE390_START_PG)<<8);
|
||||
|
||||
count = (count + 3) & ~3; /* Round up to doubleword */
|
||||
memcpy_toio(shmem, buf, count);
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODULE
|
||||
#define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */
|
||||
static struct net_device *dev_lne[MAX_LNE_CARDS];
|
||||
static int io[MAX_LNE_CARDS];
|
||||
static int irq[MAX_LNE_CARDS];
|
||||
static int mem[MAX_LNE_CARDS];
|
||||
|
||||
module_param_array(io, int, NULL, 0);
|
||||
module_param_array(irq, int, NULL, 0);
|
||||
module_param_array(mem, int, NULL, 0);
|
||||
MODULE_PARM_DESC(io, "I/O base address(es)");
|
||||
MODULE_PARM_DESC(irq, "IRQ number(s)");
|
||||
MODULE_PARM_DESC(mem, "memory base address(es)");
|
||||
MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
int __init init_module(void)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int this_dev, found = 0;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
|
||||
if (io[this_dev] == 0 && this_dev != 0)
|
||||
break;
|
||||
dev = alloc_ei_netdev();
|
||||
if (!dev)
|
||||
break;
|
||||
dev->irq = irq[this_dev];
|
||||
dev->base_addr = io[this_dev];
|
||||
dev->mem_start = mem[this_dev];
|
||||
if (do_lne390_probe(dev) == 0) {
|
||||
dev_lne[found++] = dev;
|
||||
continue;
|
||||
}
|
||||
free_netdev(dev);
|
||||
printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
return 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static void cleanup_card(struct net_device *dev)
|
||||
{
|
||||
free_irq(dev->irq, dev);
|
||||
release_region(dev->base_addr, LNE390_IO_EXTENT);
|
||||
iounmap(ei_status.mem);
|
||||
}
|
||||
|
||||
void __exit cleanup_module(void)
|
||||
{
|
||||
int this_dev;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
|
||||
struct net_device *dev = dev_lne[this_dev];
|
||||
if (dev) {
|
||||
unregister_netdev(dev);
|
||||
cleanup_card(dev);
|
||||
free_netdev(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* MODULE */
|
||||
|
@ -1,346 +0,0 @@
|
||||
/*
|
||||
ne3210.c
|
||||
|
||||
Linux driver for Novell NE3210 EISA Network Adapter
|
||||
|
||||
Copyright (C) 1998, Paul Gortmaker.
|
||||
|
||||
This software may be used and distributed according to the terms
|
||||
of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
Information and Code Sources:
|
||||
|
||||
1) Based upon my other EISA 8390 drivers (lne390, es3210, smc-ultra32)
|
||||
2) The existing myriad of other Linux 8390 drivers by Donald Becker.
|
||||
3) Info for getting IRQ and sh-mem gleaned from the EISA cfg file
|
||||
|
||||
The NE3210 is an EISA shared memory NS8390 implementation. Shared
|
||||
memory address > 1MB should work with this driver.
|
||||
|
||||
Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
|
||||
around (or perhaps there are some defective/backwards cards ???)
|
||||
|
||||
This driver WILL NOT WORK FOR THE NE3200 - it is completely different
|
||||
and does not use an 8390 at all.
|
||||
|
||||
Updated to EISA probing API 5/2003 by Marc Zyngier.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/eisa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "8390.h"
|
||||
|
||||
#define DRV_NAME "ne3210"
|
||||
|
||||
static void ne3210_reset_8390(struct net_device *dev);
|
||||
|
||||
static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
|
||||
static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
|
||||
static void ne3210_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
|
||||
|
||||
#define NE3210_START_PG 0x00 /* First page of TX buffer */
|
||||
#define NE3210_STOP_PG 0x80 /* Last page +1 of RX ring */
|
||||
|
||||
#define NE3210_IO_EXTENT 0x20
|
||||
#define NE3210_SA_PROM 0x16 /* Start of e'net addr. */
|
||||
#define NE3210_RESET_PORT 0xc84
|
||||
#define NE3210_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
|
||||
|
||||
#define NE3210_ADDR0 0x00 /* 3 byte vendor prefix */
|
||||
#define NE3210_ADDR1 0x00
|
||||
#define NE3210_ADDR2 0x1b
|
||||
|
||||
#define NE3210_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
|
||||
#define NE3210_CFG2 0xc90
|
||||
#define NE3210_CFG_EXTENT (NE3210_CFG2 - NE3210_CFG1 + 1)
|
||||
|
||||
/*
|
||||
* You can OR any of the following bits together and assign it
|
||||
* to NE3210_DEBUG to get verbose driver info during operation.
|
||||
* Currently only the probe one is implemented.
|
||||
*/
|
||||
|
||||
#define NE3210_D_PROBE 0x01
|
||||
#define NE3210_D_RX_PKT 0x02
|
||||
#define NE3210_D_TX_PKT 0x04
|
||||
#define NE3210_D_IRQ 0x08
|
||||
|
||||
#define NE3210_DEBUG 0x0
|
||||
|
||||
static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
|
||||
static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
|
||||
static const char * const ifmap[] __initconst = {"UTP", "?", "BNC", "AUI"};
|
||||
static int ifmap_val[] __initdata = {
|
||||
IF_PORT_10BASET,
|
||||
IF_PORT_UNKNOWN,
|
||||
IF_PORT_10BASE2,
|
||||
IF_PORT_AUI,
|
||||
};
|
||||
|
||||
static int __init ne3210_eisa_probe (struct device *device)
|
||||
{
|
||||
unsigned long ioaddr, phys_mem;
|
||||
int i, retval, port_index;
|
||||
struct eisa_device *edev = to_eisa_device (device);
|
||||
struct net_device *dev;
|
||||
|
||||
/* Allocate dev->priv and fill in 8390 specific dev fields. */
|
||||
if (!(dev = alloc_ei_netdev ())) {
|
||||
printk ("ne3210.c: unable to allocate memory for dev!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
SET_NETDEV_DEV(dev, device);
|
||||
dev_set_drvdata(device, dev);
|
||||
ioaddr = edev->base_addr;
|
||||
|
||||
if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) {
|
||||
retval = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!request_region(ioaddr + NE3210_CFG1,
|
||||
NE3210_CFG_EXTENT, DRV_NAME)) {
|
||||
retval = -EBUSY;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
#if NE3210_DEBUG & NE3210_D_PROBE
|
||||
printk("ne3210-debug: probe at %#x, ID %s\n", ioaddr, edev->id.sig);
|
||||
printk("ne3210-debug: config regs: %#x %#x\n",
|
||||
inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
|
||||
#endif
|
||||
|
||||
port_index = inb(ioaddr + NE3210_CFG2) >> 6;
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
|
||||
printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
|
||||
edev->slot, ifmap[port_index], dev->dev_addr);
|
||||
|
||||
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
|
||||
dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
|
||||
printk("ne3210.c: using IRQ %d, ", dev->irq);
|
||||
|
||||
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
|
||||
if (retval) {
|
||||
printk (" unable to get IRQ %d.\n", dev->irq);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
phys_mem = shmem_map[inb(ioaddr + NE3210_CFG2) & 0x07] * 0x1000;
|
||||
|
||||
/*
|
||||
BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
|
||||
the card mem within the region covered by `normal' RAM !!!
|
||||
*/
|
||||
if (phys_mem > 1024*1024) { /* phys addr > 1MB */
|
||||
if (phys_mem < virt_to_phys(high_memory)) {
|
||||
printk(KERN_CRIT "ne3210.c: Card RAM overlaps with normal memory!!!\n");
|
||||
printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
|
||||
printk(KERN_CRIT "ne3210.c: or to an address above 0x%llx.\n",
|
||||
(u64)virt_to_phys(high_memory));
|
||||
printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
|
||||
retval = -EINVAL;
|
||||
goto out3;
|
||||
}
|
||||
}
|
||||
|
||||
if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
|
||||
printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
|
||||
phys_mem);
|
||||
goto out3;
|
||||
}
|
||||
|
||||
printk("%dkB memory at physical address %#lx\n",
|
||||
NE3210_STOP_PG/4, phys_mem);
|
||||
|
||||
ei_status.mem = ioremap(phys_mem, NE3210_STOP_PG*0x100);
|
||||
if (!ei_status.mem) {
|
||||
printk(KERN_ERR "ne3210.c: Unable to remap card memory !!\n");
|
||||
printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
|
||||
retval = -EAGAIN;
|
||||
goto out4;
|
||||
}
|
||||
printk("ne3210.c: remapped %dkB card memory to virtual address %p\n",
|
||||
NE3210_STOP_PG/4, ei_status.mem);
|
||||
dev->mem_start = (unsigned long)ei_status.mem;
|
||||
dev->mem_end = dev->mem_start + (NE3210_STOP_PG - NE3210_START_PG)*256;
|
||||
|
||||
/* The 8390 offset is zero for the NE3210 */
|
||||
dev->base_addr = ioaddr;
|
||||
|
||||
ei_status.name = "NE3210";
|
||||
ei_status.tx_start_page = NE3210_START_PG;
|
||||
ei_status.rx_start_page = NE3210_START_PG + TX_PAGES;
|
||||
ei_status.stop_page = NE3210_STOP_PG;
|
||||
ei_status.word16 = 1;
|
||||
ei_status.priv = phys_mem;
|
||||
|
||||
if (ei_debug > 0)
|
||||
printk("ne3210 loaded.\n");
|
||||
|
||||
ei_status.reset_8390 = &ne3210_reset_8390;
|
||||
ei_status.block_input = &ne3210_block_input;
|
||||
ei_status.block_output = &ne3210_block_output;
|
||||
ei_status.get_8390_hdr = &ne3210_get_8390_hdr;
|
||||
|
||||
dev->netdev_ops = &ei_netdev_ops;
|
||||
|
||||
dev->if_port = ifmap_val[port_index];
|
||||
|
||||
if ((retval = register_netdev (dev)))
|
||||
goto out5;
|
||||
|
||||
NS8390_init(dev, 0);
|
||||
return 0;
|
||||
|
||||
out5:
|
||||
iounmap(ei_status.mem);
|
||||
out4:
|
||||
release_mem_region (phys_mem, NE3210_STOP_PG*0x100);
|
||||
out3:
|
||||
free_irq (dev->irq, dev);
|
||||
out2:
|
||||
release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
|
||||
out1:
|
||||
release_region (ioaddr, NE3210_IO_EXTENT);
|
||||
out:
|
||||
free_netdev (dev);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ne3210_eisa_remove(struct device *device)
|
||||
{
|
||||
struct net_device *dev = dev_get_drvdata(device);
|
||||
unsigned long ioaddr = to_eisa_device (device)->base_addr;
|
||||
|
||||
unregister_netdev (dev);
|
||||
iounmap(ei_status.mem);
|
||||
release_mem_region (ei_status.priv, NE3210_STOP_PG*0x100);
|
||||
free_irq (dev->irq, dev);
|
||||
release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
|
||||
release_region (ioaddr, NE3210_IO_EXTENT);
|
||||
free_netdev (dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset by toggling the "Board Enable" bits (bit 2 and 0).
|
||||
*/
|
||||
|
||||
static void ne3210_reset_8390(struct net_device *dev)
|
||||
{
|
||||
unsigned short ioaddr = dev->base_addr;
|
||||
|
||||
outb(0x04, ioaddr + NE3210_RESET_PORT);
|
||||
if (ei_debug > 1) printk("%s: resetting the NE3210...", dev->name);
|
||||
|
||||
mdelay(2);
|
||||
|
||||
ei_status.txing = 0;
|
||||
outb(0x01, ioaddr + NE3210_RESET_PORT);
|
||||
if (ei_debug > 1) printk("reset done\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: In the following three functions is the implicit assumption
|
||||
* that the associated memcpy will only use "rep; movsl" as long as
|
||||
* we keep the counts as some multiple of doublewords. This is a
|
||||
* requirement of the hardware, and also prevents us from using
|
||||
* eth_io_copy_and_sum() since we can't guarantee it will limit
|
||||
* itself to doubleword access.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Grab the 8390 specific header. Similar to the block_input routine, but
|
||||
* we don't need to be concerned with ring wrap as the header will be at
|
||||
* the start of a page, so we optimize accordingly. (A single doubleword.)
|
||||
*/
|
||||
|
||||
static void
|
||||
ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
|
||||
{
|
||||
void __iomem *hdr_start = ei_status.mem + ((ring_page - NE3210_START_PG)<<8);
|
||||
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
|
||||
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Block input and output are easy on shared memory ethercards, the only
|
||||
* complication is when the ring buffer wraps. The count will already
|
||||
* be rounded up to a doubleword value via ne3210_get_8390_hdr() above.
|
||||
*/
|
||||
|
||||
static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb,
|
||||
int ring_offset)
|
||||
{
|
||||
void __iomem *start = ei_status.mem + ring_offset - NE3210_START_PG*256;
|
||||
|
||||
if (ring_offset + count > NE3210_STOP_PG*256) {
|
||||
/* Packet wraps over end of ring buffer. */
|
||||
int semi_count = NE3210_STOP_PG*256 - ring_offset;
|
||||
memcpy_fromio(skb->data, start, semi_count);
|
||||
count -= semi_count;
|
||||
memcpy_fromio(skb->data + semi_count,
|
||||
ei_status.mem + TX_PAGES*256, count);
|
||||
} else {
|
||||
/* Packet is in one chunk. */
|
||||
memcpy_fromio(skb->data, start, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void ne3210_block_output(struct net_device *dev, int count,
|
||||
const unsigned char *buf, int start_page)
|
||||
{
|
||||
void __iomem *shmem = ei_status.mem + ((start_page - NE3210_START_PG)<<8);
|
||||
|
||||
count = (count + 3) & ~3; /* Round up to doubleword */
|
||||
memcpy_toio(shmem, buf, count);
|
||||
}
|
||||
|
||||
static struct eisa_device_id ne3210_ids[] = {
|
||||
{ "EGL0101" },
|
||||
{ "NVL1801" },
|
||||
{ "" },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(eisa, ne3210_ids);
|
||||
|
||||
static struct eisa_driver ne3210_eisa_driver = {
|
||||
.id_table = ne3210_ids,
|
||||
.driver = {
|
||||
.name = "ne3210",
|
||||
.probe = ne3210_eisa_probe,
|
||||
.remove = ne3210_eisa_remove,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(eisa, ne3210_ids);
|
||||
|
||||
static int ne3210_init(void)
|
||||
{
|
||||
return eisa_driver_register (&ne3210_eisa_driver);
|
||||
}
|
||||
|
||||
static void ne3210_cleanup(void)
|
||||
{
|
||||
eisa_driver_unregister (&ne3210_eisa_driver);
|
||||
}
|
||||
|
||||
module_init (ne3210_init);
|
||||
module_exit (ne3210_cleanup);
|
@ -1,463 +0,0 @@
|
||||
/* smc-ultra32.c: An SMC Ultra32 EISA ethernet driver for linux.
|
||||
|
||||
Sources:
|
||||
|
||||
This driver is based on (cloned from) the ISA SMC Ultra driver
|
||||
written by Donald Becker. Modifications to support the EISA
|
||||
version of the card by Paul Gortmaker and Leonard N. Zubkoff.
|
||||
|
||||
This software may be used and distributed according to the terms
|
||||
of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
Theory of Operation:
|
||||
|
||||
The SMC Ultra32C card uses the SMC 83c790 chip which is also
|
||||
found on the ISA SMC Ultra cards. It has a shared memory mode of
|
||||
operation that makes it similar to the ISA version of the card.
|
||||
The main difference is that the EISA card has 32KB of RAM, but
|
||||
only an 8KB window into that memory. The EISA card also can be
|
||||
set for a bus-mastering mode of operation via the ECU, but that
|
||||
is not (and probably will never be) supported by this driver.
|
||||
The ECU should be run to enable shared memory and to disable the
|
||||
bus-mastering feature for use with linux.
|
||||
|
||||
By programming the 8390 to use only 8KB RAM, the modifications
|
||||
to the ISA driver can be limited to the probe and initialization
|
||||
code. This allows easy integration of EISA support into the ISA
|
||||
driver. However, the driver development kit from SMC provided the
|
||||
register information for sliding the 8KB window, and hence the 8390
|
||||
is programmed to use the full 32KB RAM.
|
||||
|
||||
Unfortunately this required code changes outside the probe/init
|
||||
routines, and thus we decided to separate the EISA driver from
|
||||
the ISA one. In this way, ISA users don't end up with a larger
|
||||
driver due to the EISA code, and EISA users don't end up with a
|
||||
larger driver due to the ISA EtherEZ PIO code. The driver is
|
||||
similar to the 3c503/16 driver, in that the window must be set
|
||||
back to the 1st 8KB of space for access to the two 8390 Tx slots.
|
||||
|
||||
In testing, using only 8KB RAM (3 Tx / 5 Rx) didn't appear to
|
||||
be a limiting factor, since the EISA bus could get packets off
|
||||
the card fast enough, but having the use of lots of RAM as Rx
|
||||
space is extra insurance if interrupt latencies become excessive.
|
||||
|
||||
*/
|
||||
|
||||
static const char *version = "smc-ultra32.c: 06/97 v1.00\n";
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/eisa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "8390.h"
|
||||
|
||||
#define DRV_NAME "smc-ultra32"
|
||||
|
||||
static int ultra32_probe1(struct net_device *dev, int ioaddr);
|
||||
static int ultra32_open(struct net_device *dev);
|
||||
static void ultra32_reset_8390(struct net_device *dev);
|
||||
static void ultra32_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
|
||||
int ring_page);
|
||||
static void ultra32_block_input(struct net_device *dev, int count,
|
||||
struct sk_buff *skb, int ring_offset);
|
||||
static void ultra32_block_output(struct net_device *dev, int count,
|
||||
const unsigned char *buf,
|
||||
const int start_page);
|
||||
static int ultra32_close(struct net_device *dev);
|
||||
|
||||
#define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */
|
||||
#define ULTRA32_RESET 0x80 /* Board reset, in ULTRA32_CMDREG. */
|
||||
#define ULTRA32_MEMENB 0x40 /* Enable the shared memory. */
|
||||
#define ULTRA32_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
|
||||
#define ULTRA32_IO_EXTENT 32
|
||||
#define EN0_ERWCNT 0x08 /* Early receive warning count. */
|
||||
|
||||
/*
|
||||
* Defines that apply only to the Ultra32 EISA card. Note that
|
||||
* "smc" = 10011 01101 00011 = 0x4da3, and hence !smc8010.cfg translates
|
||||
* into an EISA ID of 0x1080A34D
|
||||
*/
|
||||
#define ULTRA32_BASE 0xca0
|
||||
#define ULTRA32_ID 0x1080a34d
|
||||
#define ULTRA32_IDPORT (-0x20) /* 0xc80 */
|
||||
/* Config regs 1->7 from the EISA !SMC8010.CFG file. */
|
||||
#define ULTRA32_CFG1 0x04 /* 0xca4 */
|
||||
#define ULTRA32_CFG2 0x05 /* 0xca5 */
|
||||
#define ULTRA32_CFG3 (-0x18) /* 0xc88 */
|
||||
#define ULTRA32_CFG4 (-0x17) /* 0xc89 */
|
||||
#define ULTRA32_CFG5 (-0x16) /* 0xc8a */
|
||||
#define ULTRA32_CFG6 (-0x15) /* 0xc8b */
|
||||
#define ULTRA32_CFG7 0x0d /* 0xcad */
|
||||
|
||||
static void cleanup_card(struct net_device *dev)
|
||||
{
|
||||
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET;
|
||||
/* NB: ultra32_close_card() does free_irq */
|
||||
release_region(ioaddr, ULTRA32_IO_EXTENT);
|
||||
iounmap(ei_status.mem);
|
||||
}
|
||||
|
||||
/* Probe for the Ultra32. This looks like a 8013 with the station
|
||||
address PROM at I/O ports <base>+8 to <base>+13, with a checksum
|
||||
following.
|
||||
*/
|
||||
|
||||
struct net_device * __init ultra32_probe(int unit)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int base;
|
||||
int irq;
|
||||
int err = -ENODEV;
|
||||
|
||||
if (!EISA_bus)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
dev = alloc_ei_netdev();
|
||||
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (unit >= 0) {
|
||||
sprintf(dev->name, "eth%d", unit);
|
||||
netdev_boot_setup_check(dev);
|
||||
}
|
||||
|
||||
irq = dev->irq;
|
||||
|
||||
/* EISA spec allows for up to 16 slots, but 8 is typical. */
|
||||
for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) {
|
||||
if (ultra32_probe1(dev, base) == 0)
|
||||
break;
|
||||
dev->irq = irq;
|
||||
}
|
||||
if (base >= 0x9000)
|
||||
goto out;
|
||||
err = register_netdev(dev);
|
||||
if (err)
|
||||
goto out1;
|
||||
return dev;
|
||||
out1:
|
||||
cleanup_card(dev);
|
||||
out:
|
||||
free_netdev(dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
|
||||
static const struct net_device_ops ultra32_netdev_ops = {
|
||||
.ndo_open = ultra32_open,
|
||||
.ndo_stop = ultra32_close,
|
||||
.ndo_start_xmit = ei_start_xmit,
|
||||
.ndo_tx_timeout = ei_tx_timeout,
|
||||
.ndo_get_stats = ei_get_stats,
|
||||
.ndo_set_rx_mode = ei_set_multicast_list,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = ei_poll,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
|
||||
{
|
||||
int i, edge, media, retval;
|
||||
int checksum = 0;
|
||||
const char *model_name;
|
||||
static unsigned version_printed;
|
||||
/* Values from various config regs. */
|
||||
unsigned char idreg;
|
||||
unsigned char reg4;
|
||||
const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
|
||||
|
||||
if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
|
||||
return -EBUSY;
|
||||
|
||||
if (inb(ioaddr + ULTRA32_IDPORT) == 0xff ||
|
||||
inl(ioaddr + ULTRA32_IDPORT) != ULTRA32_ID) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
media = inb(ioaddr + ULTRA32_CFG7) & 0x03;
|
||||
edge = inb(ioaddr + ULTRA32_CFG5) & 0x08;
|
||||
printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n",
|
||||
ioaddr >> 12, ifmap[media],
|
||||
(edge ? "Edge Triggered" : "Level Sensitive"));
|
||||
|
||||
idreg = inb(ioaddr + 7);
|
||||
reg4 = inb(ioaddr + 4) & 0x7f;
|
||||
|
||||
/* Check the ID nibble. */
|
||||
if ((idreg & 0xf0) != 0x20) { /* SMC Ultra */
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Select the station address register set. */
|
||||
outb(reg4, ioaddr + 4);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
checksum += inb(ioaddr + 8 + i);
|
||||
if ((checksum & 0xff) != 0xff) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ei_debug && version_printed++ == 0)
|
||||
printk(version);
|
||||
|
||||
model_name = "SMC Ultra32";
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
dev->dev_addr[i] = inb(ioaddr + 8 + i);
|
||||
|
||||
printk("%s: %s at 0x%X, %pM",
|
||||
dev->name, model_name, ioaddr, dev->dev_addr);
|
||||
|
||||
/* Switch from the station address to the alternate register set and
|
||||
read the useful registers there. */
|
||||
outb(0x80 | reg4, ioaddr + 4);
|
||||
|
||||
/* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
|
||||
outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
|
||||
|
||||
/* Reset RAM addr. */
|
||||
outb(0x00, ioaddr + 0x0b);
|
||||
|
||||
/* Switch back to the station address register set so that the
|
||||
MS-DOS driver can find the card after a warm boot. */
|
||||
outb(reg4, ioaddr + 4);
|
||||
|
||||
if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) {
|
||||
printk("\nsmc-ultra32: Card RAM is disabled! "
|
||||
"Run EISA config utility.\n");
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0)
|
||||
printk("\nsmc-ultra32: Ignoring Bus-Master enable bit. "
|
||||
"Run EISA config utility.\n");
|
||||
|
||||
if (dev->irq < 2) {
|
||||
unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
|
||||
int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07];
|
||||
if (irq == 0) {
|
||||
printk(", failed to detect IRQ line.\n");
|
||||
retval = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
dev->irq = irq;
|
||||
}
|
||||
|
||||
/* The 8390 isn't at the base address, so fake the offset */
|
||||
dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET;
|
||||
|
||||
/* Save RAM address in the unused reg0 to avoid excess inb's. */
|
||||
ei_status.reg0 = inb(ioaddr + ULTRA32_CFG3) & 0xfc;
|
||||
|
||||
dev->mem_start = 0xc0000 + ((ei_status.reg0 & 0x7c) << 11);
|
||||
|
||||
ei_status.name = model_name;
|
||||
ei_status.word16 = 1;
|
||||
ei_status.tx_start_page = 0;
|
||||
ei_status.rx_start_page = TX_PAGES;
|
||||
/* All Ultra32 cards have 32KB memory with an 8KB window. */
|
||||
ei_status.stop_page = 128;
|
||||
|
||||
ei_status.mem = ioremap(dev->mem_start, 0x2000);
|
||||
if (!ei_status.mem) {
|
||||
printk(", failed to ioremap.\n");
|
||||
retval = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
dev->mem_end = dev->mem_start + 0x1fff;
|
||||
|
||||
printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
|
||||
dev->irq, dev->mem_start, dev->mem_end);
|
||||
ei_status.block_input = &ultra32_block_input;
|
||||
ei_status.block_output = &ultra32_block_output;
|
||||
ei_status.get_8390_hdr = &ultra32_get_8390_hdr;
|
||||
ei_status.reset_8390 = &ultra32_reset_8390;
|
||||
|
||||
dev->netdev_ops = &ultra32_netdev_ops;
|
||||
NS8390_init(dev, 0);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
release_region(ioaddr, ULTRA32_IO_EXTENT);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ultra32_open(struct net_device *dev)
|
||||
{
|
||||
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
|
||||
int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : IRQF_SHARED;
|
||||
int retval;
|
||||
|
||||
retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
|
||||
outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
|
||||
outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
|
||||
outb(0x01, ioaddr + 6); /* Enable Interrupts. */
|
||||
/* Set the early receive warning level in window 0 high enough not
|
||||
to receive ERW interrupts. */
|
||||
outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
|
||||
outb(0xff, dev->base_addr + EN0_ERWCNT);
|
||||
ei_open(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ultra32_close(struct net_device *dev)
|
||||
{
|
||||
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
if (ei_debug > 1)
|
||||
printk("%s: Shutting down ethercard.\n", dev->name);
|
||||
|
||||
outb(0x00, ioaddr + ULTRA32_CFG6); /* Disable Interrupts. */
|
||||
outb(0x00, ioaddr + 6); /* Disable interrupts. */
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
NS8390_init(dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ultra32_reset_8390(struct net_device *dev)
|
||||
{
|
||||
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC base addr */
|
||||
|
||||
outb(ULTRA32_RESET, ioaddr);
|
||||
if (ei_debug > 1) printk("resetting Ultra32, t=%ld...", jiffies);
|
||||
ei_status.txing = 0;
|
||||
|
||||
outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
|
||||
outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
|
||||
outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
|
||||
outb(0x01, ioaddr + 6); /* Enable Interrupts. */
|
||||
if (ei_debug > 1) printk("reset done\n");
|
||||
}
|
||||
|
||||
/* Grab the 8390 specific header. Similar to the block_input routine, but
|
||||
we don't need to be concerned with ring wrap as the header will be at
|
||||
the start of a page, so we optimize accordingly. */
|
||||
|
||||
static void ultra32_get_8390_hdr(struct net_device *dev,
|
||||
struct e8390_pkt_hdr *hdr,
|
||||
int ring_page)
|
||||
{
|
||||
void __iomem *hdr_start = ei_status.mem + ((ring_page & 0x1f) << 8);
|
||||
unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
|
||||
|
||||
/* Select correct 8KB Window. */
|
||||
outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg);
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
/* Officially this is what we are doing, but the readl() is faster */
|
||||
/* unfortunately it isn't endian aware of the struct */
|
||||
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
|
||||
hdr->count = le16_to_cpu(hdr->count);
|
||||
#else
|
||||
((unsigned int*)hdr)[0] = readl(hdr_start);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Block input and output are easy on shared memory ethercards, the only
|
||||
complication is when the ring buffer wraps, or in this case, when a
|
||||
packet spans an 8KB boundary. Note that the current 8KB segment is
|
||||
already set by the get_8390_hdr routine. */
|
||||
|
||||
static void ultra32_block_input(struct net_device *dev,
|
||||
int count,
|
||||
struct sk_buff *skb,
|
||||
int ring_offset)
|
||||
{
|
||||
void __iomem *xfer_start = ei_status.mem + (ring_offset & 0x1fff);
|
||||
unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
|
||||
|
||||
if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) {
|
||||
int semi_count = 8192 - (ring_offset & 0x1FFF);
|
||||
memcpy_fromio(skb->data, xfer_start, semi_count);
|
||||
count -= semi_count;
|
||||
if (ring_offset < 96*256) {
|
||||
/* Select next 8KB Window. */
|
||||
ring_offset += semi_count;
|
||||
outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg);
|
||||
memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
|
||||
} else {
|
||||
/* Select first 8KB Window. */
|
||||
outb(ei_status.reg0, RamReg);
|
||||
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
|
||||
}
|
||||
} else {
|
||||
memcpy_fromio(skb->data, xfer_start, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void ultra32_block_output(struct net_device *dev,
|
||||
int count,
|
||||
const unsigned char *buf,
|
||||
int start_page)
|
||||
{
|
||||
void __iomem *xfer_start = ei_status.mem + (start_page<<8);
|
||||
unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
|
||||
|
||||
/* Select first 8KB Window. */
|
||||
outb(ei_status.reg0, RamReg);
|
||||
|
||||
memcpy_toio(xfer_start, buf, count);
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
#define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */
|
||||
static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
|
||||
|
||||
MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
int __init init_module(void)
|
||||
{
|
||||
int this_dev, found = 0;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
|
||||
struct net_device *dev = ultra32_probe(-1);
|
||||
if (IS_ERR(dev))
|
||||
break;
|
||||
dev_ultra[found++] = dev;
|
||||
}
|
||||
if (found)
|
||||
return 0;
|
||||
printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
void __exit cleanup_module(void)
|
||||
{
|
||||
int this_dev;
|
||||
|
||||
for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
|
||||
struct net_device *dev = dev_ultra[this_dev];
|
||||
if (dev) {
|
||||
unregister_netdev(dev);
|
||||
cleanup_card(dev);
|
||||
free_netdev(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* MODULE */
|
||||
|
Loading…
Reference in New Issue
Block a user