/*
* Digi RightSwitch SE-X loadable device driver for Linux
*
* The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and
* a NIC on an internal board.
*
* Author: Rick Richardson, rick@remotepoint.com
* Derived from the SVR4.2 (UnixWare) driver for the same card.
*
* Copyright 1995-1996 Digi International Inc.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For information on purchasing a RightSwitch SE-4 or SE-6
* board, please contact Digi's sales department at 1-612-912-3444
* or 1-800-DIGIBRD. Outside the U.S., please check our Web page
* at http://www.dgii.com for sales offices worldwide.
*
* OPERATION:
* When compiled as a loadable module, this driver can operate
* the board as either a 4/6 port switch with a 5th or 7th port
* that is a conventional NIC interface as far as the host is
* concerned, OR as 4/6 independent NICs. To select multi-NIC
* mode, add "nicmode=1" on the insmod load line for the driver.
*
* This driver uses the "dev" common ethernet device structure
* and a private "priv" (dev->priv) structure that contains
* mostly DGRS-specific information and statistics. To keep
* the code for both the switch mode and the multi-NIC mode
* as similar as possible, I have introduced the concept of
* "dev0"/"priv0" and "devN"/"privN" pointer pairs in subroutines
* where needed. The first pair of pointers points to the
* "dev" and "priv" structures of the zeroth (0th) device
* interface associated with a board. The second pair of
* pointers points to the current (Nth) device interface
* for the board: the one for which we are processing data.
*
* In switch mode, the pairs of pointers are always the same,
* that is, dev0 == devN and priv0 == privN. This is just
* like previous releases of this driver which did not support
* NIC mode.
*
* In multi-NIC mode, the pairs of pointers may be different.
* We use the devN and privN pointers to reference just the
* name, port number, and statistics for the current interface.
* We use the dev0 and priv0 pointers to access the variables
* that control access to the board, such as board address
* and simulated 82596 variables. This is because there is
* only one "fake" 82596 that serves as the interface to
* the board. We do not want to try to keep the variables
* associated with this 82596 in sync across all devices.
*
* This scheme works well. As you will see, except for
* initialization, there is very little difference between
* the two modes as far as this driver is concerned. On the
* receive side in NIC mode, the interrupt *always* comes in on
* the 0th interface (dev0/priv0). We then figure out which
* real 82596 port it came in on from looking at the "chan"
* member that the board firmware adds at the end of each
* RBD (a.k.a. TBD). We get the channel number like this:
* int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
*
* On the transmit side in multi-NIC mode, we specify the
* output 82596 port by setting the new "dstchan" structure
* member that is at the end of the RFD, like this:
* priv0->rfdp->dstchan = privN->chan;
*
* TODO:
* - Multi-NIC mode is not yet supported when the driver is linked
* into the kernel.
* - Better handling of multicast addresses.
*
* Fixes:
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
* - fix dgrs_found_device wrt checking kmalloc return and
* rollbacking the partial steps of the whole process when
* one of the devices can't be allocated. Fix SET_MODULE_OWNER
* on the loop to use devN instead of repeated calls to dev.
*
* davej <davej@suse.de> - 9/2/2001
* - Enable PCI device before reading ioaddr/irq
*
*/
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
static char version[] __initdata =
"$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $";
/*
* DGRS include files
*/
typedef unsigned char uchar;
#define vol volatile
#include "dgrs.h"
#include "dgrs_es4h.h"
#include "dgrs_plx9060.h"
#include "dgrs_i82596.h"
#include "dgrs_ether.h"
#include "dgrs_asstruct.h"
#include "dgrs_bcomm.h"
#ifdef CONFIG_PCI
static struct pci_device_id dgrs_pci_tbl[] = {
{ SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
#endif
#ifdef CONFIG_EISA
static struct eisa_device_id dgrs_eisa_tbl[] = {
{ "DBI0A01" },
{ }
};
MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl);
#endif
MODULE_LICENSE("GPL");
/*
* Firmware. Compiled separately for local compilation,
* but #included for Linux distribution.
*/
#ifndef NOFW
#include "dgrs_firmware.c"
#else
extern int dgrs_firmnum;
extern char dgrs_firmver[];
extern char dgrs_firmdate[];
extern uchar dgr
|