// Sample code file: cne2000.c

// Warning: This code has been marked up for HTML

/*--------------------------------------------------------------------------*
 * $name: CNE2000.C
 * $version: 6
 * $date_modified: 12181998 
 * $description: This module contains the HardWare specific routines
 *               to initialize and control the Novell NE2000 board.  
 * $owner:  ODI LAN Driver Manager
 * Copyright (c) 1996, 1997, 1998 Novell, Inc. All Rights Reserved.
 *
 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND 
 * TREATIES. USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE
 * AGREEMENT ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS
 * THIS WORK. PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS 
 * TO DEVELOPER A ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S 
 * SAMPLE CODE IN ITS PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE 
 * DISTRIBUTION RIGHTS TO MARKET, DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE
 * AS A COMPONENT OF DEVELOPER'S PRODUCTS. NOVELL SHALL HAVE NO 
 * OBLIGATIONS TO DEVELOPER OR DEVELOPER'S CUSTOMERS WITH RESPECT TO THIS 
 * CODE.
 *--------------------------------------------------------------------------*/
/*****************************************************************************
 *
 * Title:         C language NE2000 HSM
 *
 * Filename:      NE2000.C
 *
 * ODI Spec Ver:   1.11
 *
 * Description:       This module contains the HardWare specific routines
 *               to initialize and control the Novell NE2000 board.
 *
 * Modification History: 
 *
 * 10-07-96 AYD      Set Bus Tag to zero assume that ISA is default bus
 *               Replaced MSMGetMicroTimer call with MSMGetCurrentTime call
 *               in DriverSend path and DriverCallBack
 *
 * 10-08-96 MCD      Added null entry to Driver Parameter Block structure for
 *                   Driver Priority Queue entry
 *
 * 10-08-96 TNL    Modified DriverPromiscuousChange code to support RMC bit.
 *
 * 12-04-96 MPK      Made changes in Driverinit, to make sure that the MLID
 *               is registered before the Hardware Interrupts are enabled.
 *               Also made changes to make sure that the NBI code does not
 *               acciendentally corrupt the DBus_tag Pointer in case of failure
 *
 * 02-19-97 MPK      Made changes in Driverinit, to call CMSMInitParser to use
 *               the new parser operations.  Also made the change in
 *               CheckForSharedRAM to call CMSMParseParameter
 *               instead of CMSMParseDriverParameter.
 *
 *   07-01-97 PSK      Changed DriverISR() to check for physical board
 *               shutdown, not logical board shutdown.
 *
 * 08-19-97 JCJ DriverShutdown is modified to check the scope of the operation
 *              SPD# 161807
 *
 * 11-25-97 WTT DriverInit was fixed to re-enable the card for new 
 *                frame types. CheckForSharedRAM leaves the card disabled which 
 *                is okay for the first frame type since DriverReset is called.
 *                However, the loading of additional frame types left the card
 *                disabled until something else triggered a reset. The code now
 *                calls driverReset for new frame types.
 *                SPD #161807
 *
 * 08-25-98 KRA   Fixed CheckForSharedRAM to supply the ParseString for the
 *                  MemOption record.  Since CMSMParseSingleParameter is used,
 *                  There must be a valid ParseString.  If the parse was
 *                  successful, the memory address is stored in the config table.
 *                  SPD 201866.
 *            
****************************************************************************/

#ifdef OUT_CHAR
#include "..\..\..\nios_h\nios.h"
UINT32   NiosDebugCharOut(UINT8);
#endif

/*===[ Include files specific to current platform ]======================*/

#include <portable.h>

/*===[ Generic HSM Include files ]===========================*/

#include <odi.h>
#include <odi_nbi.h>
#include <odi_nesl.h>
/*AYD */
#include <nesl_str.h>
#include <parser.h>
#include <cmsm.h>
#include <cne2000.txt>

#ifndef NULL
#define NULL 0L
#endif

/*===[ External data ]===================================================*/

extern   MLID_CONFIG_TABLE   DriverConfigTemplate;


/*===[ Manifest constants ]==============================================*/

#define    MAX_NUM_NE2000s         16

#define   RECEIVESTATUSTEST       0x4e
#define   MAX_MAC_HEADER            14+3+5 /* SNAP header is max for ethernet. */

/* Variable equates (for convenience and/or clarity) */

/* PCMCIA Option */
#define  PROD_ID_LEN             0x0004   /* 4 byte product ID for PCMCIA   */

/* Control1 Register Bits */
#define    NIC_SMADDRLOW        0x3F
#define   NIC_SMMEMENABLE         0x40
#define   NIC_SMRESET             0x80

/* Control2 Register Bits */
#define    NIC_SMADDRHI         0x1F
#define    NIC_SMMEMWIDTH       0x40
#define    NIC_SMBUSWIDTH       0x80


/* Command Register Bits */
#define   NIC_PAGE0               0x22
#define   NIC_PAGE1               0x62
#define   NIC_PAGE0DMAWRITE       0x12
#define   NIC_PAGE2DMAWRITE       0x92
#define   NIC_REMOTEDMAWR         0x12
#define   NIC_REMOTEDMARD         0x0A
#define   NIC_ABORTDMAWR          0x32
#define   NIC_ABORTDMARD          0x2A
#define   NIC_PAGE0STOP           0x21
#define   NIC_PAGE1STOP           0x61
#define   NIC_TRANSMIT            0x26
#define   NIC_TXINPROGRESS        0x04

/* Interrupt Mask Register Bits */
#define   NIC_MASKBYTE            0x00
#define   NIC_UNMASKBYTE          0x1f

/* Interrupt Status Register Bits */
#define   NIC_PACKETREADY         0x15
#define   NIC_RECVERROR           0x14
#define  NIC_RDC                0x40
#define   NIC_TXCOMPLETE          0x0A
#define   NIC_TRANSMITERROR       0x08
#define   NIC_OVW                 0x10
#define   NIC_RXERR               0x04
#define   NIC_RX                  0x01
#define   NIC_REQINT              0x7F

/* Transmit Status Flag Bits */

#define   SENDINGPAGEONE          0x01
#define USEPAGEONE              0x02
#define   PAGETWOWAITING          0x04

/* Transmit Status Register Bits */

#define   NIC_COLLISIONS          0x04
#define   NIC_EXCESSCOLLISIONS    0x08
#define   NIC_CARRIERSENSELOST    0x10
#define   NIC_FIFOUNDERRUN        0x20
#define   NIC_CDHEARTBEAT         0x40
#define   NIC_OUTOFWINDOWCOLL     0x80


/* Receive Status Register Bits */
#define   NIC_CRCERROR            0x02
#define   NIC_FRAMECRCERROR       0x06
#define   NIC_FIFOOVERRUNERROR    0x08
#define   NIC_MISSEDPACKETERROR   0x10


/* Receive Configuration Bits */
#define   NIC_SAVEERRORS          0x01
#define   NIC_SAVERUNTS           0x02
#define   NIC_BROADCAST           0x04
#define   NIC_MULTICAST           0x08
#define   NIC_PROMISCUOUS         0x10
#define   NIC_MONITOR             0x20

/* Transmit Configuration Register Bits */
#define   NIC_INTLOOPBACK         0x02
#define   NIC_EXTLOOPBACK         0x04

/* Data Configuration Register Bits */
#define   NIC_NORMALDATACONFIG    0x49

#define   PSTART                  0x4C
#define   PSTOP                   0x80
#define   RAMPSTART               0x0C
#define   RAMPSTOP                0x40

#define   RPACKET                 4

/*===[ Type definitions ]==================================================*/


/*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
   Get Configuration Info Structure.
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
typedef struct _GetConfigInfo_ {
    UINT16   Socket;
    UINT16   Attributes;
    UINT8   Vcc;
    UINT8   Vpp1;
    UINT8   Vpp2;
    UINT8   IntType;
    UINT32   ConfigBase;
    UINT8   Status;
    UINT8   Pin;
    UINT8   Copy;
    UINT8   ConfigIndex;
    UINT8   Present;
    UINT8   FirstDevType;
    UINT8   FuncCode;
    UINT8   SysInitMask;
    UINT8   ManufCode[4];
/*  UINT16   ManufCode;
    UINT16   ManufInfo; */
    UINT8   CardValues;
    UINT8   AssignedIRQ;
    UINT16   IRQAttributes;
    UINT16  BasePort1;
    UINT8   NumPorts1;
    UINT8   Attributes1;
    UINT16   BasePort2;
    UINT8     NumPorts2;
    UINT8   Attributes2;
    UINT8   IOAddrLines;
} GetConfigInfo;


typedef struct _HW8390hdr_
{
   UINT8    RReceiveStatus;
   UINT8    RNextBuffer;
   UINT16   RByteCount;
} HW8390hdr;

typedef   struct   _DRIVER_DATA_
{
   UINT8    *NICRAMSegmentBase;
   UINT8    *NICRAMSegmentLimit;
   UINT8    *NICRAMReceiveRingStart;
   UINT32   TxStartTime;
   UINT32   TransmitSize1;
   UINT32   TransmitSize2;
   UINT32   RxFragments;
   UINT32   SkipValue;
   int      TotalBytes;
   UINT32   RetryCounter;
   void     *BusTag;
   UINT8    Control1Value;
   UINT8    Control2Value;
   UINT8    TransmitStatusFlag;
   UINT8    ReceiveStatusTest;
   UINT8    NextPage;
   UINT8    RetryTxFlag;
   UINT8    OverflowRestartFlag;
   UINT8    FirstTimeInit;
   UINT8    TransmitPage0;
   UINT8    TransmitPage1;
   UINT8    CRCWorkArea[6];
   UINT8      PCMCIAFlag;
   UINT8    Align0[3];               /* TNL 9/21/95 Changed from Align0[2]   */

/* NE2000 I/O Register Values */
   void     *Control1;              /* Shared RAM, IO Base + 0  */
   void     *Control2;              /* Shared RAM, IO Base + 5  */
   void     *Prom;                  /* Shared RAM, IO Base + 8  */
   void     *Command;               /* IO Base + 0    (or 0x10) */
   void     *PageStart;             /* IO Base + 1    (or 0x11) */
   void     *PageStop;              /* IO Base + 2    (or 0x12) */
   void     *Boundary;              /* IO Base + 3    (or 0x13) */
   void     *TransmitStatus;        /* IO Base + 4    (or 0x14) */
   void     *TransmitByteCount0;    /* IO Base + 5    (or 0x15) */
   void     *TransmitByteCount1;    /* IO Base + 6    (or 0x16) */
   void     *InterruptStatus;       /* IO Base + 7    (or 0x17) */
   void     *RemoteStartAddress0;   /* IO Base + 8    (or 0x18) */
   void     *RemoteStartAddress1;   /* IO Base + 9    (or 0x19) */
   void     *RemoteByteCount0;      /* IO Base + A    (or 0x1A) */
   void     *RemoteByteCount1;      /* IO Base + B    (or 0x1B) */
   void     *ReceiveConfiguration;  /* IO Base + C    (or 0x1C) */
   void     *TransmitConfiguration; /* IO Base + D    (or 0x1D) */
   void     *DataConfiguration;     /* IO Base + E    (or 0x1E) */
   void     *InterruptMask;         /* IO Base + F    (or 0x1F) */
   void     *NICData;               /* IO Base + 0x10 (or 0x20) */
   void     *Reset;                 /* IO Base + 0x1f (or NA  ) */

#define PhysicalReg0      PageStart
#define TransmitPage      TransmitStatus
#define NumberCollisions  TransmitByteCount0
#define FIFO              TransmitByteCount1
#define Current           InterruptStatus
#define ReceiveStatus     ReceiveConfiguration
#define CurrentDMA0       RemoteStartAddress0
#define CurrentDMA1       RemoteStartAddress1
#define MulticastAddrReg  RemoteStartAddress0
#define TallyCounter0     TransmitConfiguration
#define TallyCounter1     DataConfiguration
#define TallyCounter2     InterruptMask
#define SizeOfCRCField    4


/* Look ahead buffer. Max lookahead size + max mac hdr + 8390 hdr + */
/*  a byte (rounded up to 4) for evenization overflow.              */
UINT8   ReceiveHeader[128 + MAX_MAC_HEADER + 4 + 4];

/* AES ECB   */
   MLID_AES_ECB   mlidAESECB;

/* Statistics Table */

   MLID_STATS_TABLE   StatsTable;

/* Generic Statistics Table Entries */
   StatTableEntry      TotalTxPacketTable;
   StatTableEntry      TotalRxPacketTable;
   StatTableEntry      NoECBAvailableTable;
   StatTableEntry      PacketTxTooBigTable;
   StatTableEntry      PacketTxTooSmallTable;
   StatTableEntry      PacketRxOverflowTable;
   StatTableEntry      PacketRxTooBigTable;
   StatTableEntry      PacketRxTooSmallTable;
   StatTableEntry      PacketTxMiscErrorTable;
   StatTableEntry      PacketRxMiscErrorTable;
   StatTableEntry      RetryTxTable;
   StatTableEntry      ChecksumErrorTable;
   StatTableEntry      HardwareRxMismatchTable;
   StatTableEntry      TotalTxOKByteTable;
   StatTableEntry      TotalRxOKByteTable;
   StatTableEntry      TotalGroupAddrTxTable;
   StatTableEntry      TotalGroupAddrRxTable;
   StatTableEntry      AdapterResetTable;
   StatTableEntry      AdapterOprTimeStampTable;
   StatTableEntry      QDepthTable;

/* Media Statistics Table Entries */
   StatTableEntry      TxOKSingleCollisionTable;
   StatTableEntry      TxOKMultipleCollisionsTable;
   StatTableEntry      TxOKButDeferredTable;
   StatTableEntry      TxAbortLateCollisionTable;
   StatTableEntry      TxAbortExcessCollisionsTable;
   StatTableEntry      TxAbortCarrierSenseTable;
   StatTableEntry      TxAbortExDeferralTable;
   StatTableEntry      RxAbortFrameAlignmentTable;

/* Custom Statistics Table Entries */
   StatTableEntry      UnderrunErrorTable;
   StatTableEntry      TransmitTimeoutTable;
   StatTableEntry      RxPagingErrorTable;
   StatTableEntry      RxFIFOOverrunErrorTable;
   StatTableEntry      RxMissedPacketTable;
   StatTableEntry      GotNothingTable;
   StatTableEntry      UnsupportedFrameTable;
   StatTableEntry      UnsupportedMulticastTable;
   StatTableEntry      BackToBackSendTable;
   StatTableEntry      EnqueueSendTable;


/* Generic counters */
   UINT32            TotalTxPacketCount;
   UINT32            TotalRxPacketCount;
   UINT32            NoECBAvailableCount;
   UINT32            PacketTxTooBigCount;
   UINT32            PacketTxTooSmallCount;
   UINT32            PacketRxOverflowCount;
   UINT32            PacketRxTooBigCount;
   UINT32            PacketRxTooSmallCount;
   UINT32            PacketTxMiscErrorCount;
   UINT32            PacketRxMiscErrorCount;
   UINT32            RetryTxCount;
   UINT32            ChecksumErrorCount;
   UINT32            HardwareRxMismatchCount;
   UINT64            TotalTxOKByteCount;
   UINT64            TotalRxOKByteCount;
   UINT32            TotalGroupAddrTxCount;
   UINT32            TotalGroupAddrRxCount;
   UINT32            AdapterResetCount;
   UINT32            AdapterOprTimeStamp;
   UINT32            QDepth;

/* Media counters */
   UINT32            TxOKSingleCollision;
   UINT32            TxOKMultipleCollisions;
   UINT32            TxOKButDeferred;
   UINT32            TxAbortLateCollision;
   UINT32            TxAbortExcessCollisions;
   UINT32            TxAbortCarrierSense;
   UINT32            TxAbortExDeferral;
   UINT32            RxAbortFrameAlignment;

/* Custom counters */
   UINT32      UnderrunErrorCount;
   UINT32      TransmitTimeoutCount;
   UINT32      RxPagingErrorCount;
   UINT32      RxFIFOOverrunErrorCount;
   UINT32      RxMissedPacketCount;
   UINT32      GotNothingCount;
   UINT32      UnsupportedFrameCount;
   UINT32      UnsupportedMulticastCount;
   UINT32      BackToBackSendCount;
   UINT32      EnqueueSendCount;

} DRIVER_DATA;

/* Parameter Option Description Structures */

struct
{
   UINT32   OptionCount;
   UINT32   UNumOptVal[24];
} MemOptionList =
   {24, {0x0d0000, 0x0d4000, 0x0d8000, 0x0dc000,
         0x0c0000, 0x0c4000, 0x0c8000, 0x0cc000,
         0x0e0000, 0x0e2000, 0x0e4000, 0x0e6000,
         0x0e8000, 0x0ea000, 0x0ec000, 0x0ee000,
         0x0f0000, 0x0f2000, 0x0f4000, 0x0f6000,
         0x0f8000, 0x0fa000, 0x0fc000, 0x0fe000}};

struct
{
   UINT32   OptionCount;
   UINT32   UNumOptVal[7];
} IoOptionList = {7, {0x300, 0x320, 0x340, 0x360, 0x240, 0x280, 0x2c0}};

struct
{
   UINT32   OptionCount;
   UINT32   UNumOptVal[9];
} IntOptionList = {9, {3, 2, 4, 5, 9, 10, 11, 12, 15}};

struct
{
   UINT32    OptionCount;
   UINT32    UNumOptVal[8];
} SlotsWithMyBoard = {0, {0, 0, 0, 0, 0, 0, 0, 0}};


DRIVER_OPTION MemOption =
         { NULL, NULL, (PARAMETER_OPTIONS *)&MemOptionList, 0, 0, MEMPARAM,
               OPTIONALPARAM | ENUMPARAM, };
DRIVER_OPTION IoOption =
         { &MemOption, NULL, (PARAMETER_OPTIONS *)&IoOptionList, 0, 0, PORTPARAM,
               REQUIREDPARAM | ENUMPARAM, };
DRIVER_OPTION IntOption =
         { &IoOption, NULL, (PARAMETER_OPTIONS *)&IntOptionList, 0, 0, INTPARAM,
               REQUIREDPARAM | ENUMPARAM, };
DRIVER_OPTION SlotOption =
         { NULL, NULL, (PARAMETER_OPTIONS *)&SlotsWithMyBoard, 0, 0, SLOTPARAM, 
               REQUIREDPARAM | ENUMPARAM, };

/*===[ Include files specific Ethernet MLIDs ]===========================*/
#include "ethertsm.h"
         
/*===[ Global variables ]==================================================*/

MEON_STRING CHSMSPEC[] = {CNE2000_SPECVER_TXTMSG};

MEON_STRING NICShortName[] =  {CNE2000_SHORTNAME_TXTMSG};

/* DriverMessages will be filled in by MSM(<TSM>RegisterHSM) to point      */
/* to message enabled messages.                                             */

MEON   **DriverMessages = NULL;

#define    NUM_OF_PROD_ID      2
MEON       NE2000ProdID[8] = {0x8f, 0x00, 0x07, 0x2A, 
                             0xA4, 0x00, 0x02, 0x00};

/* Data pointers needed for NESL event production   */

EPB        *NESL_EPBPtr = NULL;
NESL_ECB *NESLServiceResumeNECBPtr = NULL;
BOOLEAN   NESLRegisterDone = FALSE;


/* Driver Data Space template. MSMRegisterHardwareOptions will initialize   */
/* each adapter data space with the values in this template.               */

#define   NUMBER_OF_GENERICS   20L
#define   NUMBER_OF_MEDIAS      8L
#define   NUMBER_OF_CUSTOMS      10L


DRIVER_DATA   DriverDataTemplate =
{
   NULL,                           /* NICRAMSegmentBase */
   NULL,                           /* NICRAMSegmentLimit */
   NULL,                           /* NICRAMReceiveRingStart */
   0,                              /* TxStartTime; */
   0,                              /* TransmitSize1; */
   0,                              /* TransmitSize2; */
   0,                              /* RxFragments */
   0,                              /* SkipValue    */
   0,                              /* TotalBytes   */
   0,                              /* RetryCounter */
   NULL,                           /* BusTag */
   0,                              /* Control1Value */
   0,                              /* Control2Value */
   0x0002,                        /* TransmitStatusFlag; */
   0x4E,                           /* ReceiveStatusTest */
   PSTART + 1,                     /* NextPage; */
   0,                              /* RetryTxFlag; */
   0,                              /* OverflowRestartFlag; */
   1,                              /* FirstTimeInit; */
   0xC0,                           /* TransmitPage0 */
   0xC6,                           /* TransmitPage1 */
   {0},                           /* CRCWorkArea[6]; */
     0,                              /* PCMCIA Flag */
   {0},                           /* Align0[3]; */        

/* NE2000 I/O Register Values */
   NULL,                        /* Control1 */
   NULL,                        /* Control2 */
   NULL,                        /* Prom */
   NULL,                        /* Command;                        IO Base + 0 */
   NULL,                        /* PageStart;                     IO Base + 1 */
   NULL,                        /* PageStop;                     IO Base + 2 */
   NULL,                        /* Boundary;                     IO Base + 3 */
   NULL,                        /* TransmitStatus;               IO Base + 4 */
   NULL,                        /* TransmitByteCount0;            IO Base + 5 */
   NULL,                        /* TransmitByteCount1;            IO Base + 6 */
   NULL,                        /* InterruptStatus;               IO Base + 7 */
   NULL,                        /* RemoteStartAddress0;            IO Base + 8 */
   NULL,                        /* RemoteStartAddress1;            IO Base + 9 */
   NULL,                        /* RemoteByteCount0;               IO Base + 10 */
   NULL,                        /* RemoteByteCount1;               IO Base + 11 */
   NULL,                        /* ReceiveConfiguration;         IO Base + 12 */
   NULL,                        /* TransmitConfiguration;         IO Base + 13 */
   NULL,                        /* DataConfiguration;            IO Base + 14 */
   NULL,                        /* InterruptMask;                  IO Base + 15 */
   NULL,                        /* NICData;                        IO Base + 16 */
   NULL,                        /* Reset;                        IO Base + 1f */

/* Look ahead buffer.  ReceiveHeader[128] */
   {0},

/* AES ECB, MLID_AES_ECB   mlidAESECB */
   {
      NULL,                                       /* NextLink          */
      NULL,                                       /* fn ptr               */
      AES_TYPE_PROCESS_CONTINUOUS,               /* type                  */
      1000,                                       /* interval in ms   */
      NULL,                                       /* reserved            */
       {0},
   },

/* Statistics Table */
   {
   0x04,                           /* StatisticsMajVer; */
   0x00,                           /* StatisticsMinVer; */

   NUMBER_OF_GENERICS,            /* StatsTable->MNumGenericCounters         */
   (StatTableEntry (*)[])&DriverDataTemplate.TotalTxPacketTable,
                                 /* StatsTable->MGenericCountsPtr            */
   NUMBER_OF_MEDIAS,               /* StatsTable->MNumMediaCounters            */
   (StatTableEntry (*)[])&DriverDataTemplate.TxOKSingleCollisionTable,
                                 /* StatsTable->MMediaCountersPtr            */
   NUMBER_OF_CUSTOMS,            /* StatsTable->MNumCustomCounters         */
   (StatTableEntry (*)[])&DriverDataTemplate.UnderrunErrorTable
   },                           /* StatsTable->MCustomCountersPtr         */

/* Generic Statistics Table Entries */

   {ODI_STAT_UINT32,               /* TotalTxPacketTable->StatUseFlag         */
   &DriverDataTemplate.TotalTxPacketCount,         /* ->StatCounter         */
   NULL},                                          /* ->StatString         */

   {ODI_STAT_UINT32,               /* TotalRxPacketTable->StatUseFlag         */
   &DriverDataTemplate.TotalRxPacketCount,         /* ->StatCounter         */
   NULL},                                          /*  ->StatString         */

   {ODI_STAT_UINT32,               /* NoECBAvailableTable->StatUseFlag         */
   &DriverDataTemplate.NoECBAvailableCount,         /*  ->StatCounter         */
   NULL},                                          /*  ->StatString         */

   {ODI_STAT_UINT32,               /* PacketTxTooBigTable->StatUseFlag         */
   &DriverDataTemplate.PacketTxTooBigCount,         /*  ->StatCounter         */
   NULL},                                          /*  ->StatString         */

   {ODI_STAT_UINT32,               /* PacketTxTooSmallTable->StatUseFlag      */
   &DriverDataTemplate.PacketTxTooSmallCount,         /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT32,               /* PacketRxOverflowTable->StatUseFlag      */
   &DriverDataTemplate.PacketRxOverflowCount,         /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT32,               /* PacketRxTooBigTable->StatUseFlag         */
   &DriverDataTemplate.PacketRxTooBigCount,         /*  ->StatCounter         */
   NULL},                                          /*  ->StatString         */

   {ODI_STAT_UINT32,               /* PacketRxTooSmallTable->StatUseFlag      */
   &DriverDataTemplate.PacketRxTooSmallCount,         /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT32,               /* PacketTxMiscErrorTable->StatUseFlag      */
   &DriverDataTemplate.PacketTxMiscErrorCount,         /*  ->StatCounter      */
   NULL},                                             /*  ->StatString      */

   {ODI_STAT_UINT32,               /* PacketRxMiscErrorTable->StatUseFlag      */
   &DriverDataTemplate.PacketRxMiscErrorCount,         /*  ->StatCounter      */
   NULL},                                             /*  ->StatString      */

   {ODI_STAT_UINT32,                        /* RetryTxTable->StatUseFlag      */
   &DriverDataTemplate.RetryTxCount,                  /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT32,                  /* ChecksumErrorTable->StatUseFlag      */
   &DriverDataTemplate.ChecksumErrorCount,            /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT32,               /* HardwareRxMismatchTable->StatUseFlag   */
   &DriverDataTemplate.HardwareRxMismatchCount,         /*   ->StatCounter   */
   NULL},                                             /*   ->StatString      */

   {ODI_STAT_UINT64,                  /* TotalTxOKByteTable->StatUseFlag      */
   &DriverDataTemplate.TotalTxOKByteCount,            /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT64,                  /* TotalRxOKByteTable->StatUseFlag      */
   &DriverDataTemplate.TotalRxOKByteCount,            /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT32,                  /* TotalGroupAddrTxTable->StatUseFlag   */
   &DriverDataTemplate.TotalGroupAddrTxCount,            /* ->StatCounter   */
   NULL},                                                /* ->StatString   */

   {ODI_STAT_UINT32,                  /* TotalGroupAddrRxTable->StatUseFlag   */
   &DriverDataTemplate.TotalGroupAddrRxCount,            /* ->StatCounter   */
   NULL},                                                /* ->StatString   */

   {ODI_STAT_UINT32,                  /* AdapterResetTable->StatUseFlag      */
   &DriverDataTemplate.AdapterResetCount,               /*->StatCounter      */
   NULL},                                             /*->StatString         */

   {ODI_STAT_UINT32,               /* AdapterOprTimeStampTable->StatUseFlag   */
   &DriverDataTemplate.AdapterOprTimeStamp,               /* ->StatCounter   */
   NULL},                                                /* ->StatString   */

   {ODI_STAT_UINT32,                           /* QDepthTable->StatUseFlag   */
   &DriverDataTemplate.QDepth,                           /*->StatCounter   */
   NULL},                                                /*->StatString      */

/* Media Statistics Table Entries */

   {ODI_STAT_UINT32,            /* TxOKSingleCollisionTable->StatUseFlag      */
   &DriverDataTemplate.TxOKSingleCollision,            /* ->StatCounter      */
   NULL},                                             /* ->StatString      */

   {ODI_STAT_UINT32,            /* TxOKMultipleCollisionsTable->StatUseFlag   */
   &DriverDataTemplate.TxOKMultipleCollisions,         /*    ->StatCounter   */
   NULL},                                             /*    ->StatString   */

   {ODI_STAT_UINT32,                  /* TxOKButDeferredTable->StatUseFlag   */
   &DriverDataTemplate.TxOKButDeferred,               /*   ->StatCounter   */
   NULL},                                             /*   ->StatString      */

   {ODI_STAT_UINT32,               /* TxAbortLateCollisionTable->StatUseFlag   */
   &DriverDataTemplate.TxAbortLateCollision,               /*  ->StatCounter   */
   NULL},                                                /*  ->StatString   */

   {ODI_STAT_UINT32,            /* TxAbortExcessCollisionTable->StatUseFlag   */
   &DriverDataTemplate.TxAbortExcessCollisions,            /* ->StatCounter   */
   NULL},                                                /* ->StatString   */

   {ODI_STAT_UINT32,               /* TxAbortCarrierSenseTable->StatUseFlag   */
   &DriverDataTemplate.TxAbortCarrierSense,               /* ->StatCounter   */
   NULL},                                                /* ->StatString   */

   {ODI_STAT_UINT32,               /* TxAbortExDeferralTable->StatUseFlag      */
   &DriverDataTemplate.TxAbortExDeferral,               /*  ->StatCounter      */
   NULL},                                             /*  ->StatString      */

   {ODI_STAT_UINT32,            /* RxAbortFrameAlignmentTable->StatUseFlag   */
   &DriverDataTemplate.RxAbortFrameAlignment,         /*   ->StatCounter   */
   NULL},                                             /*   ->StatString      */

/* Custom Statistics Table Entries */

   {ODI_STAT_UINT32,                     /* UnderrunErrorTable->StatUseFlag   */
   &DriverDataTemplate.UnderrunErrorCount,            /*  ->StatCounter   */
   NULL},                                                /*  ->StatString   */
   {ODI_STAT_UINT32,                     /* TransmitTimeoutTable->StatUseFlag      */
   &DriverDataTemplate.TransmitTimeoutCount,         /*  ->StatCounter      */
   NULL},                                             /*  ->StatString      */
   {ODI_STAT_UINT32,                     /* RxPagingErrorTable->StatUseFlag      */
   &DriverDataTemplate.RxPagingErrorCount,            /* ->StatCounter      */
   NULL},                                             /* ->StatString      */
   {ODI_STAT_UINT32,                     /* RxFIFOOverrunErrorTable->StatUseFlag      */
   &DriverDataTemplate.RxFIFOOverrunErrorCount,            /*  ->StatCounter      */
   NULL},                                             /*  ->StatString      */
   {ODI_STAT_UINT32,                  /* RxMissedPacketTable->StatUseFlag      */
   &DriverDataTemplate.RxMissedPacketCount,         /* ->StatCounter      */
   NULL},                                             /* ->StatString      */
   {ODI_STAT_UINT32,                  /* GotNothingTable->StatUseFlag      */
   &DriverDataTemplate.GotNothingCount,               /* ->StatCounter      */
   NULL},                                             /* ->StatString      */
   {ODI_STAT_UINT32,                  /* UnsupportedFrameTable->StatUseFlag   */
   &DriverDataTemplate.UnsupportedFrameCount,      /*   ->StatCounter   */
   NULL},                                             /*   ->StatString      */
   {ODI_STAT_UINT32,               /* UnsupportedMulticastTable->StatUseFlag      */
   &DriverDataTemplate.UnsupportedMulticastCount,   /* ->StatCounter      */
   NULL},                                             /* ->StatString      */
   {ODI_STAT_UINT32,               /* BackToBackTable->StatUseFlag      */
   &DriverDataTemplate.BackToBackSendCount,         /* ->StatCounter      */
   NULL},                                             /* ->StatString      */
   {ODI_STAT_UINT32,               /* EnqueueSendTable->StatUseFlag      */
   &DriverDataTemplate.EnqueueSendCount,               /* ->StatCounter      */
   NULL},                                             /* ->StatString      */


/* Generic counters */
   0,                              /* TotalTxPacketCount; */
   0,                              /* TotalRxPacketCount; */
   0,                              /* NoECBAvailableCount; */
   0,                              /* PacketTxTooBigCount; */
   0,                              /* PacketTxTooSmallCount; */
   0,                              /* PacketRxOverflowCount; */
   0,                              /* PacketRxTooBigCount; */
   0,                              /* PacketRxTooSmallCount; */
   0,                              /* PacketTxMiscErrorCount; */
   0,                              /* PacketRxMiscErrorCount; */
   0,                              /* RetryTxCount; */
   0,                              /* ChecksumErrorCount; */
   0,                              /* HardwareRxMismatchCount; */
   0,                              /* TotalTxOKByteCountLow; */
   0,                              /* TotalTxOKByteCountHigh; */
   0,                              /* TotalRxOKByteCountLow; */
   0,                              /* TotalRxOkByteCountHigh; */
   0,                              /* TotalGroupAddrTxCount; */
   0,                              /* TotalGroupAddrRxCount; */
   0,                              /* AdapterResetCount; */
   0,                              /* AdapterOprTimeStamp; */
   0,                              /* QDepth; */
   
/* Media counters */
   0,                              /* TxOKSingleCollision; */
   0,                              /* TxOKMultipleCollisions; */
   0,                              /* TxOKButDeferred; */
   0,                              /* TxAbortLateCollision; */
   0,                              /* TxAbortExcessCollisions; */
   0,                              /* TxAbortCarrierSense; */
   0,                              /* TxAbortExDeferral; */
   0,                              /* RxAbortFrameAlignment; */
      
/* Custom counters */
   0,                              /* UnderrunErrorCount; */
   0,                              /* TransmitTimeoutCount; */
   0,                              /* RxPagingErrorCount; */
   0,                              /* RxFIFOOverrunErrorCount; */
   0,                              /* RxMissedPacketCount; */
   0,                              /* GotNothingCount; */
   0,                              /* UnsupportedFrameCount; */
   0,                              /* UnsupportedMulticastCount; */
   0,                              /* BackToBackSendCount; */
   0,                              /* EnqueueSendCount; */
   
};

/*===[ Function prototypes ]=============================================== */

void DriverSend(
               DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable,
               TCB                  *tcb,
               UINT32             bytesToSend,
               void               *phystcb);

void DriverISR(
         DRIVER_DATA      *driverData);

ODISTAT   DriverReset(
               DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable,
               OPERATION_SCOPE operationScope);

ODISTAT   DriverShutdown(
               DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable,
               UINT32         shutdownType,
               OPERATION_SCOPE operationScope);

ODISTAT   DriverMulticastChange(
         DRIVER_DATA            *driverData,
               CONFIG_TABLE         *configTable,
               GROUP_ADDR_LIST_NODE   *mcTable,
               UINT32                 numEntries,
               UINT32                 funAddrBits);

ODISTAT   DriverPromiscuousChange(
               DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable,
               UINT32             changeTo);

BOOLEAN   DriverDisableInterrupt(
               DRIVER_DATA      *driverData,
              BOOLEAN        flag);

void   DriverEnableInterrupt(
               DRIVER_DATA      *driverData);

ODISTAT DriverTestHardware(
         DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable);

UINT32 CalculateHash(GROUP_ADDR_LIST_NODE   *multiaddress);

void ModifyNICHashTableBit(
         DRIVER_DATA      *driverData,
               UINT32 BitIndex);

void DriverCallback(
               DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable);

void CFixUpStatStrings(DRIVER_DATA *driverData);


/*===[ DriverParameterBlock ]=============================================== */

DRIVER_PARM_BLOCK   DriverParameters =
{
sizeof(DRIVER_PARM_BLOCK),/* DriverParameterSize  */
   NULL,                               /* DriverInitParamPointer. */
   0,                                  /* DriverModuleHandle set by MSM; */
   NULL,                               /* *DriverBoardPointer Set by MSM */
   NULL,                               /* *DriverAdapterPointer Set by MSM */
   &DriverConfigTemplate,              /* *DriverConfigTemplatePointer; */
   0,                                  /* DriverFirmwareSize Not used */
   NULL,                               /* *DriverFirmwareBuffer Not used */
   0,                                  /* DPB_Reserved0 */
   0,                                  /* DPB_Reserved1 */
   0,                                  /* DPB_Reserved2 */
   0,                                  /* DPB_Reserved3 */
   sizeof(DRIVER_DATA),                /* DRIVER_DATASize; */
   &DriverDataTemplate,                /* *DRIVER_DATATemplatePtr; */
   (UINT32)&(((DRIVER_DATA *)NULL)->StatsTable), /* DriverStatisticsTableOffset; */
   0,                                  /* DriverEndOfChainFlag; */
   0,                                  /* DriverSendWantsECBs; */
   -1,                                 /* DriverMaxMulticast; */
   0,                                  /* DriverNeedsBelow16Meg; */
   NULL,
   NULL,
   DriverISR,
   DriverMulticastChange,
   NULL,                               /* DriverPoll */
   DriverReset,
   DriverSend,
   DriverShutdown,
   NULL,                               /* DPB_Reserved4 */
   DriverPromiscuousChange,
   NULL,                               /* DriverStatisticsChange */
   NULL,                               /* DriverRxLookAheadChange */
   NULL,                               /* DriverManagement */
   DriverEnableInterrupt,
   DriverDisableInterrupt,
   NULL,                               /* DriverISR2 */
   &DriverMessages,                    /* DriverMessagesPtr          */
   &CHSMSPEC,                          /* HSM Specification Version */
   NULL,                                /* DrvierPriorityQueue */
   NULL               /* DriverDisableInterrupt2Ptr */
};





MLID_CONFIG_TABLE   DriverConfigTemplate =
{
   CNE2000_CONFIGSIG_TXTMSG,        /* MLIDCFG_Signature[26]; */
   0x01,                              /* MLIDCFG_MajorVersion; */
   0x21,                              /* MLIDCFG_MinorVersion; */
   {0xff,0xff,0xff,0xff,0xff,0xff},   /* MLIDCFG_NodeAddress[ADDR_SIZE]; */
   0xAC48,                           /* MLIDCFG_ModeFlags; */
   0x0000,                           /* MLIDCFG_BoardNumber; */
   0x0000,                           /* MLIDCFG_BoardInstance; */
   0x000005ea,                         /* MLIDCFG_MaxFrameSize; */
   0x000005dc,                        /* MLIDCFG_BestDataSize; */
   0x000005dc,                        /* MLIDCFG_WorstDataSize; */
   NULL,                              /* *MLIDCFG_CardName; */
   NICShortName,                      /* *MLIDCFG_ShortName; */
   NULL,                            /* *MLIDCFG_FrameTypeString; */
   0x0000,                           /* MLIDCFG_Reserved0; */
   0x0003,                           /* MLIDCFG_FrameID; */
   0x0001,                           /* MLIDCFG_TransportTime; */
   NULL,                              /* *MLIDCFG_SourceRouting; */
   10,                              /* MLIDCFG_LineSpeed; */
   18,                              /* MLIDCFG_LookAheadSize; */
   0,                               /* MLIDCFG_SGCount            */
   0,                               /* MLIDCFG_Reserved1         */
   0,                                 /* MLIDCFG_PrioritySup; */
   NULL,                              /* MLIDCFG_Reserved2; */
   0,                                 /* MLIDCFG_DriverMajorVer; */
   0,                                 /* MLIDCFG_DriverMinorVer; */
   0x0000,                           /* MLIDCFG_Flags; */
   0x000A,                           /* MLIDCFG_SendRetries; */
   NULL,                              /* *MLIDCFG_DriverLink; */
   0x0000,                           /* MLIDCFG_SharingFlags; */
   0xffff,                           /* MLIDCFG_Slot; */
   0x0300,                           /* MLIDCFG_IOPort0; */
   32,                              /* MLIDCFG_IORange0; */
   0x0000,                           /* MLIDCFG_IOPort1; */
   0,                                 /* MLIDCFG_IORange1; */
   NULL,                              /* MLIDCFG_MemoryAddress0; */
   0x0000,                           /* MLIDCFG_MemorySize0; */
   NULL,                              /* MLIDCFG_MemoryAddress1; */
   0x0000,                           /* MLIDCFG_MemorySize1; */
   0x03,                              /* MLIDCFG_Interrupt0; */
   0xff,                              /* MLIDCFG_Interrupt1; */
   0xff,                              /* MLIDCFG_DMALine0; */
   0xff,                              /* MLIDCFG_DMALine1; */
   NULL,                              /* *MLIDCFG_ResourceTag; */
   NULL,                              /* *MLIDCFG_Config; */
   NULL,                              /* *MLIDCFG_CommandString; */
   {0},                              /* MLIDCFG_LogicalName[18]; */
   0x00000000,                        /* MLID_LinearMemory0; */
   0x00000000,                        /* MLID_LinearMemory1; */
   0x0000,                           /* MLIDChannelNumber */
   NULL,                              /* MLIDCFG_DBusTag; */
   1,                                 /* MLIDCFG_DIOConfigMajor; */
   0,                                 /* MLIDCFG_DIOConfigMinor; */
};


UINT32    IoPortData[] = {0x300, 0x320, 0x340, 0x360, 0x240, 0x280, 0x2c0};
UINT32    Interrupt0Data[] = {2, 3, 4, 5, 10, 11, 12, 15};
UINT32    MemoryDecode0Data[] = {
                                 0x0d0000, 0x0d4000, 0x0d8000, 0x0dc000,
                                 0x0c0000, 0x0c4000, 0x0c8000, 0x0cc000,
                                 0x0e0000, 0x0e2000, 0x0e4000, 0x0e6000,
                                 0x0e8000, 0x0ea000, 0x0ec000, 0x0ee000,
                                 0x0f0000, 0x0f2000, 0x0f4000, 0x0f6000,
                                 0x0f8000, 0x0fa000, 0x0fc000, 0x0fe000};

UINT8   IntTable[] = {3, 4, 5, 2, 10, 11, 12, 15};

/*======================================================================
  Procedure Name:   DriverSend

  Arguments:   
             driverData  - Ptr to Our Data Space
             configTable - Ptr to Our config Table.
             tcb         - Ptr to the TCB
             bytesToSend - Has the number of bytes to send.

  Returns:      void

  Abstract:      This function will transfer the packet described by the
                  TCB to the NIC and initiate the send.

  Notes:            

=======================================================================*/
void DriverSend(
               DRIVER_DATA         *driverData,
               CONFIG_TABLE      *configTable,
               TCB                     *tcb,
               UINT32                bytesToSend,
               void                  *phystcb)
{
   TCB_FRAGMENT_BLOCK   *fragbase;
   FRAGMENT_STRUCT      *fragmentptr;
   UINT32               packetsize;
   UINT32               i, j, oddbyte;
   UINT16               tempword;
   UINT8                  nicstatus, *dataptr;


DriverSendTop:

#ifdef OUT_CHAR
   NiosDebugCharOut ('S');
#endif /* OUT_CHAR */

/* Set DMA complete, if not set. */
   Out8(driverData->BusTag, driverData->InterruptStatus, NIC_RDC);

/* Figure out which xmit buf to use next */
   if (driverData->TransmitStatusFlag & USEPAGEONE)
   {
      driverData->TransmitSize1 = bytesToSend;
      Out8(driverData->BusTag, driverData->RemoteStartAddress0, 0x00);
      Out8(driverData->BusTag, driverData->RemoteStartAddress1, 0x40);
   }
   else
   {
      driverData->TransmitSize2 = bytesToSend;
      Out8(driverData->BusTag, driverData->RemoteStartAddress0, 0x00);
      Out8(driverData->BusTag, driverData->RemoteStartAddress1, 0x46);
   }

/* Evenize packetsize */
   packetsize = tcb->TCB_DataLen;
   packetsize += (packetsize & 1);

   Out8(driverData->BusTag, driverData->RemoteByteCount0, (UINT8)(packetsize /* & 0xFF */ ));
   Out8(driverData->BusTag, driverData->RemoteByteCount1, (UINT8)(packetsize >> 8));

   Out8(driverData->BusTag, driverData->Command, NIC_REMOTEDMAWR);

/* Copy Frame header to the NIC */
/* We can only copy even values to card. */
/* So if odd send all but last byte of hdr now (we will do the last */
/*  byte later.) */

   OutBuff16(
      driverData->BusTag,
      driverData->NICData,
      &tcb->TCB_MediaHeader,
      tcb->TCB_MediaHeaderLen / 2);


/* Setup the fragment pointers */
   fragbase = tcb->TCB_FragBlockPtr;
   fragmentptr = &(fragbase->TCB_Fragment);


/* Check if frame header is odd length */
   if (tcb->TCB_MediaHeaderLen & 1)
   {
/* The header is odd copy it plus first data byte */
      oddbyte = 1;
      tempword = VALUE_TO_HILO_UINT16((*((UINT8 *)(&(tcb->TCB_MediaHeader)) + tcb->TCB_MediaHeaderLen -1) << 8) |
                              (*(UINT8 *)fragmentptr->FragmentAddress));

      Out16(
         driverData->BusTag,
         driverData->NICData,
         tempword);
   }
   else oddbyte = 0;

/* Copy fragments to the NIC. */
   for(i = fragbase->TCB_FragmentCount; i > 0; --i)
   {
      if (fragmentptr->FragmentLength == 0)
         ++fragmentptr;
      else
      {
         dataptr = fragmentptr->FragmentAddress;

         OutBuff16(
            driverData->BusTag,
            driverData->NICData,
            dataptr + oddbyte,
            (fragmentptr->FragmentLength - oddbyte) / 2);

         if((fragmentptr->FragmentLength - oddbyte) & 1)
         {
            oddbyte = 1;
            tempword = (dataptr[fragmentptr->FragmentLength - 1]) << 8;
            while (i > 1)      /* Don't illegal access off the end of the frag list */
            {
               ++fragmentptr;
               if (fragmentptr->FragmentLength != 0)
               {
                  dataptr = fragmentptr->FragmentAddress;
                  tempword = tempword | dataptr[0];
                  break;
               }
               --i;
            }
              tempword = VALUE_TO_HILO_UINT16(tempword);
            Out16(driverData->BusTag, driverData->NICData, tempword);
         }
         else
         {
            ++fragmentptr;
            oddbyte = 0;
         }
      }
   }

/* Check if NIC is ready to send. */
 for (nicstatus = 0, j = 0; !(nicstatus & NIC_RDC) & j  < 65534;
          nicstatus = In8( driverData->BusTag, driverData->InterruptStatus), j++);

   if ( !nicstatus & NIC_RDC)
   {
/* Can't get DMA_Complete, this is bad */
      Out8(driverData->BusTag, driverData->InterruptStatus, NIC_RDC);   /* Set the DMA complete */
      CMSMPrintString( configTable, MSG_TYPE_RUNTIME_ERROR, CNE2000_DMAERR_MSG, 0, 0);
      DriverReset(driverData, configTable, OP_SCOPE_ADAPTER);
      goto DriverSendTop;
   }

   if (!(driverData->TransmitStatusFlag & SENDINGPAGEONE))
   {
      Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage0);
      Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize1 /* & 0xFF */));
      Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize1 >> 8));

/* Send packet */
      Out8(driverData->BusTag, driverData->Command, NIC_TRANSMIT);

/* Note the time */
      driverData->TxStartTime = CMSMGetCurrentTime();
      driverData->RetryCounter = configTable->MLIDCFG_SendRetries;
      driverData->TransmitStatusFlag = SENDINGPAGEONE;

/* Give TCB back to MSM (Lying Send) */
      CEtherTSMFastSendComplete(driverData, tcb, 0);

#ifdef OUT_CHAR
   NiosDebugCharOut ('s');
#endif /* OUT_CHAR */

      return;
   }
   else
   {
#ifdef OUT_CHAR
   NiosDebugCharOut ('w');
#endif /* OUT_CHAR */

      driverData->TransmitStatusFlag = PAGETWOWAITING;
      CEtherTSMFastSendComplete(driverData, tcb, 0);
   }

/* Junk to keep compiler happy, optimizer should remove. */
   phystcb = phystcb;


}


/*=====================================================================

  Procedure Name:   DriverSendSharedRAM

  Arguments:   
             driverData   - Ptr to Our Data Space
             configTable  - Ptr to Our config Table.
             tcb          - Ptr to the TCB
             bytesToSend  - Has the number of bytes to send.

  Returns:      void

  Abstract:      This function will transfer the packet described by the
                  TCB to the NIC and initiate the send.

  Notes:            

=======================================================================*/
void DriverSendSharedRAM(
               DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable,
               TCB                  *tcb,
               UINT32             bytesToSend,
               void                  *phystcb)
{
   FRAGMENTSTRUCT  *fragmentptr;
   UINT32          fragsize;
   UINT32          i;
   UINT8           *fragptr, *dataptr;

/* Figure out which xmit buf to use next */
   if (driverData->TransmitStatusFlag & USEPAGEONE)
   {
      driverData->TransmitSize1 = bytesToSend;
      dataptr = driverData->NICRAMSegmentBase;
   }
   else
   {
      driverData->TransmitSize2 = bytesToSend;
      dataptr = driverData->NICRAMSegmentBase + 0x600;
   }

/* Copy Frame header to the NIC */

   MovToBus16(driverData->BusTag, NULL, dataptr,
      &tcb->TCB_MediaHeader, tcb->TCB_MediaHeaderLen / 2);
   if (tcb->TCB_MediaHeaderLen & 1)
   {
      MovToBus8 (driverData->BusTag, NULL, dataptr + tcb->TCB_MediaHeaderLen - 1,
         ((UINT8 *)&tcb->TCB_MediaHeader) + tcb->TCB_MediaHeaderLen - 1, 1);
   }
   dataptr += tcb->TCB_MediaHeaderLen;

   fragmentptr = &(tcb->TCB_FragBlockPtr->TCB_Fragment);
   for(i = tcb->TCB_FragBlockPtr->TCB_FragmentCount; i > 0; --i)
   {
      fragptr = fragmentptr->FragmentAddress;
      fragsize = fragmentptr->FragmentLength;
      MovToBus16(driverData->BusTag, NULL, dataptr,
         fragptr, fragsize / 2);
      if (fragsize & 1)
         MovToBus8 (driverData->BusTag, NULL, dataptr + fragsize - 1,
      fragptr + fragsize - 1, 1);
      ++fragmentptr;
      dataptr += fragsize;
   }

   if (!(driverData->TransmitStatusFlag & SENDINGPAGEONE))
   {
      Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage0);
      Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize1 /* & 0xFF */));
      Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize1 >> 8));

/* Send packet */
      Out8(driverData->BusTag, driverData->Command, NIC_TRANSMIT);

/* Note the time */
      driverData->TxStartTime = CMSMGetCurrentTime();
      driverData->RetryCounter = configTable->MLIDCFG_SendRetries;
      driverData->TransmitStatusFlag = SENDINGPAGEONE;

/* Give TCB back to MSM (Lying Send) */
      CEtherTSMFastSendComplete(driverData, tcb, 0);

      return;
   }
   else
   {
      driverData->TransmitStatusFlag = PAGETWOWAITING;
      CEtherTSMFastSendComplete(driverData, tcb, 0);
   }

/* Junk to keep compiler happy, optimizer should remove. */
   phystcb = phystcb;
   configTable = configTable;

}


/*======================================================================
  Procedure Name:   DriverISR

  Arguments:   driverData         -   ptr to our local data spaace.

  Returns:      void


  Abstract:   This routine handles packet reception and transmit
                     complete interrupts.

  Notes:            

========================================================================*/
void DriverISR(
            DRIVER_DATA   *driverData)
{
   CONFIG_TABLE   *configTable;
   int                     i, j, k;
   UINT32               rcvStatus, status, StartTime, curtime, elapsedtime;
   UINT8                  nicstatus, currentcommand, currentpage, newboundary;
   UINT8                  oddbyte;
   UINT16               bytecount, tempword;
   RCB                     *rcb;
   UINT32               pktsize = 0, startbyte, numbytes, fragsize;
   FRAGMENTSTRUCT   *fragmentptr;
   UINT8                  *dataptr, *fragptr, *tempptr;
   HW8390hdr            *HW_hdr;


/* 970701 PSK - Check physical board shutdown status, not logical board.
   if ((DADSP_TO_CMSMADSP(driverData)->CMSMDefaultVirtualBoard->
      MLIDCFG_SharingFlags) & MS_SHUTDOWN_BIT)
*/

/* Is the driver shutdown? */
   if ( DADSP_TO_CMSMADSP(driverData)->CMSMStatusFlags & SHUTDOWN )

/* If so, clear any interrupts that the NIC is requesting and exit. */
   {
      Out8(driverData->BusTag, driverData->InterruptStatus, In8(driverData->BusTag, driverData->InterruptStatus));

#ifdef OUT_CHAR
   NiosDebugCharOut ('x');
#endif /* OUT_CHAR */

      return;
   }
   else
   {

PollAgain:

/* Get NIC status */
      nicstatus = In8(driverData->BusTag, driverData->InterruptStatus);

/* Check for packet ready to be received. */
      if(nicstatus & NIC_PACKETREADY)
      {

         if(nicstatus & NIC_RECVERROR)

         {


/* 950228 MCD removed a "switch" stmt here and replaced it with the  */
/*    following "if" tests.  These tests MUST be done in this order; */
/*    do not change them.                                            */

/* We have Errors, Handle them. */
            if (nicstatus & NIC_OVW) /* Buffer Overflow */
            {

#ifdef OUT_CHAR
   NiosDebugCharOut ('O');
#endif /* OUT_CHAR */

               ++(driverData->PacketRxOverflowCount);
/* Save Tx active bit */
               currentcommand = In8(driverData->BusTag, driverData->Command);
/* Put NIC in STOP mode */
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE0STOP);
/* Stop the remote DMA */
               Out8(driverData->BusTag, driverData->RemoteByteCount0, 0);
               Out8(driverData->BusTag, driverData->RemoteByteCount1, 0);
/* Idle for about 2 ms to let current Tx or Rx finish */
               StartTime = CMSMGetMicroTimer();

               for (elapsedtime = 0; elapsedtime < 2000;
                  elapsedtime = ((curtime = CMSMGetMicroTimer()) - StartTime > 0)
                  ? (curtime - StartTime) : (StartTime - curtime));
/* Reset the overflow bit */
               Out8(driverData->BusTag, driverData->InterruptStatus, NIC_OVW);
/* If Tx'ing during overflow set flag so can restart Tx later */
               if ((currentcommand & NIC_TXINPROGRESS) &&
                  !(In8(driverData->BusTag, driverData->InterruptStatus) & NIC_TXCOMPLETE))
                  ++(driverData->RetryTxFlag);
/* Put NIC into Loopback mode until we empty receive buffers */
/*  Note that we are using external loopback, this fixes */
/*  overflow hangs on rev C 8390s in IPXLOAD test */
               Out8(driverData->BusTag, driverData->TransmitConfiguration, NIC_EXTLOOPBACK);
/* Re-enable card in loopback mode */
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);
               ++(driverData->OverflowRestartFlag);
/* see if more packets are waiting */
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE1);
               currentpage = In8(driverData->BusTag, driverData->InterruptStatus);
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);

               if(currentpage != (driverData->NextPage))
                  goto ReceiveNextPacket;
               goto TestForLoopback;
            }
            else if (nicstatus & NIC_RXERR) /* Receive Error */
            {

#ifdef OUT_CHAR
   NiosDebugCharOut ('o');
#endif /* OUT_CHAR */

               Out8(driverData->BusTag, driverData->InterruptStatus, NIC_RXERR);
               if (In8(driverData->BusTag, driverData->ReceiveStatus) & NIC_FIFOOVERRUNERROR)
               {
                  ++(driverData->RxFIFOOverrunErrorCount);   /* Inform diagnostics */
                  ++(driverData->PacketRxMiscErrorCount);
               }
                  driverData->RxAbortFrameAlignment += (i = In8(driverData->BusTag, driverData->TallyCounter0));
                  driverData->PacketRxMiscErrorCount += i;
                  driverData->ChecksumErrorCount += In8(driverData->BusTag, driverData->TallyCounter1);
                  driverData->RxMissedPacketCount += (i = In8(driverData->BusTag, driverData->TallyCounter2));
                  driverData->PacketRxMiscErrorCount += i;

                  goto PollAgain;

            }

            configTable = DADSP_TO_CMSMADSP(driverData)->CMSMDefaultVirtualBoard;
            DriverReset(driverData, configTable, OP_SCOPE_ADAPTER);

         }
         else   /* Receive with no error   */
         {

#ifdef OUT_CHAR
   NiosDebugCharOut ('R');
#endif /* OUT_CHAR */

/* Is there data to receive? */
/* Switch to page1 registers */

            Out8(driverData->BusTag, driverData->Command, NIC_PAGE1);
            currentpage = In8(driverData->BusTag, driverData->Current);
            Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);

            if (currentpage == driverData->NextPage)
            {
               Out8(driverData->BusTag, driverData->InterruptStatus, NIC_RX);
               ++driverData->GotNothingCount;
               goto PollAgain;
            }

ReceiveNextPacket:

/* Clear Receive status */
            Out8(driverData->BusTag, driverData->InterruptStatus, NIC_RX);

            if (driverData->NICRAMSegmentBase == 0)
/* Card is not in shared RAM mode */
            {

/****************************************************************\
*                                                                  *
* Time to read in the packet received.                           *
*                                                                  *
* Read in 4 byte buffers header, 14 byte Ethernet header and      *
* following X bytes into ReceiveHeader to properly analyse         *
* packet length and media type and do look ahead.                *
*                                                                  *
\****************************************************************/

/* Time to receive the packet. */
/* Setup the Remote Start Address of NIC */

               Out8(driverData->BusTag, driverData->RemoteStartAddress0, 00);
               Out8(driverData->BusTag, driverData->RemoteStartAddress1, (UINT8)(driverData->NextPage));
   
/* Calculate evenized (hdr size + 4 byte 8390 hdr) */
               bytecount = ((DADSP_TO_CMSMADSP(driverData)->CMSMMaxFrameHeaderSize) + 5) & ~0x01;
   
               Out8(driverData->BusTag, driverData->RemoteByteCount0, (UINT8)bytecount /* & 0xFF */);
               Out8(driverData->BusTag, driverData->RemoteByteCount1, 00);   

/* Issue the Remote Read DMA command to the NIC. */
               Out8(driverData->BusTag, driverData->Command, NIC_REMOTEDMARD);

/* Read in the frame header. */
               status = InBuff16(
                  driverData->ReceiveHeader,
                  driverData->BusTag,
                  driverData->NICData,
                  bytecount / 2);
               HW_hdr = (HW8390hdr *) driverData->ReceiveHeader;
               if(HW_hdr->RReceiveStatus & driverData->ReceiveStatusTest)
               {
/* We have a paging Error. */
                  goto PagingError;
               }
/* Number of bytes in incoming packet is the harware reported value minus   */
/* the four byte hardware header.                                                               */

               bytecount = VALUE_FROM_LOHI_UINT16(GET_UINT16(&(HW_hdr->RByteCount)));

/* If # pages > 8 the reported length is wrong (it is MOD 2048) */
/*  so let's correct it. */

               if ((i = ((int)HW_hdr->RNextBuffer - (int)driverData->NextPage)) < 0)
                  i += PSTOP - PSTART;
               if (i > 8)
                  bytecount += (--i >> 3) << 11;

               pktsize = (UINT16)bytecount - 4; /* HW hdr size */

/* Figure out new NextPage and see if we agree with the HW */
/* Round up to include the four byte CRC and the rest of the */
/*  current page.                */

               bytecount += 4 /* size of CRC */ + 0xFF;

/* High order byte of bytecount now has number of pages used, */
/*  add this to NextPage to calc new NextPage. */

               bytecount += driverData->NextPage << 8;

/* Adjust if we wrapped. */

               if((bytecount >> 8) >= PSTOP)
               {
/* 950228 MCD fixed the following calculation.  */
                  bytecount += (PSTART - PSTOP) << 8;
               }

         
               if((bytecount >> 8) != HW_hdr->RNextBuffer)
               {
/* We have a paging Error. */
                  goto PagingError;
               }

/* Update the Boundary */
               driverData->NextPage = (UINT8)(bytecount >> 8);

/* Let the upper level guys decide if (and where) we want the packet. */

               rcvStatus = (HW_hdr->RReceiveStatus >> 1) & 0x03;

               rcb = CEtherTSMGetRCB(
                  driverData,
                  (UINT8 *)(&(driverData->ReceiveHeader[RPACKET])),
                  pktsize,
                  rcvStatus,
                  &startbyte,
                  &numbytes);

               if(rcb)
               {

#ifdef OUT_CHAR
   NiosDebugCharOut ('G');
#endif /* OUT_CHAR */


/* 950317 MCD added this test for protection */

                  if (numbytes > 0)
                  {
                     startbyte += sizeof(HW8390hdr);
                     driverData->TotalBytes = numbytes;

/* The next piece is complicated.  Here is the theory.  If startbyte  */
/* and numbytes are both even we are OK.  If startbyte is even and    */
/* numbytes is odd we need to inc numbytes so we can read an even     */
/* number of bytes.  If startbyte is odd and numbytes is even we need */
/* to dec startbyte and inc numbytes by 2 to start even and read an   */
/* even number of bytes.  If both start byte and numbytes is odd we   */
/* need to dec startbyte and inc numbytes by one.                     */

                     if (startbyte & 1)
                     {
                        --startbyte;
                        driverData->SkipValue = 1;
                        ++numbytes;
                     }
                     numbytes += (numbytes & 1);

                     Out8(driverData->BusTag, driverData->RemoteStartAddress0, (UINT8)(startbyte /* 0xFF */));
                     Out8(driverData->BusTag, driverData->RemoteByteCount0, (UINT8)(numbytes /* 0xFF */));
                     Out8(driverData->BusTag, driverData->RemoteByteCount1, (UINT8)(numbytes >> 8));
                     Out8(driverData->BusTag, driverData->Command, NIC_REMOTEDMARD);

                     fragmentptr = (FRAGMENTSTRUCT *)(&(rcb->RCBFragStruct));

                     oddbyte = 0;
               
                     for(i = rcb->RCBFragCount; i > 0 && driverData->TotalBytes > 0; --i)
                     {
                        if (fragmentptr->FragmentLength == 0)
                           ++fragmentptr;
                        else
                        {
                           dataptr = fragmentptr->FragmentAddress;
                           fragsize = fragmentptr->FragmentLength - oddbyte;

                           if ((driverData->TotalBytes - (int)fragsize) <= 0)
                           {
                              fragsize = driverData->TotalBytes - oddbyte;
                           }

                           driverData->TotalBytes -= fragsize + oddbyte;

                           if( driverData->SkipValue == 1)
                           {
                              tempword = In16( driverData->BusTag, driverData->NICData);
                              HOST_TO_HILO_UINT16(&tempword);
                              tempptr = dataptr + oddbyte;
                              *tempptr = (UINT8) tempword;
                              driverData->SkipValue = 0;
                              ++dataptr;
                              --fragsize;
                           }

                           status = InBuff16(
                              dataptr + oddbyte,
                              driverData->BusTag,
                              driverData->NICData,
                              (UINT32)fragsize / 2);

                           if(fragsize & 1)
                           {
                              tempword = In16(driverData->BusTag, driverData->NICData);
                                 HOST_TO_HILO_UINT16(&tempword);
            
                              ((UINT8 *)dataptr)[fragsize + oddbyte - 1] = (UINT8)(tempword >> 8);

                              j = i;

                              while (j > 1)      /* Don't illegal access off the end of the frag list */
                              {
                                 ++fragmentptr;
                                 if (fragmentptr->FragmentLength != 0)
                                 {
                                    oddbyte = 1;
                                    dataptr = fragmentptr->FragmentAddress;
                                    dataptr[0] = (UINT8)tempword;
                                    j = 0;
                                 }
                                 else
                                 {
                                    --i;
                                    --j;
                                 }
                              }
                           }
                           else
                           {
                              oddbyte = 0;
                              ++fragmentptr;
                           }
                        }
                     }
                  }

#ifdef OUT_CHAR
   NiosDebugCharOut ('r');
#endif /* OUT_CHAR */

         
                  CEtherTSMFastRcvComplete(
                     driverData,
                     rcb);

               }

               newboundary = driverData->NextPage;
               --newboundary;
               if(newboundary < PSTART)
               {
                  newboundary = PSTOP - 1;
               }
               
               Out8(driverData->BusTag, driverData->Boundary, newboundary);
      
/* see if more packets are waiting */
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE1);
               currentpage = In8(driverData->BusTag, driverData->InterruptStatus);
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);

               if(currentpage != (driverData->NextPage))
               {
                  goto ReceiveNextPacket;
               }

            }
            else
            {
   
/* Receive a packet, shared RAM mode. */
               HW_hdr = (HW8390hdr *)(driverData->NICRAMSegmentBase + (driverData->NextPage << 8));
               dataptr = (UINT8 *)HW_hdr + sizeof(HW8390hdr);
               if (HW_hdr->RReceiveStatus & driverData->ReceiveStatusTest)
               {
/* We have a paging Error. */

                  goto PagingError;
               }
/* Number of bytes in incoming packet is the harware reported value minus   */
/* the four byte hardware header.                                                               */

               bytecount = VALUE_FROM_LOHI_UINT16(GET_UINT16(&(HW_hdr->RByteCount)));

/* If # pages > 8 the reported length is wrong (it is MOD 2048) */
/* so let's correct it. */

               if ((i = ((int)HW_hdr->RNextBuffer - (int)driverData->NextPage)) < 0)
                  i += RAMPSTOP - RAMPSTART;

               if (i > 8)
                  bytecount += (--i >> 3) << 11;

               pktsize = (UINT16)bytecount - 4; /* HW hdr size */

/* Figure out new NextPage and see if we agree with the HW */
/* Round up to include the four byte CRC and the rest of the */
/*  current page.                */

               bytecount += 4 /* size of CRC */ + 0xFF;

/* High order byte of bytecount now has number of pages used, */
/*  add this to NextPage to calc new NextPage. */

               bytecount += driverData->NextPage << 8;

/* Adjust if we wrapped. */
               if((bytecount >> 8) >= RAMPSTOP)
               {
                  bytecount += (RAMPSTART - RAMPSTOP) << 8;
               }
               if((bytecount >> 8) != HW_hdr->RNextBuffer)
               {
/* We have a paging Error. */

                  goto PagingError;
               }

/* Update the Boundary */
               driverData->NextPage = (UINT8)(bytecount >> 8);

/* Let the upper level guys decide if (and where) we want the packet. */

               rcvStatus = (HW_hdr->RReceiveStatus >> 1) & 0x03;

               rcb = CEtherTSMGetRCB(
                  driverData,
                  (UINT8 *)dataptr,
                  pktsize,
                  rcvStatus,
                  &startbyte,
                  &numbytes);

               if(rcb)
               {

/* This test is for protection */

                  if (numbytes > 0)
                  {
                     driverData->TotalBytes = numbytes;
                     dataptr += startbyte;
                     fragmentptr = (FRAGMENTSTRUCT *)(&(rcb->RCBFragStruct));
                     for(i = rcb->RCBFragCount; i > 0 && driverData->TotalBytes > 0; --i)
                     {
                        if (fragmentptr->FragmentLength == 0)
                           ++fragmentptr;
                        else
                        {
                           fragptr = fragmentptr->FragmentAddress;
                           fragsize = fragmentptr->FragmentLength;

/* Change next line from "< 0" to "<= 0"   */
                           if ((driverData->TotalBytes - (int)fragsize) <= 0)
                           {
                              fragsize = driverData->TotalBytes;
                           }
                           driverData->TotalBytes -= fragsize;
                           if(dataptr + fragsize <= driverData->NICRAMSegmentLimit)
                           {
                              MovFromBus16(fragptr, driverData->BusTag,
                                 NULL, dataptr, fragsize / 2);
                              if (fragsize & 1)
                                 MovFromBus8 (fragptr + fragsize - 1, driverData->BusTag, NULL,
                                    dataptr + fragsize - 1, 1);
                              dataptr += fragsize;
                           }
                           else
                           {
                              MovFromBus16(fragptr, driverData->BusTag, NULL, (void *) dataptr,
                                 (j = (UINT8 *)driverData->NICRAMSegmentLimit - dataptr) / 2);
                              if (j & 1)
                                 MovFromBus8 (fragptr + j - 1, driverData->BusTag, NULL,
                                    dataptr + j - 1, 1);
                              k = fragsize - j;
                              MovFromBus16(fragptr + j, driverData->BusTag, NULL,
                                 driverData->NICRAMReceiveRingStart, k / 2);
                              if (k & 1)
                                 MovFromBus8 (fragptr + fragsize - 1, driverData->BusTag, NULL,
                                    (UINT8 *)driverData->NICRAMReceiveRingStart + k - 1, 1);
                              dataptr = driverData->NICRAMReceiveRingStart + k;
                           }
                           ++fragmentptr;
                        }
                     }
                  }
                  CEtherTSMFastRcvComplete(driverData, rcb);
               }
               newboundary = driverData->NextPage;
               --newboundary;
               if(newboundary < RAMPSTART)
               {
                  newboundary = RAMPSTOP - 1;
               }
               Out8(driverData->BusTag, driverData->Boundary, newboundary);
/* see if more packets are waiting */
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE1);
               currentpage = In8(driverData->BusTag, driverData->InterruptStatus);
               Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);

               if(currentpage != (driverData->NextPage))
               {
                  goto ReceiveNextPacket;
               }
            }
         }

/* No more data in receive buffers, before we go back to PollAgain */
/*  check to see if we were cleaning out the receive buffers because */
/*  of a receive overflow. */

TestForLoopback:
         if (!driverData->OverflowRestartFlag)
            goto PollAgain;
         else
         {
/****************************************************************\
*                                                                                                *
* Now that receive buffers are empty, we can finish handling         *
* the Buffer Overflow error by placing the NIC out of the            *
* loopback mode   and sending out the current Tx buffer if it had   *
* been active at the time of overflow and got cancelled by the      *
* stop command.                                                                           *
*                                                                                                *
\****************************************************************/

#ifdef OUT_CHAR
   NiosDebugCharOut ('o');
#endif /* OUT_CHAR */


            Out8(driverData->BusTag, driverData->TransmitConfiguration, 0);
            driverData->OverflowRestartFlag = 0;
            if (!driverData->RetryTxFlag)
               goto PollAgain;
            else
            {
/****************************************************************\
*                                                                                                *
* A transmit was cancelled during overflow condition.                  *
* Re-send it.                                                                              *
*                                                                                                *
\****************************************************************/

#ifdef OUT_CHAR
   NiosDebugCharOut ('q');
#endif /* OUT_CHAR */

               driverData->RetryTxFlag = 0;
               if (driverData->TransmitStatusFlag & USEPAGEONE)
               {
                  Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage0);
                  Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize1 /* & 0xFF */));
                  Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize1 >> 8));
               }
               else
               {
                  Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage1);
                  Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize2 /* & 0xFF */));
                  Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize2 >> 8));
               }
               Out8(driverData->BusTag, driverData->Command, NIC_TRANSMIT);
      /* AYD  10-07-96 */
               driverData->TxStartTime = CMSMGetCurrentTime();
   /* TNL 7/11/95 Add next line    */
               configTable = DADSP_TO_CMSMADSP(driverData)->CMSMDefaultVirtualBoard;
               driverData->RetryCounter = configTable->MLIDCFG_SendRetries;
               goto PollAgain;
            }
         }
      }
      else

/* Check for Transmit Complete or Error */
      if(nicstatus & NIC_TXCOMPLETE)
      {

/* Reset interrupt bits */
         Out8(driverData->BusTag, driverData->InterruptStatus, NIC_TXCOMPLETE);
      
/* Check for a Transmit Error. */
         if(nicstatus & NIC_TRANSMITERROR)
         {
/* We have an Error. Handle it. */

#ifdef OUT_CHAR
   NiosDebugCharOut ('e');
#endif /* OUT_CHAR */

            if ((status = In8(driverData->BusTag, driverData->TransmitStatus)) & NIC_EXCESSCOLLISIONS)
            {
               ++(driverData->TxAbortExcessCollisions);
               ++(driverData->PacketTxMiscErrorCount);
            }
            else if (status & NIC_FIFOUNDERRUN)
            {
               ++(driverData->UnderrunErrorCount);
               ++(driverData->PacketTxMiscErrorCount);
               if (status  & NIC_COLLISIONS)
               {
                  if ((i = In8(driverData->BusTag, driverData->NumberCollisions)) > 1)
                     driverData->TxOKMultipleCollisions += i;
                  else
                     ++(driverData->TxOKSingleCollision);
               }
            }
            if (--(driverData->RetryCounter) == 0)
               goto TransmitNextPacket;
            ++(driverData->RetryTxCount);
            if (driverData->TransmitStatusFlag & USEPAGEONE)
            {
               Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage0);
               Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize1 /* & 0xFF */));
               Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize1 >> 8));
            }
            else
            {
               Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage1);
               Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize2 /* & 0xFF */));
               Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize2 >> 8));
            }
            Out8(driverData->BusTag, driverData->Command, NIC_TRANSMIT);
      /* AYD  10-07-96 */
            driverData->TxStartTime = CMSMGetCurrentTime();

            goto PollAgain;
         }
         else
         {
/* We had a Transmit complete. */


#ifdef OUT_CHAR
   NiosDebugCharOut ('T');
#endif /* OUT_CHAR */

/* Increment collision counters */
            if (i = In8(driverData->BusTag, driverData->NumberCollisions))
               if (i > 1)
                  driverData->TxOKMultipleCollisions += i;
               else
                  ++(driverData->TxOKSingleCollision);
TransmitNextPacket:
            ++(DADSP_TO_CMSMADSP(driverData)->CMSMTxFreeCount);
            driverData->TxStartTime = 0;
            if (driverData->TransmitStatusFlag & PAGETWOWAITING)

/****************************************************************\
*                                                                                                *
* We just completed a send, but there is already another               *
* packet transfered to the board. We just need to issue the         *
* send for it.                                                                              *
*                                                                                                *
\****************************************************************/
            {
               ++driverData->BackToBackSendCount;
               if (driverData->TransmitStatusFlag & USEPAGEONE)
               {
                  Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage0);
                  Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize1 /* & 0xFF */));
                  Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize1 >> 8));
               }
               else
               {
                  Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage1);
                  Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize2 /* & 0xFF */));
                  Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize2 >> 8));
               }
               Out8(driverData->BusTag, driverData->Command, NIC_TRANSMIT);
               /* AYD 10-07-96 */
               driverData->TxStartTime = CMSMGetCurrentTime();

   /* TNL 7/11/95 Add next line    */
               configTable = DADSP_TO_CMSMADSP(driverData)->CMSMDefaultVirtualBoard;
               driverData->RetryCounter = configTable->MLIDCFG_SendRetries;
               driverData->TransmitStatusFlag ^= (USEPAGEONE | PAGETWOWAITING);
            }
            else
            {
               driverData->TransmitStatusFlag = USEPAGEONE;
            }
#ifdef OUT_CHAR
   NiosDebugCharOut ('t');
#endif /* OUT_CHAR */

         }
      }
   }

   return;
PagingError:

#ifdef OUT_CHAR
   NiosDebugCharOut ('P');
#endif /* OUT_CHAR */

   ++(driverData->RxPagingErrorCount);   /* Inform diagnostics */
   ++(driverData->PacketRxMiscErrorCount);
   configTable = DADSP_TO_CMSMADSP(driverData)->CMSMDefaultVirtualBoard;
   DriverReset(driverData, configTable, OP_SCOPE_ADAPTER);

}


/*=========================================================================
  Procedure Name:   DriverReset

  Arguments:   
                     driverData      -   is a ptr to the adapter data space.
                     framedata      -   is a ptr to the frame specific data.
                     operationScope   - OP_SCOPE_ADAPTER or OP_SCOPE_LOGICAL_BOARD.

  Returns:      ODISTAT
                     SUCCESSFUL      -   The adapter was reset successfully.
                     FAIL               -   The adapter failed the reset.

  Abstract:   This routine is to initialize the adapter a leave it
                     in an operational state.

  Notes:            

==========================================================================*/
ODISTAT   DriverReset(
                     DRIVER_DATA  *driverData,
                     CONFIG_TABLE *configTable,
                     OPERATION_SCOPE operationScope)
{
   UINT8   portvalue, temp8a, temp8b;

   if (operationScope == OP_SCOPE_ADAPTER)
   {
   
   /* increment stats counter. */
      ++driverData->AdapterResetCount;
   
      if (driverData->NICRAMSegmentBase == 0)
      {
   /* Board in I/O mode, do I/O reset stuff */
   /* Do a hard reset. */
         portvalue = In8(driverData->BusTag, driverData->Reset);
         Slow();
         Out8(driverData->BusTag, driverData->Reset, portvalue);
      }
      else
      {
   /* Board in Shared Mem Mode so do Shared Mem reset stuff */
         Out8(driverData->BusTag, driverData->Control2, driverData->Control2Value);
   /* Pull on the reset signal for a while */
         Out8(driverData->BusTag, driverData->Control1, driverData->Control1Value | NIC_SMRESET);
         Slow();
         Out8(driverData->BusTag, driverData->Control1, driverData->Control1Value | !NIC_SMRESET);
      }
   
   /* Set to Page 0 registers */
      Out8(driverData->BusTag, driverData->Command, NIC_PAGE0STOP);
      Slow();
   
      if(driverData->FirstTimeInit)
      {
   /* Check if command register is alive */
         portvalue = In8(driverData->BusTag, driverData->Command);
   
         if((portvalue != 0x21) && (portvalue != 0x23))
         {
   /* port failure return fail */
            CMSMPrintString(configTable, MSG_TYPE_INIT_ERROR, CNE2000_BADBOARD_MSG, 0, 0);
            Out8(driverData->BusTag, driverData->Command, NIC_PAGE0STOP);
            return ODISTAT_FAIL;
         }
      }
   
      Out8(driverData->BusTag, driverData->DataConfiguration, NIC_NORMALDATACONFIG);
   
   /* Clear RBCR0 and RBCR1 */
      Out8(driverData->BusTag, driverData->RemoteByteCount0, 0x00);
      Out8(driverData->BusTag, driverData->RemoteByteCount1, 0x00);
   
      Out8(driverData->BusTag, driverData->ReceiveConfiguration, NIC_BROADCAST);
      driverData->RetryTxFlag = 0;
      driverData->OverflowRestartFlag = 0;
   
      CEtherTSMUpdateMulticast(driverData);
         
   /* We need to be in loopback mode to prevent getting a receive during */
   /*  the RAM tests */
   
      if (driverData->NICRAMSegmentBase == 0)
      {
         temp8a = PSTART;
         temp8b = PSTOP;
      }
      else
      {
         temp8a = RAMPSTART;
         temp8b = RAMPSTOP;
      }
   
      Out8(driverData->BusTag, driverData->TransmitConfiguration, NIC_INTLOOPBACK);
      Out8(driverData->BusTag, driverData->PageStart, temp8a);
      Out8(driverData->BusTag, driverData->Boundary, temp8a);
      Out8(driverData->BusTag, driverData->PageStop, temp8b);
   
   /* Clear interrupt bits */
      Out8(driverData->BusTag, driverData->InterruptStatus, 0xff);
      Out8(driverData->BusTag, driverData->InterruptMask, NIC_UNMASKBYTE);
   
   
      Out8(driverData->BusTag, driverData->Command, NIC_PAGE1STOP);
      Out8(driverData->BusTag, driverData->InterruptStatus, temp8a + 1);   /* Current */
   
      driverData->NextPage = temp8a + 1;
   
      Out8(driverData->BusTag, driverData->Command, NIC_PAGE0STOP);
   
      if(driverData->FirstTimeInit)
      {
         if (DriverTestHardware(driverData, configTable))
            {
            Out8(driverData->BusTag, driverData->Command, NIC_PAGE0STOP);
            return ODISTAT_FAIL;
         }
      }
   
      Out8(driverData->BusTag, driverData->TransmitPage,
         driverData->TransmitPage0);
      driverData->TransmitStatusFlag = USEPAGEONE;
      DADSP_TO_CMSMADSP(driverData)->CMSMTxFreeCount = 2;
   
      Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);
      Out8(driverData->BusTag, driverData->TransmitConfiguration, 0x00);
      driverData->OverflowRestartFlag = 0;
   
      return ODISTAT_SUCCESSFUL;
   }
   else
      return ODISTAT_SUCCESSFUL;
}   /* End DriverReset. */


/*======================================================================
  Procedure Name:   CheckForSharedRAM

  Arguments:         none

  Returns:      ODISTAT
         ODISTAT_SUCCESSFUL - Card in I/O mode or
                              card in shared mem mode and "MEM=" present.
         ODISTAT_FAIL       - Doesn't happen right now but, if we find
                              a situation we can't deal with.

  Abstract: This routine tests the card's hardware and the driver's config
               table to be sure that we have all the parameters we need
               and sets DriverSendPtr in the Driver Parameter Block to
               point to DriverSendSharedRAM.  This is necessary in and of
               itself and also is used in DriverInit to tell us which
               mode we are in.

  Notes:

========================================================================*/
ODISTAT CheckForSharedRAM(
                     CONFIG_TABLE *configTable)

{
   UINT8      oldVal, newVal, saveVal;
   void     *rsa;

/* Assume for now card is NOT shared RAM, save current value of NICCommand */
/* register   and force to page 0 */

   saveVal = In8(configTable->MLIDCFG_DBusTag, (void *)configTable->MLIDCFG_IOPort0);
   Out8(configTable->MLIDCFG_DBusTag, (void *)configTable->MLIDCFG_IOPort0, NIC_PAGE0STOP);
   Slow();

/* Read the RemoteStartAddress */

   rsa = (void *)(configTable->MLIDCFG_IOPort0 + 8);
   oldVal = In8(configTable->MLIDCFG_DBusTag, rsa);

/* Write a new value           */

   Out8(configTable->MLIDCFG_DBusTag, rsa, oldVal ^ 0x01);
   Slow();

/* Try to read it back */

   newVal = In8(configTable->MLIDCFG_DBusTag, rsa);

/* Put back the original value */

   Out8(configTable->MLIDCFG_DBusTag, rsa, oldVal);

   if (newVal == oldVal ^ 0x01)
   {

/* Card is in I/O mode */

      DriverParameters.DriverSendPtr = &DriverSend;
      return ODISTAT_SUCCESSFUL;
   }
   else
   {

/* Card is in shared memory mode, restore saved value */

      Out8(configTable->MLIDCFG_DBusTag, (void *)(configTable->MLIDCFG_IOPort0), saveVal);
      Slow();

/* Put NIC in PAGE0 mode just in case we aren't there already.         */

      saveVal = In8(configTable->MLIDCFG_DBusTag, (void *)(configTable->MLIDCFG_IOPort0 + 0x10));
      Out8(configTable->MLIDCFG_DBusTag, (void *)(configTable->MLIDCFG_IOPort0 + 0x10), NIC_PAGE0STOP);
      Slow();

/* Check to see if card is even present   */

      rsa = (void *)(configTable->MLIDCFG_IOPort0 + 0x10 + 8);
      oldVal = In8(configTable->MLIDCFG_DBusTag, rsa);

/* Write a new value           */

      Out8(configTable->MLIDCFG_DBusTag, rsa, oldVal ^ 0x01);
      Slow();

/* Try to read it back */

      newVal = In8(configTable->MLIDCFG_DBusTag, rsa);

/* Put back the original value */

      Out8(configTable->MLIDCFG_DBusTag, rsa, oldVal);

      if (newVal == oldVal ^ 0x01)
      {
/* Shared RAM card IS present   */

         DriverParameters.DriverSendPtr = &DriverSendSharedRAM;
         if (configTable->MLIDCFG_MemoryAddress0 != 0)

/* We have a memory address so we are done */

            return ODISTAT_SUCCESSFUL;
         else
         {

/* The card is in shared memory mode and the user has not supplied */
/*   a memory address so, lets ask him for one.                    */

            MemOption.Flags |= REQUIREDPARAM;
/* MPK 970219  CMSMParseDriverParameters(&DriverParameters, &MemOption); */

            /* Set up the ParseString.  Since MEM is being parsed for */
            /* with CMSMParseSingleParameter and not by */
            /* CMSMParseDriverParameters, we have to provide the ParseString. */
            MemOption.ParseString = CNE2000_MEM_PARSE_STRING_TXTMSG;
            if (CMSMParseSingleParameter(&MemOption) != ODISTAT_SUCCESSFUL)
            {
               return ODISTAT_FAIL;
            }

            /* Save the parsed MEM value in the config table. */
            configTable->MLIDCFG_MemoryAddress0 =
               (void *)MemOption.Parameter1.Max;

         }
      }
      else
      {
/* No card there, restore saved value   */

         Out8(configTable->MLIDCFG_DBusTag, (void *)(configTable->MLIDCFG_IOPort0 + 0x10), saveVal);
         Slow();
         return ODISTAT_FAIL;
      }
   }

   return ODISTAT_SUCCESSFUL;

} /* End CheckForSharedRAM */

/*======================================================================
  Procedure Name:   DoRAMTest

  Arguments:         UINT16 testPattern

  Returns:      UINT32
                     TRUE         -   The NE2000's memory passed the test.
                     FALSE         -   The NE2000's memory failed the test.

  Abstract:   This routine will test Static RAM by writing the pattern
                     provided to all areas of memory and reading them back.

  Notes:            

========================================================================*/
UINT32 DoRAMTest(
         DRIVER_DATA   *driverData,
               UINT16          testPattern)

{
   UINT32      i, j;

   if (driverData->NICRAMSegmentBase == 0)
   {
/* Set remote start address to 0x4000 */
      Out8(driverData->BusTag, driverData->RemoteStartAddress0, 0);
      Out8(driverData->BusTag, driverData->RemoteStartAddress1, 0x40);

/* Set remote byte count to 0x4000 */
      Out8(driverData->BusTag, driverData->RemoteByteCount0, 0);
      Out8(driverData->BusTag, driverData->RemoteByteCount1, 0x40);

/* Tell the NIC to start writing */
      Out8(driverData->BusTag, driverData->Command, NIC_REMOTEDMAWR);

/* And feed it our test pattern to write. */
      for (i = 0; i < 0x2000; i++)
         Out16(driverData->BusTag, driverData->NICData, testPattern);

/* Now read it back and check it. */

/* Set remote start address to 0x4000 */
      Out8(driverData->BusTag, driverData->RemoteStartAddress0, 0);
      Out8(driverData->BusTag, driverData->RemoteStartAddress1, 0x40);

/* Set remote byte count to 0x4000 */
      Out8(driverData->BusTag, driverData->RemoteByteCount0, 0);
      Out8(driverData->BusTag, driverData->RemoteByteCount1, 0x40);

/* Tell the NIC to start reading */
      Out8(driverData->BusTag, driverData->Command, NIC_REMOTEDMARD);

/* Read and compare. */
      for (i = 0; i < 0x2000; i++)
      {
         j = In16(driverData->BusTag, driverData->NICData);
         if (j != testPattern)
            return FALSE;
      }
      return ODISTAT_SUCCESSFUL;
   }
   else
   {
/* First write the test pattern to the shared memory buffer. */
      Set16(driverData->BusTag, NULL, driverData->NICRAMSegmentBase, testPattern, 0x2000);

/* Then read it back and compare. */
      for (i = 0; i < 0x2000; i++)
      {
         j = Rd16(driverData->BusTag, NULL, driverData->NICRAMSegmentBase + (i * 2));
         if (j != testPattern)
            return FALSE;
      }
      return ODISTAT_SUCCESSFUL;
   }
}

/*======================================================================
  Procedure Name:   DriverTestHardware

  Arguments:   framedata   - Pointer to the Frame data space.
              *driverData - Pointer to the Drivers data space.

  Returns:      ODISTAT
                     ODISTAT_SUCCESSFUL - The Hardware is OK.
                     ODISTAT_FAIL       - The Hardware is not OK.

  Abstract:         This routine will set the NIC's node address, the NIC's
                     physical registers, and test the NIC's static RAM.

  Notes:            

=======================================================================*/
ODISTAT DriverTestHardware(
           DRIVER_DATA  *driverData,
           CONFIG_TABLE *configTable)
{
   UINT32  i;
   UINT8   *memptr;
   UINT8   buffer[20];
   
   
   if (driverData->NICRAMSegmentBase == 0)
   {
      Out8(driverData->BusTag, driverData->RemoteStartAddress0, 0);
      Out8(driverData->BusTag, driverData->RemoteStartAddress1, 0);

/* Read 16 bytes (I don't understand this `16 * 2' but, it is that */
/*  way in the ASM code.) */
      Out8(driverData->BusTag, driverData->RemoteByteCount0, 16 * 2);
      Out8(driverData->BusTag, driverData->RemoteByteCount1, 0);

      Out8(driverData->BusTag, driverData->Command, NIC_REMOTEDMARD);

/* Get the node address.  Place it in the config table unless the user has */
/*  supplied a node address override. */
      if( configTable->MLIDCFG_NodeAddress.nodeAddress[0] == 0xff)
         memptr = (UINT8 *)&(configTable->MLIDCFG_NodeAddress);
      else
         memptr = (UINT8 *)&(driverData->ReceiveHeader);

      for( i = 0 ; i < 6; ++i)
         memptr[i] = In8(driverData->BusTag, driverData->NICData);

/* Check that this is an NE2000 in a 16 bit slot by looking for the 'WW'  */
/*  signature in the next 10 bytes of the PROM. */

      if ( driverData->PCMCIAFlag == 0)
      {

         for( i = 0; i < 10; ++i)
         {
            buffer[i] = In8(driverData->BusTag, driverData->NICData);
         }
         if (buffer[8] != 'W' || buffer[9] != 'W')
         {
            if (buffer[8] == 'B' || buffer[9] == 'B')
            {
               CMSMPrintString(configTable, MSG_TYPE_INIT_ERROR, CNE2000_8BITSLOT_MSG, 0, 0);
            }
            else
            {
               CMSMPrintString(configTable, MSG_TYPE_INIT_ERROR, CNE2000_NOBOARD_MSG, 0, 0);
            }
            return ODISTAT_FAIL;
         }
      }   /* End of if PCCard = 0 ? */
   }
   else
   {
/* Board in shared memory mode */
      if( configTable->MLIDCFG_NodeAddress.nodeAddress[0] == 0xff)
      for( i = 0, memptr = driverData->Prom; i < 6; ++i, ++memptr)
         configTable->MLIDCFG_NodeAddress.nodeAddress[i] = In8(driverData->BusTag, (void *)memptr);
   }

/* Set to page 1 registers */
   Out8(driverData->BusTag, driverData->Command, NIC_PAGE1STOP);


/* Write address to Register */
   Out8(driverData->BusTag, driverData->PageStart, configTable->MLIDCFG_NodeAddress.nodeAddress[0]);
   Out8(driverData->BusTag, driverData->PageStop, configTable->MLIDCFG_NodeAddress.nodeAddress[1]);
   Out8(driverData->BusTag, driverData->Boundary, configTable->MLIDCFG_NodeAddress.nodeAddress[2]);
   Out8(driverData->BusTag, driverData->TransmitStatus, configTable->MLIDCFG_NodeAddress.nodeAddress[3]);
   Out8(driverData->BusTag, driverData->TransmitByteCount0, configTable->MLIDCFG_NodeAddress.nodeAddress[4]);
   Out8(driverData->BusTag, driverData->TransmitByteCount1, configTable->MLIDCFG_NodeAddress.nodeAddress[5]);

/* Set to page 0 Registers */
   Out8(driverData->BusTag, driverData->Command, NIC_PAGE0STOP);

/****************************************************************\
*                                                                *
* Now that we know we are really dealing with an NE2000 in the   *
* right   slot, we can safely test memory.                        *
* NE2000 contain Static RAM. Running a checkerboard test will    *
* catch retention, open or shorted faults common to S-RAM.       *
*                                                                *
\****************************************************************/

   if (DoRAMTest(driverData, 0xa5a5) || DoRAMTest(driverData, 0x5a5a))
   {
      CMSMPrintString(configTable, MSG_TYPE_INIT_ERROR, CNE2000_MEMERR_MSG, 0, 0);
      return ODISTAT_FAIL;
   }

/* Verify that the HSM's INT matches what the board is configured for     */

   if (VerifyIRQ( driverData, configTable))
   {
      CMSMPrintString(configTable, MSG_TYPE_INIT_ERROR, CNE2000_IRQERR_MSG, 0, 0);
      return ODISTAT_FAIL;
   }

   return ODISTAT_SUCCESSFUL;
}


/*=========================================================================
  Procedure Name:   VerifyIRQ

  Arguments:   
             driverData  - is a ptr to the adapter data space.
             configTable - is a ptr to the config table.

  Returns:      ODISTAT
                     SUCCESSFUL - The IRQ was verified successfully.
                     FAIL       - No IRQ was received from the adapter.

  Abstract:   This routine will verify that the IRQ selected by the user
              matches the IRQ configured on the adapter.  This is done by
              configuring the card for internal lookback, performing a
              (garbage) transmit to force an interrupt, and seeing if the
              appropriate interrupt is generated.

  Notes:            

==========================================================================*/
ODISTAT   VerifyIRQ(
                     DRIVER_DATA  *driverData,
                     CONFIG_TABLE *configTable)
{
   UINT8  intIndex;

   if (driverData->NICRAMSegmentBase != 0)
/* Card is an NE2000+ (AT/LANTIC chip) */
   {
   /* Read mode config reg A, mask off and shift INT bits. */
      intIndex = In8(driverData->BusTag, driverData->RemoteByteCount0);
      intIndex = (intIndex & 0x38) >> 3;
      if (configTable->MLIDCFG_Interrupt0 == IntTable[intIndex])
         return ODISTAT_SUCCESSFUL;
      else
         return ODISTAT_FAIL;
    }

/* If card is an NE2000 (8390 chip) we can not verify the IRQ.             */
   return ODISTAT_SUCCESSFUL;
}

/*======================================================================
  Procedure Name:   DriverInit

  Arguments:         None.

  Returns:      
                     SUCCESSFUL      -   The Hardware has been initilized.
                     FAIL               -   The Hardware failed to initilize.

  Abstract:      This routine is called by the MSM at load time.  It will
                  call EtherTSMRegisterHSM, MSMSetHardwareInterrupt,
                  MSMRegisterMLID.  It will also initialize variables in the
                  Adapter Data Space and initialize the card.

  Notes:            

========================================================================*/
ODISTAT DriverInit(
   struct _MODULE_HANDLE_ *ModuleHandle,
   SCREEN_HANDLE            *ScreenHandle,
   MEON                   *CommandLine,
   MEON                   *ModuleLoadPath,
   UINT32                 UnitializedDataLength,
   void                   *CustomDataFileHandle,
   UINT32                 (* FileRead)(
                              void      *FileHandle,
                              UINT32   FileOffset,
                              void      *FileBuffer,
                              UINT32   FileSize),
   UINT32                 CustomDataOffset,
   UINT32                 CustomDataSize,
   UINT32                 NumMsgs,
   MEON                   **Msgs)

{
   UINT32                 iooffset;
   CONFIG_TABLE           *configTable;
   DRIVER_DATA            *driverData;
   UINT32                 error;
   REG_TYPE               retValue;
   UINT8                  k;

   UINT32                    slotsWithMyBoardCount;
   UINT32                    magicNumber, uniqueID;
   UINT8                     *configInfo = 0;
   UINT8                     pcCard = 0;
   UINT8                     numOfProductID = 0;
   GetConfigInfo            *gConfInfo;

   CHSM_STACK                chsmStack;
   void         *temp_DBusTag;

/* Setup a Stack */

   chsmStack.ModuleHandle          = ModuleHandle;
   chsmStack.ScreenHandle          = ScreenHandle;
   chsmStack.CommandLine           = CommandLine;
   chsmStack.ModuleLoadPath        = ModuleLoadPath;
   chsmStack.UnitializedDataLength = UnitializedDataLength;
   chsmStack.CustomDataFileHandle  = CustomDataFileHandle;
   chsmStack.FileRead              = FileRead;
   chsmStack.CustomDataOffset      = CustomDataOffset;
   chsmStack.CustomDataSize        = CustomDataSize;
   chsmStack.NumMsgs               = NumMsgs;
   chsmStack.Msgs                  = Msgs;

   DriverParameters.DriverInitParmPointer = &chsmStack;

/* MPK 970219 - Must initialize the parser before we can call it */
   CMSMInitParser(&DriverParameters);


   if (CEtherTSMRegisterHSM(&DriverParameters, &configTable) != ODISTAT_SUCCESSFUL)
   {
      CMSMReturnDriverResources(configTable);
      return ODISTAT_FAIL;
   }

/***********************************************************************\
 **    scan all socket for our card
\***********************************************************************/

   slotsWithMyBoardCount = 0;

   for (k = 0, numOfProductID = 0; 
        numOfProductID < NUM_OF_PROD_ID; 
        ++numOfProductID, k += PROD_ID_LEN)
   {
      magicNumber = -1;

      while    (   CMSMSearchAdapter(&magicNumber, ODI_BUSTYPE_PCMCIA,
                     PROD_ID_LEN, (MEON *)&NE2000ProdID[k],
                     &temp_DBusTag,
                     &uniqueID) == ODI_NBI_SUCCESSFUL)
      {
         configTable->MLIDCFG_DBusTag = temp_DBusTag;
         if ( CMSMGetInstanceNumber(configTable->MLIDCFG_DBusTag,
                  uniqueID,
                  (UINT16 *)&SlotsWithMyBoard.UNumOptVal[slotsWithMyBoardCount])
                  == ODI_NBI_SUCCESSFUL)
         {
            ++slotsWithMyBoardCount;
         }
      }
   }

   if (slotsWithMyBoardCount)
     {
       SlotsWithMyBoard.OptionCount = slotsWithMyBoardCount;
       pcCard = 1;

       if (slotsWithMyBoardCount == 1)
         {
      configTable->MLIDCFG_Slot = SlotsWithMyBoard.UNumOptVal[0];
      if (CMSMParseDriverParameters(&DriverParameters, NULL) == ODISTAT_FAIL)
           {
                CMSMReturnDriverResources(configTable);
                return ODISTAT_FAIL;
           }
         }
       else if (CMSMParseDriverParameters(&DriverParameters, &SlotOption) == ODISTAT_FAIL)
         {
      CMSMReturnDriverResources(configTable);
            return ODISTAT_FAIL;
         }

       if ( CMSMGetInstanceNumberMapping( 
            configTable->MLIDCFG_Slot,
            &configTable->MLIDCFG_DBusTag,
            &uniqueID)
            != ODI_NBI_SUCCESSFUL)
         {
      CMSMReturnDriverResources(configTable);
       return ODISTAT_FAIL;
         }
            
       configInfo = CMSMInitAlloc(37 + 4096);

       if (CMSMGetCardConfigInfo(
            configTable->MLIDCFG_DBusTag,
            uniqueID, (37 + 4096), 37, 0, configInfo) == ODI_NBI_SUCCESSFUL)
         {
      gConfInfo = ( GetConfigInfo *)configInfo;
      configTable->MLIDCFG_Interrupt0 = gConfInfo->AssignedIRQ;
      configTable->MLIDCFG_IOPort0 = gConfInfo->BasePort1;
      configTable->MLIDCFG_NodeAddress.nodeAddress[0] = configInfo[0xFF0 + 37];
      configTable->MLIDCFG_NodeAddress.nodeAddress[1] = configInfo[0xFF2 + 37];
      configTable->MLIDCFG_NodeAddress.nodeAddress[2] = configInfo[0xFF4 + 37];
      configTable->MLIDCFG_NodeAddress.nodeAddress[3] = configInfo[0xFF6 + 37];
      configTable->MLIDCFG_NodeAddress.nodeAddress[4] = configInfo[0xFF8 + 37];
      configTable->MLIDCFG_NodeAddress.nodeAddress[5] = configInfo[0xFFA + 37];
      CMSMFree(NULL, configInfo);
         }
       else
         {
      CMSMFree(NULL, configInfo);
            CMSMReturnDriverResources(configTable);
      return ODISTAT_FAIL;
         }
     }
   else      /* Legacy ISA NE2000 card   */
     {
       if (CMSMParseDriverParameters(&DriverParameters, &IntOption) != ODISTAT_SUCCESSFUL)
            {
      CMSMReturnDriverResources(configTable);
            return ODISTAT_FAIL;
         }
       /* Set Bus Tag to zero assume that ISA is default bus */
       configTable->MLIDCFG_DBusTag = 0;
     }


   if (CheckForSharedRAM(configTable) != ODISTAT_SUCCESSFUL)
   {
      CMSMPrintString(configTable, MSG_TYPE_INIT_ERROR, CNE2000_NOBOARD_MSG, 0, 0);
      CMSMReturnDriverResources(configTable);
      return ODISTAT_FAIL;
   }

/*   Restore Io/MemOption Parameter1 field since parser blows it away   */
   MemOption.Parameter1.Range = IoOption.Parameter1.Range = 0;

   if (DriverParameters.DriverSendPtr != &DriverSend)
/* Card is in Shared RAM mode so, lets set the shared memory length */
   {
      configTable->MLIDCFG_MemorySize0 = 0x400;
   }

/* Register the Hardware Options */
   retValue = CMSMRegisterHardwareOptions(
                                          configTable,
                                          &driverData);

   if (retValue == REG_TYPE_NEW_ADAPTER)
   {

/* This is a new adpater */

      CFixUpStatStrings(driverData);      /* Initialize statistics strings */

/* Get the BusTag */

      driverData->BusTag = configTable->MLIDCFG_DBusTag;

/* Set up the I/O address table. */

      iooffset = 0;

      if (DriverParameters.DriverSendPtr != &DriverSend)
/* Card is in Shared RAM mode */
      {
         driverData->Control1Value = (((int)configTable->MLIDCFG_MemoryAddress0 >> 13) & 0x3F )| 0x40;
         driverData->Control2Value = ((int)configTable->MLIDCFG_MemoryAddress0 >> 19) | 0xC0;
         driverData->NICRAMSegmentBase = configTable->MLIDCFG_LinearMemory0;

         driverData->NICRAMReceiveRingStart = (UINT8 *)configTable->MLIDCFG_LinearMemory0 + (RAMPSTART << 8);
         driverData->NICRAMSegmentLimit = driverData->NICRAMReceiveRingStart + ((RAMPSTOP - RAMPSTART) << 8);

         driverData->Control1 = (void *)(configTable->MLIDCFG_IOPort0 + 0x00);
         driverData->Control2 = (void *)(configTable->MLIDCFG_IOPort0 + 0x05);
         driverData->Prom = (void *)(configTable->MLIDCFG_IOPort0 + 0x08);
         driverData->TransmitPage0 = 0x00;
         driverData->TransmitPage1 = 0x06;
         iooffset = 0x10;
      }


/* Setup the rest of the I/O addresses from Base IO and iooffset. */

      driverData->Command =               (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x00);
      driverData->PageStart =             (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x01);
      driverData->PageStop =              (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x02);
      driverData->Boundary =              (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x03);
      driverData->TransmitStatus =        (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x04);
      driverData->TransmitByteCount0 =    (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x05);
      driverData->TransmitByteCount1 =    (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x06);
      driverData->InterruptStatus =       (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x07);
      driverData->RemoteStartAddress0 =   (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x08);
      driverData->RemoteStartAddress1 =   (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x09);
      driverData->RemoteByteCount0 =      (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x0a);
      driverData->RemoteByteCount1 =      (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x0b);
      driverData->ReceiveConfiguration =  (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x0c);
      driverData->TransmitConfiguration = (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x0d);
      driverData->DataConfiguration =     (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x0e);
      driverData->InterruptMask =         (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x0f);
      driverData->NICData =               (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x10);
      driverData->Reset =                 (void *)(configTable->MLIDCFG_IOPort0 + iooffset + 0x1f);


/* Setup the TxFreeCount */
      DADSP_TO_CMSMADSP(driverData)->CMSMTxFreeCount = 2;

      driverData->PCMCIAFlag = pcCard;
      error = DriverReset(driverData, configTable, OP_SCOPE_ADAPTER);

      if (error)
      {
         CMSMReturnDriverResources(configTable);
         return ODISTAT_FAIL;
      }

      driverData->FirstTimeInit = 0;
      --driverData->AdapterResetCount;

      if (CMSMRegisterMLID(driverData, configTable) != ODISTAT_SUCCESSFUL)
      {
         CMSMReturnDriverResources(configTable);
         return ODISTAT_FAIL;
      }
      else
        {
        /* Connect the Hardware Interrupt */
    error = CMSMSetHardwareInterrupt(
       driverData,
       configTable);

          if (error)
        {
              CMSMReturnDriverResources(configTable);
              return ODISTAT_FAIL;
            }

          driverData->mlidAESECB.DriverAES = &DriverCallback;
          if (CMSMScheduleAES(driverData, &(driverData->mlidAESECB)))
            {
              CMSMPrintString(configTable, MSG_TYPE_INIT_ERROR, CNE2000_AESERR_MSG, 0, 0);
         CMSMReturnDriverResources(configTable);
           return ODISTAT_FAIL;
            }

/***********************************************************************\
 ** TNL 12/05/95 Register with NESL as producer of Service Resume event.
\***********************************************************************/

         if (!NESLRegisterDone)
         {
            if ((NESLServiceResumeNECBPtr = (
                 NESL_ECB *)CMSMInitAlloc(sizeof(NESL_ECB))) == NULL)
            {
               CMSMReturnDriverResources(configTable);
               return ODISTAT_FAIL;
            }

            NESLServiceResumeNECBPtr->NecbVersion = NESL_VERSION2;
            NESLServiceResumeNECBPtr->NecbEventName = NESL_Service_Resume;
            NESLServiceResumeNECBPtr->NecbRefData = NESL_NOT_UNIQUE_PRODUCER |
               NESL_BROADCAST_EVENT | NESL_SORT_CONSUMER_BOTTOM_UP; 
            NESLServiceResumeNECBPtr->NecbOwner = ModuleHandle;
            NESLServiceResumeNECBPtr->NecbContext = NULL;

            if (CMSMNESLRegisterProducer(NESLServiceResumeNECBPtr) != NESL_OK)
            {
               CMSMReturnDriverResources(configTable);
               return ODISTAT_FAIL;
            }

            if ((NESL_EPBPtr = (EPB *)CMSMInitAlloc(sizeof(EPB))) == NULL)
            {
               CMSMReturnDriverResources(configTable);
               return ODISTAT_FAIL;
            }
                  
            NESL_EPBPtr->EPBMajorVersion = EPBMajVer;
            NESL_EPBPtr->EPBMinorVersion = EPBMinVer;
            NESLRegisterDone = TRUE;
         }

         /* Set up to produce NESL MLID Card Insertion Complete event */

         NESL_EPBPtr->EPBEventName  = NESL_Service_Resume;
         NESL_EPBPtr->EPBEventType  = NESL_MLID_Card_Insertion_Complete;
         NESL_EPBPtr->EPBModuleName   = NICShortName;
         NESL_EPBPtr->EPBDataPtr0   = configTable;
         NESL_EPBPtr->EPBDataPtr1   = NULL;
         NESL_EPBPtr->EPBEventScope = EPB_SPECIFIC_EVENT;
         NESL_EPBPtr->EPBReserved   = 0;

         /* Generate NESL MLID Card Insertion Complete Event */
         CMSMNESLProduceEvent(NESLServiceResumeNECBPtr,
                                  NULL,
                                  NESL_EPBPtr);

         return ODISTAT_SUCCESSFUL;
      }

   }
   else if (retValue == REG_TYPE_NEW_FRAME)
   {

/* This is a new frame type for an existing board */
/* Re-Enable the card - CheckForSharedRAM left the card disabled. */
/* Set up to produce NESL MLID Card Insertion Complete event */

      error = DriverReset(driverData, configTable, OP_SCOPE_ADAPTER);

      if (error)
      {
         CMSMReturnDriverResources(configTable);
         return ODISTAT_FAIL;
      }

      --driverData->AdapterResetCount;

      NESL_EPBPtr->EPBDataPtr0   = configTable;

      /* Generate NESL MLID Card Insertion Complete Event */
      CMSMNESLProduceEvent(NESLServiceResumeNECBPtr,
                               NULL,
                               NESL_EPBPtr);

      return ODISTAT_SUCCESSFUL;
   }
   else
   {
      CMSMReturnDriverResources(configTable);
      return ODISTAT_FAIL;
   }
}


/***********************************************************************\
*                                                                       *
*
*   Name:
*      void   CFixUpStatStrings(
*                        DRIVER_DATA         *driverData)
*
*   Description:
*
*      This function initializes the statistic table entry strings to
*      point to the language enabled message strings.
*
*   Parameters in:
*
*      driverData -      Pointer to HSM's Adapter Data Space.
*
*   Values returned:
*   
*                                                                       *
************************************************************************/

void CFixUpStatStrings(DRIVER_DATA *driverData)

{
   driverData->UnderrunErrorTable.StatString=(MEON_STRING *)CNE2000_UNDRRUN_STR;
   driverData->TransmitTimeoutTable.StatString=(MEON_STRING *)CNE2000_TXTIMEOUT_STR;
   driverData->RxPagingErrorTable.StatString=(MEON_STRING *)CNE2000_RXPAGERR_STR;
   driverData->RxFIFOOverrunErrorTable.StatString=(MEON_STRING *)CNE2000_RXOVRRUN_STR;
   driverData->RxMissedPacketTable.StatString=(MEON_STRING *)CNE2000_MISSDPKT_STR;
   driverData->GotNothingTable.StatString=(MEON_STRING *)CNE2000_GOTNOTHING_STR;
   driverData->UnsupportedFrameTable.StatString=(MEON_STRING *)CNE2000_UNSUPFRAME_STR;
   driverData->UnsupportedMulticastTable.StatString=(MEON_STRING *)CNE2000_UNSUPMULTI_STR;
   driverData->BackToBackSendTable.StatString=(MEON_STRING *)CNE2000_BTOBSEND_STR;
   driverData->EnqueueSendTable.StatString=(MEON_STRING *)CNE2000_QDSEND_STR;

}   /* End CFixUpStatStrings */


/*======================================================================
  Procedure Name:   DriverRemove

  Arguments:   none

  Returns:      void

  Abstract:   This routine is called to do any necessary clean up
                     and shutdown and then call MSMDriver remove.  It
                     prepares the driver to be removed.
                     

  Notes:            

========================================================================*/

void DriverRemove()
{

/* Clean up all NESL related stuff   */

   CMSMNESLDeRegisterProducer(NESLServiceResumeNECBPtr);
   CMSMFree(NULL,NESLServiceResumeNECBPtr);
   CMSMFree(NULL,NESL_EPBPtr);

   CMSMDriverRemove(DriverParameters.DriverModuleHandle);
   return;
}


/*======================================================================
  Procedure Name:   DriverMulticastChange

  Arguments:   configTable       - Ptr to Our config Table.
             driverData        - Ptr to Our Data Space
             mcTable                  -   Ptr to the multicast table (mostly
                                                      for use in ethernet)
                     numEntries            -   The number of valid entries in the
                                                      multicast table.
                     funAddrBits            - Thirty-two word with bit set for each
                                                      active functional address (for Token
                                                      Ring and FDDI)

  Returns:      void

  Abstract:
                  This routine will modify the NIC's multicast registers to
                  enable it to receive the multicast addresses listed in
                  the multicast table. Each entry in the multicast table is as
                  follows:

                  bytes 0-5 = Multicast Address.
                  bytes 6-7 = Entry used(Non zero if used).

                     

  Notes:            

=========================================================================*/

ODISTAT   DriverMulticastChange(
               DRIVER_DATA         *driverData,
                        CONFIG_TABLE          *configTable,
                        GROUP_ADDR_LIST_NODE   *mcTable,
                        UINT32               numEntries,
                        UINT32               funAddrBits)
{
   UINT32   i, bitindex;

   Out8(driverData->BusTag, driverData->Command, NIC_PAGE1);
   for ( i = 0; i < 8; i++)
      Out8(driverData->BusTag, ((UINT8 *)(driverData->MulticastAddrReg)) + i, 0);
   Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);
   for ( i = 0; i < numEntries; i++)
   {
      bitindex = CalculateHash(mcTable + i);
      ModifyNICHashTableBit(driverData, bitindex);
   }
   Out8(driverData->BusTag, driverData->ReceiveConfiguration, NIC_MULTICAST | NIC_BROADCAST);

/* Junk to keep compiler happy, optimizer should remove. */

   configTable = configTable;
   funAddrBits = funAddrBits;

   return ODISTAT_SUCCESSFUL;
}



/*======================================================================
  Procedure Name:   CalculateHash

  Arguments:      This routine will take the 6-byte multicast address
      passed to it and calculate a CRC as the 8390 would. It
      will return the upper 6-bits of the CRC.

  Returns:      UINT32 Index to the bit to be set in the 8390's
      multicast hash table.

  Abstract:   
                     

  Notes:            

========================================================================*/

UINT32 CalculateHash(GROUP_ADDR_LIST_NODE   *multiAddress)
{
   UINT32 crc, index, j, carry;
   UINT8  temp[6];

#define POLYNOMIAL 0x04C11DB6

   COPY_ADDR(temp, multiAddress->GRP_ADDR.nodeAddress);
   crc = 0xFFFFFFFF;
   for (index = 0; index < 6; ++index)
   {
      for (j = 0; j < 8; ++j)
      {
         carry = ( (crc & 0x80000000) ? 1 : 0) ^ (temp[index] & 01);
         crc <<= 1;
         temp[index] >>= 1;
         if(carry)
            crc = ((crc ^ POLYNOMIAL) | carry);
      }
   }
   crc >>= 26;
   return (crc);
}



/*======================================================================
  Procedure Name:   ModifyNICHashTableBit

  Arguments:   UINT32 bitIndex

  Returns:      void

  Abstract:   Thus routine will set a bit in the 8390 multicast
                     hash table.
                     

  Notes:            

========================================================================*/

void ModifyNICHashTableBit(
         DRIVER_DATA   *driverData,
         UINT32 bitIndex)
{
   UINT8 temp;
   UINT32 tmpIndex;

   tmpIndex = bitIndex >> 3;
   Out8(driverData->BusTag, driverData->Command, NIC_PAGE1);
   temp = In8 (driverData->BusTag, (void *)((UINT8 *)driverData->MulticastAddrReg + tmpIndex));
   Out8(driverData->BusTag, (void *)((UINT8 *)driverData->MulticastAddrReg + tmpIndex),
      temp | (0x01 << ((tmpIndex << 3) ^ bitIndex)));
   Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);
}


/*======================================================================
  Procedure Name:   DriverPromiscuousChange

  Arguments:   configTable       - Ptr to Our config Table.
             driverData        - Ptr to Our Data Space
                     changeTo               - 0 disable promiscous mode

                                          - PROM_MODE_RMC enable remote
                                            multicast frames only

                                           - OTHER enable full promiscous mode
  Returns:      void

  Abstract:   
                     

  Notes:            

========================================================================*/

ODISTAT   DriverPromiscuousChange(
               DRIVER_DATA      *driverData,
               CONFIG_TABLE   *configTable,
               UINT32             changeTo)

{
   UINT32   i;
   UINT8      temp;


   if (changeTo == PROM_MODE_RMC)
   {
/* Enable remote multicast   */
      driverData->ReceiveStatusTest = 0x4e;
      Out8(driverData->BusTag, driverData->ReceiveConfiguration,
      NIC_BROADCAST | NIC_MULTICAST);
      temp = 0xff;
   }
   else if (changeTo)
   {
/* Enable promiscous mode */
      driverData->ReceiveStatusTest = 0x40;
      Out8(driverData->BusTag, driverData->ReceiveConfiguration,
      NIC_SAVEERRORS | NIC_SAVERUNTS | NIC_BROADCAST | NIC_MULTICAST | NIC_PROMISCUOUS);
      temp = 0xff;
   }
   else
   {
/* Disable promiscous mode */
      driverData->ReceiveStatusTest = 0x4e;
      Out8(driverData->BusTag, driverData->ReceiveConfiguration,
      NIC_BROADCAST | NIC_MULTICAST);
      temp = 0x00;
   }
   Out8(driverData->BusTag, driverData->Command, NIC_PAGE1);
   for ( i = 0; i < 8; i++)
      Out8(driverData->BusTag, ((UINT8 *)(driverData->MulticastAddrReg)) + i, temp);
   Out8(driverData->BusTag, driverData->Command, NIC_PAGE0);

/* Junk to keep compiler happy, optimizer should remove. */

   configTable = configTable;

   return ODISTAT_SUCCESSFUL;
}


/*======================================================================
  Procedure Name:   DriverCallback

  Arguments:   
             driverData        - Ptr to Our Data Space.
             configTable       - Ptr to Our config Table.

  Returns:      void

  Abstract:   This routine will be executed once every second. It will
      detect if the hardware does not complete a transmission. If this
      happens the hardware will be reset, the transmission
      of that packet will be aborted and the next packet in the
      queue will be sent if there is one.

                     

  Notes:            

========================================================================*/

void DriverCallback(
                     DRIVER_DATA      *driverData,
                     CONFIG_TABLE   *configTable)
{
   UINT32   i;

#ifdef OUT_CHAR
   NiosDebugCharOut ('C');
#endif /* OUT_CHAR */


/* If no Tx active or Tx not yet active for 2 sec then exit */
      /* AYD  10-07-96*/
      /* CMSMGetMicroTimer() - driverData->TxStartTime < 2000000) */
   if (!driverData->TxStartTime |
      CMSMGetCurrentTime() - driverData->TxStartTime <= 36)
   {

#ifdef OUT_CHAR
   NiosDebugCharOut ('c');
#endif /* OUT_CHAR */

      return;
   }
/* Increment approp stats counters */
   if ((i = In8(driverData->BusTag, driverData->NumberCollisions)) > 1)
      driverData->TxOKMultipleCollisions += i;
   else
   ++(driverData->TxOKSingleCollision);
   if (In8(driverData->BusTag, driverData->Command) & NIC_TXINPROGRESS)
   {
      CMSMPrintString(
                     configTable,
                     MSG_TYPE_RUNTIME_WARNING,
                     CNE2000_TXTIMEOUT_MSG,
                     0, 0);
   }
   DriverReset(driverData, configTable, OP_SCOPE_ADAPTER);
   ++(driverData->TransmitTimeoutCount);
   ++(driverData->PacketTxMiscErrorCount);
   driverData->TxStartTime = 0;
   Out8(driverData->BusTag, driverData->InterruptStatus, 0x0A);      /* Reset all transmit bits */

/* Another transmit waiting? */
   if (driverData->TransmitStatusFlag & PAGETWOWAITING)

/****************************************************************\
*                                                                                                *
* We just aborted a send, but there is already another                  *
* packet transfered to the board. We just need to issue the         *
* send for it.                                                                              *
*                                                                                                *
\****************************************************************/
   {
      ++driverData->BackToBackSendCount;
      if (driverData->TransmitStatusFlag & USEPAGEONE)
      {
         Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage0);
         Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize1 /* & 0xFF */));
         Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize1 >> 8));
      }
      else
      {
         Out8(driverData->BusTag, driverData->TransmitPage, driverData->TransmitPage1);
         Out8(driverData->BusTag, driverData->TransmitByteCount0, (UINT8)(driverData->TransmitSize2 /* & 0xFF */));
         Out8(driverData->BusTag, driverData->TransmitByteCount1, (UINT8)(driverData->TransmitSize2 >> 8));
      }
      Out8(driverData->BusTag, driverData->Command, NIC_TRANSMIT);
      /* AYD  10-07-96 */
      driverData->TxStartTime = CMSMGetCurrentTime();
      driverData->RetryCounter = configTable->MLIDCFG_SendRetries;
      driverData->TransmitStatusFlag ^= (USEPAGEONE | PAGETWOWAITING);
   }
   else
   {
      driverData->TransmitStatusFlag = USEPAGEONE;
   }

#ifdef OUT_CHAR
   NiosDebugCharOut ('d');
#endif /* OUT_CHAR */


   return;
}



/*======================================================================
  Procedure Name:   DriverDisableInterrupt

  Arguments:   
             driverData        - Ptr to Our Data Space.

  Returns:      0(false) if the driver was requesting an interrupt
                    1(true) if the driver was  not requesting an interrupt

  Abstract:   This routine will disable the adapters ability to
                     interrupt the host.
                     

  Notes:            

========================================================================*/

BOOLEAN   DriverDisableInterrupt(
               DRIVER_DATA   *driverData,
               BOOLEAN     flag)
{
UINT8                        nicstatus;

#ifdef OUT_CHAR
   NiosDebugCharOut ('{');
#endif /* OUT_CHAR */

   flag = flag;
   nicstatus = In8(driverData->BusTag, driverData->InterruptStatus);
   Out8(driverData->BusTag, driverData->InterruptMask, NIC_MASKBYTE);
   if (nicstatus & NIC_REQINT)
   {
      return TRUE;
   }
   else
   {
      return FALSE;
   }
}



/*======================================================================
  Procedure Name:   DriverEnableInterrupt

  Arguments:   
             driverData        - Ptr to Our Data Space.

  Returns:      void


  Abstract:   This routine will enable the adapters ability to
                     interrupt the host.
                     

  Notes:            

========================================================================*/

void   DriverEnableInterrupt(
            DRIVER_DATA   *driverData)
{
#ifdef OUT_CHAR
   NiosDebugCharOut ('}');
#endif /* OUT_CHAR */

   Out8(driverData->BusTag, driverData->InterruptMask, NIC_UNMASKBYTE);
   return;
}


/*======================================================================
  Procedure Name:   DriverShutdown

  Arguments:
            driverData        - Ptr to Our Data Space.
            configTable       - Ptr to Our config Table.
            shutdownType       - 0 if permanent shutdown
                                   1 if partial shutdown
            operationScope      - OP_SCOPE_ADAPTER or OP_SCOPE_LOGICAL_BOARD.

  Returns:      0 if successful, ODISTAT_FAIL if unsuccessful

  Abstract:   This routine will turn off the NIC.
                     

  Notes:            

========================================================================*/

ODISTAT   DriverShutdown(
            DRIVER_DATA      *driverData,
            CONFIG_TABLE   *configTable,
            UINT32         shutdownType,
            OPERATION_SCOPE operationScope)
{
//JCJ 19-Aug-97 SPD# 161807
//If DriverShutdown is called with a scope of LOGICAL_BOARD, adapter shout not be
//shut down.

   if(operationScope == OP_SCOPE_ADAPTER)
   {
      Out8(driverData->BusTag, driverData->InterruptMask, NIC_MASKBYTE);
      Out8(driverData->BusTag, driverData->Command, NIC_PAGE0STOP);
      if (driverData->NICRAMSegmentBase != 0)
   /* Card is in shared RAM mode */
      {
   /* Clear memory enable bit and reset adapter */
         Out8(driverData->BusTag, driverData->Control1, driverData->Control1Value & !0x40);
      }
   /* Junk to keep compiler happy, optimizer should remove. */

      configTable = configTable;
      shutdownType = shutdownType;
   }
   return ODISTAT_SUCCESSFUL;
}


/*=======================================================================*/
/*=======================================================================*/