www.pudn.com > VxWorksENDv306.zip > csSysEnd.c


/* csSysEnd.c - PCx86 or ARM system-dependent module for CS8900 Ethernet driver */ 
/*                                                                          */ 
/* Copyright 2000 Crystal Semiconductor Corp.                               */ 
/*                                                                          */ 
/*               Last release: v3.05a                                       */ 
/* Mod level for last release: 05a                                          */ 
 
/* 
MODIFICATION HISTORY 
-------------------- 
v3.05a,06/26/01, kml - Added Support for Interrupt Level and Interrupt Vector for  
                       Non-Ix86 processors.  
					 - Added CS8900_INTERRUPT_REQUEST_PIN_NUM for Non-Ix86 processors to  
					   write their interrupt pin number to InterruptNumber Register. 
                     - Modified the code so that logMsg is used only when CS_DEBUG_ENABLE is 
					   defined.  Thus, compiler warning mesages can be avoided if  
					   CS_DEBUG_ENABLE is not defined. 
                     - Added "Define your BSP Type" for users to define their 
					   CS_BSP_TYPE string. 
 
 
v3.03a,10/02/00, kml -Merged for PCx86 and ARM. 
 
   June 20000        -Modified for ARM 940 by Conexant Systems, Inc.                      
 
v3.02a,24Sep99, kml  -Set offset 2 to the receiving buffer pointer when copying received frames from chip 
                      so that the IP header stars from the 17th bytes for 32-bits-Alignment. 
                     -Change receiving buffer size from 32 to 64. 
                     -Correction: If the memory address parameter is zero, the CS8900 operates in the 
                      mode specified by EEPROM or the Config Flag parameter. 
 
v3.01a,07May, kml    ported to the Enhanced Network Driver (END) model  
                       to support the MUX interface:   
 
 
10f,11apr97,rks  Added variables for "early tx" support to CS_END_DEVICE structure 
                 (TxUnderruns, TotalTxUnderruns, TxStartCMD, and TxLenght. 
 
10e,05apr97,rks  Added CS_MAX_NET_JOBS and STRESS_TESTING defines. 
 
10d,11mar97,rks  Moved some typedefs to this file so "config.h" could include 
                 "if_cs.h" easily.  
 
01c,25feb97,rks  Changed SysEnetAddrGet parameters to Unit, IA addr pointer 
 
01b,31jan97,rks  Modified sysEnetAddrGet to take Ethernet address from EEPROM 
                 or from the csEnetAddr array based on the value of the  
                 GET_ENET_ADDR_FROM_BOARD flag. 
		  
01a,16dec96,rks  Written (using routines originally written by q_s in "if_cs.c". 
*/ 
 
 
/* 
DESCRIPTION 
 
This module provides PCx86 and ARM board-specific routines and data types require 
by the Crystal Semiconductor CS8900 Ethernet VxWorks END network interface driver.   
It implements five routines called from the "csEnd.c" main driver module: 
 
* sysEnetGetConfig( CS_END_DEVICE *pCS ) 
This routine takes configuration parameters not specifed to csLoad(), if any, 
from non-volatile storage (e.g. an attached EEPROM) and puts them in the  
CS_END_DEVICE structure. If all the parameters were specified to csLoad(), then  
this routine does not attempt to read the EEPROM. 
 
* sysEnetAddrGet( CS_END_DEVICE pCS, unsigned char *pAddr ) 
This routine obtains the Ethernet MAC address from non-volatile storage or from  
the "csEnetAddr" array defined in csSysEnd.c and saves it in the CS_END_DEVICE 
structure. 
 
* sysEnetHWInit( CS_END_DEVICE *pCS ) 
This routine uses global variables in the CS_END_DEVICE structure to configure the  
adapter for the board-specific IO circuitry and supported media types. 
 
* sysEnetIntEnable( CS_END_DEVICE *pCS ) 
This routine enables the interrupt used by the CS8900 at the system level.  
  
* sysEnetIntDisable( CS_END_DEVICE *pCS ) 
This routine disables the interrupt used by the CS8900 at the system level.   
*/ 
 
 
 
/* DEFINES */ 
 
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 
 * Driver Configuration Defines                                            * 
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 
 
/* Maximum number of CS8900 chips supported */ 
 
#define CS_MAX_NUM_UNITS        1  
 
 
/* Maximum number of receive buffers */  
      
#define CS_NUM_RX_BUFFERS      64 
 
/* Minimum bytes of first buffer for chain used by scattered transmission. */ 
#define CS_MIN_FBUF  5 
 
/* Number of elements held by TX and RX queues */ 
#define CS_QUEUE_SIZE  200  /* @kml */ 
 
 
/* Initial TXStartCMD (number of bytes to buffer before CS8900 starts the TX */ 
/* Select one of: [TX_CMD_START_5 | TX_CMD_START_381 | TX_CMD_START_1021 |  
 * TX_CMD_START_ALL ] */ 
 
#define CS_INITIAL_START_CMD	TX_CMD_START_5 
 
/* Number of underruns with current TXStartCMD before TXStartCMD is set to next value */ 
 
#define CS_TX_UNDRUN_TRHSHOLD   2  
 
/* BSP type supported by this driver */  
#if CPU_FAMILY ==  ARM  
#define CS_BSP_TYPE	"ARM" 
 
#elif  CPU_FAMILY ==  MIPS          
#define CS_BSP_TYPE	"MIPS" 
 
#elif  CPU_FAMILY == I80X86 
#define CS_BSP_TYPE	"i[3|4]86" 
 
#else 
#define CS_BSP_TYPE	"Unknown BSP Type" 
#endif 
 
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 
 * Miscellaneous and BSP-specific defines                                  * 
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 
 
/* Define a unique cluster type */ 
 
/*  
This flag determines if the Ethernet address is taked from EEPROM or from 
the csEnetAddr array defined below.  Define as 0 to take the Ethernet address 
from csEnetAddr.  WARNING! The Ethernet address must be unique for each Ethernet 
device on the network. 
*/ 
 
#define GET_ENET_ADDR_FROM_BOARD  1 
 
/*  
These macros are used to communicate with the CS8900. These functions need to be supplied  
by syslib.c 
*/ 
  
/* Macros used to provide platform independence for IO accesses */ 
 
#if CPU_FAMILY ==  ARM 
#define SYS_ENET_OUT_WORD(port, value)	sysOutWord((int)(port), (value)) 
#define SYS_ENET_IN_WORD(port)			sysInWord((int)(port)) 
#define SYS_ENET_IN_BYTE(port)			sysInByte((int)(port)) 
#else 
#define SYS_ENET_OUT_WORD(port, value)	sysOutWord(port, value) 
#define SYS_ENET_IN_WORD(port)			sysInWord(port) 
#define SYS_ENET_IN_BYTE(port)			sysInByte(port) 
#endif 
 
/* TYPEDEFS */ 
 
/* Individual Address (Ethernet Address) */ 
typedef struct 
{ 
   USHORT word[3]; 
} IA, *PIA; 
 
 
 
typedef struct  
{ 
    void  *Queue[CS_QUEUE_SIZE+1]; 
    int    Head; 
    int    Tail;    
} CIR_QUEUE;  
 
 
#if CPU_FAMILY ==  ARM 
typedef unsigned long IOADDR;    /* IO space address is 32-bit */ 
#else 
typedef unsigned short IOADDR;    /* IO space address is 16-bit */ 
IMPORT UINT sysVectorIRQ0;           /* vector for IRQ0 */ 
#endif 
 
/* Driver control structure for a single unit */ 
 
typedef struct 
{ 
   END_OBJ    end; 
   int        unit; 
   UCHAR      enetAddr[6]; 
   IOADDR     IOAddr; 
   USHORT     IntLevel; 
   USHORT     IntVector; 
   unsigned short    *pPacketPage;       
   USHORT     MediaType; 
   USHORT     ConfigFlags; 
   BOOL       InMemoryMode; 
   BOOL       Resetting; 
   USHORT     MaxTxDepth; 
   USHORT     TxQueueDepth; 
   USHORT     MaxTxQueueDepth; 
   UINT	      Rdy4TxInts; 
   M_BLK_ID   pTxFrameChain; 
   BOOL       TxInProgress; 
   BOOL       InISR; 
   CIR_QUEUE *pTxBuffFreeList; 
   CIR_QUEUE *pRxBuffProcessList; 
   CIR_QUEUE *pTxQueue; 
   UINT	      NetJobDepth; 
   USHORT     TxStartCMD; 
   USHORT     TxUnderruns; 
   UINT       TotalTxUnderruns; 
   UINT       TxLength; 
   UINT       Collisions; 
   CL_POOL_ID pClPoolId; 
   USHORT     MulticastTable[4]; 
} CS_END_DEVICE; 
 
 
 
/* Define GET_ENET_ADDR_FROM_BOARD as 0 to take the Ethernet address 
from csEnetAddr.  */ 
 
/* LOCALS */ 
unsigned char csEnetAddr [6] = { 0x08, 0x00, 0x20, 0x74, 0x80, 0xa7 }; 
 
/* Instance variables */ 
LOCAL CS_END_DEVICE cs_end[CS_MAX_NUM_UNITS];   
CIR_QUEUE TxBuffFreeList; 
CIR_QUEUE RxBuffProcessList; 
CIR_QUEUE TxQueue; 
 
 
 
/* For ARM user only:   */ 
/* The following code is specific for Conexant IRD, ARM 940. You can take it as an 
   example or ignore it. */ 
 
/* @Conexant ARM 940 specific code */  
/* 
#include "basetype.h" 
#include "sabine.h" 
#include "hwconfig.h" 
#include "hwlib.h" 
#include "retcodes.h" 
 
extern  PFNISR  ethernetChainNode;  // ISR linked list node storage 
extern  void csIntr(CS_END_DEVICE *arg); 
 
CS_END_DEVICE *EndObject; 
 
int ethernetIntHandler(unsigned int IntID, int FIQ, PFNISR *nextNode) 
{ 
 
    csIntr(EndObject); 
    *nextNode = ethernetChainNode; 
    return(RC_ISR_NOTHANDLED);  // All PCI ints return this 
} 
 
void    init_cs8900(void) 
{ 
 
   // Set the memory base address 
   SYS_ENET_OUT_WORD(0x3150030a, 0x002c); 
   SYS_ENET_OUT_WORD(0x3150030c, 0x0000); 
   SYS_ENET_OUT_WORD(0x3150030a, 0x002e); 
   SYS_ENET_OUT_WORD(0x3150030c, 0x0000); 
 
   int_register_isr(INT_GPIO68, (PFNISR)ethernetIntHandler, FALSE, FALSE, 
                   ðernetChainNode); 
   set_gpio_int_edge(68, POS_EDGE); 
}     
 
 
 
int    sysCsIntAck(void) 
{ 
     
    clear_pic_interrupt(PIC_GPIO, INT_GPIO68); 
    return 1; 
} 
*/ 
/* end of Conexant IRD, ARM 940 */ 
 
 
 
/* Crystal Semiconductor supplied code */ 
 
/* FORWARD DECLARATIONS */ 
LOCAL STATUS sysEnetGetConfig( CS_END_DEVICE *pCS ); 
LOCAL STATUS sysEnetAddrGet( CS_END_DEVICE *pCS, unsigned char *pAddr ); /*@kml*/ 
LOCAL void   sysEnetHWInit( CS_END_DEVICE *pCS ); 
LOCAL STATUS sysEnetIntEnable( CS_END_DEVICE *pCS ); 
LOCAL STATUS sysEnetIntDisable( CS_END_DEVICE *pCS );  /*@kml*/ 
 
 
/* sub-routines for above functions */ 
 
LOCAL STATUS csGetUnspecifiedParms( CS_END_DEVICE *pCS ); 
LOCAL STATUS csValidateParms( CS_END_DEVICE *pCS ); 
LOCAL STATUS csReadEEPROM( CS_END_DEVICE *pCS, USHORT Offset, USHORT *pValue ); 
 
#ifdef TRUE 
/* These routines defined in csEnd.c but available for use here. */ 
/* Ifdef FALSE if none are called from this module */ 
#define DECLARED_IN_SYS_ENET 
LOCAL USHORT csReadPacketPage( CS_END_DEVICE *pCS, USHORT Offset ); 
LOCAL void   csWritePacketPage( CS_END_DEVICE *pCS, USHORT Offset, USHORT Value ); 
#endif 
 
 
#define MAXLOOP       0x8888  /* Delay loop counter  */         
 
 
/****************************************************************************** 
* 
* sysEnetGetConfig - Get any CS8900 parameters not specifed to csLoad 
* 
* This routine gets parameters that were not specifed to csAttach() from an  
* EEPROM, if used, and puts them in the CS_END_DEVICE structure.  If all the  
* parameters were specified to csAttach(), then this routine does not attempt  
* to read the EEPROM. 
* 
* RETURNS: OK or ERROR 
* 
*/ 
 
LOCAL STATUS sysEnetGetConfig( CS_END_DEVICE *pCS ) 
{ 
	/* Get parameters, which were not specified, from the EEPROM */ 
   if ( csGetUnspecifiedParms(pCS) == ERROR ) 
      return ERROR; 
 
	/* Verify that parameters are valid */ 
   if ( csValidateParms(pCS) == ERROR ) 
      return ERROR; 
 
   /* If memory address was specified but configuration flags were not */ 
   if ( pCS->pPacketPage != 0  ) 
      pCS->ConfigFlags |= CFGFLG_MEM_MODE;  /* Implictly set memory mode */ 
 
   /* If the interrupt vector was not specified then derive it */ 
   if ( pCS->IntVector == 0 ) { 
#if CPU_FAMILY == I80X86 
    pCS->IntVector = sysVectorIRQ0 + pCS->IntLevel; 
#else 
     pCS->IntVector = pCS->IntLevel; 
#endif 
   } 
	return OK; 
} 
 
 
/******************************************************************************* 
* 
* sysEnetAddrGet - saves the Ethernet address to the CS_END_DEVICE structure 
* 
* The Ethernet address is taked from EEPROM or from the csEnetAddr array  
* then the Ethernet address was saved in the CS_END_DEVICE structure. 
* 
* pAddr: the pointer points to the array holding Ethernet Addr in CA_END_DEVICE 
* 
* RETURNS: OK or ERROR 
*/ 
 
LOCAL STATUS sysEnetAddrGet( CS_END_DEVICE *pCS, unsigned char *pAddr ) 
{ 
   USHORT SelfStatus; 
   PIA pIA; 
 
 
   /* Setup pointer for the Ethernet address */ 
   pIA = (PIA)pAddr; 
 
   /* If the Ethernet address in EEPROM */ 
   if ( GET_ENET_ADDR_FROM_BOARD )   /* defined in config.h */ 
   { 
      /* Verify that the EEPROM is present and OK */ 
      SelfStatus = csReadPacketPage( pCS, PKTPG_SELF_ST ); 
      if ( !((SelfStatus & SELF_ST_EEP_PRES) && (SelfStatus & SELF_ST_EEP_OK))) 
      { 
#ifdef CS_DEBUG_ENABLE 
         logMsg("\ncs0 - EEPROM is missing or bad\n",0,0,0,0,0,0); 
#endif 
         return ERROR; 
      } 
 
      /* Get Ethernet address from the EEPROM */ 
      if ( csReadEEPROM(pCS,EEPROM_IND_ADDR_H,&pIA->word[0]) == ERROR ) 
         return ERROR; 
      if ( csReadEEPROM(pCS,EEPROM_IND_ADDR_M,&pIA->word[1]) == ERROR ) 
         return ERROR; 
      if ( csReadEEPROM(pCS,EEPROM_IND_ADDR_L,&pIA->word[2]) == ERROR ) 
         return ERROR; 
   } 
   else  /* Use Ethernet Address defined in csEnetAddr */ 
      bcopyBytes ((char *) csEnetAddr, (char *) pIA, 6); 
 
   return OK; 
} 
 
 
/******************************************************************************* 
* 
* sysEnetHWInit - configure the adapter for board-specific IO and media support 
* 
* This routine uses global variables in the CS_END_DEVICE structure to configure the  
* adapter for the board-specific IO circuitry and media types supported. 
*         
* RETURNS: Nothing 
*          
*/ 
 
LOCAL void sysEnetHWInit( CS_END_DEVICE *pCS ) 
{ 
   USHORT BusCtl; 
   USHORT SelfCtl; 
   IOADDR DataPort; 
   IOADDR AddrPort; 
 
   DataPort=pCS->IOAddr + PORT_PKTPG_DATA; 
   AddrPort=pCS->IOAddr + PORT_PKTPG_PTR; 
 
   /* If memory mode is enabled */ 
   if ( pCS->ConfigFlags & CFGFLG_MEM_MODE ) 
   { 
      /* If external logic is present for address decoding */ 
      if ( csReadPacketPage(pCS,PKTPG_SELF_ST) & SELF_ST_EL_PRES ) 
      { 
         /* Program the external logic to decode address bits SA20-SA23 */ 
         csWritePacketPage( pCS, PKTPG_EEPROM_CMD, 
               ((UINT)(pCS->pPacketPage)>>20) | EEPROM_CMD_ELSEL ); 
      } 
 
      /* Setup chip for memory mode */ 
      csWritePacketPage( pCS, PKTPG_MEM_BASE, (UINT)(pCS->pPacketPage)&0xFFFF ); 
      csWritePacketPage( pCS, PKTPG_MEM_BASE+2, (UINT)(pCS->pPacketPage)>>16 ); 
      BusCtl = BUS_CTL_MEM_MODE; 
      if ( pCS->ConfigFlags & CFGFLG_USE_SA ) 
         BusCtl |= BUS_CTL_USE_SA; 
      csWritePacketPage( pCS, PKTPG_BUS_CTL, BusCtl ); 
 
      /* We are in memory mode now! */ 
      pCS->InMemoryMode = TRUE; 
   } 
 
   /* If IOCHRDY is enabled then clear the bit in the BusCtl register */ 
   BusCtl = csReadPacketPage( pCS, PKTPG_BUS_CTL ); 
   if ( pCS->ConfigFlags & CFGFLG_IOCHRDY ) 
      csWritePacketPage( pCS, PKTPG_BUS_CTL, BusCtl & ~BUS_CTL_IOCHRDY ); 
   else 
      csWritePacketPage( pCS, PKTPG_BUS_CTL, BusCtl | BUS_CTL_IOCHRDY ); 
 
   /* Set the Line Control register to match the media type */ 
   if ( pCS->MediaType == MEDIA_10BASET ) 
      csWritePacketPage( pCS, PKTPG_LINE_CTL, LINE_CTL_10BASET ); 
   else 
      csWritePacketPage( pCS, PKTPG_LINE_CTL, LINE_CTL_AUI_ONLY ); 
 
   /* Set the BSTATUS/HC1 pin to be used as HC1 */ 
   /* HC1 is used to enable the DC/DC converter */ 
   SelfCtl = SELF_CTL_HC1E; 
 
   /* If the media type is 10Base2 */ 
   if ( pCS->MediaType == MEDIA_10BASE2 ) 
   { 
      /* Enable the DC/DC converter */ 
      /* If the DC/DC converter has a low enable */ 
      if ( (pCS->ConfigFlags & CFGFLG_DCDC_POL) == 0 ) 
         /* Set the HCB1 bit, which causes the HC1 pin to go low */ 
         SelfCtl |= SELF_CTL_HCB1; 
   } 
   else  /* Media type is 10BaseT or AUI */ 
   { 
      /* Disable the DC/DC converter */ 
      /* If the DC/DC converter has a high enable */ 
      if ( (pCS->ConfigFlags & CFGFLG_DCDC_POL) != 0 ) 
         /* Set the HCB1 bit, which causes the HC1 pin to go low */ 
         SelfCtl |= SELF_CTL_HCB1; 
   } 
   csWritePacketPage( pCS, PKTPG_SELF_CTL, SelfCtl ); 
 
   /* If media type is 10BaseT */ 
   if ( pCS->MediaType == MEDIA_10BASET ) 
   { 
      /* If full duplex mode then set the FDX bit in TestCtl register */ 
      if ( pCS->ConfigFlags & CFGFLG_FDX ) 
         csWritePacketPage( pCS, PKTPG_TEST_CTL, TEST_CTL_FDX ); 
   } 
  
} 
 
 
 
/****************************************************************************** 
* 
* sysEnetIntEnable - enable CS8900 interrupts at the system level 
* 
* This routine enables the interrupt used by the CS8900 at the system level.   
* For the i386/i486 BSPs, this is done by making the system call  
* sysIntEnablePIC to enable the CS8900's interrupt at the 8259 PIC. 
* 
* RETURNS: OK or ERROR 
*/ 
 
LOCAL STATUS sysEnetIntEnable( CS_END_DEVICE *pCS ) 
{ 
#if CPU_FAMILY == ARM 
	/* For ARM user: 
	   Please make sure how to enable your ARM interrupt for CS8900. */ 
   /* Enable interrupt at the Interrupt Controller */ 
    int_enable(INT_GPIO68);  /* turn on the GPIO IRQ bit*/ 
#else 
   /* For generic processor */ 
   /*  intEnable(pCS->IntLevel); */ 
 
   /* Enable interrupt at the 8259 PIC */ 
   if ( sysIntEnablePIC(pCS->IntLevel) == ERROR ) 
   { 
      return ERROR; 
   } 
#endif 
 
   return OK; 
} 
 
 
/****************************************************************************** 
* 
* sysEnetIntDisable - disable CS8900 interrupts at the system level 
* 
* This routine disables the interrupt used by the CS8900 at the system level.   
* For the i386/i486 BSPs, this is done by making the system call  
* sysIntDisablePIC to disable the CS8900's interrupt at the 8259 PIC. 
* 
* NOTE: This routine is not currently required by the CS8900 driver. 
* 
* RETURNS: OK or ERROR 
*/ 
 
LOCAL STATUS sysEnetIntDisable( CS_END_DEVICE *pCS ) 
{ 
    
#if CPU_FAMILY == ARM 
	/* For ARM user: 
	   Please make sure how to disable your ARM interrupt for CS8900.*/ 
   /* disable interrupt at the Interrupt Controller */ 
  int_disable(INT_GPIO68);/* turn off the GPIO IRQ bit*/ 
#else 
   /* For generic processor */ 
   /*  intDisable(pCS->IntLevel); */ 
 
   if ( sysIntDisablePIC(pCS->IntLevel) == ERROR ) 
   { 
      return ERROR; 
   } 
#endif 
 
   return OK; 
} 
 
void   INT_UNLOCK(int lockKey) 
{ 
#if CPU_FAMILY ==  ARM 
/* For ARM User: 
   Please modify these two functions to fit your board.*/ 
   int_enable(INT_GPIO68); /*turn on the GPIO IRQ bit*/ 
#else 
     intUnlock(lockKey); 
#endif 
} 
 
 
int    INT_LOCK(void) 
{ 
#if CPU_FAMILY ==  ARM 
/* For ARM User: 
   Please modify these two functions to fit your board.*/ 
   int_disable(INT_GPIO68); /* turn off the GPIO IRQ bit*/ 
    return 0;  
#else 
   return intLock(); 
#endif 
} 
 
 
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 
 * Support routines for the above board-specific routines                      * 
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 
 
 
/******************************************************************************* 
* 
* csGetUnspecifiedParms 
* 
* 
*/ 
 
LOCAL STATUS csGetUnspecifiedParms( CS_END_DEVICE *pCS ) 
{ 
   USHORT SelfStatus; 
   USHORT ISAConfig; 
   USHORT MemBase; 
   USHORT AdapterConfig; 
   USHORT XmitCtl; 
 
   /* If all of these parameters were specified */ 
   if ( pCS->ConfigFlags!=0 && pCS->pPacketPage!=NULL && pCS->IntLevel!=0 && 
         pCS->MediaType!=0 ) 
      return OK;  /* Don't need to get anything from the EEPROM */ 
 
   /* Verify that the EEPROM is present and OK */ 
   SelfStatus = csReadPacketPage( pCS, PKTPG_SELF_ST ); 
   if ( !((SelfStatus & SELF_ST_EEP_PRES) && (SelfStatus & SELF_ST_EEP_OK)) ) 
   { 
#ifdef CS_DEBUG_ENABLE 
      logMsg("\ncs0 - EEPROM is missing or bad\n",0,0,0,0,0,0); 
#endif 
      return ERROR; 
   } 
 
   /* Get ISA configuration from the EEPROM */ 
   if ( csReadEEPROM(pCS,EEPROM_ISA_CFG,&ISAConfig) == ERROR ) 
      return ERROR; 
 
   /* Get adapter configuration from the EEPROM */ 
   if ( csReadEEPROM(pCS,EEPROM_ADPTR_CFG,&AdapterConfig) == ERROR ) 
      return ERROR; 
 
   /* Get transmission control from the EEPROM */ 
   if ( csReadEEPROM(pCS,EEPROM_XMIT_CTL,&XmitCtl) == ERROR ) 
      return ERROR; 
 
   /* If the configuration flags were not specified */ 
   if ( pCS->ConfigFlags == 0 ) 
   { 
      /* Copy the memory mode flag */ 
      if ( ISAConfig & ISA_CFG_MEM_MODE ) 
         pCS->ConfigFlags |= CFGFLG_MEM_MODE; 
 
      /* Copy the USE_SA flag */ 
      if ( ISAConfig & ISA_CFG_USE_SA ) 
         pCS->ConfigFlags |= CFGFLG_USE_SA; 
 
      /* Copy the IO Channel Ready flag */ 
      if ( ISAConfig & ISA_CFG_IOCHRDY ) 
         pCS->ConfigFlags |= CFGFLG_IOCHRDY; 
 
      /* Copy the DC/DC Polarity flag */ 
      if ( AdapterConfig & ADPTR_CFG_DCDC_POL ) 
         pCS->ConfigFlags |= CFGFLG_DCDC_POL; 
 
      /* Copy the Full Duplex flag */ 
      if ( XmitCtl & XMIT_CTL_FDX ) 
         pCS->ConfigFlags |= CFGFLG_FDX; 
   } 
 
   /* If the PacketPage pointer was not specified */ 
   if ( pCS->pPacketPage == NULL ) 
   { 
      /* If memory mode is enabled */ 
      if ( pCS->ConfigFlags & CFGFLG_MEM_MODE ) 
      { 
         /* Get the memory base address from EEPROM */ 
         if ( csReadEEPROM(pCS,EEPROM_MEM_BASE,&MemBase) == ERROR ) 
            return ERROR; 
 
         MemBase &= MEM_BASE_MASK;  /* Clear unused bits */ 
 
         /* Setup the PacketPage pointer */ 
         pCS->pPacketPage = (unsigned short *)(((ULONG)MemBase)<<8); 
      } 
   } 
 
#if CPU_FAMILY == I80X86 
   /* If the interrupt level was not specified */ 
   if ( pCS->IntLevel == 0 ) 
   { 
      /* Get the interrupt level from the ISA config */ 
      pCS->IntLevel = ISAConfig & ISA_CFG_IRQ_MASK; 
      if ( pCS->IntLevel == 3 ) 
         pCS->IntLevel = 5; 
      else 
         pCS->IntLevel += 10; 
   } 
#endif 
 
   /* If the media type was not specified */ 
   if ( pCS->MediaType == 0 ) 
   { 
      switch( AdapterConfig & ADPTR_CFG_MEDIA ) 
      { 
         case ADPTR_CFG_AUI: 
            pCS->MediaType = MEDIA_AUI; 
            break; 
         case ADPTR_CFG_10BASE2: 
            pCS->MediaType = MEDIA_10BASE2; 
            break; 
         case ADPTR_CFG_10BASET: 
         default: 
            pCS->MediaType = MEDIA_10BASET; 
            break; 
      } 
   } 
 
   return OK; 
} 
 
 
/******************************************************************************* 
* 
* csValidateParms 
* 
* This routine verifies that the memory address, interrupt level and media 
* type are valid.  If any of these parameters are invalid, then and error 
* message is printed and ERROR is returned. 
* 
*/ 
 
LOCAL STATUS csValidateParms( CS_END_DEVICE *pCS ) 
{ 
   int MemAddr; 
 
   MemAddr = (int)(pCS->pPacketPage); 
 
   if ( (MemAddr & 0x000FFF) != 0 ) 
   { 
#ifdef CS_DEBUG_ENABLE 
      logMsg("\ncs0 - Memory address (0x%X) must start on a 4K boundry\n", 
            MemAddr,0,0,0,0,0); 
#endif 
      return ERROR; 
   } 
 
#if CPU_FAMILY == I80X86 
   if ( MemAddr > 0xFFF000 ) 
   { 
#ifdef CS_DEBUG_ENABLE 
      logMsg("\ncs0 - Memory address (0x%X) is too large\n", MemAddr,0,0,0,0,0 ); 
#endif 
      return ERROR; 
   } 
 
   if ( !(pCS->IntLevel==5 || pCS->IntLevel==10 || pCS->IntLevel==11 || 
         pCS->IntLevel==12) ) 
   { 
#ifdef CS_DEBUG_ENABLE 
      logMsg("\ncs0 - Interrupt level (%d) is invalid\n", pCS->IntLevel,0,0,0,0,0 ); 
#endif 
      return ERROR; 
   } 
#endif 
 
   if ( !(pCS->MediaType==MEDIA_AUI || pCS->MediaType==MEDIA_10BASE2 || 
         pCS->MediaType==MEDIA_10BASET) ) 
   { 
#ifdef CS_DEBUG_ENABLE 
      logMsg("\ncs0 - Media type (%d) is invalid\n", pCS->MediaType,0,0,0,0,0); 
#endif 
      return ERROR; 
   } 
 
   return OK; 
} 
 
 
 
 
/******************************************************************************* 
* 
* csReadEEPROM 
* 
* This routine reads a word from the EEPROM at the specified offset. 
* 
*/ 
 
LOCAL STATUS csReadEEPROM( CS_END_DEVICE *pCS, USHORT Offset, USHORT *pValue ) 
{ 
   int x; 
 
   /* Ensure that the EEPROM is not busy */ 
   for ( x=0; x < MAXLOOP; x++ ) 
      if ( !(csReadPacketPage(pCS,PKTPG_SELF_ST)&SELF_ST_SI_BUSY) ) 
         break; 
   if ( x == MAXLOOP ) 
   { 
#ifdef CS_DEBUG_ENABLE 
      logMsg("\ncs0 - Can not read from EEPROM\n",0,0,0,0,0,0); 
#endif 
      return ERROR; 
   } 
 
   /* Issue the command to read the offset within the EEPROM */ 
   csWritePacketPage( pCS, PKTPG_EEPROM_CMD, Offset | EEPROM_CMD_READ ); 
 
   /* Wait until the command is completed */ 
   for ( x=0; x