One less thing for drivers writers to worry about. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			2112 lines
		
	
	
	
		
			60 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2112 lines
		
	
	
	
		
			60 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*  depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
 | 
						|
 | 
						|
    Written 1994, 1995 by David C. Davies.
 | 
						|
 | 
						|
 | 
						|
                      Copyright 1994 David C. Davies
 | 
						|
		                   and
 | 
						|
			 United States Government
 | 
						|
	 (as represented by the Director, National Security Agency).
 | 
						|
 | 
						|
               Copyright 1995  Digital Equipment Corporation.
 | 
						|
 | 
						|
 | 
						|
    This software may be used and distributed according to the terms of
 | 
						|
    the GNU General Public License, incorporated herein by reference.
 | 
						|
 | 
						|
    This driver is written for the Digital Equipment Corporation series
 | 
						|
    of DEPCA and EtherWORKS ethernet cards:
 | 
						|
 | 
						|
        DEPCA       (the original)
 | 
						|
    	DE100
 | 
						|
    	DE101
 | 
						|
	DE200 Turbo
 | 
						|
	DE201 Turbo
 | 
						|
	DE202 Turbo (TP BNC)
 | 
						|
	DE210
 | 
						|
	DE422       (EISA)
 | 
						|
 | 
						|
    The  driver has been tested on DE100, DE200 and DE202 cards  in  a
 | 
						|
    relatively busy network. The DE422 has been tested a little.
 | 
						|
 | 
						|
    This  driver will NOT work   for the DE203,  DE204  and DE205 series  of
 | 
						|
    cards,  since they have  a  new custom ASIC in   place of the AMD  LANCE
 | 
						|
    chip.  See the 'ewrk3.c'   driver in the  Linux  source tree for running
 | 
						|
    those cards.
 | 
						|
 | 
						|
    I have benchmarked the driver with a  DE100 at 595kB/s to (542kB/s from)
 | 
						|
    a DECstation 5000/200.
 | 
						|
 | 
						|
    The author may be reached at davies@maniac.ultranet.com
 | 
						|
 | 
						|
    =========================================================================
 | 
						|
 | 
						|
    The  driver was originally based  on   the 'lance.c' driver from  Donald
 | 
						|
    Becker   which  is included with  the  standard  driver distribution for
 | 
						|
    linux.  V0.4  is  a complete  re-write  with only  the kernel  interface
 | 
						|
    remaining from the original code.
 | 
						|
 | 
						|
    1) Lance.c code in /linux/drivers/net/
 | 
						|
    2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
 | 
						|
       AMD, 1992 [(800) 222-9323].
 | 
						|
    3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
 | 
						|
       AMD, Pub. #17881, May 1993.
 | 
						|
    4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
 | 
						|
       AMD, Pub. #16907, May 1992
 | 
						|
    5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
 | 
						|
       Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
 | 
						|
    6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
 | 
						|
       Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
 | 
						|
    7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
 | 
						|
       Digital Equipment Corporation, 1989
 | 
						|
    8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
 | 
						|
       Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
 | 
						|
 | 
						|
 | 
						|
    Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
 | 
						|
    driver.
 | 
						|
 | 
						|
    The original DEPCA  card requires that the  ethernet ROM address counter
 | 
						|
    be enabled to count and has an 8 bit NICSR.  The ROM counter enabling is
 | 
						|
    only  done when a  0x08 is read as the  first address octet (to minimise
 | 
						|
    the chances  of writing over some  other hardware's  I/O register).  The
 | 
						|
    NICSR accesses   have been changed  to  byte accesses  for all the cards
 | 
						|
    supported by this driver, since there is only one  useful bit in the MSB
 | 
						|
    (remote boot timeout) and it  is not used.  Also, there  is a maximum of
 | 
						|
    only 48kB network  RAM for this  card.  My thanks  to Torbjorn Lindh for
 | 
						|
    help debugging all this (and holding my feet to  the fire until I got it
 | 
						|
    right).
 | 
						|
 | 
						|
    The DE200  series  boards have  on-board 64kB  RAM for  use  as a shared
 | 
						|
    memory network  buffer. Only the DE100  cards make use  of a  2kB buffer
 | 
						|
    mode which has not  been implemented in  this driver (only the 32kB  and
 | 
						|
    64kB modes are supported [16kB/48kB for the original DEPCA]).
 | 
						|
 | 
						|
    At the most only 2 DEPCA cards can  be supported on  the ISA bus because
 | 
						|
    there is only provision  for two I/O base addresses  on each card (0x300
 | 
						|
    and 0x200). The I/O address is detected by searching for a byte sequence
 | 
						|
    in the Ethernet station address PROM at the expected I/O address for the
 | 
						|
    Ethernet  PROM.   The shared memory  base   address  is 'autoprobed'  by
 | 
						|
    looking  for the self  test PROM  and detecting the  card name.   When a
 | 
						|
    second  DEPCA is  detected,  information  is   placed in the   base_addr
 | 
						|
    variable of the  next device structure (which  is created if necessary),
 | 
						|
    thus  enabling ethif_probe  initialization  for the device.  More than 2
 | 
						|
    EISA cards can  be  supported, but  care will  be  needed assigning  the
 | 
						|
    shared memory to ensure that each slot has the  correct IRQ, I/O address
 | 
						|
    and shared memory address assigned.
 | 
						|
 | 
						|
    ************************************************************************
 | 
						|
 | 
						|
    NOTE: If you are using two  ISA DEPCAs, it is  important that you assign
 | 
						|
    the base memory addresses correctly.   The  driver autoprobes I/O  0x300
 | 
						|
    then 0x200.  The  base memory address for  the first device must be less
 | 
						|
    than that of the second so that the auto probe will correctly assign the
 | 
						|
    I/O and memory addresses on the same card.  I can't think of a way to do
 | 
						|
    this unambiguously at the moment, since there is nothing on the cards to
 | 
						|
    tie I/O and memory information together.
 | 
						|
 | 
						|
    I am unable  to  test  2 cards   together for now,    so this  code   is
 | 
						|
    unchecked. All reports, good or bad, are welcome.
 | 
						|
 | 
						|
    ************************************************************************
 | 
						|
 | 
						|
    The board IRQ   setting must be  at an  unused IRQ which  is auto-probed
 | 
						|
    using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are
 | 
						|
    {2,3,4,5,7}, whereas the  DE200 is at {5,9,10,11,15}.  Note that IRQ2 is
 | 
						|
    really IRQ9 in machines with 16 IRQ lines.
 | 
						|
 | 
						|
    No 16MB memory  limitation should exist with this  driver as DMA is  not
 | 
						|
    used and the common memory area is in low memory on the network card (my
 | 
						|
    current system has 20MB and I've not had problems yet).
 | 
						|
 | 
						|
    The ability to load this driver as a loadable module has been added. To
 | 
						|
    utilise this ability, you have to do <8 things:
 | 
						|
 | 
						|
    0) have a copy of the loadable modules code installed on your system.
 | 
						|
    1) copy depca.c from the  /linux/drivers/net directory to your favourite
 | 
						|
    temporary directory.
 | 
						|
    2) if you wish, edit the  source code near  line 1530 to reflect the I/O
 | 
						|
    address and IRQ you're using (see also 5).
 | 
						|
    3) compile  depca.c, but include -DMODULE in  the command line to ensure
 | 
						|
    that the correct bits are compiled (see end of source code).
 | 
						|
    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
 | 
						|
    kernel with the depca configuration turned off and reboot.
 | 
						|
    5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100]
 | 
						|
       [Alan Cox: Changed the code to allow command line irq/io assignments]
 | 
						|
       [Dave Davies: Changed the code to allow command line mem/name
 | 
						|
                                                                assignments]
 | 
						|
    6) run the net startup bits for your eth?? interface manually
 | 
						|
    (usually /etc/rc.inet[12] at boot time).
 | 
						|
    7) enjoy!
 | 
						|
 | 
						|
    Note that autoprobing is not allowed in loadable modules - the system is
 | 
						|
    already up and running and you're messing with interrupts.
 | 
						|
 | 
						|
    To unload a module, turn off the associated interface
 | 
						|
    'ifconfig eth?? down' then 'rmmod depca'.
 | 
						|
 | 
						|
    To assign a base memory address for the shared memory  when running as a
 | 
						|
    loadable module, see 5 above.  To include the adapter  name (if you have
 | 
						|
    no PROM  but know the card name)  also see 5  above. Note that this last
 | 
						|
    option  will not work  with kernel  built-in  depca's.
 | 
						|
 | 
						|
    The shared memory assignment for a loadable module  makes sense to avoid
 | 
						|
    the 'memory autoprobe' picking the wrong shared memory  (for the case of
 | 
						|
    2 depca's in a PC).
 | 
						|
 | 
						|
    ************************************************************************
 | 
						|
    Support for MCA EtherWORKS cards added 11-3-98.
 | 
						|
    Verified to work with up to 2 DE212 cards in a system (although not
 | 
						|
      fully stress-tested).
 | 
						|
 | 
						|
    Currently known bugs/limitations:
 | 
						|
 | 
						|
    Note:  with the MCA stuff as a module, it trusts the MCA configuration,
 | 
						|
           not the command line for IRQ and memory address.  You can
 | 
						|
           specify them if you want, but it will throw your values out.
 | 
						|
           You still have to pass the IO address it was configured as
 | 
						|
           though.
 | 
						|
 | 
						|
    ************************************************************************
 | 
						|
    TO DO:
 | 
						|
    ------
 | 
						|
 | 
						|
 | 
						|
    Revision History
 | 
						|
    ----------------
 | 
						|
 | 
						|
    Version   Date        Description
 | 
						|
 | 
						|
      0.1     25-jan-94   Initial writing.
 | 
						|
      0.2     27-jan-94   Added LANCE TX hardware buffer chaining.
 | 
						|
      0.3      1-feb-94   Added multiple DEPCA support.
 | 
						|
      0.31     4-feb-94   Added DE202 recognition.
 | 
						|
      0.32    19-feb-94   Tidy up. Improve multi-DEPCA support.
 | 
						|
      0.33    25-feb-94   Fix DEPCA ethernet ROM counter enable.
 | 
						|
                          Add jabber packet fix from murf@perftech.com
 | 
						|
			  and becker@super.org
 | 
						|
      0.34     7-mar-94   Fix DEPCA max network memory RAM & NICSR access.
 | 
						|
      0.35     8-mar-94   Added DE201 recognition. Tidied up.
 | 
						|
      0.351   30-apr-94   Added EISA support. Added DE422 recognition.
 | 
						|
      0.36    16-may-94   DE422 fix released.
 | 
						|
      0.37    22-jul-94   Added MODULE support
 | 
						|
      0.38    15-aug-94   Added DBR ROM switch in depca_close().
 | 
						|
                          Multi DEPCA bug fix.
 | 
						|
      0.38axp 15-sep-94   Special version for Alpha AXP Linux V1.0.
 | 
						|
      0.381   12-dec-94   Added DE101 recognition, fix multicast bug.
 | 
						|
      0.382    9-feb-95   Fix recognition bug reported by <bkm@star.rl.ac.uk>.
 | 
						|
      0.383   22-feb-95   Fix for conflict with VESA SCSI reported by
 | 
						|
                          <stromain@alf.dec.com>
 | 
						|
      0.384   17-mar-95   Fix a ring full bug reported by <bkm@star.rl.ac.uk>
 | 
						|
      0.385    3-apr-95   Fix a recognition bug reported by
 | 
						|
                                                <ryan.niemi@lastfrontier.com>
 | 
						|
      0.386   21-apr-95   Fix the last fix...sorry, must be galloping senility
 | 
						|
      0.40    25-May-95   Rewrite for portability & updated.
 | 
						|
                          ALPHA support from <jestabro@amt.tay1.dec.com>
 | 
						|
      0.41    26-Jun-95   Added verify_area() calls in depca_ioctl() from
 | 
						|
                          suggestion by <heiko@colossus.escape.de>
 | 
						|
      0.42    27-Dec-95   Add 'mem' shared memory assignment for loadable
 | 
						|
                          modules.
 | 
						|
                          Add 'adapter_name' for loadable modules when no PROM.
 | 
						|
			  Both above from a suggestion by
 | 
						|
			  <pchen@woodruffs121.residence.gatech.edu>.
 | 
						|
			  Add new multicasting code.
 | 
						|
      0.421   22-Apr-96	  Fix alloc_device() bug <jari@markkus2.fimr.fi>
 | 
						|
      0.422   29-Apr-96	  Fix depca_hw_init() bug <jari@markkus2.fimr.fi>
 | 
						|
      0.423    7-Jun-96   Fix module load bug <kmg@barco.be>
 | 
						|
      0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
 | 
						|
      0.44     1-Sep-97   Fix *_probe() to test check_region() first - bug
 | 
						|
                           reported by <mmogilvi@elbert.uccs.edu>
 | 
						|
      0.45     3-Nov-98   Added support for MCA EtherWORKS (DE210/DE212) cards
 | 
						|
                           by <tymm@computer.org>
 | 
						|
      0.451    5-Nov-98   Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
 | 
						|
      0.5     14-Nov-98   Re-spin for 2.1.x kernels.
 | 
						|
      0.51    27-Jun-99   Correct received packet length for CRC from
 | 
						|
                           report by <worm@dkik.dk>
 | 
						|
      0.52    16-Oct-00   Fixes for 2.3 io memory accesses
 | 
						|
                          Fix show-stopper (ints left masked) in depca_interrupt
 | 
						|
			   by <peterd@pnd-pc.demon.co.uk>
 | 
						|
      0.53    12-Jan-01	  Release resources on failure, bss tidbits
 | 
						|
      			   by acme@conectiva.com.br
 | 
						|
      0.54    08-Nov-01	  use library crc32 functions
 | 
						|
      			   by Matt_Domsch@dell.com
 | 
						|
      0.55    01-Mar-03   Use EISA/sysfs framework <maz@wild-wind.fr.eu.org>
 | 
						|
 | 
						|
    =========================================================================
 | 
						|
*/
 | 
						|
 | 
						|
#include <linux/module.h>
 | 
						|
#include <linux/kernel.h>
 | 
						|
#include <linux/string.h>
 | 
						|
#include <linux/errno.h>
 | 
						|
#include <linux/ioport.h>
 | 
						|
#include <linux/slab.h>
 | 
						|
#include <linux/interrupt.h>
 | 
						|
#include <linux/delay.h>
 | 
						|
#include <linux/init.h>
 | 
						|
#include <linux/crc32.h>
 | 
						|
#include <linux/netdevice.h>
 | 
						|
#include <linux/etherdevice.h>
 | 
						|
#include <linux/skbuff.h>
 | 
						|
#include <linux/time.h>
 | 
						|
#include <linux/types.h>
 | 
						|
#include <linux/unistd.h>
 | 
						|
#include <linux/ctype.h>
 | 
						|
#include <linux/moduleparam.h>
 | 
						|
#include <linux/platform_device.h>
 | 
						|
#include <linux/bitops.h>
 | 
						|
 | 
						|
#include <asm/uaccess.h>
 | 
						|
#include <asm/io.h>
 | 
						|
#include <asm/dma.h>
 | 
						|
 | 
						|
#ifdef CONFIG_MCA
 | 
						|
#include <linux/mca.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef CONFIG_EISA
 | 
						|
#include <linux/eisa.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "depca.h"
 | 
						|
 | 
						|
static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
 | 
						|
 | 
						|
#ifdef DEPCA_DEBUG
 | 
						|
static int depca_debug = DEPCA_DEBUG;
 | 
						|
#else
 | 
						|
static int depca_debug = 1;
 | 
						|
#endif
 | 
						|
 | 
						|
#define DEPCA_NDA 0xffe0	/* No Device Address */
 | 
						|
 | 
						|
#define TX_TIMEOUT (1*HZ)
 | 
						|
 | 
						|
/*
 | 
						|
** Ethernet PROM defines
 | 
						|
*/
 | 
						|
#define PROBE_LENGTH    32
 | 
						|
#define ETH_PROM_SIG    0xAA5500FFUL
 | 
						|
 | 
						|
/*
 | 
						|
** Set the number of Tx and Rx buffers. Ensure that the memory requested
 | 
						|
** here is <= to the amount of shared memory set up by the board switches.
 | 
						|
** The number of descriptors MUST BE A POWER OF 2.
 | 
						|
**
 | 
						|
** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
 | 
						|
*/
 | 
						|
#define NUM_RX_DESC     8	/* Number of RX descriptors */
 | 
						|
#define NUM_TX_DESC     8	/* Number of TX descriptors */
 | 
						|
#define RX_BUFF_SZ	1536	/* Buffer size for each Rx buffer */
 | 
						|
#define TX_BUFF_SZ	1536	/* Buffer size for each Tx buffer */
 | 
						|
 | 
						|
/*
 | 
						|
** EISA bus defines
 | 
						|
*/
 | 
						|
#define DEPCA_EISA_IO_PORTS 0x0c00	/* I/O port base address, slot 0 */
 | 
						|
 | 
						|
/*
 | 
						|
** ISA Bus defines
 | 
						|
*/
 | 
						|
#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
 | 
						|
#define DEPCA_TOTAL_SIZE 0x10
 | 
						|
 | 
						|
static struct {
 | 
						|
	u_long iobase;
 | 
						|
	struct platform_device *device;
 | 
						|
} depca_io_ports[] = {
 | 
						|
	{ 0x300, NULL },
 | 
						|
	{ 0x200, NULL },
 | 
						|
	{ 0    , NULL },
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
** Name <-> Adapter mapping
 | 
						|
*/
 | 
						|
#define DEPCA_SIGNATURE {"DEPCA",\
 | 
						|
			 "DE100","DE101",\
 | 
						|
                         "DE200","DE201","DE202",\
 | 
						|
			 "DE210","DE212",\
 | 
						|
                         "DE422",\
 | 
						|
                         ""}
 | 
						|
 | 
						|
static char* __initdata depca_signature[] = DEPCA_SIGNATURE;
 | 
						|
 | 
						|
enum depca_type {
 | 
						|
	DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
 | 
						|
};
 | 
						|
 | 
						|
static char depca_string[] = "depca";
 | 
						|
 | 
						|
static int depca_device_remove (struct device *device);
 | 
						|
 | 
						|
#ifdef CONFIG_EISA
 | 
						|
static struct eisa_device_id depca_eisa_ids[] = {
 | 
						|
	{ "DEC4220", de422 },
 | 
						|
	{ "" }
 | 
						|
};
 | 
						|
MODULE_DEVICE_TABLE(eisa, depca_eisa_ids);
 | 
						|
 | 
						|
static int depca_eisa_probe  (struct device *device);
 | 
						|
 | 
						|
static struct eisa_driver depca_eisa_driver = {
 | 
						|
	.id_table = depca_eisa_ids,
 | 
						|
	.driver   = {
 | 
						|
		.name    = depca_string,
 | 
						|
		.probe   = depca_eisa_probe,
 | 
						|
		.remove  = __devexit_p (depca_device_remove)
 | 
						|
	}
 | 
						|
};
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef CONFIG_MCA
 | 
						|
/*
 | 
						|
** Adapter ID for the MCA EtherWORKS DE210/212 adapter
 | 
						|
*/
 | 
						|
#define DE210_ID 0x628d
 | 
						|
#define DE212_ID 0x6def
 | 
						|
 | 
						|
static short depca_mca_adapter_ids[] = {
 | 
						|
	DE210_ID,
 | 
						|
	DE212_ID,
 | 
						|
	0x0000
 | 
						|
};
 | 
						|
 | 
						|
static char *depca_mca_adapter_name[] = {
 | 
						|
	"DEC EtherWORKS MC Adapter (DE210)",
 | 
						|
	"DEC EtherWORKS MC Adapter (DE212)",
 | 
						|
	NULL
 | 
						|
};
 | 
						|
 | 
						|
static enum depca_type depca_mca_adapter_type[] = {
 | 
						|
	de210,
 | 
						|
	de212,
 | 
						|
	0
 | 
						|
};
 | 
						|
 | 
						|
static int depca_mca_probe (struct device *);
 | 
						|
 | 
						|
static struct mca_driver depca_mca_driver = {
 | 
						|
	.id_table = depca_mca_adapter_ids,
 | 
						|
	.driver   = {
 | 
						|
		.name   = depca_string,
 | 
						|
		.bus    = &mca_bus_type,
 | 
						|
		.probe  = depca_mca_probe,
 | 
						|
		.remove = __devexit_p(depca_device_remove),
 | 
						|
	},
 | 
						|
};
 | 
						|
#endif
 | 
						|
 | 
						|
static int depca_isa_probe (struct platform_device *);
 | 
						|
 | 
						|
static int __devexit depca_isa_remove(struct platform_device *pdev)
 | 
						|
{
 | 
						|
	return depca_device_remove(&pdev->dev);
 | 
						|
}
 | 
						|
 | 
						|
static struct platform_driver depca_isa_driver = {
 | 
						|
	.probe  = depca_isa_probe,
 | 
						|
	.remove = __devexit_p(depca_isa_remove),
 | 
						|
	.driver	= {
 | 
						|
		.name   = depca_string,
 | 
						|
	},
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
** Miscellaneous info...
 | 
						|
*/
 | 
						|
#define DEPCA_STRLEN 16
 | 
						|
 | 
						|
/*
 | 
						|
** Memory Alignment. Each descriptor is 4 longwords long. To force a
 | 
						|
** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
 | 
						|
** DESC_ALIGN. DEPCA_ALIGN aligns the start address of the private memory area
 | 
						|
** and hence the RX descriptor ring's first entry.
 | 
						|
*/
 | 
						|
#define DEPCA_ALIGN4      ((u_long)4 - 1)	/* 1 longword align */
 | 
						|
#define DEPCA_ALIGN8      ((u_long)8 - 1)	/* 2 longword (quadword) align */
 | 
						|
#define DEPCA_ALIGN         DEPCA_ALIGN8	/* Keep the LANCE happy... */
 | 
						|
 | 
						|
/*
 | 
						|
** The DEPCA Rx and Tx ring descriptors.
 | 
						|
*/
 | 
						|
struct depca_rx_desc {
 | 
						|
	volatile s32 base;
 | 
						|
	s16 buf_length;		/* This length is negative 2's complement! */
 | 
						|
	s16 msg_length;		/* This length is "normal". */
 | 
						|
};
 | 
						|
 | 
						|
struct depca_tx_desc {
 | 
						|
	volatile s32 base;
 | 
						|
	s16 length;		/* This length is negative 2's complement! */
 | 
						|
	s16 misc;		/* Errors and TDR info */
 | 
						|
};
 | 
						|
 | 
						|
#define LA_MASK 0x0000ffff	/* LANCE address mask for mapping network RAM
 | 
						|
				   to LANCE memory address space */
 | 
						|
 | 
						|
/*
 | 
						|
** The Lance initialization block, described in databook, in common memory.
 | 
						|
*/
 | 
						|
struct depca_init {
 | 
						|
	u16 mode;		/* Mode register */
 | 
						|
	u8 phys_addr[ETH_ALEN];	/* Physical ethernet address */
 | 
						|
	u8 mcast_table[8];	/* Multicast Hash Table. */
 | 
						|
	u32 rx_ring;		/* Rx ring base pointer & ring length */
 | 
						|
	u32 tx_ring;		/* Tx ring base pointer & ring length */
 | 
						|
};
 | 
						|
 | 
						|
#define DEPCA_PKT_STAT_SZ 16
 | 
						|
#define DEPCA_PKT_BIN_SZ  128	/* Should be >=100 unless you
 | 
						|
				   increase DEPCA_PKT_STAT_SZ */
 | 
						|
struct depca_private {
 | 
						|
	char adapter_name[DEPCA_STRLEN];	/* /proc/ioports string                  */
 | 
						|
	enum depca_type adapter;		/* Adapter type */
 | 
						|
	enum {
 | 
						|
                DEPCA_BUS_MCA = 1,
 | 
						|
                DEPCA_BUS_ISA,
 | 
						|
                DEPCA_BUS_EISA,
 | 
						|
        } depca_bus;	        /* type of bus */
 | 
						|
	struct depca_init init_block;	/* Shadow Initialization block            */
 | 
						|
/* CPU address space fields */
 | 
						|
	struct depca_rx_desc __iomem *rx_ring;	/* Pointer to start of RX descriptor ring */
 | 
						|
	struct depca_tx_desc __iomem *tx_ring;	/* Pointer to start of TX descriptor ring */
 | 
						|
	void __iomem *rx_buff[NUM_RX_DESC];	/* CPU virt address of sh'd memory buffs  */
 | 
						|
	void __iomem *tx_buff[NUM_TX_DESC];	/* CPU virt address of sh'd memory buffs  */
 | 
						|
	void __iomem *sh_mem;	/* CPU mapped virt address of device RAM  */
 | 
						|
	u_long mem_start;	/* Bus address of device RAM (before remap) */
 | 
						|
	u_long mem_len;		/* device memory size */
 | 
						|
/* Device address space fields */
 | 
						|
	u_long device_ram_start;	/* Start of RAM in device addr space      */
 | 
						|
/* Offsets used in both address spaces */
 | 
						|
	u_long rx_ring_offset;	/* Offset from start of RAM to rx_ring    */
 | 
						|
	u_long tx_ring_offset;	/* Offset from start of RAM to tx_ring    */
 | 
						|
	u_long buffs_offset;	/* LANCE Rx and Tx buffers start address. */
 | 
						|
/* Kernel-only (not device) fields */
 | 
						|
	int rx_new, tx_new;	/* The next free ring entry               */
 | 
						|
	int rx_old, tx_old;	/* The ring entries to be free()ed.       */
 | 
						|
	struct net_device_stats stats;
 | 
						|
	spinlock_t lock;
 | 
						|
	struct {		/* Private stats counters                 */
 | 
						|
		u32 bins[DEPCA_PKT_STAT_SZ];
 | 
						|
		u32 unicast;
 | 
						|
		u32 multicast;
 | 
						|
		u32 broadcast;
 | 
						|
		u32 excessive_collisions;
 | 
						|
		u32 tx_underruns;
 | 
						|
		u32 excessive_underruns;
 | 
						|
	} pktStats;
 | 
						|
	int txRingMask;		/* TX ring mask                           */
 | 
						|
	int rxRingMask;		/* RX ring mask                           */
 | 
						|
	s32 rx_rlen;		/* log2(rxRingMask+1) for the descriptors */
 | 
						|
	s32 tx_rlen;		/* log2(txRingMask+1) for the descriptors */
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
** The transmit ring full condition is described by the tx_old and tx_new
 | 
						|
** pointers by:
 | 
						|
**    tx_old            = tx_new    Empty ring
 | 
						|
**    tx_old            = tx_new+1  Full ring
 | 
						|
**    tx_old+txRingMask = tx_new    Full ring  (wrapped condition)
 | 
						|
*/
 | 
						|
#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
 | 
						|
			 lp->tx_old+lp->txRingMask-lp->tx_new:\
 | 
						|
                         lp->tx_old               -lp->tx_new-1)
 | 
						|
 | 
						|
/*
 | 
						|
** Public Functions
 | 
						|
*/
 | 
						|
static int depca_open(struct net_device *dev);
 | 
						|
static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
 | 
						|
static irqreturn_t depca_interrupt(int irq, void *dev_id);
 | 
						|
static int depca_close(struct net_device *dev);
 | 
						|
static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 | 
						|
static void depca_tx_timeout(struct net_device *dev);
 | 
						|
static struct net_device_stats *depca_get_stats(struct net_device *dev);
 | 
						|
static void set_multicast_list(struct net_device *dev);
 | 
						|
 | 
						|
/*
 | 
						|
** Private functions
 | 
						|
*/
 | 
						|
static void depca_init_ring(struct net_device *dev);
 | 
						|
static int depca_rx(struct net_device *dev);
 | 
						|
static int depca_tx(struct net_device *dev);
 | 
						|
 | 
						|
static void LoadCSRs(struct net_device *dev);
 | 
						|
static int InitRestartDepca(struct net_device *dev);
 | 
						|
static int DepcaSignature(char *name, u_long paddr);
 | 
						|
static int DevicePresent(u_long ioaddr);
 | 
						|
static int get_hw_addr(struct net_device *dev);
 | 
						|
static void SetMulticastFilter(struct net_device *dev);
 | 
						|
static int load_packet(struct net_device *dev, struct sk_buff *skb);
 | 
						|
static void depca_dbg_open(struct net_device *dev);
 | 
						|
 | 
						|
static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
 | 
						|
static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
 | 
						|
static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
 | 
						|
static u_char *depca_irq;
 | 
						|
 | 
						|
static int irq;
 | 
						|
static int io;
 | 
						|
static char *adapter_name;
 | 
						|
static int mem;			/* For loadable module assignment
 | 
						|
				   use insmod mem=0x????? .... */
 | 
						|
module_param (irq, int, 0);
 | 
						|
module_param (io, int, 0);
 | 
						|
module_param (adapter_name, charp, 0);
 | 
						|
module_param (mem, int, 0);
 | 
						|
MODULE_PARM_DESC(irq, "DEPCA IRQ number");
 | 
						|
MODULE_PARM_DESC(io, "DEPCA I/O base address");
 | 
						|
MODULE_PARM_DESC(adapter_name, "DEPCA adapter name");
 | 
						|
MODULE_PARM_DESC(mem, "DEPCA shared memory address");
 | 
						|
MODULE_LICENSE("GPL");
 | 
						|
 | 
						|
/*
 | 
						|
** Miscellaneous defines...
 | 
						|
*/
 | 
						|
#define STOP_DEPCA \
 | 
						|
    outw(CSR0, DEPCA_ADDR);\
 | 
						|
    outw(STOP, DEPCA_DATA)
 | 
						|
 | 
						|
static int __init depca_hw_init (struct net_device *dev, struct device *device)
 | 
						|
{
 | 
						|
	struct depca_private *lp;
 | 
						|
	int i, j, offset, netRAM, mem_len, status = 0;
 | 
						|
	s16 nicsr;
 | 
						|
	u_long ioaddr;
 | 
						|
	u_long mem_start;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * We are now supposed to enter this function with the
 | 
						|
	 * following fields filled with proper values :
 | 
						|
	 *
 | 
						|
	 * dev->base_addr
 | 
						|
	 * lp->mem_start
 | 
						|
	 * lp->depca_bus
 | 
						|
	 * lp->adapter
 | 
						|
	 *
 | 
						|
	 * dev->irq can be set if known from device configuration (on
 | 
						|
	 * MCA or EISA) or module option. Otherwise, it will be auto
 | 
						|
	 * detected.
 | 
						|
	 */
 | 
						|
 | 
						|
	ioaddr = dev->base_addr;
 | 
						|
 | 
						|
	STOP_DEPCA;
 | 
						|
 | 
						|
	nicsr = inb(DEPCA_NICSR);
 | 
						|
	nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
 | 
						|
	outb(nicsr, DEPCA_NICSR);
 | 
						|
 | 
						|
	if (inw(DEPCA_DATA) != STOP) {
 | 
						|
		return -ENXIO;
 | 
						|
	}
 | 
						|
 | 
						|
	lp = (struct depca_private *) dev->priv;
 | 
						|
	mem_start = lp->mem_start;
 | 
						|
 | 
						|
	if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown)
 | 
						|
		return -ENXIO;
 | 
						|
 | 
						|
	printk ("%s: %s at 0x%04lx",
 | 
						|
	        device->bus_id, depca_signature[lp->adapter], ioaddr);
 | 
						|
 | 
						|
	switch (lp->depca_bus) {
 | 
						|
#ifdef CONFIG_MCA
 | 
						|
	case DEPCA_BUS_MCA:
 | 
						|
		printk(" (MCA slot %d)", to_mca_device(device)->slot + 1);
 | 
						|
		break;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef CONFIG_EISA
 | 
						|
	case DEPCA_BUS_EISA:
 | 
						|
		printk(" (EISA slot %d)", to_eisa_device(device)->slot);
 | 
						|
		break;
 | 
						|
#endif
 | 
						|
 | 
						|
	case DEPCA_BUS_ISA:
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		printk("Unknown DEPCA bus %d\n", lp->depca_bus);
 | 
						|
		return -ENXIO;
 | 
						|
	}
 | 
						|
 | 
						|
	printk(", h/w address ");
 | 
						|
	status = get_hw_addr(dev);
 | 
						|
	if (status != 0) {
 | 
						|
		printk("      which has an Ethernet PROM CRC error.\n");
 | 
						|
		return -ENXIO;
 | 
						|
	}
 | 
						|
	for (i = 0; i < ETH_ALEN - 1; i++) {	/* get the ethernet address */
 | 
						|
		printk("%2.2x:", dev->dev_addr[i]);
 | 
						|
	}
 | 
						|
	printk("%2.2x", dev->dev_addr[i]);
 | 
						|
 | 
						|
	/* Set up the maximum amount of network RAM(kB) */
 | 
						|
	netRAM = ((lp->adapter != DEPCA) ? 64 : 48);
 | 
						|
	if ((nicsr & _128KB) && (lp->adapter == de422))
 | 
						|
		netRAM = 128;
 | 
						|
 | 
						|
	/* Shared Memory Base Address */
 | 
						|
	if (nicsr & BUF) {
 | 
						|
		nicsr &= ~BS;	/* DEPCA RAM in top 32k */
 | 
						|
		netRAM -= 32;
 | 
						|
 | 
						|
		/* Only EISA/ISA needs start address to be re-computed */
 | 
						|
		if (lp->depca_bus != DEPCA_BUS_MCA)
 | 
						|
			mem_start += 0x8000;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
 | 
						|
	    > (netRAM << 10)) {
 | 
						|
		printk(",\n       requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
 | 
						|
		return -ENXIO;
 | 
						|
	}
 | 
						|
 | 
						|
	printk(",\n      has %dkB RAM at 0x%.5lx", netRAM, mem_start);
 | 
						|
 | 
						|
	/* Enable the shadow RAM. */
 | 
						|
	if (lp->adapter != DEPCA) {
 | 
						|
		nicsr |= SHE;
 | 
						|
		outb(nicsr, DEPCA_NICSR);
 | 
						|
	}
 | 
						|
 | 
						|
	spin_lock_init(&lp->lock);
 | 
						|
	sprintf(lp->adapter_name, "%s (%s)",
 | 
						|
		depca_signature[lp->adapter], device->bus_id);
 | 
						|
	status = -EBUSY;
 | 
						|
 | 
						|
	/* Initialisation Block */
 | 
						|
	if (!request_mem_region (mem_start, mem_len, lp->adapter_name)) {
 | 
						|
		printk(KERN_ERR "depca: cannot request ISA memory, aborting\n");
 | 
						|
		goto out_priv;
 | 
						|
	}
 | 
						|
 | 
						|
	status = -EIO;
 | 
						|
	lp->sh_mem = ioremap(mem_start, mem_len);
 | 
						|
	if (lp->sh_mem == NULL) {
 | 
						|
		printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n");
 | 
						|
		goto out1;
 | 
						|
	}
 | 
						|
 | 
						|
	lp->mem_start = mem_start;
 | 
						|
	lp->mem_len   = mem_len;
 | 
						|
	lp->device_ram_start = mem_start & LA_MASK;
 | 
						|
 | 
						|
	offset = 0;
 | 
						|
	offset += sizeof(struct depca_init);
 | 
						|
 | 
						|
	/* Tx & Rx descriptors (aligned to a quadword boundary) */
 | 
						|
	offset = (offset + DEPCA_ALIGN) & ~DEPCA_ALIGN;
 | 
						|
	lp->rx_ring = (struct depca_rx_desc __iomem *) (lp->sh_mem + offset);
 | 
						|
	lp->rx_ring_offset = offset;
 | 
						|
 | 
						|
	offset += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
 | 
						|
	lp->tx_ring = (struct depca_tx_desc __iomem *) (lp->sh_mem + offset);
 | 
						|
	lp->tx_ring_offset = offset;
 | 
						|
 | 
						|
	offset += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
 | 
						|
 | 
						|
	lp->buffs_offset = offset;
 | 
						|
 | 
						|
	/* Finish initialising the ring information. */
 | 
						|
	lp->rxRingMask = NUM_RX_DESC - 1;
 | 
						|
	lp->txRingMask = NUM_TX_DESC - 1;
 | 
						|
 | 
						|
	/* Calculate Tx/Rx RLEN size for the descriptors. */
 | 
						|
	for (i = 0, j = lp->rxRingMask; j > 0; i++) {
 | 
						|
		j >>= 1;
 | 
						|
	}
 | 
						|
	lp->rx_rlen = (s32) (i << 29);
 | 
						|
	for (i = 0, j = lp->txRingMask; j > 0; i++) {
 | 
						|
		j >>= 1;
 | 
						|
	}
 | 
						|
	lp->tx_rlen = (s32) (i << 29);
 | 
						|
 | 
						|
	/* Load the initialisation block */
 | 
						|
	depca_init_ring(dev);
 | 
						|
 | 
						|
	/* Initialise the control and status registers */
 | 
						|
	LoadCSRs(dev);
 | 
						|
 | 
						|
	/* Enable DEPCA board interrupts for autoprobing */
 | 
						|
	nicsr = ((nicsr & ~IM) | IEN);
 | 
						|
	outb(nicsr, DEPCA_NICSR);
 | 
						|
 | 
						|
	/* To auto-IRQ we enable the initialization-done and DMA err,
 | 
						|
	   interrupts. For now we will always get a DMA error. */
 | 
						|
	if (dev->irq < 2) {
 | 
						|
		unsigned char irqnum;
 | 
						|
		unsigned long irq_mask, delay;
 | 
						|
 | 
						|
		irq_mask = probe_irq_on();
 | 
						|
 | 
						|
		/* Assign the correct irq list */
 | 
						|
		switch (lp->adapter) {
 | 
						|
		case DEPCA:
 | 
						|
		case de100:
 | 
						|
		case de101:
 | 
						|
			depca_irq = de1xx_irq;
 | 
						|
			break;
 | 
						|
		case de200:
 | 
						|
		case de201:
 | 
						|
		case de202:
 | 
						|
		case de210:
 | 
						|
		case de212:
 | 
						|
			depca_irq = de2xx_irq;
 | 
						|
			break;
 | 
						|
		case de422:
 | 
						|
			depca_irq = de422_irq;
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			break;	/* Not reached */
 | 
						|
		}
 | 
						|
 | 
						|
		/* Trigger an initialization just for the interrupt. */
 | 
						|
		outw(INEA | INIT, DEPCA_DATA);
 | 
						|
 | 
						|
		delay = jiffies + HZ/50;
 | 
						|
		while (time_before(jiffies, delay))
 | 
						|
			yield();
 | 
						|
 | 
						|
		irqnum = probe_irq_off(irq_mask);
 | 
						|
 | 
						|
		status = -ENXIO;
 | 
						|
		if (!irqnum) {
 | 
						|
			printk(" and failed to detect IRQ line.\n");
 | 
						|
			goto out2;
 | 
						|
		} else {
 | 
						|
			for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++)
 | 
						|
				if (irqnum == depca_irq[i]) {
 | 
						|
					dev->irq = irqnum;
 | 
						|
					printk(" and uses IRQ%d.\n", dev->irq);
 | 
						|
				}
 | 
						|
 | 
						|
			if (!dev->irq) {
 | 
						|
				printk(" but incorrect IRQ line detected.\n");
 | 
						|
				goto out2;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		printk(" and assigned IRQ%d.\n", dev->irq);
 | 
						|
	}
 | 
						|
 | 
						|
	if (depca_debug > 1) {
 | 
						|
		printk(version);
 | 
						|
	}
 | 
						|
 | 
						|
	/* The DEPCA-specific entries in the device structure. */
 | 
						|
	dev->open = &depca_open;
 | 
						|
	dev->hard_start_xmit = &depca_start_xmit;
 | 
						|
	dev->stop = &depca_close;
 | 
						|
	dev->get_stats = &depca_get_stats;
 | 
						|
	dev->set_multicast_list = &set_multicast_list;
 | 
						|
	dev->do_ioctl = &depca_ioctl;
 | 
						|
	dev->tx_timeout = depca_tx_timeout;
 | 
						|
	dev->watchdog_timeo = TX_TIMEOUT;
 | 
						|
 | 
						|
	dev->mem_start = 0;
 | 
						|
 | 
						|
	device->driver_data = dev;
 | 
						|
	SET_NETDEV_DEV (dev, device);
 | 
						|
 | 
						|
	status = register_netdev(dev);
 | 
						|
	if (status == 0)
 | 
						|
		return 0;
 | 
						|
out2:
 | 
						|
	iounmap(lp->sh_mem);
 | 
						|
out1:
 | 
						|
	release_mem_region (mem_start, mem_len);
 | 
						|
out_priv:
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int depca_open(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
	s16 nicsr;
 | 
						|
	int status = 0;
 | 
						|
 | 
						|
	STOP_DEPCA;
 | 
						|
	nicsr = inb(DEPCA_NICSR);
 | 
						|
 | 
						|
	/* Make sure the shadow RAM is enabled */
 | 
						|
	if (lp->adapter != DEPCA) {
 | 
						|
		nicsr |= SHE;
 | 
						|
		outb(nicsr, DEPCA_NICSR);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Re-initialize the DEPCA... */
 | 
						|
	depca_init_ring(dev);
 | 
						|
	LoadCSRs(dev);
 | 
						|
 | 
						|
	depca_dbg_open(dev);
 | 
						|
 | 
						|
	if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) {
 | 
						|
		printk("depca_open(): Requested IRQ%d is busy\n", dev->irq);
 | 
						|
		status = -EAGAIN;
 | 
						|
	} else {
 | 
						|
 | 
						|
		/* Enable DEPCA board interrupts and turn off LED */
 | 
						|
		nicsr = ((nicsr & ~IM & ~LED) | IEN);
 | 
						|
		outb(nicsr, DEPCA_NICSR);
 | 
						|
		outw(CSR0, DEPCA_ADDR);
 | 
						|
 | 
						|
		netif_start_queue(dev);
 | 
						|
 | 
						|
		status = InitRestartDepca(dev);
 | 
						|
 | 
						|
		if (depca_debug > 1) {
 | 
						|
			printk("CSR0: 0x%4.4x\n", inw(DEPCA_DATA));
 | 
						|
			printk("nicsr: 0x%02x\n", inb(DEPCA_NICSR));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
/* Initialize the lance Rx and Tx descriptor rings. */
 | 
						|
static void depca_init_ring(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	u_int i;
 | 
						|
	u_long offset;
 | 
						|
 | 
						|
	/* Lock out other processes whilst setting up the hardware */
 | 
						|
	netif_stop_queue(dev);
 | 
						|
 | 
						|
	lp->rx_new = lp->tx_new = 0;
 | 
						|
	lp->rx_old = lp->tx_old = 0;
 | 
						|
 | 
						|
	/* Initialize the base address and length of each buffer in the ring */
 | 
						|
	for (i = 0; i <= lp->rxRingMask; i++) {
 | 
						|
		offset = lp->buffs_offset + i * RX_BUFF_SZ;
 | 
						|
		writel((lp->device_ram_start + offset) | R_OWN, &lp->rx_ring[i].base);
 | 
						|
		writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
 | 
						|
		lp->rx_buff[i] = lp->sh_mem + offset;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i <= lp->txRingMask; i++) {
 | 
						|
		offset = lp->buffs_offset + (i + lp->rxRingMask + 1) * TX_BUFF_SZ;
 | 
						|
		writel((lp->device_ram_start + offset) & 0x00ffffff, &lp->tx_ring[i].base);
 | 
						|
		lp->tx_buff[i] = lp->sh_mem + offset;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Set up the initialization block */
 | 
						|
	lp->init_block.rx_ring = (lp->device_ram_start + lp->rx_ring_offset) | lp->rx_rlen;
 | 
						|
	lp->init_block.tx_ring = (lp->device_ram_start + lp->tx_ring_offset) | lp->tx_rlen;
 | 
						|
 | 
						|
	SetMulticastFilter(dev);
 | 
						|
 | 
						|
	for (i = 0; i < ETH_ALEN; i++) {
 | 
						|
		lp->init_block.phys_addr[i] = dev->dev_addr[i];
 | 
						|
	}
 | 
						|
 | 
						|
	lp->init_block.mode = 0x0000;	/* Enable the Tx and Rx */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void depca_tx_timeout(struct net_device *dev)
 | 
						|
{
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
 | 
						|
	printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA));
 | 
						|
 | 
						|
	STOP_DEPCA;
 | 
						|
	depca_init_ring(dev);
 | 
						|
	LoadCSRs(dev);
 | 
						|
	dev->trans_start = jiffies;
 | 
						|
	netif_wake_queue(dev);
 | 
						|
	InitRestartDepca(dev);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
** Writes a socket buffer to TX descriptor ring and starts transmission
 | 
						|
*/
 | 
						|
static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
	int status = 0;
 | 
						|
 | 
						|
	/* Transmitter timeout, serious problems. */
 | 
						|
	if (skb->len < 1)
 | 
						|
		goto out;
 | 
						|
 | 
						|
	if (skb_padto(skb, ETH_ZLEN))
 | 
						|
		goto out;
 | 
						|
 | 
						|
	netif_stop_queue(dev);
 | 
						|
 | 
						|
	if (TX_BUFFS_AVAIL) {	/* Fill in a Tx ring entry */
 | 
						|
		status = load_packet(dev, skb);
 | 
						|
 | 
						|
		if (!status) {
 | 
						|
			/* Trigger an immediate send demand. */
 | 
						|
			outw(CSR0, DEPCA_ADDR);
 | 
						|
			outw(INEA | TDMD, DEPCA_DATA);
 | 
						|
 | 
						|
			dev->trans_start = jiffies;
 | 
						|
			dev_kfree_skb(skb);
 | 
						|
		}
 | 
						|
		if (TX_BUFFS_AVAIL)
 | 
						|
			netif_start_queue(dev);
 | 
						|
	} else
 | 
						|
		status = -1;
 | 
						|
 | 
						|
      out:
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** The DEPCA interrupt handler.
 | 
						|
*/
 | 
						|
static irqreturn_t depca_interrupt(int irq, void *dev_id)
 | 
						|
{
 | 
						|
	struct net_device *dev = dev_id;
 | 
						|
	struct depca_private *lp;
 | 
						|
	s16 csr0, nicsr;
 | 
						|
	u_long ioaddr;
 | 
						|
 | 
						|
	if (dev == NULL) {
 | 
						|
		printk("depca_interrupt(): irq %d for unknown device.\n", irq);
 | 
						|
		return IRQ_NONE;
 | 
						|
	}
 | 
						|
 | 
						|
	lp = (struct depca_private *) dev->priv;
 | 
						|
	ioaddr = dev->base_addr;
 | 
						|
 | 
						|
	spin_lock(&lp->lock);
 | 
						|
 | 
						|
	/* mask the DEPCA board interrupts and turn on the LED */
 | 
						|
	nicsr = inb(DEPCA_NICSR);
 | 
						|
	nicsr |= (IM | LED);
 | 
						|
	outb(nicsr, DEPCA_NICSR);
 | 
						|
 | 
						|
	outw(CSR0, DEPCA_ADDR);
 | 
						|
	csr0 = inw(DEPCA_DATA);
 | 
						|
 | 
						|
	/* Acknowledge all of the current interrupt sources ASAP. */
 | 
						|
	outw(csr0 & INTE, DEPCA_DATA);
 | 
						|
 | 
						|
	if (csr0 & RINT)	/* Rx interrupt (packet arrived) */
 | 
						|
		depca_rx(dev);
 | 
						|
 | 
						|
	if (csr0 & TINT)	/* Tx interrupt (packet sent) */
 | 
						|
		depca_tx(dev);
 | 
						|
 | 
						|
	/* Any resources available? */
 | 
						|
	if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
 | 
						|
		netif_wake_queue(dev);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Unmask the DEPCA board interrupts and turn off the LED */
 | 
						|
	nicsr = (nicsr & ~IM & ~LED);
 | 
						|
	outb(nicsr, DEPCA_NICSR);
 | 
						|
 | 
						|
	spin_unlock(&lp->lock);
 | 
						|
	return IRQ_HANDLED;
 | 
						|
}
 | 
						|
 | 
						|
/* Called with lp->lock held */
 | 
						|
static int depca_rx(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	int i, entry;
 | 
						|
	s32 status;
 | 
						|
 | 
						|
	for (entry = lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry = lp->rx_new) {
 | 
						|
		status = readl(&lp->rx_ring[entry].base) >> 16;
 | 
						|
		if (status & R_STP) {	/* Remember start of frame */
 | 
						|
			lp->rx_old = entry;
 | 
						|
		}
 | 
						|
		if (status & R_ENP) {	/* Valid frame status */
 | 
						|
			if (status & R_ERR) {	/* There was an error. */
 | 
						|
				lp->stats.rx_errors++;	/* Update the error stats. */
 | 
						|
				if (status & R_FRAM)
 | 
						|
					lp->stats.rx_frame_errors++;
 | 
						|
				if (status & R_OFLO)
 | 
						|
					lp->stats.rx_over_errors++;
 | 
						|
				if (status & R_CRC)
 | 
						|
					lp->stats.rx_crc_errors++;
 | 
						|
				if (status & R_BUFF)
 | 
						|
					lp->stats.rx_fifo_errors++;
 | 
						|
			} else {
 | 
						|
				short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
 | 
						|
				struct sk_buff *skb;
 | 
						|
 | 
						|
				skb = dev_alloc_skb(pkt_len + 2);
 | 
						|
				if (skb != NULL) {
 | 
						|
					unsigned char *buf;
 | 
						|
					skb_reserve(skb, 2);	/* 16 byte align the IP header */
 | 
						|
					buf = skb_put(skb, pkt_len);
 | 
						|
					if (entry < lp->rx_old) {	/* Wrapped buffer */
 | 
						|
						len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
 | 
						|
						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
 | 
						|
						memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len - len);
 | 
						|
					} else {	/* Linear buffer */
 | 
						|
						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
 | 
						|
					}
 | 
						|
 | 
						|
					/*
 | 
						|
					   ** Notify the upper protocol layers that there is another
 | 
						|
					   ** packet to handle
 | 
						|
					 */
 | 
						|
					skb->protocol = eth_type_trans(skb, dev);
 | 
						|
					netif_rx(skb);
 | 
						|
 | 
						|
					/*
 | 
						|
					   ** Update stats
 | 
						|
					 */
 | 
						|
					dev->last_rx = jiffies;
 | 
						|
					lp->stats.rx_packets++;
 | 
						|
					lp->stats.rx_bytes += pkt_len;
 | 
						|
					for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
 | 
						|
						if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
 | 
						|
							lp->pktStats.bins[i]++;
 | 
						|
							i = DEPCA_PKT_STAT_SZ;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					if (buf[0] & 0x01) {	/* Multicast/Broadcast */
 | 
						|
						if ((*(s16 *) & buf[0] == -1) && (*(s16 *) & buf[2] == -1) && (*(s16 *) & buf[4] == -1)) {
 | 
						|
							lp->pktStats.broadcast++;
 | 
						|
						} else {
 | 
						|
							lp->pktStats.multicast++;
 | 
						|
						}
 | 
						|
					} else if ((*(s16 *) & buf[0] == *(s16 *) & dev->dev_addr[0]) && (*(s16 *) & buf[2] == *(s16 *) & dev->dev_addr[2]) && (*(s16 *) & buf[4] == *(s16 *) & dev->dev_addr[4])) {
 | 
						|
						lp->pktStats.unicast++;
 | 
						|
					}
 | 
						|
 | 
						|
					lp->pktStats.bins[0]++;	/* Duplicates stats.rx_packets */
 | 
						|
					if (lp->pktStats.bins[0] == 0) {	/* Reset counters */
 | 
						|
						memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats));
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
 | 
						|
					lp->stats.rx_dropped++;	/* Really, deferred. */
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			/* Change buffer ownership for this last frame, back to the adapter */
 | 
						|
			for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) & lp->rxRingMask) {
 | 
						|
				writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
 | 
						|
			}
 | 
						|
			writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
 | 
						|
		}
 | 
						|
 | 
						|
		/*
 | 
						|
		   ** Update entry information
 | 
						|
		 */
 | 
						|
		lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Buffer sent - check for buffer errors.
 | 
						|
** Called with lp->lock held
 | 
						|
*/
 | 
						|
static int depca_tx(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	int entry;
 | 
						|
	s32 status;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
 | 
						|
	for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
 | 
						|
		status = readl(&lp->tx_ring[entry].base) >> 16;
 | 
						|
 | 
						|
		if (status < 0) {	/* Packet not yet sent! */
 | 
						|
			break;
 | 
						|
		} else if (status & T_ERR) {	/* An error occurred. */
 | 
						|
			status = readl(&lp->tx_ring[entry].misc);
 | 
						|
			lp->stats.tx_errors++;
 | 
						|
			if (status & TMD3_RTRY)
 | 
						|
				lp->stats.tx_aborted_errors++;
 | 
						|
			if (status & TMD3_LCAR)
 | 
						|
				lp->stats.tx_carrier_errors++;
 | 
						|
			if (status & TMD3_LCOL)
 | 
						|
				lp->stats.tx_window_errors++;
 | 
						|
			if (status & TMD3_UFLO)
 | 
						|
				lp->stats.tx_fifo_errors++;
 | 
						|
			if (status & (TMD3_BUFF | TMD3_UFLO)) {
 | 
						|
				/* Trigger an immediate send demand. */
 | 
						|
				outw(CSR0, DEPCA_ADDR);
 | 
						|
				outw(INEA | TDMD, DEPCA_DATA);
 | 
						|
			}
 | 
						|
		} else if (status & (T_MORE | T_ONE)) {
 | 
						|
			lp->stats.collisions++;
 | 
						|
		} else {
 | 
						|
			lp->stats.tx_packets++;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Update all the pointers */
 | 
						|
		lp->tx_old = (++lp->tx_old) & lp->txRingMask;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int depca_close(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	s16 nicsr;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
 | 
						|
	netif_stop_queue(dev);
 | 
						|
 | 
						|
	outw(CSR0, DEPCA_ADDR);
 | 
						|
 | 
						|
	if (depca_debug > 1) {
 | 
						|
		printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	   ** We stop the DEPCA here -- it occasionally polls
 | 
						|
	   ** memory if we don't.
 | 
						|
	 */
 | 
						|
	outw(STOP, DEPCA_DATA);
 | 
						|
 | 
						|
	/*
 | 
						|
	   ** Give back the ROM in case the user wants to go to DOS
 | 
						|
	 */
 | 
						|
	if (lp->adapter != DEPCA) {
 | 
						|
		nicsr = inb(DEPCA_NICSR);
 | 
						|
		nicsr &= ~SHE;
 | 
						|
		outb(nicsr, DEPCA_NICSR);
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	   ** Free the associated irq
 | 
						|
	 */
 | 
						|
	free_irq(dev->irq, dev);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void LoadCSRs(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
 | 
						|
	outw(CSR1, DEPCA_ADDR);	/* initialisation block address LSW */
 | 
						|
	outw((u16) lp->device_ram_start, DEPCA_DATA);
 | 
						|
	outw(CSR2, DEPCA_ADDR);	/* initialisation block address MSW */
 | 
						|
	outw((u16) (lp->device_ram_start >> 16), DEPCA_DATA);
 | 
						|
	outw(CSR3, DEPCA_ADDR);	/* ALE control */
 | 
						|
	outw(ACON, DEPCA_DATA);
 | 
						|
 | 
						|
	outw(CSR0, DEPCA_ADDR);	/* Point back to CSR0 */
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
static int InitRestartDepca(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
	int i, status = 0;
 | 
						|
 | 
						|
	/* Copy the shadow init_block to shared memory */
 | 
						|
	memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
 | 
						|
 | 
						|
	outw(CSR0, DEPCA_ADDR);	/* point back to CSR0 */
 | 
						|
	outw(INIT, DEPCA_DATA);	/* initialize DEPCA */
 | 
						|
 | 
						|
	/* wait for lance to complete initialisation */
 | 
						|
	for (i = 0; (i < 100) && !(inw(DEPCA_DATA) & IDON); i++);
 | 
						|
 | 
						|
	if (i != 100) {
 | 
						|
		/* clear IDON by writing a "1", enable interrupts and start lance */
 | 
						|
		outw(IDON | INEA | STRT, DEPCA_DATA);
 | 
						|
		if (depca_debug > 2) {
 | 
						|
			printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
 | 
						|
		status = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
static struct net_device_stats *depca_get_stats(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
 | 
						|
	/* Null body since there is no framing error counter */
 | 
						|
 | 
						|
	return &lp->stats;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Set or clear the multicast filter for this adaptor.
 | 
						|
*/
 | 
						|
static void set_multicast_list(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
 | 
						|
	netif_stop_queue(dev);
 | 
						|
	while (lp->tx_old != lp->tx_new);	/* Wait for the ring to empty */
 | 
						|
 | 
						|
	STOP_DEPCA;	/* Temporarily stop the depca.  */
 | 
						|
	depca_init_ring(dev);	/* Initialize the descriptor rings */
 | 
						|
 | 
						|
	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous mode */
 | 
						|
		lp->init_block.mode |= PROM;
 | 
						|
	} else {
 | 
						|
		SetMulticastFilter(dev);
 | 
						|
		lp->init_block.mode &= ~PROM;	/* Unset promiscuous mode */
 | 
						|
	}
 | 
						|
 | 
						|
	LoadCSRs(dev);	/* Reload CSR3 */
 | 
						|
	InitRestartDepca(dev);	/* Resume normal operation. */
 | 
						|
	netif_start_queue(dev);	/* Unlock the TX ring */
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Calculate the hash code and update the logical address filter
 | 
						|
** from a list of ethernet multicast addresses.
 | 
						|
** Big endian crc one liner is mine, all mine, ha ha ha ha!
 | 
						|
** LANCE calculates its hash codes big endian.
 | 
						|
*/
 | 
						|
static void SetMulticastFilter(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	struct dev_mc_list *dmi = dev->mc_list;
 | 
						|
	char *addrs;
 | 
						|
	int i, j, bit, byte;
 | 
						|
	u16 hashcode;
 | 
						|
	u32 crc;
 | 
						|
 | 
						|
	if (dev->flags & IFF_ALLMULTI) {	/* Set all multicast bits */
 | 
						|
		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
 | 
						|
			lp->init_block.mcast_table[i] = (char) 0xff;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {	/* Clear the multicast table */
 | 
						|
			lp->init_block.mcast_table[i] = 0;
 | 
						|
		}
 | 
						|
		/* Add multicast addresses */
 | 
						|
		for (i = 0; i < dev->mc_count; i++) {	/* for each address in the list */
 | 
						|
			addrs = dmi->dmi_addr;
 | 
						|
			dmi = dmi->next;
 | 
						|
			if ((*addrs & 0x01) == 1) {	/* multicast address? */
 | 
						|
				crc = ether_crc(ETH_ALEN, addrs);
 | 
						|
				hashcode = (crc & 1);	/* hashcode is 6 LSb of CRC ... */
 | 
						|
				for (j = 0; j < 5; j++) {	/* ... in reverse order. */
 | 
						|
					hashcode = (hashcode << 1) | ((crc >>= 1) & 1);
 | 
						|
				}
 | 
						|
 | 
						|
 | 
						|
				byte = hashcode >> 3;	/* bit[3-5] -> byte in filter */
 | 
						|
				bit = 1 << (hashcode & 0x07);	/* bit[0-2] -> bit in byte */
 | 
						|
				lp->init_block.mcast_table[byte] |= bit;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
 | 
						|
{
 | 
						|
	int status = 0;
 | 
						|
 | 
						|
	if (!request_region (ioaddr, DEPCA_TOTAL_SIZE, depca_string)) {
 | 
						|
		status = -EBUSY;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	if (DevicePresent(ioaddr)) {
 | 
						|
		status = -ENODEV;
 | 
						|
		goto out_release;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!(*devp = alloc_etherdev (sizeof (struct depca_private)))) {
 | 
						|
		status = -ENOMEM;
 | 
						|
		goto out_release;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
 out_release:
 | 
						|
	release_region (ioaddr, DEPCA_TOTAL_SIZE);
 | 
						|
 out:
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef CONFIG_MCA
 | 
						|
/*
 | 
						|
** Microchannel bus I/O device probe
 | 
						|
*/
 | 
						|
static int __init depca_mca_probe(struct device *device)
 | 
						|
{
 | 
						|
	unsigned char pos[2];
 | 
						|
	unsigned char where;
 | 
						|
	unsigned long iobase, mem_start;
 | 
						|
	int irq, err;
 | 
						|
	struct mca_device *mdev = to_mca_device (device);
 | 
						|
	struct net_device *dev;
 | 
						|
	struct depca_private *lp;
 | 
						|
 | 
						|
	/*
 | 
						|
	** Search for the adapter.  If an address has been given, search
 | 
						|
	** specifically for the card at that address.  Otherwise find the
 | 
						|
	** first card in the system.
 | 
						|
	*/
 | 
						|
 | 
						|
	pos[0] = mca_device_read_stored_pos(mdev, 2);
 | 
						|
	pos[1] = mca_device_read_stored_pos(mdev, 3);
 | 
						|
 | 
						|
	/*
 | 
						|
	** IO of card is handled by bits 1 and 2 of pos0.
 | 
						|
	**
 | 
						|
	**    bit2 bit1    IO
 | 
						|
	**       0    0    0x2c00
 | 
						|
	**       0    1    0x2c10
 | 
						|
	**       1    0    0x2c20
 | 
						|
	**       1    1    0x2c30
 | 
						|
	*/
 | 
						|
	where = (pos[0] & 6) >> 1;
 | 
						|
	iobase = 0x2c00 + (0x10 * where);
 | 
						|
 | 
						|
	/*
 | 
						|
	** Found the adapter we were looking for. Now start setting it up.
 | 
						|
	**
 | 
						|
	** First work on decoding the IRQ.  It's stored in the lower 4 bits
 | 
						|
	** of pos1.  Bits are as follows (from the ADF file):
 | 
						|
	**
 | 
						|
	**      Bits
 | 
						|
	**   3   2   1   0    IRQ
 | 
						|
	**   --------------------
 | 
						|
	**   0   0   1   0     5
 | 
						|
	**   0   0   0   1     9
 | 
						|
	**   0   1   0   0    10
 | 
						|
	**   1   0   0   0    11
 | 
						|
	*/
 | 
						|
	where = pos[1] & 0x0f;
 | 
						|
	switch (where) {
 | 
						|
	case 1:
 | 
						|
		irq = 9;
 | 
						|
		break;
 | 
						|
	case 2:
 | 
						|
		irq = 5;
 | 
						|
		break;
 | 
						|
	case 4:
 | 
						|
		irq = 10;
 | 
						|
		break;
 | 
						|
	case 8:
 | 
						|
		irq = 11;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		printk("%s: mca_probe IRQ error.  You should never get here (%d).\n", mdev->name, where);
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	** Shared memory address of adapter is stored in bits 3-5 of pos0.
 | 
						|
	** They are mapped as follows:
 | 
						|
	**
 | 
						|
	**    Bit
 | 
						|
	**   5  4  3       Memory Addresses
 | 
						|
	**   0  0  0       C0000-CFFFF (64K)
 | 
						|
	**   1  0  0       C8000-CFFFF (32K)
 | 
						|
	**   0  0  1       D0000-DFFFF (64K)
 | 
						|
	**   1  0  1       D8000-DFFFF (32K)
 | 
						|
	**   0  1  0       E0000-EFFFF (64K)
 | 
						|
	**   1  1  0       E8000-EFFFF (32K)
 | 
						|
	*/
 | 
						|
	where = (pos[0] & 0x18) >> 3;
 | 
						|
	mem_start = 0xc0000 + (where * 0x10000);
 | 
						|
	if (pos[0] & 0x20) {
 | 
						|
		mem_start += 0x8000;
 | 
						|
	}
 | 
						|
 | 
						|
	/* claim the slot */
 | 
						|
	strncpy(mdev->name, depca_mca_adapter_name[mdev->index],
 | 
						|
		sizeof(mdev->name));
 | 
						|
	mca_device_set_claim(mdev, 1);
 | 
						|
 | 
						|
        /*
 | 
						|
	** Get everything allocated and initialized...  (almost just
 | 
						|
	** like the ISA and EISA probes)
 | 
						|
	*/
 | 
						|
	irq = mca_device_transform_irq(mdev, irq);
 | 
						|
	iobase = mca_device_transform_ioport(mdev, iobase);
 | 
						|
 | 
						|
	if ((err = depca_common_init (iobase, &dev)))
 | 
						|
		goto out_unclaim;
 | 
						|
 | 
						|
	dev->irq = irq;
 | 
						|
	dev->base_addr = iobase;
 | 
						|
	lp = dev->priv;
 | 
						|
	lp->depca_bus = DEPCA_BUS_MCA;
 | 
						|
	lp->adapter = depca_mca_adapter_type[mdev->index];
 | 
						|
	lp->mem_start = mem_start;
 | 
						|
 | 
						|
	if ((err = depca_hw_init(dev, device)))
 | 
						|
		goto out_free;
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
 out_free:
 | 
						|
	free_netdev (dev);
 | 
						|
	release_region (iobase, DEPCA_TOTAL_SIZE);
 | 
						|
 out_unclaim:
 | 
						|
	mca_device_set_claim(mdev, 0);
 | 
						|
 | 
						|
	return err;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
** ISA bus I/O device probe
 | 
						|
*/
 | 
						|
 | 
						|
static void __init depca_platform_probe (void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	struct platform_device *pldev;
 | 
						|
 | 
						|
	for (i = 0; depca_io_ports[i].iobase; i++) {
 | 
						|
		depca_io_ports[i].device = NULL;
 | 
						|
 | 
						|
		/* if an address has been specified on the command
 | 
						|
		 * line, use it (if valid) */
 | 
						|
		if (io && io != depca_io_ports[i].iobase)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pldev = platform_device_alloc(depca_string, i);
 | 
						|
		if (!pldev)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pldev->dev.platform_data = (void *) depca_io_ports[i].iobase;
 | 
						|
		depca_io_ports[i].device = pldev;
 | 
						|
 | 
						|
		if (platform_device_add(pldev)) {
 | 
						|
			depca_io_ports[i].device = NULL;
 | 
						|
			pldev->dev.platform_data = NULL;
 | 
						|
			platform_device_put(pldev);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!pldev->dev.driver) {
 | 
						|
		/* The driver was not bound to this device, there was
 | 
						|
		 * no hardware at this address. Unregister it, as the
 | 
						|
		 * release fuction will take care of freeing the
 | 
						|
		 * allocated structure */
 | 
						|
 | 
						|
			depca_io_ports[i].device = NULL;
 | 
						|
			pldev->dev.platform_data = NULL;
 | 
						|
			platform_device_unregister (pldev);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static enum depca_type __init depca_shmem_probe (ulong *mem_start)
 | 
						|
{
 | 
						|
	u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
 | 
						|
	enum depca_type adapter = unknown;
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; mem_base[i]; i++) {
 | 
						|
		*mem_start = mem ? mem : mem_base[i];
 | 
						|
		adapter = DepcaSignature (adapter_name, *mem_start);
 | 
						|
		if (adapter != unknown)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return adapter;
 | 
						|
}
 | 
						|
 | 
						|
static int __init depca_isa_probe (struct platform_device *device)
 | 
						|
{
 | 
						|
	struct net_device *dev;
 | 
						|
	struct depca_private *lp;
 | 
						|
	u_long ioaddr, mem_start = 0;
 | 
						|
	enum depca_type adapter = unknown;
 | 
						|
	int status = 0;
 | 
						|
 | 
						|
	ioaddr = (u_long) device->dev.platform_data;
 | 
						|
 | 
						|
	if ((status = depca_common_init (ioaddr, &dev)))
 | 
						|
		goto out;
 | 
						|
 | 
						|
	adapter = depca_shmem_probe (&mem_start);
 | 
						|
 | 
						|
	if (adapter == unknown) {
 | 
						|
		status = -ENODEV;
 | 
						|
		goto out_free;
 | 
						|
	}
 | 
						|
 | 
						|
	dev->base_addr = ioaddr;
 | 
						|
	dev->irq = irq;		/* Use whatever value the user gave
 | 
						|
				 * us, and 0 if he didn't. */
 | 
						|
	lp = dev->priv;
 | 
						|
	lp->depca_bus = DEPCA_BUS_ISA;
 | 
						|
	lp->adapter = adapter;
 | 
						|
	lp->mem_start = mem_start;
 | 
						|
 | 
						|
	if ((status = depca_hw_init(dev, &device->dev)))
 | 
						|
		goto out_free;
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
 out_free:
 | 
						|
	free_netdev (dev);
 | 
						|
	release_region (ioaddr, DEPCA_TOTAL_SIZE);
 | 
						|
 out:
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** EISA callbacks from sysfs.
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef CONFIG_EISA
 | 
						|
static int __init depca_eisa_probe (struct device *device)
 | 
						|
{
 | 
						|
	struct eisa_device *edev;
 | 
						|
	struct net_device *dev;
 | 
						|
	struct depca_private *lp;
 | 
						|
	u_long ioaddr, mem_start;
 | 
						|
	int status = 0;
 | 
						|
 | 
						|
	edev = to_eisa_device (device);
 | 
						|
	ioaddr = edev->base_addr + DEPCA_EISA_IO_PORTS;
 | 
						|
 | 
						|
	if ((status = depca_common_init (ioaddr, &dev)))
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/* It would have been nice to get card configuration from the
 | 
						|
	 * card. Unfortunately, this register is write-only (shares
 | 
						|
	 * it's address with the ethernet prom)... As we don't parse
 | 
						|
	 * the EISA configuration structures (yet... :-), just rely on
 | 
						|
	 * the ISA probing to sort it out... */
 | 
						|
 | 
						|
	depca_shmem_probe (&mem_start);
 | 
						|
 | 
						|
	dev->base_addr = ioaddr;
 | 
						|
	dev->irq = irq;
 | 
						|
	lp = dev->priv;
 | 
						|
	lp->depca_bus = DEPCA_BUS_EISA;
 | 
						|
	lp->adapter = edev->id.driver_data;
 | 
						|
	lp->mem_start = mem_start;
 | 
						|
 | 
						|
	if ((status = depca_hw_init(dev, device)))
 | 
						|
		goto out_free;
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
 out_free:
 | 
						|
	free_netdev (dev);
 | 
						|
	release_region (ioaddr, DEPCA_TOTAL_SIZE);
 | 
						|
 out:
 | 
						|
	return status;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static int __devexit depca_device_remove (struct device *device)
 | 
						|
{
 | 
						|
	struct net_device *dev;
 | 
						|
	struct depca_private *lp;
 | 
						|
	int bus;
 | 
						|
 | 
						|
	dev  = device->driver_data;
 | 
						|
	lp   = dev->priv;
 | 
						|
 | 
						|
	unregister_netdev (dev);
 | 
						|
	iounmap (lp->sh_mem);
 | 
						|
	release_mem_region (lp->mem_start, lp->mem_len);
 | 
						|
	release_region (dev->base_addr, DEPCA_TOTAL_SIZE);
 | 
						|
	bus = lp->depca_bus;
 | 
						|
	free_netdev (dev);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Look for a particular board name in the on-board Remote Diagnostics
 | 
						|
** and Boot (readb) ROM. This will also give us a clue to the network RAM
 | 
						|
** base address.
 | 
						|
*/
 | 
						|
static int __init DepcaSignature(char *name, u_long base_addr)
 | 
						|
{
 | 
						|
	u_int i, j, k;
 | 
						|
	void __iomem *ptr;
 | 
						|
	char tmpstr[16];
 | 
						|
	u_long prom_addr = base_addr + 0xc000;
 | 
						|
	u_long mem_addr = base_addr + 0x8000; /* 32KB */
 | 
						|
 | 
						|
	/* Can't reserve the prom region, it is already marked as
 | 
						|
	 * used, at least on x86. Instead, reserve a memory region a
 | 
						|
	 * board would certainly use. If it works, go ahead. If not,
 | 
						|
	 * run like hell... */
 | 
						|
 | 
						|
	if (!request_mem_region (mem_addr, 16, depca_string))
 | 
						|
		return unknown;
 | 
						|
 | 
						|
	/* Copy the first 16 bytes of ROM */
 | 
						|
 | 
						|
	ptr = ioremap(prom_addr, 16);
 | 
						|
	if (ptr == NULL) {
 | 
						|
		printk(KERN_ERR "depca: I/O remap failed at %lx\n", prom_addr);
 | 
						|
		return unknown;
 | 
						|
	}
 | 
						|
	for (i = 0; i < 16; i++) {
 | 
						|
		tmpstr[i] = readb(ptr + i);
 | 
						|
	}
 | 
						|
	iounmap(ptr);
 | 
						|
 | 
						|
	release_mem_region (mem_addr, 16);
 | 
						|
 | 
						|
	/* Check if PROM contains a valid string */
 | 
						|
	for (i = 0; *depca_signature[i] != '\0'; i++) {
 | 
						|
		for (j = 0, k = 0; j < 16 && k < strlen(depca_signature[i]); j++) {
 | 
						|
			if (depca_signature[i][k] == tmpstr[j]) {	/* track signature */
 | 
						|
				k++;
 | 
						|
			} else {	/* lost signature; begin search again */
 | 
						|
				k = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (k == strlen(depca_signature[i]))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Check if name string is valid, provided there's no PROM */
 | 
						|
	if (name && *name && (i == unknown)) {
 | 
						|
		for (i = 0; *depca_signature[i] != '\0'; i++) {
 | 
						|
			if (strcmp(name, depca_signature[i]) == 0)
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return i;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Look for a special sequence in the Ethernet station address PROM that
 | 
						|
** is common across all DEPCA products. Note that the original DEPCA needs
 | 
						|
** its ROM address counter to be initialized and enabled. Only enable
 | 
						|
** if the first address octet is a 0x08 - this minimises the chances of
 | 
						|
** messing around with some other hardware, but it assumes that this DEPCA
 | 
						|
** card initialized itself correctly.
 | 
						|
**
 | 
						|
** Search the Ethernet address ROM for the signature. Since the ROM address
 | 
						|
** counter can start at an arbitrary point, the search must include the entire
 | 
						|
** probe sequence length plus the (length_of_the_signature - 1).
 | 
						|
** Stop the search IMMEDIATELY after the signature is found so that the
 | 
						|
** PROM address counter is correctly positioned at the start of the
 | 
						|
** ethernet address for later read out.
 | 
						|
*/
 | 
						|
static int __init DevicePresent(u_long ioaddr)
 | 
						|
{
 | 
						|
	union {
 | 
						|
		struct {
 | 
						|
			u32 a;
 | 
						|
			u32 b;
 | 
						|
		} llsig;
 | 
						|
		char Sig[sizeof(u32) << 1];
 | 
						|
	}
 | 
						|
	dev;
 | 
						|
	short sigLength = 0;
 | 
						|
	s8 data;
 | 
						|
	s16 nicsr;
 | 
						|
	int i, j, status = 0;
 | 
						|
 | 
						|
	data = inb(DEPCA_PROM);	/* clear counter on DEPCA */
 | 
						|
	data = inb(DEPCA_PROM);	/* read data */
 | 
						|
 | 
						|
	if (data == 0x08) {	/* Enable counter on DEPCA */
 | 
						|
		nicsr = inb(DEPCA_NICSR);
 | 
						|
		nicsr |= AAC;
 | 
						|
		outb(nicsr, DEPCA_NICSR);
 | 
						|
	}
 | 
						|
 | 
						|
	dev.llsig.a = ETH_PROM_SIG;
 | 
						|
	dev.llsig.b = ETH_PROM_SIG;
 | 
						|
	sigLength = sizeof(u32) << 1;
 | 
						|
 | 
						|
	for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
 | 
						|
		data = inb(DEPCA_PROM);
 | 
						|
		if (dev.Sig[j] == data) {	/* track signature */
 | 
						|
			j++;
 | 
						|
		} else {	/* lost signature; begin search again */
 | 
						|
			if (data == dev.Sig[0]) {	/* rare case.... */
 | 
						|
				j = 1;
 | 
						|
			} else {
 | 
						|
				j = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (j != sigLength) {
 | 
						|
		status = -ENODEV;	/* search failed */
 | 
						|
	}
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
 | 
						|
** reason: access the upper half of the PROM with x=0; access the lower half
 | 
						|
** with x=1.
 | 
						|
*/
 | 
						|
static int __init get_hw_addr(struct net_device *dev)
 | 
						|
{
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
	struct depca_private *lp = dev->priv;
 | 
						|
	int i, k, tmp, status = 0;
 | 
						|
	u_short j, x, chksum;
 | 
						|
 | 
						|
	x = (((lp->adapter == de100) || (lp->adapter == de101)) ? 1 : 0);
 | 
						|
 | 
						|
	for (i = 0, k = 0, j = 0; j < 3; j++) {
 | 
						|
		k <<= 1;
 | 
						|
		if (k > 0xffff)
 | 
						|
			k -= 0xffff;
 | 
						|
 | 
						|
		k += (u_char) (tmp = inb(DEPCA_PROM + x));
 | 
						|
		dev->dev_addr[i++] = (u_char) tmp;
 | 
						|
		k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
 | 
						|
		dev->dev_addr[i++] = (u_char) tmp;
 | 
						|
 | 
						|
		if (k > 0xffff)
 | 
						|
			k -= 0xffff;
 | 
						|
	}
 | 
						|
	if (k == 0xffff)
 | 
						|
		k = 0;
 | 
						|
 | 
						|
	chksum = (u_char) inb(DEPCA_PROM + x);
 | 
						|
	chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
 | 
						|
	if (k != chksum)
 | 
						|
		status = -1;
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Load a packet into the shared memory
 | 
						|
*/
 | 
						|
static int load_packet(struct net_device *dev, struct sk_buff *skb)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	int i, entry, end, len, status = 0;
 | 
						|
 | 
						|
	entry = lp->tx_new;	/* Ring around buffer number. */
 | 
						|
	end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
 | 
						|
	if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {	/* Enough room? */
 | 
						|
		/*
 | 
						|
		   ** Caution: the write order is important here... don't set up the
 | 
						|
		   ** ownership rights until all the other information is in place.
 | 
						|
		 */
 | 
						|
		if (end < entry) {	/* wrapped buffer */
 | 
						|
			len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
 | 
						|
			memcpy_toio(lp->tx_buff[entry], skb->data, len);
 | 
						|
			memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
 | 
						|
		} else {	/* linear buffer */
 | 
						|
			memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
 | 
						|
		}
 | 
						|
 | 
						|
		/* set up the buffer descriptors */
 | 
						|
		len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
 | 
						|
		for (i = entry; i != end; i = (i+1) & lp->txRingMask) {
 | 
						|
			/* clean out flags */
 | 
						|
			writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
 | 
						|
			writew(0x0000, &lp->tx_ring[i].misc);	/* clears other error flags */
 | 
						|
			writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);	/* packet length in buffer */
 | 
						|
			len -= TX_BUFF_SZ;
 | 
						|
		}
 | 
						|
		/* clean out flags */
 | 
						|
		writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
 | 
						|
		writew(0x0000, &lp->tx_ring[end].misc);	/* clears other error flags */
 | 
						|
		writew(-len, &lp->tx_ring[end].length);	/* packet length in last buff */
 | 
						|
 | 
						|
		/* start of packet */
 | 
						|
		writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
 | 
						|
		/* end of packet */
 | 
						|
		writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
 | 
						|
 | 
						|
		for (i = end; i != entry; --i) {
 | 
						|
			/* ownership of packet */
 | 
						|
			writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
 | 
						|
			if (i == 0)
 | 
						|
				i = lp->txRingMask + 1;
 | 
						|
		}
 | 
						|
		writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
 | 
						|
 | 
						|
		lp->tx_new = (++end) & lp->txRingMask;	/* update current pointers */
 | 
						|
	} else {
 | 
						|
		status = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
static void depca_dbg_open(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
	struct depca_init *p = &lp->init_block;
 | 
						|
	int i;
 | 
						|
 | 
						|
	if (depca_debug > 1) {
 | 
						|
		/* Do not copy the shadow init block into shared memory */
 | 
						|
		/* Debugging should not affect normal operation! */
 | 
						|
		/* The shadow init block will get copied across during InitRestartDepca */
 | 
						|
		printk("%s: depca open with irq %d\n", dev->name, dev->irq);
 | 
						|
		printk("Descriptor head addresses (CPU):\n");
 | 
						|
		printk("        0x%lx  0x%lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring);
 | 
						|
		printk("Descriptor addresses (CPU):\nRX: ");
 | 
						|
		for (i = 0; i < lp->rxRingMask; i++) {
 | 
						|
			if (i < 3) {
 | 
						|
				printk("%p ", &lp->rx_ring[i].base);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		printk("...%p\n", &lp->rx_ring[i].base);
 | 
						|
		printk("TX: ");
 | 
						|
		for (i = 0; i < lp->txRingMask; i++) {
 | 
						|
			if (i < 3) {
 | 
						|
				printk("%p ", &lp->tx_ring[i].base);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		printk("...%p\n", &lp->tx_ring[i].base);
 | 
						|
		printk("\nDescriptor buffers (Device):\nRX: ");
 | 
						|
		for (i = 0; i < lp->rxRingMask; i++) {
 | 
						|
			if (i < 3) {
 | 
						|
				printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
 | 
						|
			}
 | 
						|
		}
 | 
						|
		printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
 | 
						|
		printk("TX: ");
 | 
						|
		for (i = 0; i < lp->txRingMask; i++) {
 | 
						|
			if (i < 3) {
 | 
						|
				printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
 | 
						|
			}
 | 
						|
		}
 | 
						|
		printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
 | 
						|
		printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
 | 
						|
		printk("        mode: 0x%4.4x\n", p->mode);
 | 
						|
		printk("        physical address: ");
 | 
						|
		for (i = 0; i < ETH_ALEN - 1; i++) {
 | 
						|
			printk("%2.2x:", p->phys_addr[i]);
 | 
						|
		}
 | 
						|
		printk("%2.2x\n", p->phys_addr[i]);
 | 
						|
		printk("        multicast hash table: ");
 | 
						|
		for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
 | 
						|
			printk("%2.2x:", p->mcast_table[i]);
 | 
						|
		}
 | 
						|
		printk("%2.2x\n", p->mcast_table[i]);
 | 
						|
		printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
 | 
						|
		printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
 | 
						|
		printk("buffers (Phys): 0x%8.8lx\n", lp->mem_start + lp->buffs_offset);
 | 
						|
		printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen);
 | 
						|
		printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
 | 
						|
		outw(CSR2, DEPCA_ADDR);
 | 
						|
		printk("CSR2&1: 0x%4.4x", inw(DEPCA_DATA));
 | 
						|
		outw(CSR1, DEPCA_ADDR);
 | 
						|
		printk("%4.4x\n", inw(DEPCA_DATA));
 | 
						|
		outw(CSR3, DEPCA_ADDR);
 | 
						|
		printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA));
 | 
						|
	}
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Perform IOCTL call functions here. Some are privileged operations and the
 | 
						|
** effective uid is checked in those cases.
 | 
						|
** All multicast IOCTLs will not work here and are for testing purposes only.
 | 
						|
*/
 | 
						|
static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 | 
						|
{
 | 
						|
	struct depca_private *lp = (struct depca_private *) dev->priv;
 | 
						|
	struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru;
 | 
						|
	int i, status = 0;
 | 
						|
	u_long ioaddr = dev->base_addr;
 | 
						|
	union {
 | 
						|
		u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
 | 
						|
		u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
 | 
						|
		u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
 | 
						|
	} tmp;
 | 
						|
	unsigned long flags;
 | 
						|
	void *buf;
 | 
						|
 | 
						|
	switch (ioc->cmd) {
 | 
						|
	case DEPCA_GET_HWADDR:	/* Get the hardware address */
 | 
						|
		for (i = 0; i < ETH_ALEN; i++) {
 | 
						|
			tmp.addr[i] = dev->dev_addr[i];
 | 
						|
		}
 | 
						|
		ioc->len = ETH_ALEN;
 | 
						|
		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
 | 
						|
			return -EFAULT;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_SET_HWADDR:	/* Set the hardware address */
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
 | 
						|
			return -EFAULT;
 | 
						|
		for (i = 0; i < ETH_ALEN; i++) {
 | 
						|
			dev->dev_addr[i] = tmp.addr[i];
 | 
						|
		}
 | 
						|
		netif_stop_queue(dev);
 | 
						|
		while (lp->tx_old != lp->tx_new)
 | 
						|
			cpu_relax();	/* Wait for the ring to empty */
 | 
						|
 | 
						|
		STOP_DEPCA;	/* Temporarily stop the depca.  */
 | 
						|
		depca_init_ring(dev);	/* Initialize the descriptor rings */
 | 
						|
		LoadCSRs(dev);	/* Reload CSR3 */
 | 
						|
		InitRestartDepca(dev);	/* Resume normal operation. */
 | 
						|
		netif_start_queue(dev);	/* Unlock the TX ring */
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_SET_PROM:	/* Set Promiscuous Mode */
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		netif_stop_queue(dev);
 | 
						|
		while (lp->tx_old != lp->tx_new)
 | 
						|
			cpu_relax();	/* Wait for the ring to empty */
 | 
						|
 | 
						|
		STOP_DEPCA;	/* Temporarily stop the depca.  */
 | 
						|
		depca_init_ring(dev);	/* Initialize the descriptor rings */
 | 
						|
		lp->init_block.mode |= PROM;	/* Set promiscuous mode */
 | 
						|
 | 
						|
		LoadCSRs(dev);	/* Reload CSR3 */
 | 
						|
		InitRestartDepca(dev);	/* Resume normal operation. */
 | 
						|
		netif_start_queue(dev);	/* Unlock the TX ring */
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_CLR_PROM:	/* Clear Promiscuous Mode */
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		netif_stop_queue(dev);
 | 
						|
		while (lp->tx_old != lp->tx_new)
 | 
						|
			cpu_relax();	/* Wait for the ring to empty */
 | 
						|
 | 
						|
		STOP_DEPCA;	/* Temporarily stop the depca.  */
 | 
						|
		depca_init_ring(dev);	/* Initialize the descriptor rings */
 | 
						|
		lp->init_block.mode &= ~PROM;	/* Clear promiscuous mode */
 | 
						|
 | 
						|
		LoadCSRs(dev);	/* Reload CSR3 */
 | 
						|
		InitRestartDepca(dev);	/* Resume normal operation. */
 | 
						|
		netif_start_queue(dev);	/* Unlock the TX ring */
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_SAY_BOO:	/* Say "Boo!" to the kernel log file */
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		printk("%s: Boo!\n", dev->name);
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_GET_MCA:	/* Get the multicast address table */
 | 
						|
		ioc->len = (HASH_TABLE_LEN >> 3);
 | 
						|
		if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
 | 
						|
			return -EFAULT;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_SET_MCA:	/* Set a multicast address */
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (ioc->len >= HASH_TABLE_LEN)
 | 
						|
			return -EINVAL;
 | 
						|
		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
 | 
						|
			return -EFAULT;
 | 
						|
		set_multicast_list(dev);
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_CLR_MCA:	/* Clear all multicast addresses */
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		set_multicast_list(dev);
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_MCA_EN:	/* Enable pass all multicast addressing */
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		set_multicast_list(dev);
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_GET_STATS:	/* Get the driver statistics */
 | 
						|
		ioc->len = sizeof(lp->pktStats);
 | 
						|
		buf = kmalloc(ioc->len, GFP_KERNEL);
 | 
						|
		if(!buf)
 | 
						|
			return -ENOMEM;
 | 
						|
		spin_lock_irqsave(&lp->lock, flags);
 | 
						|
		memcpy(buf, &lp->pktStats, ioc->len);
 | 
						|
		spin_unlock_irqrestore(&lp->lock, flags);
 | 
						|
		if (copy_to_user(ioc->data, buf, ioc->len))
 | 
						|
			status = -EFAULT;
 | 
						|
		kfree(buf);
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_CLR_STATS:	/* Zero out the driver statistics */
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		spin_lock_irqsave(&lp->lock, flags);
 | 
						|
		memset(&lp->pktStats, 0, sizeof(lp->pktStats));
 | 
						|
		spin_unlock_irqrestore(&lp->lock, flags);
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEPCA_GET_REG:	/* Get the DEPCA Registers */
 | 
						|
		i = 0;
 | 
						|
		tmp.sval[i++] = inw(DEPCA_NICSR);
 | 
						|
		outw(CSR0, DEPCA_ADDR);	/* status register */
 | 
						|
		tmp.sval[i++] = inw(DEPCA_DATA);
 | 
						|
		memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
 | 
						|
		ioc->len = i + sizeof(struct depca_init);
 | 
						|
		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
 | 
						|
			return -EFAULT;
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		return -EOPNOTSUPP;
 | 
						|
	}
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
static int __init depca_module_init (void)
 | 
						|
{
 | 
						|
        int err = 0;
 | 
						|
 | 
						|
#ifdef CONFIG_MCA
 | 
						|
        err = mca_register_driver (&depca_mca_driver);
 | 
						|
#endif
 | 
						|
#ifdef CONFIG_EISA
 | 
						|
        err |= eisa_driver_register (&depca_eisa_driver);
 | 
						|
#endif
 | 
						|
	err |= platform_driver_register (&depca_isa_driver);
 | 
						|
	depca_platform_probe ();
 | 
						|
 | 
						|
        return err;
 | 
						|
}
 | 
						|
 | 
						|
static void __exit depca_module_exit (void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
#ifdef CONFIG_MCA
 | 
						|
        mca_unregister_driver (&depca_mca_driver);
 | 
						|
#endif
 | 
						|
#ifdef CONFIG_EISA
 | 
						|
        eisa_driver_unregister (&depca_eisa_driver);
 | 
						|
#endif
 | 
						|
	platform_driver_unregister (&depca_isa_driver);
 | 
						|
 | 
						|
	for (i = 0; depca_io_ports[i].iobase; i++) {
 | 
						|
		if (depca_io_ports[i].device) {
 | 
						|
			depca_io_ports[i].device->dev.platform_data = NULL;
 | 
						|
			platform_device_unregister (depca_io_ports[i].device);
 | 
						|
			depca_io_ports[i].device = NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
module_init (depca_module_init);
 | 
						|
module_exit (depca_module_exit);
 |