/*
 *  depca.c
 *
 *  Linux driver for dec's depca Ethernet adapter family.
 *    not otherwise copyrighted parts (by the contributed
 *    authors and their parents) are  copyrighted by
 *    (C) Peter Bauer, Systematika GmbH (100136,3530@compuserve.com)
 *  This driver is based on 
 *    depca.asm version 3 Copyright Russell Nelson, Crynwr Software 
 *    =packet driver
 *  and (as sample linux eth driver) d_link.c of lx99pl10
 *    (Portions (C) Copyright 1993 by Bjorn Ekwall bj0rn@blox.se,
 *     father of this sample is donald becker@super.org)
 *
 *  The intention of this driver is to work with most of the DEC's 
 *  DEPCA-family ethernet cards. This intention comes from the packet
 *  driver, which also attempts to serve the whole family. However,
 *  for me it was until now only possible to test this driver against 
 *  a DE200 card.
 *  The whole adapter-programing is deriverd from the packet-driver, and
 *  the whole linux-programing is derived from d_link.c (I used this one
 *  because its a driver and because it drives a ethernet device and 
 *  because it's `standalone' (as opposed to the more complex 8390-family)
 *
 *  If the driver refuses to load, put a #define ANY_SIGNATURE somewhere
 *  at the beginning, this may help
 *
 * Revision 0.1:
 *  working ALPHA-release (at least with an DE200 (DEC Etherworks Turbo))
 *  no tuning attempted, no cli/sti's in code (?) 
 * Revision 0.2:
 *  - toggle led of card in interrupt-routine
 *  - dont disable cards interrupts when in isr. The ony communication with
 *    the card now is to read the interrupt-cause, and, in case of trans-
 *    mitting another packet, toggling the CSR0_TDMD - Bit. Also the 
 *    address-register is no longer set before writes to the data-register, 
 *    because it points during normal operation always to CSR0
 *  - enable interrupts at entry to isr. They seem not to harm. This is
 *    a result of the card's communication-logic: there is a well defined
 *    ownership of each buffer, and the change-mechanism of the ownership-
 *    status is also well defined: we may give the ownership to the card,
 *    and the card gives the ownership to us. 
 *  - inside the isr, poll the interupt-status until no more interrupt-
 *    reason-bits set. 
 *    This because I found that after reading the isr and doing the ack
 *    for this, imedeatly another interrrupt bit may apear in
 *    the isr (for which no other interrupt will occur). This happened
 *    only under very high load and caused the card to become inoperable.
 *    (I think because it expected another int-ack). After the modification,
 *    i was not able to break it again, although the procedure looks not
 *    completely save...
 * Revision 0.3:
 *  - 0.2 Version didn't compile with pl10
 *  - cosmetic changes
 *  - handle IDON-interrupt seperate (also cosmetic)
 * Revision 0.4:
 *  - fixed bug in isRom (shoud be <<9 and not <<8) (This will only harm 
 *    those, which have rom installed at the address where the depca wants 
 *    to live)
 *  - fixed bug in adapter_init, which will prevent depca's with address-
 *    bases not at 64K-boundary not to work (This is true i think for
 *    all depca's with less than 64K address-space... :-)
 *  - reduced calls to xlateAndMap to a minimum
 *  
 * (the revision counter gets ++ each time something gets changed after i have
 *  given a copy to someone)
 */

static char *version =
  "depca.c: $Revision: 0.4 ALPHA $,  Peter Bauer (100136,3530@compuserve.com)\n";


/* First put some garlic to keep the vampires away: */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 */


/* I did'nt believe in it, but it's essential for the driver to work 
   correctly: (Took me 1 and a half day to find out) */
#define REALLY_SLOW_IO
/* the above isnt slow enough! i just removed some debbuging code, which
   I had built around outb/outw, and the driver won't work anymore. The
   two SlowerOut-routines below now do the job (on my 386DX-40)
*/

/* undefine ALPHA to make him shut up nearly complete */
#define ALPHA
/* define DEPCA_DEBUG to get more info ... look at the code before doing so */
/* #define DEPCA_DEBUG */
/* redefine priv to private to compile with pl10 */
/* #define priv private */


#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include "iow.h" /* This should go into <asm/io.h> */
#include <netinet/in.h>
#include <linux/ptrace.h>
#include <asm/system.h>
#include <errno.h>

#include "inet.h"
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sock.h"
#include "arp.h"

static void SlowerOutb (int v, int p) {
  outb_p (v,p);
}
static void SlowerOutw (int v, int p) {
  outw_p (v,p);
}
#ifdef outb
#undef outb
#endif
#ifdef outw
#undef outw
#endif
#define outb SlowerOutb
#define outw SlowerOutw

#ifdef ALPHA
#define BlaBla(bla) {iAm (realdev);printk bla;}
#else
#define BlaBla(sagIchNicht) 
#endif

/* Common network statistics -- these will be in *.h someday. */
struct netstats {
  int tx_packets;
  int rx_packets;
  int tx_errors;
  int rx_errors;
  int missed_packets;
  int soft_tx_errors;
  int soft_rx_errors;
  int soft_trx_err_bits;
};
static struct netstats *localstats;

/*
 * Index to functions, as function prototypes.
 */

/* Put in the device structure. */
static int depca_open(struct device *dev);
static int depca_close(struct device *dev);
static int depca_start_xmit(struct sk_buff *skb, struct device *dev);

/* Dispatch from interrupts. */
static void depca_interrupt(int reg_ptr);
static void depca_tx_intr(struct device *dev);
static void depca_rx_intr(struct device *dev);

/* Initialization */
int depca_init(struct device *dev);
static void adapter_init(struct device *dev, int startp);

/* Passed to sigaction() to register the interrupt handler. */
static struct sigaction depca_sigaction = {
  &depca_interrupt,
  0,
  0,
  NULL,
};

/*
 * DEPCA driver constants, structs and variables:
 */

#define uword unsigned short
#define uchar unsigned char

#define RUNT    60
#define GIANT 1514 /* largest legal size packet, no fcs */

#define NI_CSR     (0+realdev->base_addr)
#define RBI        (2+realdev->base_addr)
#define DATA_REG   (4+realdev->base_addr)
#define ADDR_REG   (6+realdev->base_addr)
#define CSR0       0 /* These are registers addressable through ADDR_REG */
#define CSR1       1
#define CSR2       2
#define CSR3       3
#define EBASE      (12+realdev->base_addr)
#define RBSA       (14+realdev->base_addr)

/* CSR bit definitions */
 
#define CSR_RBT      0x0100
#define CSR_SHE      0x80     /* enables shared memory */
#define CSR_SWAP32   0x40     /* swaps window between the two 32k areas */
#define CSR_BUF      0x20
#define CSR_RBE      0x10
#define CSR_DUM      0x08     /* for rev E. DEPCA compatability */
#define CSR_IM       0x04
#define CSR_IEN      0x02
#define CSR_LED      0x01

/* Control and Status Register 0 (CSR0) bit definitions */

#define CSR0_ERR     0x8000 /* Error summary */
#define CSR0_BABL    0x4000 /* Babble transmitter timeout error  */
#define CSR0_CERR    0x2000 /* Collision Error */
#define CSR0_MISS    0x1000 /* Missed packet */
#define CSR0_MERR    0x0800 /* Memory Error */
#define CSR0_RINT    0x0400 /* Reciever Interrupt */
#define CSR0_TINT    0x0200 /* Transmit Interrupt */
#define CSR0_IDON    0x0100 /* Initialization Done */
#define CSR0_INTR    0x0080 /* Interrupt Flag */
#define CSR0_INEA    0x0040 /* Interrupt Enable */
#define CSR0_RXON    0x0020 /* Receiver on */
#define CSR0_TXON    0x0010 /* Transmitter on */
#define CSR0_TDMD    0x0008 /* Transmit Demand */
#define CSR0_STOP    0x0004 /* Stop */
#define CSR0_STRT    0x0002 /* Start */
#define CSR0_INIT    0x0001 /* Initialize */

/* Initialization Block  Mode operation Bit Definitions. */

#define M_PROM       0x8000 /* Promiscuous Mode */
#define M_INTL       0x0040 /* Internal Loopback */
#define M_DRTY       0x0020 /* Disable Retry */
#define M_COLL       0x0010 /* Force Collision */
#define M_DTCR       0x0008 /* Disable Transmit CRC */
#define M_LOOP       0x0004 /* Loopback */
#define M_DTX        0x0002 /* Disable the Transmitter */
#define M_DRX        0x0001 /* Disable the Reciever */

/* Receive message descriptor bit definitions. */

#define RCV_OWN      0x8000 /* owner bit 0 = host, 1 = lance */
#define RCV_ERR      0x4000 /* Error Summary */
#define RCV_FRAM     0x2000 /* Framing Error */
#define RCV_OFLO     0x1000 /* Overflow Error */
#define RCV_CRC      0x0800 /* CRC Error */
#define RCV_BUF_ERR  0x0400 /* Buffer Error */
#define RCV_START    0x0200 /* Start of Packet */
#define RCV_END      0x0100 /* End of Packet */

/* Transmit  message descriptor bit definitions. */

#define XMIT_OWN     0x8000 /* owner bit 0 = host, 1 = lance */
#define XMIT_ERR     0x4000 /* Error Summary */
#define XMIT_RETRY   0x1000 /* more the 1 retry needed to Xmit */
#define XMIT_1_RETRY 0x0800 /* one retry needed to Xmit */
#define XMIT_DEF     0x0400 /* Deferred */
#define XMIT_START   0x0200 /* Start of Packet */
#define XMIT_END     0x0100 /* End of Packet */

/* Miscellaneous Equates */

#define TransmitBufCount      1 /* must be a power of two. */
#define ReceiveBufCount      16 /* must be a power of two. */
#define ReceiveBufSize     1518     

struct RecMsgHeader { /* Receive Message Descriptor */
  uword bufLo;     /* Rec. Buffer Lo-Address */
  uword bufHi;     /* Status bits / Hi-Address */
  uword negBufLen; /* Buff Byte-length (2's Comp) */
  uword msgLen;    /* Receive message length */
};
struct XmitMsgHeader { /*Transmit Message Descriptor */
  uword bufLo;     /* Xmit Buffer Lo-Address */
  uword bufHi;     /* Status bits / Hi-Address */
  uword negBufLen; /* Buff Byte-length (2's Comp) */
  uword bufStat;   /* Buffer Status bits & TDR value */
};
struct InitBlock { /* LANCE Initialization Block */
  uword initMode;
  uchar initAddr [ETH_ALEN]; /* Our Ethernet address */
  uchar initFilter [8];       /* Multicast filter. */
  uword initReceive [2];      /* Receive Ring Pointer. */
  uword initTransmit [2];     /* Transmit Ring Pointer. */
};
struct Lance { 
  struct XmitMsgHeader tramsmitHeaders[TransmitBufCount];
  struct RecMsgHeader  receiveHeaders [ReceiveBufCount];
  struct InitBlock initBlock;
};

#define lance ((struct Lance*)(realdev->mem_start))
static struct device *realdev;

#define transmitBufs 0x0800
#define receiveBufs  0x1000

/* unused static uword transmitHead=0;*/ /* ptr next packet to be filled by host. */
static uword receiveHead=0;  /* ptr next packet to be filled by LANCE. */

static uchar adapterInitOk=0;

static void valToPort (uword v,uword reg) {
  outw (reg,ADDR_REG);
  inw  (ADDR_REG);
  outw (v,DATA_REG);
  inw  (DATA_REG);
}

static uchar niCsrValue=CSR_SHE|CSR_DUM|CSR_IEN|CSR_SWAP32;

#ifdef DEPCA_DEBUG
static void dump (char *p,int l) {
  int o=0;
  while (o<l) {
    int i;
    printk ("%8.8x ",&p[o]);
    for (i=0;i<16;i++) {
      if ((i+o) < l)
        printk ("%2.2x ",(unsigned char)p[i+o]);
    }
    printk (" !");
    for (i=0;i<16;i++) {
      if ((i+o) < l)
        printk ("%c",(p[i+o]&0x7f)>=32&&(p[i+o]&0x7f)<=126?(p[i+o]&0x7f):'.');
    }
    printk ("!\n");
    o+=16;
  }
}
static char *screen=(char*)0xb8000;
static void inc (uword ofs) {
  screen[ofs<<1]++;
}
static int noint=0;
#define nointPP noint++
#define nointZero noint=0;
static int tpos=0;
static void T (char t) {
  if (noint < 5) {
    screen[tpos+1]=0x71; 
    tpos=(tpos+2) & 0x7f;
    screen[tpos]=t;
    screen[tpos+1]=0x17; 
  }
};
static void T (uword w) {
  int i=0;
  char s[10];
  sprintf (s,"%4.4x",w);
  while (s[i])
    T (s[i++]);
}
#else
#define T(a)
#define dump(a,b)
#define nointPP
#define nointZero
#endif

static void iAm (struct device *dev) {
  printk ("%s: DEPCA ",dev->name);
}
enum {translate_64k,translate_32k,translate_2k} xlatemode;

/* returns a flat pointer to the lance's memory. a is the desired offset 
   into lance's internal memory. the lance-window itself is remapped
   according to the xlatemode required by the card. 
*/
static uchar xlcnt;
static uchar* xlateAndMap (uword a) {
  switch (xlatemode) {
    case translate_64k: return (uchar *)lance+a;
    case translate_32k: outb ((char)(a & 0x8000
                        ?niCsrValue & ~CSR_SWAP32:niCsrValue),NI_CSR);
                        return (uchar *)lance+(a & 0x7fff);
    case translate_2k : outb ((uchar)(a>>11),RBI);
                        return (uchar *)lance+0;
  }
}

/*
 * Open/initialize the board.  This is called (in the current kernel)
 * sometime after booting when the 'config <dev->name>' program is run.
 *
 * This routine should set everything up anew at each open, even
 * registers that "should" only need to be set once at boot, so that
 * there is a non-reboot way to recover if something goes wrong.
 */
static int depca_open(struct device *dev) {
  adapter_init(dev, 1);
  dev->tbusy = 0; /* Transmit busy...  */
  dev->interrupt = 0;
  return adapterInitOk?0:1;
}

/* The inverse routine to depca_open().  */
static int depca_close(struct device *dev) {
  dev->start = 0;
  adapter_init(dev, 0);
  return 0;
}

/* try to find available lance-xmit-buffer. return index to buffer
   if fnd, else -1 */
static int getXmitBuf (void) {
  uword i;
  for (i=0;i<TransmitBufCount;i++) {
    if (!(lance->tramsmitHeaders[i].bufHi & XMIT_OWN))
      return i;
  }
  return -1;
}

/* Copy a buffer to the adapter transmit page memory. Start sending. */
static int depca_start_xmit(struct sk_buff *skb, struct device *dev) {
  int xmitBufIdx;
  unsigned char *buffer = (unsigned char *)(skb + 1);
  /* If some higher layer thinks we've missed a tx-done interrupt, we are 
     passed NULL. Caution: dev_tint() handles the cli()/sti() itself.  
  */
  nointPP;
  T ('G');
  if (skb == NULL) {
  T ('S');
    dev_tint(dev);
    return 0;
  }

  /* For ethernet, fill in the header (hardware addresses) with an arp. */
  if (!skb->arp  &&  dev->rebuild_header(skb + 1, dev)) {
    skb->dev = dev;
    arp_queue (skb);
    return 0;
  }

  if ((xmitBufIdx=getXmitBuf())==-1) { /* Do timeouts, to avoid hangs. */
    int tickssofar;
    T ('R');
    dev->tbusy=1; /* Dont know if this makes sense here. */
    tickssofar = jiffies - dev->trans_start;
    if (tickssofar >= 5) {
      iAm (dev);
      printk("transmit timed out (%d), driver error or Hardware (cable) problem\n",
             tickssofar);
      adapter_init(dev, 1);
    }
    return 1;
  }
  {struct XmitMsgHeader* lanceDest=&lance->tramsmitHeaders[xmitBufIdx];
   lanceDest->bufHi &= 
     ~(XMIT_ERR|XMIT_DEF|XMIT_1_RETRY|XMIT_RETRY);/* reset error indications. */
   lanceDest->bufStat = 0; /* reset all error bits. */
   lanceDest->negBufLen=
        skb->len<RUNT?-RUNT:-(int)skb->len; /* store the negative of the cnt. */
   memcpy (xlateAndMap (lanceDest->bufLo),
            buffer,skb->len);/*store the packet. */
   xlateAndMap (0);
   lanceDest->bufHi |=XMIT_OWN; /* give it to the lance chip. */
  }
  dev->trans_start = jiffies;
  if (TransmitBufCount==1)
    dev->tbusy; /* in this case easy, otherwise have to scan all buffers. */
                /* Dont know if this would be worth the info? */
  T ('H');
  outw (CSR0_INEA|CSR0_TDMD,DATA_REG);/* Inform LANCE to poll for a packet. */
  T ('I');
  if (skb->free) {
    kfree_skb (skb, FREE_WRITE);
  }
  return 0;
}
static int ints=0;

/* The typical workload of the driver: Handle the network interface interrupts.*/
static void depca_interrupt(int reg_ptr) {
  int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
  struct device *dev = realdev;
  uword         interrupts;

  ints++;
  if (ints>1) {
    iAm (dev);
    printk ("Things become interesting now, reentering isr %d. time\n",ints);
  }
  nointZero;
  T ('J');
  sti ();
  outb (niCsrValue^=CSR_LED,NI_CSR); /* toggle led ... */
  while (outw ((interrupts=inw(DATA_REG)) 
         & ~(CSR0_TDMD|CSR0_STOP|CSR0_STRT|CSR0_INIT),DATA_REG),
        interrupts & 0xff00) {
    T (interrupts);
    T ('U');
    if (dev == NULL) {
      printk ("?: DEPCA: irq %d for unknown device.\n", irq);
    }
    else {
      dev->interrupt = 1;
      if (dev->start == 0) {
        if (interrupts & CSR0_IDON) {
          dev->start=1; /* Now we have the GO from the card */
          T ('Y');
        }
      }
      else {
        if (interrupts & CSR0_TINT) {
          T ('K');
          depca_tx_intr(dev);
        }
        if (interrupts & CSR0_RINT) {
          T ('L');
          depca_rx_intr(dev);
        }
        if (interrupts & CSR0_IDON) {
          iAm (dev);
          printk ("reinitialized\n"); 
        }
        if (interrupts & ~(CSR0_TINT|CSR0_RINT|CSR0_IDON|0xff)) {/* Card reports error */
          iAm (dev);printk ("reports error %4.4x\n",interrupts);
        }
      }
      dev->interrupt = 0;
    }
  }
  T ('M');
  --ints;
  return;
}

/*
 * Do internal handshake: Transmitter done (of this page).
 * Also handle the case of a pending transmit page.
 */
static void depca_tx_intr(struct device *dev) {
  localstats->tx_packets++;
  dev->tbusy = 0;
  mark_bh(INET_BH);
  T ('O');
}

/*
 * We have a good packet(s), get it/them out of the buffers.
 */
static void depca_rx_intr(struct device *dev) {
  struct sk_buff *skb=NULL;
  int            size=0;
  int            sksize;
  int            fullrno=0,rno=receiveHead;
  int            steps=0;
  while (steps++<ReceiveBufCount) { /* this while loop fights against
                                         lost interrupts. Maybe this 
                                         makes no sense for linux? */
    /* I left this algorythm in here because it was contained (in a
       slightly different way) in the packet driver (depca.asm). If
       no interrupts could get lost, and every received packet would
       produce one interrupt, i would omit the while loop and only look at
       the next buffer. */
    if (!(lance->receiveHeaders[rno].bufHi & RCV_OWN)) {
      steps=0;
      fullrno=rno;
      if (lance->receiveHeaders[rno].bufHi & RCV_ERR) {
        T ('T');
        localstats->rx_errors++; /* count all receive errors */
      }
      else {                                  /*  v reserved  v CRC */
        size=(lance->receiveHeaders[rno].msgLen & 0x0fff)     - 4;
        if ((size < RUNT  ||  size > GIANT)) {
          iAm (dev);printk("Bogus packet size %d.\n", size);
        }
        else {
          sksize = sizeof(struct sk_buff) + size;
          if ((skb = (struct sk_buff*)kmalloc(sksize, GFP_ATOMIC)) == NULL) {
            iAm (dev);printk("couldn't allocate a sk_buff of size %d.\n",
                             sksize);
            return;
          }
          else {
            skb->lock = 0;
            skb->mem_len = sksize;
            skb->mem_addr = skb;
            /* 'skb + 1' points to the start of sk_buff data area. */
            memcpy ((unsigned char *)(skb +1),xlateAndMap 
                    (lance->receiveHeaders[rno].bufLo),size);
            xlateAndMap (0);
            localstats->rx_packets++; /* count all receives */
            T ('P');
            if (dev_rint((uchar *)skb, 
                size, IN_SKBUFF, dev)) /* ok, give it to them */ { 
              /* these guys did'nt want this precious packet... */
              iAm (dev);
              printk ("dev_rint doesn't like packet: skb-address %8.8x size %d. Why ?\n",
                      skb,size); 
              return;
            }
            T ('Q');
          }  
        }
      }
      lance->receiveHeaders[rno].bufHi &= 
        ~(RCV_ERR|RCV_FRAM|RCV_OFLO|RCV_CRC|RCV_BUF_ERR);
      lance->receiveHeaders[rno].bufHi |= 
        RCV_OWN; /* Give buffer back to lance */
    }
    rno=(rno+1) % ReceiveBufCount; /* advance to next */
  }
  receiveHead=(fullrno+1) % ReceiveBufCount;
  /* If any worth-while packets have been received, dev_rint()
   * has done a mark_bh(INET_BH) for us and will work on them
   * when we get to the bottom-half routine.
   */
  return;
}

/* This routine tries to check, if the desired area is a rom, or
   a part of a rom starting elsewhere before p. 
*/
static int isRom (uchar* p,uword l) {
  uchar *romstart=(uchar*)0xc0000;
  while (romstart<=p) {
    if (*(uword*)romstart==0xaa55) {
      uword romlen=romstart[3]<<9;
      uchar accu=0;
      uword rp;
      for (rp=0;rp<romlen;accu+=romstart[rp++]);
      if (!accu) /* a valid pc rom: start with aa55,len and sum up to 0 */
        if (&romstart[romlen]>=p)
          return 0;
        else
          romstart+=romlen;
    }
    else
      romstart+=0x800;
  }
  return 1;
};

static int isRam (uchar *p,uword l) {
  uword i,r=1;
  uchar v,other;
  for (i=0;i<l;i++) {
    v    =p[i];
    other=p[i+2];
    p[i]=~v;
    p[i+2]=other;
    if (p[i]!=(uchar)~v) {
      p[i]=v;
      r=0;
      break;
    }
    else  
      p[i]=v;
  }                               
  return r;
}  

/* This scans next 40 bytes of port p if they contain depcaPattern */       
static int detectPort (uword p) { /* this is only minor voodo */
  uchar depcaPattern [8]= {0xFF, 0x00, 0x55, 0xAA, 0xFF, 0x00, 0x55, 0xAA};
  int i,dpos=0;
  for (i=0;i<32+8;i++) {
    uchar v=inb(p);
    if (v == depcaPattern [dpos++]) {
      if (dpos==8)
        return 1;
    }
    else
      dpos=0;
  }
  return 0;
}

/* test to see if a board is located at dev->base_addr.               */
/* setup to read first byte of ethernet address rom when successful.  */
/* return 0 if not.                                                   */
static int detectBoard (void) {
  int ok;
  outb (CSR_DUM,NI_CSR);
  ok=detectPort(EBASE)||detectPort(EBASE+1);
  outb (niCsrValue,NI_CSR);
  return ok;
}

static int initialize (void) {
  uword w;
  int   laengerNicht;
  long  offset=realdev->mem_start+((uchar*)&lance->initBlock-(uchar*)lance);
  valToPort (CSR0_STOP,CSR0); /* reset the INIT bit. */
  valToPort (2,CSR3);         /* write the bus config register. */
  valToPort (offset & 0xffff,CSR1); /* write offset of init-block (low word) */
  valToPort (offset >> 16,CSR2); /* write offset of init-block (high word). */
  valToPort (CSR0_INEA|CSR0_STRT|CSR0_INIT,CSR0); /* reinit and restart. */
  laengerNicht=jiffies+36; /* wait max 2 seconds */
  w=inw (DATA_REG);
  while (!(w & CSR0_IDON)) { 
    if (jiffies>laengerNicht)
      return 0;
    w=inw (DATA_REG);           
  }    
  return 1;
}

static void initializeMulti (int v) {
  int i;
  for (i=0;i<8;i++)
    lance->initBlock.initFilter[i]=v;
}

static int initializeNoMulti (int v) {
  lance->initBlock.initMode=v;
  return initialize();
}


enum receiveModeType {disaReceiveXmit,noMulticast,multicast,promiscuous};

static int receiveMode (enum receiveModeType r) {
  switch (r) {
    case disaReceiveXmit: return initializeNoMulti (M_DRX|M_DTX);
    case noMulticast    : initializeMulti (0);
                          return initializeNoMulti (0);
    case multicast      : initializeMulti (-1);
                          return initializeNoMulti (0);
    case promiscuous    : return initializeNoMulti (M_PROM);
  }
}

static uword computeLog2 (uword n) {
  int res=-1;
  do {
    res ++;
    n = n >> 1;
  } while (n);
  return res << 13;
}

static char *KnownSignatures [] = {"DEPCA","DE200",""};

static char *checkSignature (uchar * p) {
#ifdef ANY_SIGNATURE
  return "ANY";
#else
  int i=0;
  while (1) {
    if (strlen (KnownSignatures [i])==0) {
      BlaBla (("Unknon adapter signature '%s'\n",p));
      return 0;
    }
    else {
      if (memcmp (p,KnownSignatures [i],strlen (KnownSignatures [i]))==0) {
        BlaBla (("Found a '%s' (Signature known)\n",p));
        return KnownSignatures [i]; 
        /* dont return p, it points into later unmapped adapter-rom*/
      }
    }
    i++;
  }
#endif
} 

int depca_init(struct device *dev) {
  uchar nic;
  uchar * ptr;
  int boardfound=1;
  int havemem=0;
  int error=1; /* Our default return */

  realdev = dev;

  BlaBla ((version));
  if (dev->base_addr!=0) {   /* The ioaddress is hardcoded, so check if its ok */
    if (!detectBoard()) {
      boardfound=0;          /* Sorry, at your address is no depca */
      BlaBla(("could not find DEPCA-Adapter at %x\n",dev->base_addr));
    }
  }
  else { /* we are requested to look if we can find the board at 0x300 or 0x200 */
    dev->base_addr=0x0300;
    if (!detectBoard()) {
      dev->base_addr=0x0200;
      if (!detectBoard()) {
        boardfound=0; /* can't find ioports giving the right answer */
        BlaBla (("could not find DEPCA-Adapter at 0x300 or 0x200"));
      }
    }
  }
  if (boardfound) {
    if (((dev->mem_start & 0x7ff) != 0)  /* must be on 2K boundary. */
       || ((dev->mem_start & 0x80000) == 0) /* must be in upper 512K. */
       || ((dev->mem_start & 0xfff00000) != 0)) { /*high word must be zero.*/
      iAm (dev);printk ("bad shared memory-address %x\n",dev->mem_start);
    }
    else { /* The following is a kind of voodo mixed with black digital equip-
              ment magic and salted with the art of predicting the future out 
              of the interiors of chickens... */
      char *Signature="?"; /* unused for now... */

      cli (); /* now we detect whether we're set to 2K, 32K, or 64K. */
              /* first, we see if the ROM is mappable in and out.    */
      outb (nic=(inb (NI_CSR) & ~CSR_SHE),NI_CSR); /* disa the RAM, ena ROM. */
      ptr=(uchar*)(dev->mem_start+0x4000);
      xlatemode=translate_32k;
      if (!(nic & CSR_BUF)) {
        niCsrValue &= ~CSR_SWAP32;
        outb ((uchar) (niCsrValue & ~CSR_SHE),NI_CSR);
        ptr+=0x8000;
        xlatemode=translate_64k;
      }
      if (!isRam (ptr,0x4000)) {
        outb ((uchar)(inb (NI_CSR)|CSR_SHE),NI_CSR); /* reenable RAM */
        if (!isRam (ptr,0x4000)) {
          if (*(uword*)ptr==0xaa55) 
            havemem=(Signature=checkSignature (ptr+6))!=NULL;
        }
        else havemem=1;
      }
      if (!havemem) { /* we got here because we decided that the */ 
                      /* ROM couldn't be mapped into memory.     */
        Signature="OLD DEPCA";
        xlatemode=translate_2k;
        niCsrValue &= ~CSR_SWAP32;
        outw (0xf000,RBSA); /* put our memory somewhere it can't be. */
        if (isRom ((uchar*)dev->mem_start,0x800)
          ||isRam ((uchar*)dev->mem_start,0x800)) {
          iAm (dev);printk ("remap not possible due to address in use %x\n",dev->mem_start);
        }
        else { /* Weder Fisch noch Fleisch */
            outw ((uword)(dev->mem_start&0xffff),
              RBSA); /* the memory block is empty - put our memory there */
            havemem=1; /* Da haste aber grad nochmal Glueck gehabt...*/
        }
      }
      sti (); /* end voodo */
      if (havemem) {
        int i;
        for (i = 0; i < ETH_ALEN; i++) {
          dev->dev_addr[i] = inb(EBASE);
          dev->broadcast[i] = 0xff;
        }
        memcpy (lance->initBlock.initAddr,dev->dev_addr,ETH_ALEN);
        /* Initialize the device structure. */
        dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);
        localstats = 
          (struct netstats*) dev->priv; /* moved here from the interrupt */
        memset(dev->priv, 0, sizeof(struct netstats));
        for (i = 0; i < DEV_NUMBUFFS; i++)
          dev->buffs[i] = NULL;
        dev->hard_header = eth_header;
        dev->add_arp = eth_add_arp;
        dev->queue_xmit = dev_queue_xmit;
        dev->rebuild_header = eth_rebuild_header;
        dev->type_trans = eth_type_trans;
        dev->open = &depca_open;
        dev->stop = &depca_close;
        dev->hard_start_xmit = &depca_start_xmit;
        /* These are ethernet specific. */
        dev->type = ARPHRD_ETHER;
        dev->hard_header_len = ETH_HLEN;
        dev->mtu = 1500; /* eth_mtu */
        dev->addr_len = ETH_ALEN;
        /* New-style flags. */
        dev->flags = IFF_BROADCAST;
        dev->family = AF_INET;
        dev->pa_addr = 0;
        dev->pa_brdaddr = 0;
        dev->pa_mask = 0;
        dev->pa_alen = sizeof(unsigned long);
        /* This i think does, from pure logic, not belong here. What here should
           be done is only to tell/ask the kernel, if we are allowed to do
           so later ... */
        if (irqaction (dev->irq, &depca_sigaction)) { 
          iAm (dev);printk ("unable to get IRQ %d\n", dev->irq);
        }
        else {
          char *wsize[3]={"64","32","2"};
          error=0; /* uff */
          iAm (dev);
          printk ("ethernet adapter (%sK, IOBase %x, MemStart %x, Ethernet %2.2X", 
                   wsize[xlatemode],dev->base_addr,dev->mem_start,dev->dev_addr[0]);
          for (i = 1; i < ETH_ALEN; i++)
            printk(":%2.2X",dev->dev_addr[i]);
          printk(") ok.\n");
        }
      }
    }
  }
  return error;
}

static void adapter_init(struct device *dev, int startp) {
  adapterInitOk=1; /* assume we succeed */
  cli();
  realdev = dev;
  valToPort (CSR0_STOP,CSR0);
  if (startp) {
    int  i;
    long bufadr;

    xlateAndMap (0);
    bufadr=transmitBufs;
    for (i=0;i<TransmitBufCount;i++) { /* set up transmit descriptor ring. */
      lance->tramsmitHeaders[i].bufLo = bufadr & 0xffff;
      lance->tramsmitHeaders[i].bufHi = (bufadr>>16) | XMIT_START | XMIT_END;
      bufadr += 0x800;
    }
    bufadr=receiveBufs;
    for (i=0;i<ReceiveBufCount;i++) { /* set up receive descriptor ring. */
      lance->receiveHeaders[i].bufLo = bufadr & 0xffff;
      lance->receiveHeaders[i].bufHi = (bufadr>>16) | RCV_OWN;
      lance->receiveHeaders[i].negBufLen = (uword)-ReceiveBufSize;
      lance->receiveHeaders[i].msgLen = 0;
      bufadr += 0x800;
    }
    bufadr=((uchar*)&lance->receiveHeaders[0]-(uchar*)lance);
    lance->initBlock.initReceive[0]=bufadr & 0xffff;
    lance->initBlock.initReceive[1]=(bufadr >> 16) | 
                                     computeLog2 (ReceiveBufCount);
    bufadr=((uchar*)&lance->tramsmitHeaders[0]-(uchar*)lance);
    lance->initBlock.initTransmit[0]=bufadr & 0xffff;
    lance->initBlock.initTransmit[1]=(bufadr >> 16) | 
                                     computeLog2 (TransmitBufCount);
    irqaction (dev->irq, &depca_sigaction); /* Already done in depca_init, */
               /* but really needed only before the receiveMode-call       */
    if (!receiveMode (noMulticast))
      adapterInitOk=0;
    outb (niCsrValue,NI_CSR);
  }
  else
    irqaction(dev->irq, NULL);
  sti();
}
/* ... 
   I hate tabs, empty lines, returns in middle of a function, and underscores 
   PB
   ... */

