www.pudn.com > 2410winceCE_l80t64.rar > DETECT.C


//--------------------------------------------------------------------------- 
// 
//  Copyright (C) 1996-1997. Unpublished Work of Crystal Semiconductor Corp. 
//  All Rights Reserved. 
// 
//  THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, 
//  PROPRIETARY AND TRADE SECRET INFORMATION OF CRYSTAL SEMICONDUCTOR. 
//  ACCESS TO THIS WORK IS RESTRICTED TO (I) CRYSTAL SEMICONDUCTOR EMPLOYEES 
//  WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR 
//  ASSIGNMENTS  AND (II) ENTITIES OTHER THAN CRYSTAL SEMICONDUCTOR WHO 
//  HAVE ENTERED INTO  APPROPRIATE LICENSE AGREEMENTS.  NO PART OF THIS 
//  WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, 
//  MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, 
//  COMPILED,LINKED,RECAST, TRANSFORMED, ADAPTED IN ANY FORM OR BY ANY 
//  MEANS,MANUAL, MECHANICAL, CHEMICAL, ELECTRICAL, ELECTRONIC, OPTICAL, 
//  BIOLOGICAL, OR OTHERWISE WITHOUT THE PRIOR WRITTEN PERMISSION AND 
//  CONSENT OF CRYSTAL SEMICONDUCTOR . ANY USE OR EXPLOITATION OF THIS WORK 
//  WITHOUT THE PRIOR WRITTEN CONSENT OF CRYSTAL SEMICONDUCTOR  COULD 
//  SUBJECT THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 
// 
//--------------------------------------------------------------------------- 
 
#include "cs8900a.h" 
#include "cshrd.h" 
 
 
/* External prototypes */ 
 
WORD ReadPacketPage( PCHIP pChip, PORT IOBase, WORD Offset ); 
void  PurgeTransmitQueue( IN PCHIP ); 
 
 
/* Internal prototypes */ 
//@drsc 11-3-97 3.21  add cs8900 support 
void CrystalDetermineDuplexMode( PCHIP pChip ); 
 
 
void CrystalEnableAUILoopback( PCHIP pChip ) 
{ 
   WORD   Data; 
   PORT   IOBase = pChip->Config.IOBase; 
 
   // 
   // Set the RX_OK_ACCEPT+RX_IA_ACCEPT+RX_RUNT_ACCEPT + 
   // CRYSTAL_RCR_RX_PROM_ACCEPTin RX_CTL_REG 
   // 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_RX_CONTROL_REGISTER ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 
               (CRYSTAL_RCR_RX_IA_ACCEPT|CRYSTAL_RCR_RX_RUNT_ACCEPT \ 
               |CRYSTAL_RCR_RX_OK_ACCEPT|CRYSTAL_RCR_RX_PROM_ACCEPT)); 
 
 
   VominiDelay( 1 ); 
 
   // 
   // Read the Line Control Register and or it with AUI only mode. 
   // Also enable the transmitter and receiver. 
   // 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_LINE_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 
               Data | CRYSTAL_LCR_AUI_ONLY | 
               CRYSTAL_LCR_SERIAL_RX_ON | CRYSTAL_LCR_SERIAL_TX_ON ); 
 
   // 
   // Start AUI Loop Back now. 
   // Read the TEST_CTL register and OR it with AUI loopback mode 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_TEST_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   Data &= ~(CRYSTAL_TCR_FULL_DUPLEX_ON |CRYSTAL_TCR_ENDEC_LOOPBACK); 
 
   // 
   // Or it with AUI_LOOPBACK mode 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 
               Data | CRYSTAL_TCR_AUI_LOOPBACK ); 
 
} 
 
 
void CrystalDisableAUILoopback( PCHIP pChip ) 
{ 
   WORD   Data; 
   PORT   IOBase = pChip->Config.IOBase; 
 
   // 
   // Disable AUI LOOPBACK mode. 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_TEST_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 
               (Data & ~CRYSTAL_TCR_AUI_LOOPBACK)); 
 
   /* Clear the AUI only bit in the Line Control register */ 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_LINE_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 
               (Data & ~(CRYSTAL_LCR_AUI_ONLY | 
               CRYSTAL_LCR_SERIAL_RX_ON | CRYSTAL_LCR_SERIAL_TX_ON)) ); 
 
 
} 
 
 
void CrystalEnableDCConverter( PCHIP pChip ) 
{ 
   WORD   Data; 
   PORT   IOBase = pChip->Config.IOBase; 
   PCD    pData = pChip->pData; 
 
   // 
   // Read the self control register 
   // 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_SELF_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   Data |= CRYSTAL_SCR_HCO_1_ENABLE; 
 
   // 
   // Depending on the polarity existing the Dc/Dc converter must be 
   // turned on 
   // 
 
   if (pData->ConfigFlags & CFGFLG_DCDC_POLARITY)  { 
 
      Data &= ~CRYSTAL_SCR_HCO_1; 
 
   } else { 
 
      Data |= CRYSTAL_SCR_HCO_1; 
 
   } 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), Data ); 
 
   // 
   // Delay to give the DC/DC converter time to stabilize 
   // 
 
   // Delay for 8 milliseconds.  This delay was extended 
   // from 1.5 millisecond for the Etherjet cost reduced card. 
   VominiDelay( 8 ); 
 
} 
 
 
void CrystalDisableDCConverter( PCHIP pChip ) 
{ 
   WORD   Data; 
   PORT   IOBase = pChip->Config.IOBase; 
   PCD    pData = pChip->pData; 
 
   // 
   // Disable the DC/DC converter by turning off the self control register 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_SELF_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   if (pData->ConfigFlags & CFGFLG_DCDC_POLARITY)  { 
 
      Data |= CRYSTAL_SCR_HCO_1; 
 
   } else { 
 
      Data &= ~CRYSTAL_SCR_HCO_1; 
 
   } 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), Data ); 
} 
 
 
WORD CrystalPollForRxOK( PCHIP pChip, WORD Timeout ) 
{ 
   DWORD  i; 
   WORD   Data; 
   PORT   IOBase = pChip->Config.IOBase; 
 
   // 
   // Poll for the receive event 
   // 
   Timeout = Timeout * 10; 
   for (i=0; i < Timeout; i++) { 
 
      NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
                  CRYSTAL_RX_EVENT_REGISTER ); 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
      if (Data & CRYSTAL_RER_PACKET_RECEIVED_OK) { 
         return TRUE; 
      } 
 
      VominiDelay( 1 );           // delay 1 millesecond 
   } 
 
   // 
   // Couldn't get RX_OK return false 
   // 
   return FALSE; 
} 
 
 
 
WORD CrystalSendMediaTestPacket( PCHIP pChip ) 
{ 
   // 
   // A variable to read the data from packet page. 
   // 
   WORD Data; 
 
   DWORD  i; 
   PORT   IOBase = pChip->Config.IOBase; 
   PWORD  EthernetAddress; 
 
   #define CRYSTAL_MEDIA_TEST_PACKET_LENGTH 2+ (2*ETH_LENGTH_OF_ADDRESS) 
 
   // 
   // Write the transmit command to TX_CMD port. 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_TRANSMIT_COMMAND_PORT), 
               CRYSTAL_TCR_TX_START_ALL_BYTES | CRYSTAL_TCR_TX_FORCE ); 
 
   // 
   // Write the transmit length to TX_LENGTH port. 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_TRANSMIT_LENGTH_PORT), 
               CRYSTAL_MEDIA_TEST_PACKET_LENGTH ); 
 
   // 
   // Now, check whether the chip is ready to transmit by checking the 
   // Ready for transmit bit of the BusStatusRegister. 
   // 
 
   // 
   // Wait for up to 10 milliseconds for the read for transmit now 
   // 
   for (i=0; i < 10; i++) { 
 
      NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
                  CRYSTAL_BUS_STATUS_REGISTER ); 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
      if (Data & CRYSTAL_BSR_READY_FOR_TRANSMIT_NOW) { 
         break; 
      } 
 
      VominiDelay( 1 ); 
   } 
 
   if (!(Data & CRYSTAL_BSR_READY_FOR_TRANSMIT_NOW)) { 
      // 
      // Could not get READY_FOR_TX,return with error 
      // 
      // Send with FORCE ????  and restart? 
      return FALSE; 
   } 
 
   // 
   // Transmit a frame that is addressed to ourself. 
   // Write source and destination address 
   // 
 
   EthernetAddress = (PWORD)&(pChip->Config.EthernetAddr); 
   for(i=0; i < ETH_LENGTH_OF_ADDRESS/2; i++) { 
 
      NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                  *EthernetAddress++ ); 
   } 
 
   EthernetAddress = (PWORD)&(pChip->Config.EthernetAddr); 
 
   for(i=0; i < ETH_LENGTH_OF_ADDRESS/2; i++) { 
 
      NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                  *EthernetAddress++ ); 
   } 
 
   // 
   // Transmit the length of the packet. 
   // 
 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
              CRYSTAL_MEDIA_TEST_PACKET_LENGTH ); 
 
   // 
   // Wait  for 1 ms. In this time we should have transmitted else there is 
   // traffic so we could receive some packet from the network 
   // 
 
   VominiDelay( 1 ); 
 
   // 
   // Read the TxEvent register and discard this event 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_TX_EVENT_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   // 
   // Poll for the receive event 
   // 
 
   return CrystalPollForRxOK(pChip, 12); 
 
} 
 
 
void CrystalDetect10baseT( PCHIP pChip ) 
{ 
   PORT IOBase; 
   WORD LineStatus; 
 
   IOBase = pChip->Config.IOBase; 
 
   if ( pChip->Config.CurrentDuplexMode == DUPLEX_NONE ) 
   { 
      /* Read the line status register */ 
      LineStatus = ReadPacketPage( pChip, IOBase, CRYSTAL_LINE_STATUS_REGISTER ); 
 
      /* If the link is OK */ 
      if ( LineStatus & CRYSTAL_LSR_LINK_OK ) 
      { 
         CrystalDetermineDuplexMode( pChip ); 
 
         if ( pChip->Config.CurrentDuplexMode == DUPLEX_PENDING ) 
            pChip->Config.DetectedMediaType = MEDIA_PENDING; 
         else 
            pChip->Config.DetectedMediaType = MEDIA_BASE_T; 
      } 
      else if ( pChip->Config.DetectedMediaType == MEDIA_NONE ) 
         pChip->Config.DetectedMediaType = MEDIA_PENDING; 
      else  /* DetectedMediaType == MEDIA_PENDING */ 
         pChip->Config.DetectedMediaType = MEDIA_NONE; 
 
   } 
   else if ( pChip->Config.CurrentDuplexMode == DUPLEX_PENDING ) 
   { 
      CrystalDetermineDuplexMode( pChip ); 
 
      if ( pChip->Config.CurrentDuplexMode == DUPLEX_PENDING ) 
         pChip->Config.DetectedMediaType = MEDIA_PENDING; 
      else 
         pChip->Config.DetectedMediaType = MEDIA_BASE_T; 
   } 
} 
 
 
void CrystalDetectAUI( PCHIP pChip ) 
{ 
   CrystalEnableAUILoopback(pChip); 
   CrystalDisableDCConverter(pChip); 
 
   // 
   // Send the Media Test Packet . If transmission succeeds it is AUI 
   // 
   if (CrystalSendMediaTestPacket(pChip)) { 
 
      // 
      // The media detected is AUI 
      // 
 
      pChip->Config.DetectedMediaType = MEDIA_BASE_AUI; 
      pChip->Config.CurrentDuplexMode = DUPLEX_HALF; 
   } 
 
   // 
   // Disable the AUI loop back mode 
   // 
   CrystalDisableAUILoopback(pChip); 
} 
 
 
void CrystalDetectBNC( PCHIP pChip ) 
{ 
   CrystalEnableAUILoopback(pChip); 
   CrystalEnableDCConverter(pChip); 
 
   // 
   // Send the media test packet . If the test transmission succeeds ,the 
   // medium is BNC. 
   // 
   if ( CrystalSendMediaTestPacket(pChip) ) { 
 
      // 
      // Success, BNC is connected 
      // 
      pChip->Config.DetectedMediaType = MEDIA_BASE_2; 
      pChip->Config.CurrentDuplexMode = DUPLEX_HALF; 
   } 
 
 
   CrystalDisableDCConverter(pChip); 
 
   // 
   // Disable the AUI loop back mode 
   // 
   CrystalDisableAUILoopback(pChip); 
 
} /*endproc*/ 
 
 
void CrystalAutoDetectMedia( PCHIP pChip ) 
{ 
   PCD  pData; 
 
   pData = pChip->pData; 
 
   /* If the hardware is capable of 10BaseT */ 
   if ( pData->ConfigFlags & CFGFLG_MEDIA_CAP_BASE_T ) 
   { 
      CrystalDetect10baseT( pChip ); 
      if ( pChip->Config.DetectedMediaType == MEDIA_BASE_T || 
           pChip->Config.DetectedMediaType == MEDIA_PENDING ) 
         return; 
   } 
 
   /* If the hardware is capable of AUI */ 
   if ( pData->ConfigFlags & CFGFLG_MEDIA_CAP_BASE_AUI ) 
   { 
      CrystalDetectAUI( pChip ); 
      if ( pChip->Config.DetectedMediaType == MEDIA_BASE_AUI ) 
         return; 
   } 
 
   /* If the hardware is capable of 10Base2 */ 
   if ( pData->ConfigFlags & CFGFLG_MEDIA_CAP_BASE_2 ) 
   { 
      CrystalDetectBNC( pChip ); 
      if ( pChip->Config.DetectedMediaType == MEDIA_BASE_2 ) 
         return; 
   } 
} 
 
 
void DetectMedia( PCHIP pChip ) 
{ 
   PCD  pData; 
 
   pData = pChip->pData; 
 
   /* This routine should only be called with              */ 
   /* DetectedMediaType set to MEDIA_NONE or MEDIA_PENDING */ 
 
   switch ( pChip->Config.RequestedMediaType ) 
   { 
      case MEDIA_BASE_T: 
         CrystalDetect10baseT( pChip ); 
         break; 
      case MEDIA_BASE_AUI: 
         CrystalDetectAUI( pChip ); 
         break; 
      case MEDIA_BASE_2: 
         CrystalDetectBNC( pChip ); 
         break; 
      case MEDIA_AUTO_DETECT: 
      default: 
         CrystalAutoDetectMedia( pChip ); 
         break; 
   } 
} 
 
//@drsc 11-3-97 3.21  add cs8900 support 
VOID CrystalDetermineDuplexMode( PCHIP pChip ) 
{ 
   PORT IOBase = pChip->Config.IOBase; 
   WORD AutoNegControl; 
 
 
      // Determine if it is half or full duplex.  The CS8900 
      // does not auto negotiate. 
	   // @kml 6/25/99 
      if (pChip->Config.RequestedDuplexMode == DUPLEX_FULL) 
      { 
         AutoNegControl = CRYSTAL_TCR_FULL_DUPLEX_ON; 
         pChip->Config.CurrentDuplexMode = DUPLEX_FULL; 
      } else { 
         AutoNegControl = 0; 
         pChip->Config.CurrentDuplexMode = DUPLEX_HALF; 
      } 
 
      NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
                  CRYSTAL_TEST_CONTROL_REGISTER ); 
      NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), AutoNegControl); 
        
      
} 
 
 
void VchipDetectMediaDaemon( PCHIP pChip, WORD TimerID, PVOID pParm ) 
{ 
   PCD  pData; 
   PORT IOBase; 
   WORD LineStatus; 
   WORD JustDisconnected; 
 
   pData    = pChip->pData; 
   IOBase = pChip->Config.IOBase; 
   JustDisconnected = FALSE; 
 
   /* If the cable is not currently connected */ 
   if ( pChip->Config.DetectedMediaType == MEDIA_NONE   || 
        pChip->Config.DetectedMediaType == MEDIA_PENDING ) 
   { 
      /* Try to detect the media */ 
      DetectMedia( pChip ); 
 
      /* If the cable was just connected */ 
      if ( pChip->Config.DetectedMediaType != MEDIA_NONE   && 
           pChip->Config.DetectedMediaType != MEDIA_PENDING ) 
      { 
        if ( pChip->Config.DetectedMediaType != MEDIA_BASE_T ) 
         { 
           /* Reset the chip, avoids pending receives  */ 
            VchipReset( pChip ); 
       } 
 
        /* Initialize the chip */ 
        VchipInit( pChip ); 
 
 
         /* Inform the protocol stack that the media is now connected */ 
         VpsMediaChanged( pChip ); 
 
      } 
   } 
   else if ( pChip->Config.DetectedMediaType == MEDIA_BASE_T ) 
   { 
      /* Read the line status register */ 
      LineStatus = ReadPacketPage( pChip, IOBase, CRYSTAL_LINE_STATUS_REGISTER ); 
 
      /* If the link has been lost */ 
      if ( !(LineStatus & CRYSTAL_LSR_LINK_OK) ) 
         JustDisconnected = TRUE; 
   } 
   else if ( !pData->TransmitStarted && pData->TransmitInProgress ) 
   { 
      /* A transmit did not complete within two daemon ticks. */ 
      /* An AUI or 10Base2 cable has just been disconnected.  */ 
      JustDisconnected = TRUE; 
   } 
 
   if ( JustDisconnected ) 
   { 
 
      pChip->Config.DetectedMediaType = MEDIA_NONE; 
      pChip->Config.CurrentDuplexMode = DUPLEX_NONE; 
	  PurgeTransmitQueue( pChip ); 
	   
      pData->TransmitInProgress = FALSE; 
      VpsMediaChanged( pChip ); 
      VominiDelay( 2L ); 
      //@drs 5-17-99 VchipReset( pChip ); 
   } 
 
   /* Reset the TransmitStarted flag */ 
   pData->TransmitStarted = FALSE; 
 
   VominiStartTimer( pChip, VchipDetectMediaDaemon, 2500, &pData->DetectMediaTimer, NULL ); 
} 
 
 
BOOLEAN CrystalTestInternalLoopBack( PCHIP pChip ) 
 
/*++ 
Routine Description: 
 
   This routine tests the basic functionality of the chip. It transmits a 
   predefined packet and then polls the chip for a valid receive. If 
   Successful then  it returns True indicating that the chip is functional. 
 
 
Return Value: 
 
   TRUE or FALSE 
 
--*/ 
{ 
 
#define CRYSTAL_INTERNAL_LOOPBACK_DATA_SIZE   1514 
   WORD Data; 
   WORD LineControl; 
   DWORD  i = 0; 
   PWORD  EthernetAddress; 
   PORT   IOBase = pChip->Config.IOBase; 
 
   // 
   // Read the LineControl register 
   // 
   // @jla waste this stupid subroutine 
   return CHIP_SUCCESS; 
    
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_LINE_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &LineControl ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 0 ); 
 
   // 
   // Set the RX_OK_ACCEPT+RX_IA_ACCEPT+RX_RUNT_ACCEPT in RX_CTL_REG 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_RX_CONTROL_REGISTER ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 
               (CRYSTAL_RCR_RX_IA_ACCEPT | 
               CRYSTAL_RCR_RX_RUNT_ACCEPT| 
               CRYSTAL_RCR_RX_OK_ACCEPT) ); 
 
   // 
   // Write our address to the chip. 
   // 
 
   /* Put Ethernet address into the Individual Address register */ 
   for (i=0; iConfig.EthernetAddr.Part[i] ); 
   } /* endfor */ 
 
   // 
   // Enable loopback bits in the TEST_CTL register i.e. FDX_ON and ENDEC 
   // LOOPBACK 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_TEST_CONTROL_REGISTER ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), 
               CRYSTAL_TCR_ENDEC_LOOPBACK | 
               CRYSTAL_TCR_FULL_DUPLEX_ON | 
               CRYSTAL_TCR_LINK_OFF ); 
 
   // 
   // Set the serial transmit and receive on. 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_LINE_CONTROL_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), Data | CRYSTAL_LCR_SERIAL_RX_ON | CRYSTAL_LCR_SERIAL_TX_ON ); 
 
   VominiDelay( 1); 
 
   // 
   // Now bid for transmit and then transmit pattern 
   // 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_COMMAND_PORT), 
                     CRYSTAL_TCR_TX_START_ALL_BYTES ); 
 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_LENGTH_PORT), 
              CRYSTAL_INTERNAL_LOOPBACK_DATA_SIZE); 
 
   // 
   // Loop till you get READY_FOR_TRANSMIT_NOW on 
   // 
   for (i=0; i <100; i++) { 
 
      NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
                  CRYSTAL_BUS_STATUS_REGISTER ); 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
      if ( Data & CRYSTAL_BSR_READY_FOR_TRANSMIT_NOW) { 
         break; 
      } 
      VominiDelay( 1); 
   } 
 
   if ( (Data & CRYSTAL_BSR_READY_FOR_TRANSMIT_NOW) != 
         CRYSTAL_BSR_READY_FOR_TRANSMIT_NOW ) { 
      return CHIP_FAILURE; 
   } /* endif */ 
 
   // 
   // Write the destination address (which is same as source ) on the chip 
   // 
   EthernetAddress = (PWORD)&(pChip->Config.EthernetAddr); 
   for(i=0; i < ETH_LENGTH_OF_ADDRESS/2; i++) 
   { 
 
      NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                  *EthernetAddress++ ); 
   } 
 
   EthernetAddress = (PWORD)&(pChip->Config.EthernetAddr); 
 
   for(i=0; i < ETH_LENGTH_OF_ADDRESS/2; i++) 
   { 
 
      NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                  *EthernetAddress++ ); 
   } 
 
 
   // 
   //   Write the transmit packet to the chip. 
   // 
   for (i = 0; 
        i < (CRYSTAL_INTERNAL_LOOPBACK_DATA_SIZE-(ETH_LENGTH_OF_ADDRESS*2))/2; 
        i++) 
   { 
      NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                  (WORD)0x55AA); 
   } 
 
   VominiDelay( 1); 
 
   // 
   // Poll for the Transmit Ok 
   // 
   for (i=0; i<100; i++) { 
 
      NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
                  CRYSTAL_TX_EVENT_REGISTER ); 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
      if ( Data & CRYSTAL_TER_PACKET_TRANSMITTED_OK) { 
         break; 
      } 
      VominiDelay( 3); 
   } 
 
   if ( (Data & CRYSTAL_TER_PACKET_TRANSMITTED_OK) != 
                CRYSTAL_TER_PACKET_TRANSMITTED_OK) 
   { 
      // 
      // Couldn't get TX_OK return false 
      // 
      return CHIP_FAILURE; 
 
   } 
 
   // 
   // Poll for the receive event 
   // 
   for (i=0; i< 100; i++) { 
 
      NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
                  CRYSTAL_RX_EVENT_REGISTER ); 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
      if (Data & CRYSTAL_RER_PACKET_RECEIVED_OK) { 
         break; 
      } 
      VominiDelay( 1); 
   } 
   if ((Data & CRYSTAL_RER_PACKET_RECEIVED_OK) != 
        CRYSTAL_RER_PACKET_RECEIVED_OK) 
   { 
      // 
      // Couldn't get RX_OK return false 
      // 
      return CHIP_FAILURE; 
   } 
 
   // 
   // Now read the received legth if less then bad receive 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_RECEIVE_LENGTH ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
   // 
   // If received data size does not match the transmitted data size 
   // it is not the same transmitted packet. 
   // Added 4 if CRC enabled. 
   // 
   if (Data != CRYSTAL_INTERNAL_LOOPBACK_DATA_SIZE) { 
      return CHIP_FAILURE; 
   } 
 
   // 
   // Validate the destination address (it must be ours) 
   // 
   for (i = 0; i < ETH_LENGTH_OF_ADDRESS/2 ; i++) { 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_RECEIVE_FRAME_PORT), &Data ); 
 
      if ( Data != pChip->Config.EthernetAddr.Part[i] ) { 
         return CHIP_FAILURE; 
      } 
   } 
 
   // 
   // Validate the source address (it must be ours) 
   // 
   for (i = 0; i < ETH_LENGTH_OF_ADDRESS/2 ; i++) { 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_RECEIVE_FRAME_PORT), &Data ); 
 
      if ( Data != pChip->Config.EthernetAddr.Part[i] ) { 
         return CHIP_FAILURE; 
      } 
   } 
 
   // 
   // Now  validate the receive bits 
   // 
 
   for (i = 0; 
        i < (CRYSTAL_INTERNAL_LOOPBACK_DATA_SIZE-(ETH_LENGTH_OF_ADDRESS*2))/2; 
        i++) 
   { 
 
      NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_RECEIVE_FRAME_PORT), &Data ); 
      if (Data != 0x55AA) { 
         return CHIP_FAILURE; 
      } 
   } 
 
   // 
   // Restore the serial transmit and receive. 
   // 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_LINE_CONTROL_REGISTER ); 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), LineControl ); 
 
   VominiDelay(  75 ); 
   return CHIP_SUCCESS; 
}