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;
}