// Sample code file: cne3200.c

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

/*--------------------------------------------------------------------------*
 * $version: 1.39
 * $date_modified: 121898
 * $description: LAN Device Driver for CNE3200
 * $owner: ODI LAN Driver Manager
 * Copyright (c) 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 NE3200 HSM
 *
 * Filename:      NE3200.C
 *
 * ODI Spec Ver:   1.11
 *
 * Description:       This module contains the HardWare specific routines
 *               to initialize and control the Novell NE3200 board.
 *
 * Modification History:
 *
 * 02-13-97 WTT      Changed call CMSMShutdownMlid back to DriverShutdown
 *                     in the DriverReset code.  DriverReset gets called by
 *                     DriverInit before the CMSMRegisterMLID has been called.
 *                     CMSMShutdownMLID can not be called before the MLID has
 *                     been registered with the CMSM.
 *                     SPD #150136
 *
 * 02-18-97 WTT      Moved the location of NICShortName after ADSTemplate.
 *                     When it was located before ADSTemplate it was causing
 *                     adpaterRCBList and adapterTCBList to not be on a dword
 *                     boundary.
 *                     SPD #150137
 *
 * 02-19-97 MPK      Changes made in DriverInit to call CMSMInitParser before
 *                     Parsing parameters. as per new specification.
 *
 * 07-15-97 LON      Changes made in DriverReset and DriverShutdown to enable
 *                   instance shutdown and reset of a logical board. If a
 *                   logical board is shutdown then the HSM tells the firmware
 *                   to filter out rcv frames for that particular board.
 *                     SPD# 160926
 *
 * 08-19-97 JCJ      WaitFor procedure has been changed to a simple counter based
 *                   loop from a timer based one, because we can not let other
 *                   process to run at this time.  SPD# 159385
 *
 * 09-23-97 JCJ      To avoid compiler warning -1 is type casted with
 *                   struct _TCB_ * while comparing driverData->adapterTCBList[]
 *                   SPD# 166555
 *
 *   02-10-99 LON      When the driver is unloaded it fails to release all ECBs,
 *                   because of a timing window where interrupts were still
 *                   enabled during permanent driver shutdown.   This allowed
 *                   the DriverISR routine to allocate RCBs before the
 *                   driver was unloaded (SPD 223362).
 *
 ****************************************************************************/

/*#define  OUT_CHAR    1*/

/*===[ Include files specific to this module ]===========================*/

#include "cne3200.h"
#include "cne3200.txt"


/*===[ Global variables ]==================================================*/

#define  NUMBER_OF_GENERICS (                                       \
            (UINT32 *) &((DRIVER_DATA *)0)->QDepth -                \
            (UINT32 *) &((DRIVER_DATA *)0)->TotalTxPacketCount) - 1

#define  NUMBER_OF_MEDIAS (                                          \
            (UINT32 *) &((DRIVER_DATA *)0)->RxAbortFrameAlignment -  \
            (UINT32 *) &((DRIVER_DATA *)0)->TxOKSingleCollision) + 1 \

#define  NUMBER_OF_CUSTOMS (                                         \
            (UINT32 *) &((DRIVER_DATA *)0)->NumberOfIntsFiredCount - \
            (UINT32 *) &((DRIVER_DATA *)0)->TxRetryFailureCount) + 1 \

/* NOTE: The adapter requires the adapterRCBList and adapterTCBList   */
/*       be on a dword boundary.  Do not place things before the       */
/*         following template that would cause the list not to be on a   */
/*         dword boundary.                                             */

DRIVER_DATA ADSTemplate =
{
   {0},                                      /* adapterRCBList                  */
   {0},                                      /* adapterTCBList                  */
   {0},                                      /* hostPWSList1                    */
   {0},                                      /* hostPWSList2                    */
   {0},                                      /* hostRCBList                     */
   {0},                                      /* hostTCBList                     */
   {0},                                      /* txStartList                     */

   0,                                        /* tcbQueueHead                    */
   0,                                        /* tcbQueueTail                    */

   0,                                        /* tcbInProcess                    */
   0,                                        /* txStartTime                     */
   0,                                          /* updateStatCount                 */

   0,                                        /* receiveQueueHead                */
   0,                                        /* receiveQueueTail                */
   TOTAL_RCBS,                               /* needRCBCount                    */

   0,                                        /* resetRegister                   */
   0,                                        /* eisaSystemDoorbellEnable        */
   0,                                        /* eisaSystemDoorbellStatus        */
   0,                                        /* idleMailbox                     */
   0,                                        /* updateParmMailbox               */
   0,                                        /* updateStatMailbox               */
   0,                                        /* tcbValidMailbox                 */
   0,                                        /* pollingMailbox                  */
   0,                                        /* tcbMailbox                      */
   0,                                        /* parametersMailbox               */
   
   0,                                        /* logicalToPhysicalOffset         */
   0,                                        /* nodeAddressPointer              */
   -1,                                       /* boardNumber8023                 */
   -1,                                       /* boardNumberEII                  */
   -1,                                       /* boardNumber8022                 */
   -1,                                       /* boardNumberSNAP                 */
   0,                                        /* maxReceivePacketSize            */
   0,                                        /* genericStatisticsPointer        */
   NUMBER_OF_CUSTOMS,                        /* customStatisticsCount           */
   0,                                        /* rcbListPointer                  */
   0,                                        /* multicastCount                  */
   0,                                        /* multicastTablePointer           */
   {0},                                      /* hostNodeAddress                 */
   0,                                        /* promiscuousMode                 */
   DEFAULT_TIMEOUT_VALUE,                    /* pollTimeout                     */
   GLOBAL_CONFIG,                            /* globalConfigValue               */

   0,                                        /* dummyAlignValue                 */

   0,                                        /* parameterCommand                */
   0,                                        /* parameter1                      */
   0,                                        /* parameter2                      */

   0,                                        /* inDriverPoll                    */
   0,                                        /* inDriverReset                   */
   0,                                        /* inDriverDisable                  */

   {
      NULL,                                  /* DAES->NextLink                  */
      DriverCallBack,                        /* DAES->DriverAES                 */
      AES_TYPE_PROCESS_CONTINUOUS,           /* DAES->AesType                   */
      500,                                   /* DAES->TimeInterval              */
      NULL,                                  /* DAES->AesContext                */
      {0}                                    /* DAES->AesReserved               */
   },

   0,                                        /* busType                         */
   NULL,                                     /* busTag                          */

   {  
      4,                                     /* StatsTable->MStatTableMajorVer  */
      00,                                    /* StatsTable->MStatTableMinorVer  */
      NUMBER_OF_GENERICS,                    /* StatsTable->MNumGenericCounters */
      &ADSTemplate.TotalTxPacketTable,       /* StatsTable->MGenericCountsPtr   */
      NUMBER_OF_MEDIAS,                      /* StatsTable->MNumMediaCounters   */
      &ADSTemplate.TxOKSingleCollisionTable, /* StatsTable->MMediaCountersPtr   */
      NUMBER_OF_CUSTOMS,                     /* StatsTable->MNumCustomCounters  */
      &ADSTemplate.TxRetryFailureTable,      /* StatsTable->MCustomCountersPtr  */
   },

   {
      ODI_STAT_UINT32,                       /* TotalTxPacketTable->StatUseFlag */
      &ADSTemplate.TotalTxPacketCount,       /* TotalTxPacketTable->StatCounter */
      0                                      /* TotalTxPacketTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TotalRxPacketTable->StatUseFlag */
      &ADSTemplate.TotalRxPacketCount,       /* TotalRxPacketTable->StatCounter */ 
      0                                      /* TotalRxPacketTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* NoECBAvailableTable->StatUseFlag */
      &ADSTemplate.NoECBAvailableCount,      /* NoECBAvailableTable->StatCounter */
      0                                      /* NoECBAvailableTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketTxTooBigTable->StatUseFlag */
      &ADSTemplate.PacketTxTooBigCount,      /* PacketTxTooBigTable->StatCounter */
      0                                      /* PacketTxTooBigTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketTxTooSmallTable->StatUseFlag */
      &ADSTemplate.PacketTxTooSmallCount,    /* PacketTxTooSmallTable->StatCounter */
      0                                      /* PacketTxTooSmallTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketRxOverflowTable->StatUseFlag */
      &ADSTemplate.PacketRxOverflowCount,    /* PacketRxOverflowTable->StatCounter */
      0                                      /* PacketRxOverflowTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketRxTooBigTable->StatUseFlag */
      &ADSTemplate.PacketRxTooBigCount,      /* PacketRxTooBigTable->StatCounter */
      0                                      /* PacketRxTooBigTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketRxTooSmallTable->StatUseFlag */
      &ADSTemplate.PacketRxTooSmallCount,    /* PacketRxTooSmallTable->StatCounter */
      0                                      /* PacketRxTooSmallTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketTxMiscErrorTable->StatUseFlag */
      &ADSTemplate.PacketTxMiscErrorCount,   /* PacketTxMiscErrorTable->StatCounter */
      0                                      /* PacketTxMiscErrorTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketRxMiscErrorTable->StatUseFlag */
      &ADSTemplate.PacketRxMiscErrorCount,   /* PacketRxMiscErrorTable->StatCounter */
      0                                      /* PacketRxMiscErrorTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* RetryTxTable->StatUseFlag */
      &ADSTemplate.RetryTxCount,             /* RetryTxTable->StatCounter */
      0                                      /* RetryTxTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* ChecksumErrorTable->StatUseFlag */
      &ADSTemplate.ChecksumErrorCount,       /* ChecksumErrorTable->StatCounter */
      0                                      /* ChecksumErrorTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* HardwareRxMismatchTable->StatUseFlag */
      &ADSTemplate.HardwareRxMismatchCount,  /* HardwareRxMismatchTable->StatCounter */
      0                                      /* HardwareRxMismatchTable->StatString  */
   },

   {
      ODI_STAT_UINT64,                       /* TotalTxOKByteTable->StatUseFlag */
      &ADSTemplate.TotalTxOKByteCount,       /* TotalTxOKByteTable->StatCounter */
      0                                      /* TotalTxOKByteTable->StatString  */
   },

   {
      ODI_STAT_UINT64,                       /* TotalRxOKByteTable->StatUseFlag */
      &ADSTemplate.TotalRxOKByteCount,       /* TotalRxOKByteTable->StatCounter */
      0                                      /* TotalRxOKByteTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TotalGroupAddrTxTable->StatUseFlag */
      &ADSTemplate.TotalGroupAddrTxCount,    /* TotalGroupAddrTxTable->StatCounter */
      0                                      /* TotalGroupAddrTxTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TotalGroupAddrRxTable->StatUseFlag */
      &ADSTemplate.TotalGroupAddrRxCount,    /* TotalGroupAddrRxTable->StatCounter */
      0                                      /* TotalGroupAddrRxTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* AdapterResetTable->StatUseFlag */
      &ADSTemplate.AdapterResetCount,        /* AdapterResetTable->StatCounter */
      0                                      /* AdapterResetTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* AdapterOprTimeStampTable->StatUseFlag */
      &ADSTemplate.AdapterOprTimeStamp,      /* AdapterOprTimeStampTable->StatCounter */
      0                                      /* AdapterOprTimeStampTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* QDepthTable->StatUseFlag  */
      &ADSTemplate.QDepth,                   /* QDepthTable->StatCounter  */
      0                                      /* QDepthTable->StatString   */
   },

/* topology specific counters                                             */

   {
      ODI_STAT_UINT32,                       /* TxOKSingleCollision->StatUseFlag */
      &ADSTemplate.TxOKSingleCollision,      /* TxOKSingleCollision->StatCounter */
      0                                      /* TxOKSingleCollision->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TxOKMultipleCollisions->StatUseFlag */
      &ADSTemplate.TxOKMultipleCollisions,   /* TxOKMultipleCollisions->StatCounter */
      0                                      /* TxOKMultipleCollisions->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TxOKButDeferred->StatUseFlag */
      &ADSTemplate.TxOKButDeferred,          /* TxOKButDeferred->StatCounter */
      0                                      /* TxOKButDeferred->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TxAbortLateCollision->StatUseFlag */
      &ADSTemplate.TxAbortLateCollision,     /* TxAbortLateCollision->StatCounter */
      0                                      /* TxAbortLateCollision->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TxAbortExcessCollisions->StatUseFlag */
      &ADSTemplate.TxAbortExcessCollisions,  /* TxAbortExcessCollisions->StatCounter */
      0                                      /* TxAbortExcessCollisions->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TxAbortCarrierSense->StatUseFlag */
      &ADSTemplate.TxAbortCarrierSense,      /* TxAbortCarrierSense->StatCounter */
      0                                      /* TxAbortCarrierSense->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* TxAbortExDeferral->StatUseFlag */
      &ADSTemplate.TxAbortExDeferral,        /* TxAbortExDeferral->StatCounter */
      0                                      /* TxAbortExDeferral->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* RxAbortFrameAlignment->StatUseFlag */
      &ADSTemplate.RxAbortFrameAlignment,    /* RxAbortFrameAlignment->StatCounter */
      0                                      /* RxAbortFrameAlignment->StatString  */
   },

/* custom counters                                                        */

   {
      ODI_STAT_UINT32,                       /* TxRetryFailureTable->StatUseFlag */
      &ADSTemplate.TxRetryFailureCount,      /* TxRetryFailureTable->StatCounter */
      0                                      /* TxRetryFailureTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* ClearToSendTable->StatUseFlag */
      &ADSTemplate.ClearToSendCount,         /* ClearToSendTable->StatCounter */
      0                                      /* ClearToSendTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* UnderRunTable->StatUseFlag */
      &ADSTemplate.UnderRunCount,            /* UnderRunTable->StatCounter */
      0                                      /* UnderRunTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* RxDMAOverrunTable->StatUseFlag */
      &ADSTemplate.RxDMAOverrunCount,        /* RxDMAOverrunTable->StatCounter */
      0                                      /* RxDMAOverrunTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PacketSlideTable->StatUseFlag */
      &ADSTemplate.PacketSlideCount,         /* PacketSlideTable->StatCounter */
      0                                      /* PacketSlideTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* DummyRCBTable->StatUseFlag */
      &ADSTemplate.DummyRCBCount,            /* DummyRCBTable->StatCounter */
      0                                      /* DummyRCBTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* AdapterReset1Table->StatUseFlag */
      &ADSTemplate.AdapterReset1Count,       /* AdapterReset1Table->StatCounter */
      0                                      /* AdapterReset1Table->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* BadFragLengthTable->StatUseFlag */
      &ADSTemplate.BadFragLengthCount,       /* BadFragLengthTable->StatCounter */
      0                                      /* BadFragLengthTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* PollingTimeoutTable->StatUseFlag */
      &ADSTemplate.PollingTimeoutCount,      /* PollingTimeoutTable->StatCounter */
      0                                      /* PollingTimeoutTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* AdapterDiedTable->StatUseFlag */
      &ADSTemplate.AdapterDiedCount,         /* AdapterDiedTable->StatCounter */
      0                                      /* AdapterDiedTable->StatString  */
   },

   {
      ODI_STAT_UINT32,                       /* NumberOfIntsFiredTable->StatUseFlag */
      &ADSTemplate.NumberOfIntsFiredCount,   /* NumberOfIntsFiredTable->StatCounter */
      0                                      /* NumberOfIntsFiredTable->StatString  */
   },

   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, 0},                                   /* TotalRxOKByteCount        */
   {0, 0},                                   /* TotalTxOKByteCount        */
   0,                                        /* TotalGroupAddrTxCount     */
   0,                                        /* TotalGroupAddrRxCount     */
   0,                                        /* AdapterResetCount         */
   0,                                        /* AdapterOprTimeStamp       */
   0,                                        /* QDepth                    */

/* topology counters                                                      */

   0,                                        /* TxOKSingleCollision       */
   0,                                        /* TxOKMultipleCollsions     */
   0,                                        /* TxOKButDeferred           */
   0,                                        /* TxAbortLateCollision      */
   0,                                        /* TxAbortExcessCollisions   */
   0,                                        /* TxAbortCarrierSense       */
   0,                                        /* TxAbortExDeferral         */
   0,                                        /* RxAbortFrameAlignment     */

/* custom counters                                                        */
   NUMBER_OF_CUSTOMS,                        /* CustomCounterCount          */

   0,                                        /* TxRetryFailureCount       */
   0,                                        /* ClearToSendCount          */
   0,                                        /* UnderRunCount             */
   0,                                        /* RxDMAOverrunCount         */
   0,                                        /* PacketSlideCount          */
   0,                                        /* DummyRCBCount             */
   0,                                        /* AdapterReset1Count        */
   0,                                        /* BadFragLengthCount        */
   0,                                        /* PollingTimeoutCount       */
   0,                                        /* AdapterDiedCount          */
   0,                                        /* NumberOfIntsFiredCount    */

};

MEON_STRING CHSMSPEC[] = {CNE3200_SPECVER_TXTMSG};

MEON     **DriverMessages = NULL;

/* 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.              */


MEON_STRING NICShortName[] =  {CNE3200_SHORTNAME_TXTMSG};


MLID_CONFIG_TABLE DriverConfigTemplate =
{
   CNE3200_CONFIGSIG_TXTMSG,                   /* MLIDCFG_Signature[26]; */
   01,                                         /* MLIDCFG_MajorVersion    */
   21,                                         /* MLIDCFG_MinorVersion    */
   {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},       /* MLIDCFG_NodeAddress     */
   MODE_FLAGS,                                 /* MLIDCFG_ModeFlags       */
   0,                                          /* MLIDCFG_BoardNumber     */
   0,                                          /* MLIDCFG_BoardInstance   */
   0,                                          /* MLIDCFG_MaxFrameSize    */
   0,                                          /* MLIDCFG_BestDataSize    */
   0,                                          /* MLIDCFG_WorstDataSize   */
   NULL,                                       /* MLIDCFG_CardName        */
   NICShortName,                                  /* MLIDCFG_ShortName       */
   NULL,                                       /* MLIDCFG_FrameTypeString */
   0,                                          /* MLIDCFG_Reserved0       */
   0,                                          /* MLIDCFG_FrameID         */
   1,                                          /* 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  */
   FLAGS,                                      /* MLIDCFG_Flags           */
   5,                                          /* MLIDCFG_SendRetries     */
   NULL,                                       /* MLIDCFG_DriverLink      */
   SHARING_FLAGS,                              /* MLIDCFG_SharingFlags    */
   0,                                          /* MLIDCFG_Slot            */
   0x300,                                      /* MLIDCFG_IOPort0         */
   0x30,                                       /* MLIDCFG_IORange0        */
   0,                                          /* MLIDCFG_IOPort1         */
   0,                                          /* MLIDCFG_IORange1        */
   NULL,                                       /* MLIDCFG_MemoryAddress0  */
   0,                                          /* MLIDCFG_MemorySize0     */
   NULL,                                       /* MLIDCFG_MemoryAddress1  */
   0,                                          /* MLIDCFG_MemorySize1     */
   0xff,                                       /* MLIDCFG_Interrupt0      */
   0xff,                                       /* MLIDCFG_Interrupt1      */
   0xff,                                       /* MLIDCFG_DMALine0        */
   0xff,                                       /* MLIDCFG_DMALine1        */
   NULL,                                       /* MLIDCFG_ResourceTag     */
   NULL,                                       /* MLIDCFG_Config          */
   NULL,                                       /* MLIDCFG_CommandString   */
   {0},                                        /* MLIDCFG_LogicalName     */
   0,                                          /* MLIDCFG_LinearMemory0   */
   0,                                          /* MLIDCFG_LinearMemory1   */
   0,                                          /* MLIDCFG_ChannelNumber   */
   0,                                          /* MLIDCFG_DBusTag         */
   1,                                          /* MLIDCFG_DIOConfigMajorVr*/
   0                                           /* MLIDCFG_DIOConfigMinorVr*/
};

DRIVER_PARM_BLOCK DriverParameterBlock =
{
   sizeof(DRIVER_PARM_BLOCK),                  /* DriverParameterSize        */
   NULL,                                       /* DriverInitParmPointer      */
   NULL,                                       /* DriverModuleHandle         */
   NULL,                                       /* DriverBoardPointer         */
   NULL,                                       /* DriverAdapterPointer       */
   &DriverConfigTemplate,                      /* DriverConfigTemplatePtr    */
   -1,                                         /* DriverFirmwareSize         */
   NULL,                                       /* DriverFirmwareBuffer       */
   0,                                          /* DPB_Reserved1              */
   0,                                          /* DPB_Reserved2              */
   0,                                          /* DPB_Reserved3              */
   0,                                          /* DPB_Reserved4              */
   sizeof (DRIVER_DATA),                       /* DriverAdapterDataSpaceSize */
   &ADSTemplate,                               /* DriverAdapterDataSpacePtr  */
   (UINT32) &(((DRIVER_DATA*)0)->StatsTable),  /* DriverStatisticsTableOffset*/
   0,                                          /* DriverEndOfChainFlag       */
   -1,                                         /* DriverSendWantsECBs        */
   20,                                         /* DriverMaxMulticast         */
   0,                                          /* DriverNeedsBelow16Meg      */
   NULL,                                       /* DPB_Reserved5              */
   NULL,                                         /* DPB_Reserved6              */
   DriverISR,                                  /* DriverISRPtr               */
   DriverMulticastChange,                      /* DriverMulticastChangePtr   */
   DriverPoll,                                 /* DriverPollPtr              */
   DriverReset,                                /* DriverResetPtr             */
   DriverSend,                                 /* DriverSendPtr              */
   DriverShutdown,                             /* DriverShutdownPtr          */
   NULL,                                       /* DriverTxTimeoutPtr         */
   DriverPromiscuousChange,                    /* DriverPromiscuousChangePtr */
   DriverStatisticsChange,                     /* DriverStatisticsChangePtr  */
   NULL,                                       /* DriverRxLookAheadChangePtr */
   NULL,                                       /* DriverManagementPtr        */
   DriverEnableInterrupt,                      /* DriverEnableInterruptPtr   */
   DriverDisableInterrupt,                     /* DriverDisableInterruptPtr  */
   NULL,                                       /* DriverISRPtr2              */
   &DriverMessages,                        /* DriverMessagesPtr          */
   &CHSMSPEC,            /* HSM Specification Version */
   NULL,               /* Driver Priority Queue Ptr */
   NULL               /* DriverDisableInterrupt2Ptr */
};

/**************************************************************************\
**
**    Parameters required by ParseDriverParameters.         
**
\**************************************************************************/

UINT32   SlotsWithMyBoardCount;

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

DRIVER_OPTION SlotOption =
         { NULL, NULL, (PARAMETER_OPTIONS *)&SlotsWithMyBoard, 0, 0, SLOTPARAM,
               REQUIREDPARAM | ENUMPARAM, };

UINT32      commonMaximumSize;
UINT8       eisaInterruptField;

UINT32      systemMemoryMap [2 * 8];
UINT32      pcode;

/**************************************************************************\
**
**    Custom Keyword Information.
**
\**************************************************************************/

DRIVER_OPTION PollOption =
         { &SlotOption, CNE3200_POLLOPTION_TXTMSG, 0, 0xffff, 
            DEFAULT_TIMEOUT_VALUE, CUSTOMPARAM, 
            OPTIONALPARAM | RANGEPARAM | DEFAULTPRESENT, };


/**************************************************************************\
**
**    Procedures
**
\**************************************************************************/

/**************************************************************************\
**
** PROC NAME:     DriverInit
**
**                This routine will call CEtherTSMRegisterHSM,
**                CMSMParseDriverParameters, CMSMRegisterHardwareOptions,
**                CMSMSetHardwareInterrupt, CMSMRegisterMLID, initialize
**                variables in the Adapter Data Space and reset/initialize
**                the card.
**
** Parameters:    IN    Numerous HSM Stack parameters passed in by the
**                        loader.
**
** Return Value:  ODISTAT_SUCCESSFUL   - The Hardware initialized successfully.
**                ODISTAT_FAIL         - The Hardware failed to initialize.
**
** See Also:      
**
\**************************************************************************/

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)

{
   CHSM_STACK      chsmStack;
   CONFIG_TABLE   *configTable;
   DRIVER_DATA    *driverData;
   REG_TYPE       ccode;
   UINT8          cfgBlock [EISA_CFG_BLOCK_SIZE];
   UINT16         block = 0;
   UINT32         i, physSlot;
   UINT32         scanSeq = -1;               
   UINT32         uniqueID;
   void   *temp_DBusTag;
   MEON            productID[PRODUCT_ID_LEN] = {MANUFACT_CHAR_CODE_1,
                                                MANUFACT_CHAR_CODE_2,
                                               PRODUCT_NUMBER_07,
                                               PRODUCT_NUMBER_01};
   /***********************************************************************\
   **    Fill in HSMStack fields and register the HSM
   \***********************************************************************/

   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;

   DriverParameterBlock.DriverInitParmPointer = &chsmStack;

   /* 970219 MPK - Initialize the parser before parsing */
   CMSMInitParser(&DriverParameterBlock);


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

   /***********************************************************************\
   **    Save maximum packet size for allocating RCB's at run time
   \***********************************************************************/

   commonMaximumSize = configTable->MLIDCFG_MaxFrameSize;

   /***********************************************************************\
   **    Find all of the ne3200 NICs in the machine
   \***********************************************************************/

/* Let MSM search for all NE3200 cards, first check for EISA ID "NVL 07 01 */

   SlotsWithMyBoardCount = 0;         

   while (CMSMSearchAdapter (
               &scanSeq, 
               ODI_BUSTYPE_EISA,
               PRODUCT_ID_LEN,
               productID,
               &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++;
      }
   }

/* Now check for EISA ID "NVL 07 02"   */

   scanSeq = -1;
   productID[PRODUCT_ID_LEN - 1] = PRODUCT_NUMBER_02;

   while (CMSMSearchAdapter (
               &scanSeq, 
               ODI_BUSTYPE_EISA,
               PRODUCT_ID_LEN,
               productID,
               &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++;
      }
   }

   SlotsWithMyBoard.OptionCount = SlotsWithMyBoardCount;
   
   if (!SlotsWithMyBoardCount)
   {
      CMSMPrintString (
         configTable, 
         MSG_TYPE_INIT_ERROR,
         CNE3200_NOBOARD_MSG,
         NULL,
         NULL);

      CMSMReturnDriverResources (configTable);
      return (ODISTAT_FAIL);
   }
   else if (SlotsWithMyBoardCount == 1)   
   {   /* If only one board then no need to parse for slot   */
      configTable->MLIDCFG_Slot    = SlotsWithMyBoard.UNumOptVal[0];
      PollOption.Link       = NULL;
   }

   /***********************************************************************\
   **    Let the MSM parse the command line
   \***********************************************************************/

   if ((ccode = CMSMParseDriverParameters(&DriverParameterBlock, &PollOption)) != ODISTAT_SUCCESSFUL)
   {   /* If only PollOption then don't die if ODISTAT_ITEM_NOT_PRESENT */
      if ((SlotsWithMyBoardCount == 1) && (ccode != ODISTAT_ITEM_NOT_PRESENT))
      {
         CMSMReturnDriverResources(configTable);
         return ODISTAT_FAIL;
      }
   }
   
   /***********************************************************************\
   **    Store base I/O port based on slot chosen
   \***********************************************************************/

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

   if ( CMSMGetUniqueIdentifierParameters( 
            configTable->MLIDCFG_DBusTag,
            uniqueID,
            1,
            &physSlot)
            != ODI_NBI_SUCCESSFUL)
   {
        CMSMReturnDriverResources(configTable);
        return ODISTAT_FAIL;
   }

   configTable->MLIDCFG_IOPort0 = (physSlot << 12) + SLOT_0;

   /***********************************************************************\
   **    Read configuration based on slot chosen
   \***********************************************************************/

     while (TRUE)
   {
      if (CMSMGetCardConfigInfo (
             configTable->MLIDCFG_DBusTag, 
            uniqueID,
            EISA_CFG_BLOCK_SIZE,
               block,
                NULL,
                cfgBlock) 
             != ODI_NBI_SUCCESSFUL)
      {
         CMSMPrintString (
            configTable, 
            MSG_TYPE_INIT_ERROR,
              CNE3200_NOIRQERR_MSG,
            NULL,
            NULL);

         CMSMReturnDriverResources (configTable);
         return (ODISTAT_FAIL);
      }

      block++;

      if (cfgBlock [EISA_VALID_INT] & EISA_INT_FUNCTION_BIT)
      {
         eisaInterruptField = cfgBlock [EISA_INTERRUPT];
         if (eisaInterruptField & ISOLATE_INT_MASK)
         {
            eisaInterruptField &= ISOLATE_INT_MASK;
            configTable->MLIDCFG_Interrupt0 = eisaInterruptField;
            break;
         }
      }
   }

   /***********************************************************************\
   **    Let MSM Register the hardware options
   \***********************************************************************/

   if ((ccode = CMSMRegisterHardwareOptions (configTable, &driverData)) == REG_TYPE_FAIL)
   {
      CMSMReturnDriverResources (configTable);
      return (ODISTAT_FAIL);
   }

   /***********************************************************************\
   **    Check if new frame for existing adapter... if so we're done
   \***********************************************************************/

   if (ccode == REG_TYPE_NEW_FRAME)
      goto DriverInitExit;

   DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount = TOTAL_TCBS;

   CFixUpStatStrings (driverData);

   if (eisaInterruptField & EISA_SHARED_INT_MASK)
      driverData->globalConfigValue &= GLOBAL_CFG_SHARE_MASK;

   /***********************************************************************\   
   **    Initialize the ADS now that we have a pointer to it
   \***********************************************************************/

    if (CMSMGetBusType (configTable->MLIDCFG_DBusTag, &driverData->busType) != ODI_NBI_SUCCESSFUL)
   {
      CMSMReturnDriverResources (configTable);
      return (ODISTAT_FAIL);
   }

   /***********************************************************************\
   **    Initialize all I/O port addresses and aliases
   \***********************************************************************/

   driverData->eisaSystemDoorbellEnable = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + SYSTEM_DOORBELL_MASK_REG);
   driverData->eisaSystemDoorbellStatus = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + SYSTEM_DOORBELL_INT_STATUS_REG);
   driverData->idleMailbox              = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + MAILBOX_REGISTERS + 0);
   driverData->updateParmMailbox        = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + MAILBOX_REGISTERS + 1);
   driverData->updateStatMailbox        = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + MAILBOX_REGISTERS + 2);
   driverData->updateStatCount          = 0;      
   driverData->tcbValidMailbox          = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + MAILBOX_REGISTERS + 3);
   driverData->tcbMailbox               = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + MAILBOX_REGISTERS + 4);
   driverData->pollingMailbox           = driverData->tcbMailbox;
   driverData->parametersMailbox        = (void *) ((UINT8 *) configTable->MLIDCFG_IOPort0 + MAILBOX_REGISTERS + 12);
   driverData->resetRegister            = (void *) ((UINT32)  physSlot << 12);

   /***********************************************************************\
   **    Reset the adapter
   \***********************************************************************/

   if (CMSMGetPollSupportLevel() > 1)
      driverData->pollTimeout = PollOption.Parameter1.Max;
   else
      driverData->pollTimeout   = 0; 

   for (i = 0; i < TABLE_SIZE; i++)
      driverData->adapterRCBList[i] = (RCB *)-1;

   for (i = 0; i < TCB_TABLE_SIZE; i++)
      driverData->adapterTCBList[i] = (TCB *)-1;

   if (DriverReset (driverData, configTable, OP_SCOPE_ADAPTER) != ODISTAT_SUCCESSFUL)
   {
      CMSMReturnDriverResources (configTable);
      return (ODISTAT_FAIL);
   }

   driverData->AdapterResetCount--;


   /***********************************************************************\
   **   Lets Register with the LSL
   \***********************************************************************/

   if (CMSMRegisterMLID (driverData, configTable) != ODISTAT_SUCCESSFUL)
   {
      CMSMReturnDriverResources (configTable);
      return (ODISTAT_FAIL);
   }

   /***********************************************************************\
   **    Let MSM set up our interrupt procedure and set resetlevel
   \******************yy*****************************************************/

   if (CMSMSetHardwareInterrupt (driverData, configTable) != ODISTAT_SUCCESSFUL)
   {
      CMSMReturnDriverResources (configTable);
      return (ODISTAT_FAIL);
   }

   /***********************************************************************\
   **   Let MSM enable callback and exit DriverInit
   \***********************************************************************/

   if ((CMSMScheduleAES (driverData, &driverData->DAES)) != ODISTAT_SUCCESSFUL)
   {
      CMSMReturnDriverResources (configTable);
      return (ODISTAT_FAIL);
   }

   if (driverData->pollTimeout)
   {
      if (CMSMEnablePolling (driverData) != ODISTAT_SUCCESSFUL)
      {
         CMSMReturnDriverResources (configTable);
         return (ODISTAT_FAIL);
      }
   }

   if (driverData->pollTimeout)
   {
      CMSMPrintString (
         configTable, 
         MSG_TYPE_INIT_INFO,
         CNE3200_POLLIRQBACKUP_MSG,
         (void *) (driverData->pollTimeout * 400),
         NULL);
   }
   else
   {
      CMSMPrintString (
         configTable, 
         MSG_TYPE_INIT_INFO,
         CNE3200_IRQMODEONLY_MSG,
         NULL,
         NULL);
   }

   /***********************************************************************\
   **   Determine frame type,
   **   wait for the parameter mailbox to clear,
   **   then send Parm Block to the adapter.
   \***********************************************************************/

DriverInitExit:

   switch (configTable->MLIDCFG_FrameID)
   {
      case 2:
         driverData->boardNumberEII  = configTable->MLIDCFG_BoardNumber;
         break;                  
      case 3:
         driverData->boardNumber8022 = configTable->MLIDCFG_BoardNumber;
         break;                  
      case 5:
         driverData->boardNumber8023 = configTable->MLIDCFG_BoardNumber;
         break;                  
      case 10:
         driverData->boardNumberSNAP = configTable->MLIDCFG_BoardNumber;
   }

   pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP);

   Out8 (configTable->MLIDCFG_DBusTag, driverData->updateParmMailbox, 1);

   PollOption.Parameter1.Max = 0xffff;      /* Reset Options for next load   */

/***********************************************************************\
 ** TNL 12/06/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;
}

/**************************************************************************\
**
** PROC NAME:     DriverRemove
**
**                This routine will called when the driver image is
**                to be deleted from memory.
**
** Parameters:    NONE
**
** Return Value:  NONE
**
** See Also:      
**
\**************************************************************************/

void   DriverRemove (void)
{

/* Clean up all NESL related stuff   */

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

   CMSMDriverRemove (DriverParameterBlock.DriverModuleHandle);
   return;
}

/**************************************************************************\
**
** PROC NAME:     DriverReset
**
**                This routine will called when the driver needs to be
**                reset to its original pristine state.
**
** Parameters:    IN    DRIVER_DATA       *driverData
**                IN    FRAME_DS          *configTable
**                  IN      OPERATION_SCOPE   operationScope
**
**                driverData     - Pointer to HSM's adapter data space
**                configTable    - Pointer to HSM's frame data space
**                  operationScope   - OP_SCOPE_ADPATER or OP_SCOPE_LOGICAL_BOARD
**
** Return Value:  ODISTAT_SUCCESSFUL = successful
**                ODISTAT_FAIL       = unsuccessful
**
** See Also:      
**
\**************************************************************************/

ODISTAT  DriverReset (
            DRIVER_DATA       *driverData,
            CONFIG_TABLE      *configTable,
            OPERATION_SCOPE   operationScope)
{
   RCB            *physRCB;
   RCB            *logRCB;
   void           *physAddr;
   UINT32         i, boardIndex;
   CONFIG_TABLE   *tempConfig;

   driverData->inDriverReset = -1;

   if (operationScope == OP_SCOPE_ADAPTER)
   {
      driverData->AdapterResetCount++;

      /***********************************************************************\
      **    Call DriverShutdown to reset NE3200 and return any TCB's or
      **    RCB's that the driver has in its possession.
      \***********************************************************************/

      DriverShutdown (driverData, configTable, SHUTDOWN_PARTIAL, OP_SCOPE_ADAPTER);
/*      CMSMShutdownMLID (driverData, SHUTDOWN_PARTIAL);*/

      driverData->receiveQueueHead = 0;
      driverData->receiveQueueTail = 0;

      if (logRCB = CMSMAllocateRCB (driverData, commonMaximumSize, &physRCB))
      {
         driverData->needRCBCount--;
         driverData->hostPWSList1   [0] = ((ECB *)logRCB)->ECB_ProtocolWorkspace.PWs_i32val [0];
         driverData->hostPWSList2   [0] = ((ECB *)logRCB)->ECB_ProtocolWorkspace.PWs_i32val [1];
         driverData->hostRCBList    [0] = logRCB;
         driverData->adapterRCBList [0] = physRCB;
         driverData->receiveQueueTail++;
      }

      /***********************************************************************\
      **    Wait for NIC to report its initial status.
      \***********************************************************************/

      pcode = WaitForEvent (driverData, driverData->idleMailbox, WAIT_BYTE_SET, WAIT_LOOP*2);

      /***********************************************************************\
      **    Check for error conditions.
      \***********************************************************************/

      if (!(pcode & FIRMWARE_INIT_SUCCESS))
      {
         if (!pcode)
         {
            CMSMPrintString (
               configTable, 
               MSG_TYPE_INIT_ERROR,
               CNE3200_FIRMWAREINITERR_MSG,
               NULL,
               NULL);
            driverData->inDriverReset = 0;
            return (ODISTAT_FAIL);
         }

         if (pcode & STATIC_RAM_ERROR_MASK)
         {
            CMSMPrintString (
               configTable, 
               MSG_TYPE_INIT_ERROR,
               CNE3200_MEMERR_MSG,
               NULL,
               NULL);
            driverData->inDriverReset = 0;
            return (ODISTAT_FAIL);
         }

         CMSMPrintString (
            configTable, 
            MSG_TYPE_INIT_ERROR,
            CNE3200_CHECKSUMERR_MSG,
            NULL,
            NULL);
         driverData->inDriverReset = 0;
         return (ODISTAT_FAIL);
      }

      /***********************************************************************\
      **    Firmware initialized successfully...Tell NE3200 where to read
      **    the firmware from.
      \***********************************************************************/

      Out8 (configTable->MLIDCFG_DBusTag,
         (void *) ((UINT8 *) driverData->idleMailbox + 1),
         (UINT8) (DriverParameterBlock.DriverFirmwareSize));
      Out8 (configTable->MLIDCFG_DBusTag,
         (void *) ((UINT8 *) driverData->idleMailbox + 2),
         (UINT8) (VALUE_TO_HILO_UINT16 ((UINT16) (DriverParameterBlock.DriverFirmwareSize))));

      physAddr = CMSMGetPhysical (DriverParameterBlock.DriverFirmwareBuffer);

      Out32 (configTable->MLIDCFG_DBusTag, (void *) ((UINT8 *) driverData->idleMailbox + 4), (UINT32) physAddr);
      Out32 (configTable->MLIDCFG_DBusTag, (void *) ((UINT8 *) driverData->idleMailbox + 8), 0);

      Out8 (configTable->MLIDCFG_DBusTag, driverData->idleMailbox, 0);

      /***********************************************************************\
      **    Wait for the download process to complete.
      \***********************************************************************/

      pcode = WaitForEvent (driverData, driverData->parametersMailbox, WAIT_FIRMWARE, WAIT_LOOP*2);

      if (pcode != FIRMWARE_RUNNING)
      {
         CMSMPrintString (
            configTable,
            MSG_TYPE_INIT_ERROR,
            CNE3200_FIRMWARESTARTERR_MSG,
            NULL,
            NULL);
         driverData->inDriverReset = 0;
         return (ODISTAT_FAIL);
      }

      /***********************************************************************\
      **    At this point the firmware is operational.
      **    Now fill in and send adapter parameter block to adapter.
      \***********************************************************************/

      driverData->nodeAddressPointer       = CMSMGetPhysical (&configTable->MLIDCFG_NodeAddress);
      driverData->maxReceivePacketSize     = configTable->MLIDCFG_MaxFrameSize;
      driverData->genericStatisticsPointer = CMSMGetPhysical (&driverData->PacketTxTooBigCount);
      driverData->customStatisticsCount    = NUMBER_OF_CUSTOMS;
      driverData->rcbListPointer           = CMSMGetPhysical (&driverData->adapterRCBList);

      CEtherTSMUpdateMulticast (driverData);

      for (i = 0; i < ADDR_SIZE; i++)
         driverData->hostNodeAddress [i] = configTable->MLIDCFG_NodeAddress.nodeAddress [i];

      /***********************************************************************\
      **   An OP_SCOPE_ADAPTER reset implies that any previous partial
      **   shutdowns of logical boards are now reactivated.      LON 970708
      \***********************************************************************/

      for (boardIndex=0; boardIndex < 4; boardIndex++)
      {
         if ((tempConfig = DADSP_TO_CMSMADSP
                       (driverData)->CMSMVirtualBoardLink [boardIndex]) !=NULL)
         {
            switch (tempConfig->MLIDCFG_FrameID)
            {
            case 2:
               driverData->boardNumberEII  = tempConfig->MLIDCFG_BoardNumber;
               break;
            case 3:
               driverData->boardNumber8022 = tempConfig->MLIDCFG_BoardNumber;
               break;
            case 5:
               driverData->boardNumber8023 = tempConfig->MLIDCFG_BoardNumber;
               break;
            case 10:
               driverData->boardNumberSNAP = tempConfig->MLIDCFG_BoardNumber;
            }
         }
      }

      /***********************************************************************\
      **   Tell the firmware that the driver parameters has been updated.
      \***********************************************************************/
      Out32 (configTable->MLIDCFG_DBusTag, driverData->parametersMailbox, (UINT32) (CMSMGetPhysical (&driverData->logicalToPhysicalOffset)));
      Out8 (configTable->MLIDCFG_DBusTag, driverData->updateParmMailbox, 1);

      /***********************************************************************\
      **    Wait for the parameter block to be sent to the adapter ok.
      \***********************************************************************/

      pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP * 2);

      if (pcode)
      {
         CMSMPrintString (
            configTable,
            MSG_TYPE_INIT_ERROR,
            CNE3200_BOARDFAIL_MSG,
            NULL,
            NULL);
         driverData->inDriverReset = 0;
         return (ODISTAT_FAIL);
      }

      /***********************************************************************\
      **    Parameters downloaded successfully.
      \***********************************************************************/

      Out8 (configTable->MLIDCFG_DBusTag, driverData->pollingMailbox, 0);
      Out8 (configTable->MLIDCFG_DBusTag, (void *) ((UINT8 *) driverData->eisaSystemDoorbellEnable + 1), -1);
      Out8 (configTable->MLIDCFG_DBusTag, driverData->eisaSystemDoorbellEnable, 1);
      Out8 (configTable->MLIDCFG_DBusTag, (void *) ((UINT8 *) driverData->eisaSystemDoorbellEnable - 6), driverData->globalConfigValue);
      Out8 (configTable->MLIDCFG_DBusTag, (void *) ((UINT8 *) driverData->eisaSystemDoorbellEnable - 5), 1);

      driverData->inDriverReset = 0;
      return ODISTAT_SUCCESSFUL;
   }
   else
   {

      /***********************************************************************\
      **   An OP_SCOPE_LOGICAL reset requests a previously shutdown logical
      **   board to now be reactivated.                        LON 970708
      \***********************************************************************/

      switch (configTable->MLIDCFG_FrameID)
      {
      case 2:
         driverData->boardNumberEII  = configTable->MLIDCFG_BoardNumber;
         break;
      case 3:
         driverData->boardNumber8022 = configTable->MLIDCFG_BoardNumber;
         break;
      case 5:
         driverData->boardNumber8023 = configTable->MLIDCFG_BoardNumber;
         break;
      case 10:
         driverData->boardNumberSNAP = configTable->MLIDCFG_BoardNumber;
      }

      /***********************************************************************\
      **   Tell the firmware that the driver parameters has been updated.
      **   Setting the above board to its board number causes the firmware to
      **   start receiving frames belonging to that board type.  LON 970708
      \***********************************************************************/

      pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP);
      Out8 (configTable->MLIDCFG_DBusTag, driverData->updateParmMailbox, 1);

      /***********************************************************************\
      **    Wait for the parameter block to be sent to the adapter ok.
      \***********************************************************************/

      pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP * 2);

      if (pcode)
      {
         CMSMPrintString (
            configTable,
            MSG_TYPE_INIT_ERROR,
            CNE3200_BOARDFAIL_MSG,
            NULL,
            NULL);
         driverData->inDriverReset = 0;
         return (ODISTAT_FAIL);
      }
      driverData->inDriverReset = 0;
      return ODISTAT_SUCCESSFUL;
   }
}

/**************************************************************************\
**
** PROC NAME:     DriverMulticastChange
**
**                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).
**                
** Parameters:    IN    DRIVER_DATA       *driverData
**                IN    FRAME_DS          *configTable
**                IN    GROUP_ADDR_LIST_NODE   *mcTable
**                IN    UINT32            numEntries
**                IN    UINT32            functionalTable
**
**                driverData            - Pointer to HSM's adapter data space
**                configTable            - Pointer to HSM's frame data space
**                mcTable         - Pointer to HSM's multicast table entries
**                numEntries      - The number of entires in multicast table
**                functionalTable - 32-bit functional address N/A
**
** Return Value:  NONE
**
** See Also:      ETHERTSM\CEtherTSMAddMulticastAddress
**                ETHERTSM\CEtherTSMDeleteMulticastAddress
**                ETHERTSM\CEtherTSMUpdateMulticast
**
\**************************************************************************/

ODISTAT DriverMulticastChange (
            DRIVER_DATA             *driverData,
            CONFIG_TABLE            *configTable,
            GROUP_ADDR_LIST_NODE         *mcTable,
            UINT32                  numEntries,
            UINT32                  functionalTable)
{
   functionalTable = functionalTable;

   driverData->multicastCount        = numEntries;
   driverData->multicastTablePointer = CMSMGetPhysical ((void *) mcTable);

   if (!driverData->inDriverReset)
   {
      pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP);
      pcode++;
      Out8 (configTable->MLIDCFG_DBusTag, driverData->updateParmMailbox, (UINT8) pcode);
   }
   return ODISTAT_SUCCESSFUL;
}

/**************************************************************************\
**
** PROC NAME:     DriverPromiscuousChange
**
**                This routine is called to enable or disable the 
**                promiscuous mode capabilities of the adapter. 
**
** Parameters:    IN    DRIVER_DATA    *driverData
**                IN    FRAME_DS       *configTable
**
**                driverData  - Pointer to HSM's adapter data space
**                configTable  - Pointer to HSM's frame data space
**
** Return Value:  NONE
**
** See Also:      ETHERTSM\CEtherTSMPromiscuousChange
**
\**************************************************************************/

ODISTAT DriverPromiscuousChange (
            DRIVER_DATA       *driverData,
            CONFIG_TABLE      *configTable,
            UINT32            promMode)
{
   driverData->promiscuousMode = (UINT8) promMode;

   if (!driverData->inDriverReset) 
   {
      pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP);
      pcode++;
      Out8 (configTable->MLIDCFG_DBusTag, driverData->updateParmMailbox, (UINT8) pcode);
   }
   return ODISTAT_SUCCESSFUL;
}


/**************************************************************************\
**
** PROC NAME:     DriverStatisticsChange
**
**                This routine will update the statistics table. 
**
** Parameters:    IN    DRIVER_DATA    *driverData
**                IN    FRAME_DS       *configTable
**
**                driverData  - Pointer to HSM's adapter data space
**                configTable  - Pointer to HSM's frame data space
**
** Return Value:  NONE
**
** See Also:      ETHERTSM\CEtherTSMPromiscuousChange
**
\**************************************************************************/

ODISTAT DriverStatisticsChange (
            DRIVER_DATA       *driverData,
            CONFIG_TABLE      *configTable)
{
   UINT32   startTime;

                                          /* Tell firmware to update stats   */
   Out8 (configTable->MLIDCFG_DBusTag, driverData->updateStatMailbox, 1);

   startTime = CMSMGetMicroTimer();
   for (startTime = -startTime; (CMSMGetMicroTimer() + startTime) < 16000;);

   driverData->updateStatCount = 0;
   return ODISTAT_SUCCESSFUL;
}


/**************************************************************************\
**
** PROC NAME:     DriverShutdown
**
**                This routine will called when the driver needs to be
**                shutdown either temporarily or permanently.
**
** Parameters:    IN    DRIVER_DATA       *driverData
**                IN    FRAME_DS          *configTable
**                IN    UINT32            shutDownType
**                  IN      OPERATION_SCOPE   operationScope
**
**                driverData     - Pointer to HSM's adapter data space
**                configTable    - Pointer to HSM's frame data space
**                shutDownType   - PERMANENT_SHUTDOWN or TEMPORARY_SHUTDOWN
**                  operationScope - OP_SCOPE_ADAPTER or OP_SCOPE_LOGICAL_BOARD
**
** Return Value:  ODISTAT_SUCCESSFUL = successful
**                ODISTAT_FAIL       = unsuccessful
**
** See Also:      ETHERTSM\CEtherTSMShutdown
**
\**************************************************************************/

ODISTAT  DriverShutdown (
            DRIVER_DATA       *driverData,
            MLID_ConfigTable  *configTable,
            UINT32            shutDownType,
            OPERATION_SCOPE   operationScope)
{
   RCB      *retRCB;
   TCB      *retTCB;

   UINT32   numRCBs;
   UINT32   i;


   if (operationScope == OP_SCOPE_LOGICAL_BOARD)
   {
      if ((configTable->MLIDCFG_SharingFlags & MS_SHUTDOWN_BIT)
         && (!driverData->inDriverReset))
      {
         /***********************************************************************\
         **   An OP_SCOPE_LOGICAL shutdown is a request by the MSM/TSM to
         **   shutdown one logical board.                        LON 970708
         \***********************************************************************/

         switch (configTable->MLIDCFG_FrameID)
         {
         case 2:
            driverData->boardNumberEII  = -1;
            break;
         case 3:
            driverData->boardNumber8022 = -1;
            break;
         case 5:
            driverData->boardNumber8023 = -1;
            break;
         case 10:
            driverData->boardNumberSNAP = -1;
         }

         /***********************************************************************\
         **   Tell the firmware that the driver parameters has been updated.
         **   Setting the above board to -1 causes the firmware to discard
         **   rcv frames belonging to that board type.           LON 970708
         \***********************************************************************/

         pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP);
         Out8 (configTable->MLIDCFG_DBusTag, driverData->updateParmMailbox, 1);

         /***********************************************************************\
          **    Wait for the parameter block to be sent to the adapter ok.
         \***********************************************************************/

         pcode = WaitForEvent (driverData, driverData->updateParmMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP * 2);

         if (pcode)
         {
            CMSMPrintString (
               configTable,
               MSG_TYPE_INIT_ERROR,
               CNE3200_BOARDFAIL_MSG,
               NULL,
               NULL);
            return (ODISTAT_FAIL);                       /* Exit */
         }
      }
        return ODISTAT_SUCCESSFUL;                         /* Exit */
   }

   if ( !driverData->inDriverReset)     /* OP_SCOPE_ADAPTER */
   {
      /***********************************************************************\
      **    Set card into idle state.
      \***********************************************************************/

      Out8 (configTable->MLIDCFG_DBusTag, driverData->idleMailbox, 1);
      pcode = WaitForEvent (driverData, driverData->idleMailbox, WAIT_BYTE_CLEAR, WAIT_LOOP);
   }

   if (shutDownType == SHUTDOWN_PARTIAL)  /* or someday HSM_TEMPORARY_SHUTDOWN */
   {
      /***********************************************************************\
      **    Set reset bit and clear abend mailbox.
      **    Allow reset settling time.
      \***********************************************************************/

      Out32 (configTable->MLIDCFG_DBusTag, driverData->resetRegister, 1);
      Out8 (configTable->MLIDCFG_DBusTag, driverData->idleMailbox, 0);

      WaitForEvent (driverData, NULL, WAIT_TIMEOUT, WAIT_RESET);

      Out32 (configTable->MLIDCFG_DBusTag, driverData->resetRegister, 0);

   }
   else
   {
      if ( !driverData->inDriverReset)                  /* LON 970708 */
      {
         /* MSM/TSM called for a Permanent shutdown so disable interrupts.  */
         Out8 (driverData->busTag, driverData->eisaSystemDoorbellEnable, 0);
      }
   }
   /***********************************************************************\
   **    Clear interrupt status in case it is level triggered.
   \***********************************************************************/
   Out8 (configTable->MLIDCFG_DBusTag, driverData->eisaSystemDoorbellStatus,
       In8 (configTable->MLIDCFG_DBusTag, driverData->eisaSystemDoorbellStatus));

   /***********************************************************************\
   **    Return any receive ECB's.
   \***********************************************************************/

   numRCBs = TOTAL_RCBS - driverData->needRCBCount;

   while (numRCBs)
   {
      retRCB = driverData->hostRCBList [driverData->receiveQueueHead];
      CMSMReturnRCB (driverData, retRCB);
      driverData->receiveQueueHead = (driverData->receiveQueueHead + 1) & TABLE_MASK;
      numRCBs--;
   }

   /***********************************************************************\
   **    Return any transmit ECB's.
   \***********************************************************************/

   while (DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount != TOTAL_TCBS)
   {
      retTCB = driverData->hostTCBList [driverData->tcbQueueHead];
      driverData->tcbQueueHead = (driverData->tcbQueueHead + 1) & TCB_TABLE_MASK;
      DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount++;
      CEtherTSMFastSendComplete (driverData, retTCB, -1);
   }

   /***********************************************************************\
   **    Shutdown the initialization variables.
   \***********************************************************************/

   driverData->tcbQueueHead = 0;
   driverData->tcbQueueTail = 0;

   if (shutDownType == SHUTDOWN_PARTIAL)  /* or someday HSM_TEMPORARY_SHUTDOWN */
   {
      driverData->needRCBCount = TOTAL_RCBS;
   }
   else
   {
      /* We're in the process of totally shutting down the driver due
       * to a call to our DriverRemove. We reset NeedRCBCount to zero
       * so that any pending interrupts that invoke our DriverISR will
       * not cause this HSM to request more RCBs be allocated due to
       * the NeedRCBCount being non-zero.       LON 223362
       */

      driverData->needRCBCount = 0;
   }

   DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount = TOTAL_TCBS;

   for (i = 0; i < TABLE_SIZE; i++)
   {
      driverData->adapterRCBList[i] = (RCB *)-1;
      driverData->hostRCBList[i]    = 0;
   }

   for (i = 0; i < TCB_TABLE_SIZE; i++)
   {
      driverData->adapterTCBList[i] = (TCB *)-1;
      driverData->hostTCBList[i]    = 0;
   }

   return ODISTAT_SUCCESSFUL;
}

/**************************************************************************\
**
** PROC NAME:     DriverSend
**
**                This routine will called when the driver wants to
**                send a packet described in the TCB to the NIC and 
**                initiate the send.  txStartTime and retryCounter must be
**                set to enable the deadman timer.
**
** Parameters:    IN    DRIVER_DATA    *driverData
**                IN    FRAME_DS       *configTable
**                IN    TCB            *tcb
**                IN    UINT32         pktSize   
**                IN    TCB            *physTcb
**
**                driverData    - Pointer to HSM's adapter data space
**                configTable    - Pointer to HSM's frame data space
**                tcb     - Pointer to the TCB to be processed
**                pktSize - The length of the packet to be sent
**                physTcb - N/A
**
** Return Value:  NONE
**
** See Also:      ETHERTSM\CMediaSend
**                ETHERTSM\MediaSendRaw8023
**                ETHERTSM\MediaSendEthernetII
**                ETHERTSM\MediaSend8022Over8023
**                ETHERTSM\MediaSend8022Snap
**
\**************************************************************************/

void     DriverSend (
            DRIVER_DATA      *driverData,
            CONFIG_TABLE     *configTable, 
            TCB               *logTCB,
            UINT32            pktSize,
            void              *physTCB)
{
   TCB      *oldTCB;

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

   pktSize = pktSize;

   /***********************************************************************\
   **    Update the transmit lists.
   \***********************************************************************/

   driverData->hostTCBList    [driverData->tcbQueueTail] = logTCB;
   driverData->adapterTCBList [driverData->tcbQueueTail] = physTCB;
   driverData->txStartList    [driverData->tcbQueueTail] = CMSMGetCurrentTime ();

   /***********************************************************************\
   **    Set the TRANSMIT WAITING bit and adjust Q Tail.
   \***********************************************************************/

   Out8 (configTable->MLIDCFG_DBusTag, (void *) ((UINT8 *) driverData->tcbValidMailbox), (UINT8)((driverData->tcbQueueTail+1) & TCB_TABLE_MASK));
   
   driverData->tcbQueueTail = (driverData->tcbQueueTail + 1) & TCB_TABLE_MASK;

   /***********************************************************************\
   **    Check for transmit pending/done.
   \***********************************************************************/

   if ((DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount < (TOTAL_TCBS - 1)) &&
      (driverData->adapterTCBList [driverData->tcbQueueHead] == (struct _TCB_ *)-1))
   {
#ifdef OUT_CHAR
   NiosDebugCharOut ('t');
#endif /* OUT_CHAR */

      oldTCB = driverData->hostTCBList [driverData->tcbQueueHead];
      driverData->tcbQueueHead = (driverData->tcbQueueHead + 1) & TCB_TABLE_MASK;
      DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount++;
      CEtherTSMFastSendComplete (driverData, oldTCB, 0);
   }

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

}

/**************************************************************************\
**
** PROC NAME:     CFixUpStatStrings
**
**                This routine will be called to insert the description
**                strings for each counter.
**
** Parameters:    IN    DRIVER_DATA *driverData
**
**                driverData  - Pointer to HSM's AdapterDataSPace
**
** Return Value:  NONE
**
** See Also:      DriverInit
**
\**************************************************************************/

void CFixUpStatStrings (DRIVER_DATA *driverData) 
{
   driverData->TxRetryFailureTable.StatString          = (MEON_STRING *)CNE3200_TXRETRYFAIL_STR;
   driverData->ClearToSendTable.StatString             = (MEON_STRING *)CNE3200_CLEARSENDTABLE_STR;
   driverData->UnderRunTable.StatString                = (MEON_STRING *)CNE3200_UNDERRUN_STR;
   driverData->RxDMAOverrunTable.StatString            = (MEON_STRING *)CNE3200_RXDMAOVERRUN_STR;
   driverData->PacketSlideTable.StatString             = (MEON_STRING *)CNE3200_PACKETSLIDE_STR;
   driverData->DummyRCBTable.StatString                = (MEON_STRING *)CNE3200_DUMMYRCB_STR;
   driverData->AdapterReset1Table.StatString           = (MEON_STRING *)CNE3200_ADAPTERRESET_STR;
   driverData->BadFragLengthTable.StatString           = (MEON_STRING *)CNE3200_BADFRAGLEN_STR;
   driverData->PollingTimeoutTable.StatString          = (MEON_STRING *)CNE3200_POLLTIMEOUT_STR;
   driverData->AdapterDiedTable.StatString             = (MEON_STRING *)CNE3200_ADAPTERDIED_STR;
   driverData->NumberOfIntsFiredTable.StatString       = (MEON_STRING *)CNE3200_NUMINTSFIRED_STR;
}     

/**************************************************************************\
**
** PROC NAME:     DriverCallBack
**
**                This routine will be executed once every 1/2 second.  It
**                will detect if the hardware does NOT complete a 
**                transmission.  If this happens, the harware 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.
**
** Parameters:    IN    DRIVER_DATA    *driverData
**                IN    FRAME_DS       *configTable
**
**                driverData  - Pointer to HSM's adapter data space
**                configTable  - Pointer to HSM's frame data space
**
** Return Value:  NONE
**
** See Also:      CMSM
**
\**************************************************************************/

void     DriverCallBack (
            DRIVER_DATA    *driverData, 
            CONFIG_TABLE   *configTable) 
{
#ifdef OUT_CHAR
   NiosDebugCharOut ('c');
#endif /* OUT_CHAR */

   if (driverData->updateStatCount >= 8)   /* 4 sec yet ?   */
   {

      /********************************************************************\
      **    Tell the adapter to update the statistics.
      \********************************************************************/

      driverData->updateStatCount = 0;
      Out8 (configTable->MLIDCFG_DBusTag, driverData->updateStatMailbox, 1);
   
   }

   /***********************************************************************\
   **    Check for transmits pending, then transmits complete.
   \***********************************************************************/

   if (DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount == TOTAL_TCBS)
      return;

   if (driverData->adapterTCBList [driverData->tcbQueueHead] == (struct _TCB_ *)-1)
      return;

   /***********************************************************************\
   **    Looks like we have a transmit pending AND its NOT yet complete.
   **    See if its DEAD.
   \***********************************************************************/

   if ((CMSMGetCurrentTime () - driverData->txStartList [driverData->tcbQueueHead]) >= DEADMAN_TIMEOUT)
   {
      driverData->AdapterDiedCount++;
      DriverReset (driverData, configTable, OP_SCOPE_ADAPTER);
   }
}

/**************************************************************************\
**
** PROC NAME:     DriverISR
**
**                This routine handles packet reception/errors and transmit
**                complete/errors interrupts.
**
** Parameters:    IN    DRIVER_DATA    *driverData
**
**                driverData  - Pointer to HSM's adapter data space
**
** Return Value:  NONE
**
** See Also:      CMSM\CMSMInterruptProcedure0
**
\**************************************************************************/

void   DriverISR (DRIVER_DATA *driverData)
{
   CONFIG_TABLE         *configTable;
   RCB                  *logRCB;
   RCB                  *physRCB;
   TCB                  *logTCB;
   UINT32               pktSize;
   UINT8                sInts;
   UINT32               oldRcvQHead;

   sInts = sInts;                        /* Keep compiler happy for now */

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

   configTable = DADSP_TO_CMSMADSP (driverData)->CMSMDefaultVirtualBoard;

   /***********************************************************************\
   **    See if we are in our polling routine.
   \***********************************************************************/

   driverData->NumberOfIntsFiredCount++;
   if (driverData->inDriverPoll)
      return;

   /***********************************************************************\
   **    <<< Check RCBs >>>
   **    Check for ALL RCB's and pass them up to LSL for processing.
   \***********************************************************************/

   while (!driverData->adapterRCBList [driverData->receiveQueueHead])
   {

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

      /********************************************************************\
      **    Adjust receive lists.
      \********************************************************************/

      driverData->adapterRCBList [driverData->receiveQueueHead] = (RCB *) -1;
      logRCB = driverData->hostRCBList [driverData->receiveQueueHead];

      oldRcvQHead = driverData->receiveQueueHead;
      
      driverData->receiveQueueHead = (driverData->receiveQueueHead + 1) & TABLE_MASK;
      driverData->needRCBCount++;

      /********************************************************************\
      **    We are going to use the FastRcvComplete call to process the
      **    ECB that we have gotten from the adapter.  The only problem
      **    with this is, the old firmware does NOT put the rcvStatus into
      **    the correct field of the ECB.  The current "C" spec has the
      **    rcvStatus placed in the ECB_PreviousLink field.  The firmware
      **    places the rcvStatus into the ProtocolWorkspace.  Therefore, we
      **    must copy it to the correct location.  This means we are 95% 
      **    ECB aware but not quite 100% like we should be without changing
      **    the firmware.
      \********************************************************************/

      ((ECB *) logRCB)->ECB_PreviousLink = (ECB *) (((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [0]);
      pktSize = (((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [1]);
      ((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [0] = driverData->hostPWSList1 [oldRcvQHead];
      ((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [1] = driverData->hostPWSList2 [oldRcvQHead];

      CEtherTSMFastRcvCompleteStatus (
         driverData, 
         logRCB, 
         pktSize,
         (UINT32)((ECB *) logRCB)->ECB_PreviousLink);
   }

   /***********************************************************************\
   **    <<< Pre-Allocate RCBs >>>
   **    Now that we have processed all the RCB's, let's see if we need
   **    to preallocate any more for the packets coming in off the wire.
   \***********************************************************************/

   while (driverData->needRCBCount)
   {

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

      if (logRCB = CMSMAllocateRCB (driverData, commonMaximumSize, &physRCB)) 
      {
         driverData->needRCBCount--;
         driverData->hostPWSList1   [driverData->receiveQueueTail] = ((ECB *)logRCB)->ECB_ProtocolWorkspace.PWs_i32val [0];
         driverData->hostPWSList2   [driverData->receiveQueueTail] = ((ECB *)logRCB)->ECB_ProtocolWorkspace.PWs_i32val [1];
         driverData->hostRCBList    [driverData->receiveQueueTail] = logRCB;
         driverData->adapterRCBList [driverData->receiveQueueTail] = physRCB;
         driverData->receiveQueueTail = (driverData->receiveQueueTail + 1) & TABLE_MASK;
      }
      else
         break;
   }

   /***********************************************************************\
   **    <<< Check TCBs >>>
   **    Now we have completely pre-allocated as many RCB's as we can. 
   **    Let's check out the transmits that are finished.
   \***********************************************************************/

   while ((DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount != TOTAL_TCBS) &&
         (driverData->adapterTCBList [driverData->tcbQueueHead] == (struct _TCB_ *)-1))
   {

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

      logTCB = driverData->hostTCBList [driverData->tcbQueueHead];
      driverData->tcbQueueHead = (driverData->tcbQueueHead + 1) & TCB_TABLE_MASK;
      DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount++;
      CEtherTSMFastSendComplete (driverData, logTCB, 0);
   }

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

   return;
}

/**************************************************************************\
**
** PROC NAME:     DriverPoll
**
**                This routine will be called by the MSM/OS as dictated by
**                the internal polling loop.  This will be used as a backup
**                to the interrupt method.
**
** Parameters:    IN    DRIVER_DATA    *driverData
**                IN    FRAME_DS       *configTable
**
**                driverData  - Pointer to HSM's adapter data space
**                configTable  - Pointer to HSM's frame data space
**
** Return Value:  NONE
**
** See Also:      
**
\**************************************************************************/

void     DriverPoll (
            DRIVER_DATA    *driverData, 
            CONFIG_TABLE   *configTable) 
{
   RCB                  *logRCB;
   RCB                  *physRCB;
   TCB                  *logTCB;
   UINT32               pktSize;
   UINT32               oldRcvQHead;

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

   /***********************************************************************\
   **    Set in driver poll semaphore and do mailbox thing.
   \***********************************************************************/

   driverData->inDriverPoll = 1;
   Out8 (configTable->MLIDCFG_DBusTag, driverData->pollingMailbox, 0);
   
   /***********************************************************************\
   **    <<< Check RCBs >>>
   **    Check for ALL RCB's and pass them up to LSL for processing.
   \***********************************************************************/

   while (((UINT32) driverData->adapterRCBList [driverData->receiveQueueHead]) <= MAX_PACKET_SIZE)
   {

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

      /********************************************************************\
      **    Adjust receive lists.
      \********************************************************************/

      driverData->adapterRCBList [driverData->receiveQueueHead] = (RCB *) -1;
      logRCB = driverData->hostRCBList [driverData->receiveQueueHead];

      oldRcvQHead = driverData->receiveQueueHead;
      
      driverData->receiveQueueHead = (driverData->receiveQueueHead + 1) & TABLE_MASK;
      driverData->needRCBCount++;

      /********************************************************************\
      **    We are going to use the FastRcvComplete call to process the
      **    ECB that we have gotten from the adapter.  The only problem
      **    with this is, the old firmware does NOT put the rcvStatus into
      **    the correct field of the ECB.  The current "C" spec has the
      **    rcvStatus placed in the ECB_PreviousLink field.  The firmware
      **    places the rcvStatus into the ProtocolWorkspace.  Therefore, we
      **    must copy it to the correct location.  This means we are 95% 
      **    ECB aware but not quite 100% like we should be without changing
      **    the firmware.
      \********************************************************************/

      ((ECB *) logRCB)->ECB_PreviousLink = (ECB *) (((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [0]);
      pktSize = (((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [1]);
      ((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [0] = driverData->hostPWSList1 [oldRcvQHead];
      ((ECB *) logRCB)->ECB_ProtocolWorkspace.PWs_i32val [1] = driverData->hostPWSList2 [oldRcvQHead];

      CEtherTSMFastRcvCompleteStatus (
         driverData, 
         logRCB, 
         pktSize,
         (UINT32)((ECB *) logRCB)->ECB_PreviousLink);
   }

   /***********************************************************************\
   **    <<< Pre-Allocate RCBs >>>
   **    Now that we have processed all the RCB's, let's see if we need
   **    to preallocate any more for the packets coming in off the wire.
   \***********************************************************************/

   while (driverData->needRCBCount)
   {

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

      if (logRCB = CMSMAllocateRCB (driverData, commonMaximumSize, &physRCB))
      {
         driverData->needRCBCount--;
         driverData->hostPWSList1   [driverData->receiveQueueTail] = ((ECB *)logRCB)->ECB_ProtocolWorkspace.PWs_i32val [0];
         driverData->hostPWSList2   [driverData->receiveQueueTail] = ((ECB *)logRCB)->ECB_ProtocolWorkspace.PWs_i32val [1];
         driverData->hostRCBList    [driverData->receiveQueueTail] = logRCB;
         driverData->adapterRCBList [driverData->receiveQueueTail] = physRCB;
         driverData->receiveQueueTail = (driverData->receiveQueueTail + 1) & TABLE_MASK;
      }
      else
         break;
   }

   /***********************************************************************\
   **    <<< Check TCBs >>>
   **    Now we have completely pre-allocated as many RCB's as we can. 
   **    Let's check out the transmits that are finished.
   \***********************************************************************/

   while ((DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount != TOTAL_TCBS) &&
         (driverData->adapterTCBList [driverData->tcbQueueHead] == (struct _TCB_ *) -1))
   {

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

      logTCB = driverData->hostTCBList [driverData->tcbQueueHead];
      driverData->tcbQueueHead = (driverData->tcbQueueHead + 1) & TCB_TABLE_MASK;
      DADSP_TO_CMSMADSP (driverData)->CMSMTxFreeCount++;
      CEtherTSMFastSendComplete (driverData, logTCB, 0);
   }

   driverData->inDriverPoll = 0;

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

   return;
}

/**************************************************************************\
**
** PROC NAME:     DriverDisableInterrupt
**
**                This routine will disable the adapters ability to
**                to interrupt the host.
**
** Parameters:    IN    DRIVER_DATA    *driverData
**
**                driverData  - Pointer to HSM's adapter data space
**                  flag   - TRUE if function is to return a value, else FALSE.
**                        
**
** Return Value:  TRUE if adapter generated the interrupt, else FALSE.
**
** See Also:      DriverEnableInterrupt
**
\**************************************************************************/

BOOLEAN  DriverDisableInterrupt (DRIVER_DATA *driverData, BOOLEAN flag) 
{
#ifdef OUT_CHAR
   NiosDebugCharOut ('{');
#endif /* OUT_CHAR */

   if (driverData->inDriverDisable)         /* We're already disabled, just return   */
      return (FALSE);

   if (flag)   
   {            /* We need to return value indicating if int is ours or not   */
      if (In8 (driverData->busTag, driverData->eisaSystemDoorbellStatus) & 1)         
      {                /* We generated the interrupt, first disable doorbell   */
         Out8 (driverData->busTag, driverData->eisaSystemDoorbellEnable, 0);   
         driverData->inDriverDisable = 1;               /* Set flag we're disabled   */
                                                /*  then reset our status   */
         Out8 (driverData->busTag, driverData->eisaSystemDoorbellStatus, 1);   
         return (TRUE);
      }
   }

/* 
** Either flag is FALSE or it's not our interrupt, disable NE3200's interrupt
** mechanism only.
*/

   Out8 (driverData->busTag, driverData->eisaSystemDoorbellEnable, 0);   
   driverData->inDriverDisable = 1;                  /* Set flag we're disabled   */
   return (FALSE);
}

/**************************************************************************\
**
** PROC NAME:     DriverEnableInterrupt
**
**                This routine will enable the adapters ability to
**                interrupt the host.
**
** Parameters:    IN    DRIVER_DATA    *driverData
**
**                driverData  - Pointer to HSM's adapter data space
**
** Return Value:  0 = successful
**                1 = unsuccessful
**
** See Also:      DriverDisableInterrupt
**
\**************************************************************************/

void     DriverEnableInterrupt (DRIVER_DATA *driverData) 
{
#ifdef OUT_CHAR
   NiosDebugCharOut ('}');
#endif /* OUT_CHAR */
   
   driverData->inDriverDisable = 0;                     /* Clear ints disable flag   */

/* 
**   If we have an interrupt pending, this output to eisaSystemDoorbellStatus
** will clear it, which will cause a spurious interrupt.
**
**   Best to just re-enable the adapters interrupts and if one is pending then
** we will re-enter or interrupt routine to deal with it and not miss it and
** hence no spurious interrupts.
*/

   Out8 (driverData->busTag, driverData->eisaSystemDoorbellEnable, 1);
}

/**************************************************************************\
**
** PROC NAME:     WaitForEvent
**
**                This routine sits around and waits for either the event
**                to occur or the timeout to occur.
**
** Parameters:    IN    DRIVER_DATA    *driverData
**
**                driverData  - Pointer to HSM's adapter data space
**
** Return Value:  0 = successful
**                1 = unsuccessful
**
** See Also:      
**
\**************************************************************************/

UINT32   WaitForEvent (
            DRIVER_DATA *driverData, 
            void        *port, 
            UINT8       type, 
            UINT32      timeout)
{
   UINT32   ccode;

//JCJ 20-Aug-1997 SPD# 159385 Wait loop has been modified to a simple counter
//                            based one from a timer based loop.  Because we
//                            can't let other process to run at this time.
   do
   {
      timeout--;
      switch (type)
      {
         case WAIT_BYTE_SET:
            if (ccode = (UINT32) In8 (driverData->busTag, port))
            {
               return (ccode);
            }
            break;

         case WAIT_BYTE_CLEAR:
            if (!(ccode = (UINT32) In8 (driverData->busTag, port)))
            {
               return (ccode);
            }
            break;

         case WAIT_FIRMWARE:
            ccode = In32 (driverData->busTag, port);
            if (ccode == FIRMWARE_RUNNING)
            {
               return (ccode);
            }
            break;

         case WAIT_TIMEOUT:
            break;
      }
   }while(timeout);

   return 0;
}