📄 if_cs.c
字号:
/*******************************************************************************
*
* csInitRxBuff -
*
* This routine initializes the network interface driver's collection of
* receive buffers. The receive buffers are allocated from system memory
* and linked together in a linked list of free receive buffers.
*
*/
LOCAL STATUS csInitRxBuff( CS_SOFTC *pCS )
{
PRXBUF pRxBuff;
PRXBUF pRxLast;
/* Allocate the receive frame buffers */
pCS->pFreeRxBuff = (PRXBUF)malloc( sizeof(RXBUF)*CS_NUM_RX_BUFFERS );
if ( pCS->pFreeRxBuff == NULL )
{
return ERROR;
}
/* Link all the receive frame buffers together on the free list */
pRxLast = pCS->pFreeRxBuff + CS_NUM_RX_BUFFERS - 1;
for ( pRxBuff=pCS->pFreeRxBuff; pRxBuff<pRxLast; pRxBuff++ )
{
pRxBuff->pNext = pRxBuff+1;
pRxBuff->Status = RXBUF_FREE;
}
pRxLast->pNext = NULL;
pRxLast->Status = RXBUF_FREE;
return OK;
}
/*******************************************************************************
*
* csAllocRxBuff -
*
* This routine removes a receive buffer from the free receive buffer list.
*
*/
LOCAL PRXBUF csAllocRxBuff( CS_SOFTC *pCS )
{
PRXBUF pRxBuff;
if ( pCS->pFreeRxBuff == NULL )
{
return NULL;
}
/* Remove a buffer from the free list */
pRxBuff = pCS->pFreeRxBuff;
pCS->pFreeRxBuff = pRxBuff->pNext;
pRxBuff->pNext = NULL;
/* Init the reference count to zero */
pRxBuff->RefCount = 0;
/* The buffer is now allocated */
pRxBuff->Status = RXBUF_ALLOCATED;
/* Increment number of receive buffers currently in use */
pCS->RxDepth++;
if ( pCS->RxDepth > pCS->MaxRxDepth )
{
pCS->MaxRxDepth = pCS->RxDepth;
}
return pRxBuff;
}
/*******************************************************************************
*
* csFreeRxBuff -
*
* This routine returns an allocated receive buffer back to the free list.
*
*/
LOCAL void csFreeRxBuff( CS_SOFTC *pCS, PRXBUF pRxBuff )
{
int IntState;
/* Disable interrupts at the CPU so csAllocRxBuff() will not interrupt */
IntState = intLock();
/* Put the buffer at the head of the free list */
pRxBuff->pNext = pCS->pFreeRxBuff;
pCS->pFreeRxBuff = pRxBuff;
/* The buffer is now free */
pRxBuff->Status = RXBUF_FREE;
/* Decrement the outstanding receive depth */
pCS->RxDepth--;
/* Re-enable interrupts at the CPU */
intUnlock( IntState );
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
* Misc. Routines *
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*******************************************************************************
* csInitQueue -
*
* Initializes an array-implemented circular queue.
*
* RETURNS: Nothing.
*
*/
LOCAL void csInitQueue( CIR_QUEUE *Q )
{
Q->Head = Q->Tail = 0;
}
/*******************************************************************************
* csQueueEmpty -
*
* Checks the queue's status.
*
* RETURNS: TRUE if queue is empty, FALSE if queue is not empty.
*
*/
LOCAL BOOL csQueueEmpty( CIR_QUEUE *Q )
{
if( Q->Head == Q->Tail )
return TRUE; /* Queue is empty */
else
return FALSE;
}
/*******************************************************************************
* csDequeue -
*
* This routine removes a pointer to a value from the end off an
* array-implemented circular queue. Assumes the queue is not empty.
*
* RETURNS: Pointer to the dequeued value.
*
*/
LOCAL void *csDequeue( CIR_QUEUE *Q )
{
FAST void *Element;
Element = Q->Queue[Q->Head];
Q->Head = (Q->Head == CS_MAX_QUEUE) ? 0 : (Q->Head + 1);
return Element;
}
/*******************************************************************************
* csEnqueue -
*
* This routine adds a pointer to a value to the front of an array-implmented
* circular queue.
*
* RETURNS: OK, or ERROR if the enqueue would cause a queue overflow.
*
*/
LOCAL STATUS csEnqueue( CIR_QUEUE *Q, void *pBuff )
{
/* If queue is full return ERROR */
if ( Q->Tail == ((Q->Head == 0) ? CS_MAX_QUEUE : (Q->Head -1)) )
{
LOGMSG("csEnqueue: unit %d, Queue Overflow\n",
0,0,0,0,0,0 );
return ERROR; /* Queue overflow */
}
/* Else, add data to the queue and return OK */
Q->Queue[Q->Tail] = pBuff;
Q->Tail = (Q->Tail == CS_MAX_QUEUE) ? 0 : (Q->Tail + 1);
return OK;
}
/*******************************************************************************
*
* csVerifyChip -
*
* This routine verifies that the Ethernet chip is present and correct.
*
*/
LOCAL STATUS csVerifyChip( CS_SOFTC *pCS )
{
USHORT wrVal, rdVal;
USHORT errorCount = 0;
USHORT x;
/* Verify that we can read from the chip */
x = csReadPacketPage( pCS, PKTPG_EISA_NUM );
if ( x == 0xFFFF )
{
LOGMSG("csInit: unit %d, can't read from chip (I/O address correct?)\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
return ERROR;
}
/* Verify that the chip is a Crystal Semiconductor chip */
if ( x != EISA_NUM_CRYSTAL )
{
LOGMSG("csInit: unit %d, Chip is not a Crystal Semiconductor chip\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
return ERROR;
}
/* Verify that the chip is a CS8900 */
x = csReadPacketPage(pCS,PKTPG_PRODUCT_ID);
x &= PROD_ID_MASK;
if ( x != PROD_ID_CS8900)
{
LOGMSG("csInit: unit %d, Chip is not a CS8900p\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
return ERROR;
}
/* walk a one in the memory of the enet controller */
for( wrVal = 0x0001; wrVal != 0; wrVal <<= 1 )
{
for( x=0x150; x<= 0x15d; x+=2 )
{
/* write out value - don't swap bytes */
csWritePacketPage( pCS, x, wrVal );
/* read back value - don't swap bytes */
rdVal = csReadPacketPage( pCS, x );
if( wrVal != rdVal )
{
if( errorCount <=10 )
{
LOGMSG("csVerifyChip: ERROR reg %04X, wrVal %04X, rdVal %04X\n",
x,
(unsigned int) BYTE_SWAP(wrVal),
(unsigned int) BYTE_SWAP(rdVal),0,0,0 );
}
errorCount++;
}
}
} /* end walking one test */
/* write incrementing value test */
for( x=0x150, wrVal=0x0101; x<= 0x15d; x+=2, wrVal+=0x0101 )
{
/* write out value - don't worry about swapping bytes */
csWritePacketPage( pCS, x, wrVal );
}
/* read incrementing value test */
for( x=0x150, wrVal=0x0101; x<= 0x15d; x+=2, wrVal+=0x0101 )
{
/* read back value - don't worry about swapping bytes */
rdVal = csReadPacketPage( pCS, x );
if( wrVal != rdVal )
{
LOGMSG("\ncsVerifyChip: ERROR reg %04X, wrVal %04X, rdVal %04X\n",
x,
(unsigned int) BYTE_SWAP(wrVal),
(unsigned int) BYTE_SWAP(rdVal),0,0,0 );
errorCount++;
}
} /* end walking one test */
if( errorCount != 0 )
{
LOGMSG("csVerifyChip: ERROR SRAM test failed, errorCount %d\n",
errorCount,0,0,0,0,0 );
return( ERROR );
}
return OK;
}
/*******************************************************************************
*
* csInitChip -
*
* This routine uses the instance global variables in the cs_softc structure to
* initialize the CS890.
*
*/
LOCAL void csInitChip( CS_SOFTC *pCS )
{
PIA pIA;
USHORT RxCtl;/*Promiscuous@kml*/
/* Configure the adapter for board-specific IO and media type support */
sysEnetHWInit( pCS );
/* Initialize the config and control registers */
csWritePacketPage( pCS, PKTPG_RX_CFG, RX_CFG_ALL_IE );
csWritePacketPage( pCS, PKTPG_RX_CTL,
RX_CTL_RX_OK_A | RX_CTL_IND_A | RX_CTL_BCAST_A | RX_CTL_MCAST_A);
csWritePacketPage( pCS, PKTPG_TX_CFG, TX_CFG_ALL_IE );
csWritePacketPage( pCS, PKTPG_BUF_CFG, BUF_CFG_ALL_IE );
/* Put Ethernet address into the Individual Address register */
pIA = (PIA)pCS->ArpCom.ac_enaddr;
csWritePacketPage( pCS, PKTPG_IND_ADDR, pIA->word[0] );
csWritePacketPage( pCS, PKTPG_IND_ADDR+2, pIA->word[1] );
csWritePacketPage( pCS, PKTPG_IND_ADDR+4, pIA->word[2] );
/* Set the interrupt level in the chip */
if ( pCS->IntLevel == 5 )
csWritePacketPage( pCS, PKTPG_INT_NUM, BYTE_SWAP(3) );
else
csWritePacketPage( pCS, PKTPG_INT_NUM, BYTE_SWAP( (pCS->IntLevel)-10 ) );
/* Promiscuous@kml If need to enable the promiscuous mode */
if ( pCS->ConfigFlags & CFGFLG_PROMISC_MODE ) {
RxCtl=csReadPacketPage(pCS,PKTPG_RX_CTL);
RxCtl |= (RX_CTL_PROM_A|RX_CTL_MCAST_A|RX_CTL_RX_OK_A | RX_CTL_IND_A | RX_CTL_BCAST_A);
csWritePacketPage( pCS, PKTPG_RX_CTL, RxCtl );
LOGMSG ("csInitChip() Setting promiscuous mode on!\n", 0, 0, 0, 0, 0, 0);
} else {
LOGMSG ("csInitChip() Setting promiscuous mode off!\n", 0, 0, 0, 0, 0, 0);
}
/* Enable reception and transmission of frames */
csWritePacketPage( pCS, PKTPG_LINE_CTL,
csReadPacketPage(pCS,PKTPG_LINE_CTL) | LINE_CTL_RX_ON | LINE_CTL_TX_ON );
/* Enable interrupt at the chip */
csWritePacketPage( pCS, PKTPG_BUS_CTL,
csReadPacketPage(pCS,PKTPG_BUS_CTL) | BUS_CTL_INT_ENBL );
}
/*******************************************************************************
*
* csResetChip -
*
* This routine resets the CS8900 chip.
*
*/
LOCAL STATUS csResetChip( CS_SOFTC *pCS )
{
int y;
int x;
UCHAR dummyVal;
LOGMSG("csResetChip: unit %d, Reseting the chip......\n",
pCS->ArpCom.ac_if.if_unit,0,0,0,0,0);
/*@kml assign an initial values to avoid "unused variable" warning when compiling*/
x=0;
dummyVal=0;
#ifdef HARD_RESET
/* Disable interrupts at the CPU so reset command is atomic */
y = intLock();
/* We are now resetting the chip */
/* A spurious interrupt is generated by the chip when it is reset. */
/* This variable informs the interrupt handler to ignore this interrupt. */
pCS->Resetting = TRUE;
/* Issue a reset command to the chip */
csWritePacketPage( pCS, PKTPG_SELF_CTL, SELF_CTL_RESET );
/* Re-enable interrupts at the CPU */
intUnlock( y );
/* If transmission was in progress, it is not now */
pCS->TxInProgress = FALSE;
pCS->pTxFrameChain = NULL;
/* The chip is always in IO mode after a reset */
pCS->InMemoryMode = FALSE;
/* Initialize locale flag */
pCS->InISR = FALSE;
/* Delay for 125 micro-seconds (one eighth of a second) */
taskDelay( sysClkRateGet()/8 );
/* Transition SBHE to switch chip from 8-bit to 16-bit */
dummyVal = SYS_ENET_IN_BYTE( (pCS->IOAddr)+PORT_PKTPG_PTR );
dummyVal = SYS_ENET_IN_BYTE( (pCS->IOAddr)+PORT_PKTPG_PTR+1 );
dummyVal = SYS_ENET_IN_BYTE( (pCS->IOAddr)+PORT_PKTPG_PTR );
dummyVal = SYS_ENET_IN_BYTE( (pCS->IOAddr)+PORT_PKTPG_PTR+1 );
/* If EEPROM present, wait up to 125 mSec for EEPROM not busy*/
y = sysClkRateGet()/8;
for ( x=0; x<y; x++ )
{
if( !(csReadPacketPage(pCS,PKTPG_SELF_ST)&SELF_ST_SI_BUSY) )
break;
}
if ( x == y )
return ERROR;
/* Wait up to 125 mSec for initialization is become done */
for ( x=0; x<y; x++ )
{
if ( csReadPacketPage(pCS,PKTPG_SELF_ST)&SELF_ST_INIT_DONE )
break;
}
if ( x == y )
return ERROR;
/* Reset is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -