?? ne2000end.c
字號:
{
/* Disable RX int */
pDrvCtrl->imask &= ~IM_PRXE;
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
pDrvCtrl->flags |= END_RECV_HANDLING_FLAG;
(void)netJobAdd ((FUNCPTR)ne2000HandleRcvInt, (int)pDrvCtrl,
0,0,0,0);
}
}
/* Check for transmit complete */
if ((intStat & (ISTAT_TXE | ISTAT_PTX)) != 0)
{
pDrvCtrl->flags &= ~END_TX_IN_PROGRESS;
ENDLOGMSG (("ne2000Int: Tx complete, blocked=%d\n",
(pDrvCtrl->flags & END_TX_BLOCKED) ? 1 : 0,0,0,0,0,0));
if (pDrvCtrl->flags & END_TX_BLOCKED)
{
/* Disable TX ints */
pDrvCtrl->imask &= ~(IM_TXEE | IM_PTXE);
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
pDrvCtrl->flags &= ~END_TX_BLOCKED;
netJobAdd ((FUNCPTR)muxTxRestart, (int)&pDrvCtrl->endObj,
0, 0, 0, 0);
}
}
/* Flush the write pipe */
CACHE_PIPE_FLUSH ();
}
/*******************************************************************************
*
* ne2000HandleRcvInt - task level interrupt service for input packets
*
* This routine is called at task level indirectly by the interrupt
* service routine to do any message received processing.
*
* RETURNS: N/A.
*/
LOCAL void ne2000HandleRcvInt
(
NE2000END_DEVICE *pDrvCtrl
)
{
int oldLevel;
char *pBuf;
/* END_RECV_HANDLING_FLAG set by ISR */
ENDLOGMSG (("ne2000HandleRcvInt(%x): enter (flags=%x)\n",
pDrvCtrl,pDrvCtrl->flags,0,0,0,0));
pBuf = NULL;
while (pDrvCtrl->flags & END_RECV_HANDLING_FLAG)
{
int len;
CL_BLK_ID pClBlk;
M_BLK_ID pMblk; /* MBLK to send upstream */
ENDLOGMSG (("ne2000HandleRcvInt: flags=%x imask=%x cur=%d next=%d\n",
pDrvCtrl->flags, pDrvCtrl->imask,
pDrvCtrl->current, pDrvCtrl->nextPacket,
0, 0));
/* check if all packets removed */
if (pDrvCtrl->nextPacket == pDrvCtrl->current)
break;
/* Break out if we get an overwrite condition */
if (pDrvCtrl->flags & END_OVERWRITE)
break;
/* Allocate an MBLK, and a replacement buffer */
if (!pBuf)
{
pBuf = netClusterGet (pDrvCtrl->endObj.pNetPool,
pDrvCtrl->clPoolId);
if (!pBuf)
{
ENDLOGMSG (("ne2000HandleRcvInt: Out of clusters!\n",
0, 0, 0, 0, 0, 0));
break;
}
}
/* Read packet in offset so IP header is long-aligned */
len = ne2000PacketGet (pDrvCtrl, pBuf + pDrvCtrl->offset);
if (len <= 0)
{
ENDLOGMSG (("ne2000HandleRcvInt: bad packet! (len=%d)\n",
len, 0, 0, 0, 0, 0));
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
break;
}
pMblk = mBlkGet (pDrvCtrl->endObj.pNetPool,
M_DONTWAIT, MT_DATA);
if (!pMblk)
{
ENDLOGMSG (("ne2000HandleRcvInt: Out of M Blocks!\n",
0, 0, 0, 0, 0, 0));
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
break;
}
pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT);
if (!pClBlk)
{
ENDLOGMSG (("ne2000HandleRcvInt: Out of CL Blocks!\n",
0, 0, 0, 0, 0, 0));
netMblkFree (pDrvCtrl->endObj.pNetPool, (M_BLK_ID)pMblk);
break;
}
/* Associate the data pointer with the MBLK */
netClBlkJoin (pClBlk, pBuf, NE2000_BUFSIZ, NULL, 0, 0, 0);
/* Associate the data pointer with the MBLK */
netMblkClJoin (pMblk, pClBlk);
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
pMblk->mBlkHdr.mLen = len;
pMblk->mBlkPktHdr.len = len;
/* Adjust mData to match n23000PacketGet() above */
pMblk->mBlkHdr.mData += pDrvCtrl->offset;
/* record received packet */
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
/* Call the upper layer's receive routine. */
END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk);
/* buffer was used, will need another next time around */
pBuf = NULL;
}
/* If we still have an unused buffer, free it */
if (pBuf)
netClFree (pDrvCtrl->endObj.pNetPool, (UCHAR *) pBuf);
/* Re-enable the receive interrupt */
oldLevel = intLock ();
pDrvCtrl->flags &= ~END_RECV_HANDLING_FLAG;
pDrvCtrl->imask |= IM_PRXE;
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
ENDLOGMSG (("ne2000HandleRcvInt: done (flags=%x, imask=%x)\n",
pDrvCtrl->flags,pDrvCtrl->imask,0,0,0,0));
intUnlock (oldLevel);
}
/*******************************************************************************
*
* ne2000DataIn - input bytes from NE2000 memory
*
* NOMANUAL
*/
LOCAL void ne2000DataIn
(
NE2000END_DEVICE * pDrvCtrl,
int eneAddress,
int len,
char * pData
)
{
if (len == 0)
return;
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0);
SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);
SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR0, eneAddress & 0xff);
SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR1, eneAddress >> 8);
SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, len & 0xff);
SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, len >> 8);
SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_RREAD | CMD_START);
SYS_IN_WORD_STRING (pDrvCtrl, ENE_DATA, pData, len/2);
if (len & 1)
SYS_IN_CHAR (pDrvCtrl, ENE_DATA, (pData + (len - 1)));
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
}
/*******************************************************************************
*
* ne2000DataOut - output bytes to NE2000 memory
*
* NOMANUAL
*/
LOCAL void ne2000DataOut
(
NE2000END_DEVICE * pDrvCtrl,
char * pData,
int len,
int eneAddress
)
{
if (len == 0)
return;
SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, (char)0xff);
SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);
SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR0, eneAddress & 0xff);
SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR1, eneAddress >> 8);
SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, len & 0xff);
SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, len >> 8);
SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_RWRITE | CMD_START);
SYS_OUT_WORD_STRING (pDrvCtrl, ENE_DATA, pData, len/2);
if (len & 1)
SYS_OUT_CHAR (pDrvCtrl, ENE_DATA, *(pData + (len - 1)));
}
/*******************************************************************************
*
* ne2000Send - the driver send routine
*
* This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
* The buffer must already have the addressing information properly installed
* in it. This is done by a higher layer. The last arguments are a free
* routine to be called when the device is done with the buffer and a pointer
* to the argument to pass to the free routine.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS ne2000Send
(
void* pCookie, /* device ptr */
M_BLK_ID pMblk /* data to send */
)
{
int len;
UCHAR cmdStat;
NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;
/*
* Obtain exclusive access to transmitter. This is necessary because
* we might have more than one stack transmitting at once.
*/
if (pDrvCtrl->flags & (END_OVERWRITE | END_OVERWRITE2))
{
return (END_ERR_BLOCK);
}
ENDLOGMSG (("ne2000Send: enter: (flags=%x, imask=%x)\n",
pDrvCtrl->flags, pDrvCtrl->imask, 0, 0, 0, 0));
/* Note device receive interrupts may still be enabled */
END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
pDrvCtrl->flags |= END_TX_BLOCKED;
if (pDrvCtrl->flags & END_TX_IN_PROGRESS)
{
int cnt;
ENDLOGMSG (("ne2000Send: waiting for TX_IN_PROGRESS\n",
0,0,0,0,0,0));
/* Wait up to 1 second */
cnt = sysClkRateGet ();
while ((pDrvCtrl->flags & END_TX_IN_PROGRESS) && (cnt-- > 0))
taskDelay (1);
}
/* Disable device interrupts and check for overwrite detected */
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0);
if (pDrvCtrl->flags & (END_OVERWRITE | END_OVERWRITE2))
{
ENDLOGMSG (("ne2000Send: overwrite detected (timeout)\n",
0, 0, 0, 0, 0, 0));
pDrvCtrl->flags &= ~END_TX_BLOCKED;
END_TX_SEM_GIVE (&pDrvCtrl->endObj);
return (END_ERR_BLOCK);
}
/* If TX still in progress, re-configure chip */
if (pDrvCtrl->flags & END_TX_IN_PROGRESS)
{
UCHAR tstat;
SYS_IN_CHAR (pDrvCtrl, ENE_TSTAT, &tstat);
SYS_IN_CHAR (pDrvCtrl, ENE_CMD, &cmdStat);
ENDLOGMSG (("ne2000Send: timeout: flags=%x cmd=%02x stat=%02x\n",
pDrvCtrl->flags, cmdStat, tstat, 0, 0, 0));
ne2000Config (pDrvCtrl, FALSE);
}
/* Copy and free the MBLK */
len = netMblkToBufCopy (pMblk, pDrvCtrl->packetBuf, NULL);
netMblkClChainFree (pMblk);
len = max (len, ETHERSMALL);
/* Transfer to the device */
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0x00);
ne2000DataOut (pDrvCtrl, pDrvCtrl->packetBuf, len, (NE2000_TSTART << 8));
/* Flush the write pipe */
CACHE_PIPE_FLUSH ();
/* kick Transmitter */
SYS_OUT_CHAR (pDrvCtrl, ENE_TSTART, NE2000_TSTART);
SYS_OUT_CHAR (pDrvCtrl, ENE_TCNTH, len >> 8);
SYS_OUT_CHAR (pDrvCtrl, ENE_TCNTL, len & 0xff);
SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_TXP | CMD_START);
/* mark tx as in progress */
pDrvCtrl->flags |= END_TX_IN_PROGRESS;
/* Re-enable device TX interrupts */
pDrvCtrl->imask |= (IM_TXEE | IM_PTXE);
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
END_TX_SEM_GIVE (&pDrvCtrl->endObj);
/* update statistics */
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
ENDLOGMSG (("ne2000Send: done: imask=%02x\n",
pDrvCtrl->imask, 0, 0, 0, 0, 0));
return (OK);
}
/*******************************************************************************
*
* ne2000PacketGet - get next received message
*
* Get next received message. Returns NULL if none are
* ready.
*
* RETURNS: ptr to next packet, or NULL if none ready.
*/
LOCAL int ne2000PacketGet
(
NE2000END_DEVICE *pDrvCtrl,
char *pData
)
{
UINT packetSize;
UCHAR uppByteCnt;
UINT8 tempPage; /* used in buffer validation */
UINT8 pageCount; /* used in buffer validation */
UINT packetLen = 0;
NE2000_HEADER h;
if (pDrvCtrl->nextPacket == pDrvCtrl->current)
return (0);
ne2000DataIn (pDrvCtrl,
(((UINT)pDrvCtrl->nextPacket << 8) & 0x0000ffff),
sizeof (NE2000_HEADER), (char *) &h);
/*
* Calculate upper byte count in case it's corrupted,
* though this supposedly happens only in StarLAN applications
* with bus clock frequence greater than 4 mHz.
*/
if (h.next > pDrvCtrl->nextPacket)
uppByteCnt = (UCHAR) (h.next - pDrvCtrl->nextPacket);
else
uppByteCnt = (UCHAR) ((NE2000_PSTOP - pDrvCtrl->nextPacket)
+ (h.next - NE2000_PSTART));
if (h.lowByteCnt > 0xfc)
uppByteCnt -= 2;
else
uppByteCnt -= 1;
h.uppByteCnt = uppByteCnt;
/* compute packet size excluding Ethernet checksum bytes */
packetSize = (((UINT)h.uppByteCnt << 8) + h.lowByteCnt) - 4;
/* Check for packet (and header) shifted in memory (by heavy load).
* The method and solution are recommended by 3Com in their
* EtherLink II Adapter Technical Manual, with the addition of
* a reasonableness check on the next-page link.
*/
pageCount = (UCHAR) ((packetSize + 4 + sizeof (NE2000_HEADER)
+ (ENE_PAGESIZE - 1)) / ENE_PAGESIZE);
tempPage = (UCHAR) (pDrvCtrl->nextPacket + pageCount);
if (tempPage >= NE2000_PSTOP)
tempPage -= (NE2000_PSTOP - NE2000_PSTART);
if ((h.next != tempPage) ||
(h.next < NE2000_PSTART) || (h.next >= NE2000_PSTOP))
{
/* can't trust anything now */
pDrvCtrl->stats.badPacket++;
pDrvCtrl->stats.rerror++;
/* stop and restart the interface */
if (!(pDrvCtrl->flags & (END_OVERWRITE|END_OVERWRITE2)))
ne2000Config (pDrvCtrl, TRUE);
return (-1);
}
/* reject runts, although we are configured to reject them */
if (packetSize < 60)
{
pDrvCtrl->stats.shortPacket++;
goto doneGet;
}
/* reject packets larger than our scratch buffer */
if (packetSize > NE2000_BUFSIZ)
goto doneGet;
if (h.rstat & RSTAT_PRX)
{
/* 3Com says this status marks a packet bit-shifted in memory;
* the data cannot be trusted but the NIC header is OK.
*/
if (h.rstat & (RSTAT_DFR | RSTAT_DIS))
{
pDrvCtrl->stats.badPacket++;
pDrvCtrl->stats.rerror++;
goto doneGet;
}
pDrvCtrl->stats.rnoerror++;
}
else
{
if (h.rstat & RSTAT_DFR)
pDrvCtrl->stats.jabber++;
pDrvCtrl->stats.rerror++;
goto doneGet;
}
/* Signal that we received a good packet */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -