📄 if_cs.c
字号:
#ifdef BSD43_DRIVER
ether_attach (&pCS->ArpCom.ac_if, Unit, "cs", csInit, csIoctl, csOutput,
(FUNCPTR)csReset);
#else
ether_attach (
&pCS->ArpCom.ac_if,
Unit,
"cs",
(FUNCPTR) csInit,
(FUNCPTR) csIoctl,
(FUNCPTR) ether_output, /* generic ether_output */
(FUNCPTR) csReset
);
pCS->ArpCom.ac_if.if_start = (FUNCPTR) csStartOutput;
#endif
/* Promiscuous@kml Set promiscuous mode if user asked for. */
if ( pCS->ConfigFlags & CFGFLG_PROMISC_MODE ) {
pCS->ArpCom.ac_if.if_flags |= IFF_PROMISC;
}
return OK;
}
/*******************************************************************************
*
* csInit -
*
* This routine is a major entry point and is called to initialize this network
* interface driver. This routine may be called several times for each
* operating system reboot to dynamically bring the network interface driver
* to an up and running state. This routine is called by the protocol stack,
* the set_if_addr() routine, and the csIoctl() routine.
*
* This routine resets and then initializes the CS8900 chip.
*
*/
LOCAL STATUS csInit( int Unit )
{
FAST CS_SOFTC *pCS;
if ( Unit >= CS_MAX_NUM_UNITS )
return ERROR;
pCS = &cs_softc[Unit];
/* Mark the interface as down */
pCS->ArpCom.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
LOGMSG("csInit: unit %d, Initializing interface\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
/* Reset the chip */
if ( csResetChip(pCS) == ERROR )
{
LOGMSG("csInit: unit %d, Can not reset the chip\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
return ERROR;
}
/* Initialize the chip */
csInitChip( pCS );
/* Mark the interface as up and running and supporting multicasting*/
#ifdef BSD43_DRIVER
pCS->ArpCom.ac_if.if_flags |= (IFF_UP | IFF_RUNNING ); /* Multicast not supported by BSD43. */
#else
pCS->ArpCom.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_MULTICAST );
#endif
return OK;
}
/*******************************************************************************
*
* csReset -
*
* This routine is a major entry point and is called by the protocol stack to
* shut down this network interface driver. This routine may be called several
* times for each operating system reboot to dynamically bring the network
* interface driver to a non-running state.
*
* This routine resets the CS8900 chip.
*
*/
LOCAL void csReset( int Unit )
{
FAST CS_SOFTC *pCS;
if ( Unit >= CS_MAX_NUM_UNITS )
return;
pCS = &cs_softc[Unit];
LOGMSG("csReset: unit %d, Resetting interface\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
/* Mark the interface as down */
pCS->ArpCom.ac_if.if_flags &= ~IFF_RUNNING;
/* Reset the chip */
csResetChip( pCS );
}
/*******************************************************************************
*
* csIoctl -
*
* This routine is a major entry point and is called by the protocol stack to
* modify characteristics of this network interface driver. There are many
* network interface ioctl commands, but this driver only supports two of them:
* Set Interface Address and Set Interface Flags.
*
*/
LOCAL int csIoctl( struct ifnet *pIf, int Command, char *pData )
{
int State;
int Result;
FAST CS_SOFTC *pCS;
State = splnet();
pCS = &cs_softc[pIf->if_unit];
Result = OK; /* Assume everything will go OK */
switch( Command )
{
case SIOCSIFADDR: /* Set interface address (IP address) */
LOGMSG("csIoctl: unit %d, Set interface address\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
Result = set_if_addr( pIf, pData, (UCHAR *)pCS->ArpCom.ac_enaddr );
/* Note: set_if_addr() calls csInit() */
break;
case SIOCSIFFLAGS: /* Set interface flags */
LOGMSG("csIoctl: unit %d, Set interface flags\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
/* Promiscuous@kml If need to enable the promiscuous mode */
if (pIf->if_flags & IFF_PROMISC) {
pCS->ArpCom.ac_if.if_flags |= IFF_PROMISC;
pCS->ConfigFlags |= CFGFLG_PROMISC_MODE;
} else {
pCS->ArpCom.ac_if.if_flags &= ~IFF_PROMISC;
pCS->ConfigFlags &= ~CFGFLG_PROMISC_MODE;
}
if ( pIf->if_flags & IFF_UP )
{
/* Mark the interface as up and running */
pCS->ArpCom.ac_if.if_flags |= (IFF_UP | IFF_RUNNING);
/* Initialize the interface */
csInit( pIf->if_unit );
}
else /* The interface is down */
{
/* Mark the interface as down */
pCS->ArpCom.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
/* Reset the chip */
csResetChip( pCS );
}
break;
#ifndef BSD43_DRIVER
case SIOCADDMULTI:
if ( !pData) {
Result = EINVAL; /* Invalid argument */
break;
}
csMCastAdd (pCS, pData);
break;
case SIOCDELMULTI:
if ( !pData) {
Result = EINVAL; /* Invalid argument */
break;
}
csMCastDel(pCS, pData);
break;
#endif
default:
Result = EINVAL; /* Invalid argument */
break;
}
splx( State );
return Result;
}
#ifdef BSD43_DRIVER
/*******************************************************************************
*
* csOutput -
*
* This routine is a major entry point and is called by the protocol stack to
* transmit a packet across the LAN. The packet data is passed to this routine
* in a chain of mbuf structures.
*
* This routine calls the ether_output() routine, which in turn calls the
* csStartOutput() routine. The ether_output() routine resolves the destination
* IP address to it's Ethernet address, builds an Ethernet header and prepends
* the Ethernet header to the mbuf chain. The mbuf chain is added to the end
* of the network interface driver's transmit queue.
*
*/
LOCAL int csOutput( struct ifnet *pIf, struct mbuf *pMbufChain, SOCKADDR *pDst )
{
FAST CS_SOFTC *pCS;
pCS = &cs_softc[pIf->if_unit];
/* Call ether_ouput to queue the TX frame */
return ether_output( pIf, pMbufChain, pDst, (FUNCPTR)csStartOutput,
&pCS->ArpCom );
}
#endif /* BSD43_DRIVER */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
* Interrupt-handler Routines *
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*******************************************************************************
*
* csIntr -
*
* This routine in the interrupt service routine. This routine is called by
* VxWorks wrapper code whenever the CS8900 chip generates and interrupt. The
* wrapper code issues an EOI command.
*
* This routine processes the events on the Interrupt Status Queue. The events
* are read one at a time from the ISQ and the appropriate event handlers are
* called. The ISQ is read until it is empty. Reading a zero from the ISQ will
* deassert the interrupt request line.
*
* RETURNS: Nothing
*
*/
LOCAL void csIntr( int Unit )
{
FAST CS_SOFTC *pCS;
USHORT Event;
struct ifnet *pIf;
if( Unit >= CS_MAX_NUM_UNITS )
return;
pCS = &cs_softc[Unit];
pIf = &pCS->ArpCom.ac_if;
/* Ignore any interrupts that happen while the chip is being reset */
if( pCS->Resetting )
return;
/* Set locale flag */
pCS->InISR = TRUE;
/* Read an event from the Interrupt Status Queue */
if( pCS->InMemoryMode )
Event = csReadPacketPage( pCS, PKTPG_ISQ );
else
Event = SYS_ENET_IN_WORD( (pCS->IOAddr)+PORT_ISQ );
/* Process all the events in the Interrupt Status Queue */
while( Event != 0 )
{
/* Dispatch to an event handler based on the register number */
switch ( Event & REG_NUM_MASK )
{
case REG_NUM_RX_EVENT:
csReceiveEvent( pCS, Event );
break;
case REG_NUM_TX_EVENT:
csTransmitEvent( pCS, Event );
break;
case REG_NUM_BUF_EVENT:
csBufferEvent( pCS, Event );
break;
case REG_NUM_RX_MISS:
/* Read the Rx Miss count (clears the counter). */
/* Miss count is in the 10 MSBs */
pCS->ArpCom.ac_if.if_ierrors += ( (BYTE_SWAP(Event)) >> 6);
LOGMSG("csRxMissEvent: unit %d,, %d added to RX miss counter\n",
pCS->ArpCom.ac_if.if_unit, ( (BYTE_SWAP(Event)) >> 6),0,0,0,0 );
break;
case REG_NUM_TX_COL:
/* Read the collision counter (clears the counter). */
/* Collision count is in the 10 MSBs */
pCS->ArpCom.ac_if.if_collisions += ( (BYTE_SWAP(Event)) >> 6);
LOGMSG("csTxColEvent: unit %d, %d added to collision counter\n",
pCS->ArpCom.ac_if.if_unit, ( (BYTE_SWAP(Event)) >> 6),0,0,0,0 );
break;
default:
LOGMSG("csIntr: unit %d, Unknown interrupt event: %04X\n",
pCS->ArpCom.ac_if.if_unit, (BYTE_SWAP(Event)),0,0,0,0 );
break;
}
/* Read another event from the Interrupt Status Queue */
if ( pCS->InMemoryMode )
Event = csReadPacketPage( pCS, PKTPG_ISQ );
else
Event = SYS_ENET_IN_WORD( (pCS->IOAddr)+PORT_ISQ );
}
/* Ensure task-level event handler is running */
if( pCS->NetJobDepth < 2 )
{
pCS->NetJobDepth++;
netJobAdd ((FUNCPTR)csEventHandler, (int)pCS, 0, 0, 0, 0);
}
/* Clear locale flag */
pCS->InISR = FALSE;
}
/*******************************************************************************
*
* csBufferEvent -
*
* The routine is called whenever an event occurs regarding the transmit and
* receive buffers within the CS8900 chip. The only buffer events we
* currently handle are Rdy4TX interrupts, Tx Underruns, and SW ints.
*
*/
LOCAL void csBufferEvent( CS_SOFTC *pCS, USHORT BufEvent )
{
USHORT BusStatus;
if ( BufEvent & BUF_EVENT_TX_UNDR )
{
/* TX underrun occured */
pCS->TxUnderruns++;
/* Modify start command if total underruns > threshold value */
/* by setting TX start command to next increment */
if( pCS->TxUnderruns == CS_TX_UNDRUN_TRHSHOLD )
{
/* Reset the threshold counter */
pCS->TxUnderruns = 0;
/* Select the next TxStartCommand */
if( pCS->TxStartCMD == TX_CMD_START_5 )
pCS->TxStartCMD = TX_CMD_START_381;
else if( pCS->TxStartCMD == TX_CMD_START_381 )
pCS->TxStartCMD = TX_CMD_START_1021;
else pCS->TxStartCMD = TX_CMD_START_ALL;
}
/* Try to TX the frame again */
if ( pCS->InMemoryMode )
{
csWritePacketPage( pCS, PKTPG_TX_CMD, pCS->TxStartCMD );
csWritePacketPage( pCS, PKTPG_TX_LENGTH, BYTE_SWAP(pCS->TxLength) );
}
else /* In IO mode */
{
SYS_ENET_OUT_WORD( (pCS->IOAddr)+PORT_TX_CMD, pCS->TxStartCMD );
SYS_ENET_OUT_WORD( (pCS->IOAddr)+PORT_TX_LENGTH,
BYTE_SWAP(pCS->TxLength));
}
/* Read BusStatus register which indicates success of the request */
BusStatus = csReadPacketPage( pCS, PKTPG_BUS_ST );
if ( BusStatus & BUS_ST_RDY4TXNOW )
{
/* On-chip buffer space available -- start transmission */
csCopyTxFrame( pCS, pCS->pTxFrameChain );
} /* @kml Do NOT give up the frame. */
/* else
{*/
/* Give up on this frame */
/* Queue the mbuf chain to be freed at task level */
/* csEnqueue( pCS->pTxBuffFreeList, pCS->pTxFrameChain );*/
/* Set TX not in progress */
/* pCS->pTxFrameChain = NULL;
pCS->TxInProgress = FALSE;*/
/* Update output stats */
/* pCS->ArpCom.ac_if.if_opackets--;*/
/* @kml The definition of the MIB-II variable ifOutUcastPkts in Interface
group from RFC 1158 is "The total number of packets that higher-level
protocols requested be transmitted to a subnetwork-unicast address,
INCLUDE those that were discarded or not sent."*/
/* pCS->ArpCom.ac_if.if_oerrors++;*/
/* Start TX of the next frame if any */
/*csTxNextFrame( pCS );*/
/*}*/
LOGMSG("csBufferEvent: unit %d, Transmit underrun\n",
pCS->ArpCom.ac_if.if_unit, 0,0,0,0,0 );
pCS->TotalTxUnderruns++;
}
else if ( BufEvent & BUF_EVENT_RDY4TX )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -