smsc100.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,011 行 · 第 1/3 页
C
1,011 行
}
DWORD
Smsc100FdGetPendingInterrupts ()
{
Smsc100FdInterrupt ();
if (fFrameReceived)
return (INTR_TYPE_RX);
return (0);
}
//
// This routine is polled to find out if a frame has been received. If there are no frames
// in the RX FIFO, the routine will return 0. If there was a frame that was received correctly,
// it will be stored in pwData, otherwise it will be discarded.
//
UINT16
Smsc100FdGetFrame (BYTE *pbData, UINT16 *pusLength)
{
UINT uiStatusControl;
UINT16 usStatusWord, usControlWord;
DWORD *pdwData;
UINT uiDwordCount;
UINT uiCount;
UINT uiRemainder;
DWORD dwStartTime;
BOOL fDropFrame;
UINT16 usBufLen = *pusLength;
// EdbgOutputDebugString ("+Smsc100FdGetFrame\r\n");
// For the bootloader we don't want to deal with interrupts, so I'll poll the ISR routine
Smsc100FdInterrupt ();
while (fFrameReceived)
{
//
// Setup the pointer address register to point to first byte of the Frame.
//
SelectBank (BANK2);
WriteWord (POINTER, PTR_RCV | PTR_AUTOINC | PTR_READ);
//
// Check for an error.
//
uiStatusControl = ReadDWord (DATA_1);
// EdbgOutputDebugString (" Smsc100FdGetFrame: uiStatusControl = 0x%x\n", uiStatusControl);
usStatusWord = uiStatusControl & 0xffff;
// EdbgOutputDebugString (" Smsc100FdGetFrame: Status = 0x%x\n", usStatusWord);
if (usStatusWord & (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT))
fDropFrame = TRUE; // Don't deliver this frame
else
{
fDropFrame = FALSE;
pdwData = (DWORD *)pbData;
//
// The top bits of the byte count are reserved, so mask them off.
// The byte count includes the status word, byte count and control byte so subtract 6 bytes from the length.
//
*pusLength = uiStatusControl >> 16;
// EdbgOutputDebugString (" Smsc100FdGetFrame: Raw Length = 0x%x\n", *pusLength);
*pusLength = (*pusLength & 0x07FF) - 6;
// EdbgOutputDebugString (" Smsc100FdGetFrame: Adjusted Length = 0x%x\n", *pusLength);
if (*pusLength > usBufLen)
{
EdbgOutputDebugString ("Smsc100FdGetFrame: Received packet length (%u) is larger than buffer length (%u).\n", *pusLength, usBufLen);
fDropFrame = TRUE;
goto ReleaseFrame;
}
//
// Calculate the number of DWORDs to read
//
uiCount = 0;
uiDwordCount = *pusLength >> 2; // Number of DWORDs to move
uiRemainder = *pusLength & 0x3; // Number of bytes in last DWORD
// EdbgOutputDebugString (" Smsc100FdGetFrame: uiDwordCount = %d (0x%x)\n", uiDwordCount, uiDwordCount);
// EdbgOutputDebugString (" Smsc100FdGetFrame: uiRemainder = %d (0x%x)\n", uiRemainder, uiRemainder);
//
// Read all but the last word, which contains the control word
//
for (; uiCount < uiDwordCount; uiCount++)
*pdwData++ = ReadDWord (DATA_1);
//
// Read the last dword and extract the control word and trailing 1 to 3 bytes
//
uiStatusControl = ReadDWord (DATA_1);
// EdbgOutputDebugString (" Smsc100FdGetFrame: Last DWORD = 0x%x\n", uiStatusControl);
switch (uiRemainder)
{
case 0:
case 1:
usControlWord = uiStatusControl;
break;
case 2:
case 3:
usControlWord = uiStatusControl >> 16;
*(PWORD)pdwData = (WORD)(uiStatusControl);
(PBYTE)pdwData += sizeof (WORD);
break;
}
//
// If the received packet length is odd, extract the last byte from the control word.
//
if (usControlWord & RC_ODDFRAME)
{
*(PBYTE)pdwData = (BYTE)usControlWord;
(*pusLength)++;
}
}
//
// Release the memory for the received Frame.
//
ReleaseFrame:
WriteWord (MMU_CMD, MC_RELEASE);
//
// Wait until the MMU command finishes executing.
//
dwStartTime = OEMEthGetSecs ();
while (ReadWord (MMU_CMD) & MC_BUSY)
{
if ((OEMEthGetSecs () - dwStartTime) > 2)
{
EdbgOutputDebugString (" Smsc100FdGetFrame: Timed out releasing memory.\n");
break;
}
}
//
// If the buffer is now empty, re-enable the IS_RCV_INT and clear the fFrameReceived flag.
//
if (!(ReadWord (INTERRUPT_REGISTER) & IS_RCV_INT))
{
fFrameReceived = 0;
WriteWord (INTERRUPT_REGISTER, wIntMask);
}
//
// Check the status word for errors.
#if 0
if (usStatusWord & RS_ALGNERR)
EdbgOutputDebugString ("Smsc100FdGetFrame: Receive Alignment Error\n" );
if (usStatusWord & RS_BADCRC)
EdbgOutputDebugString ("Smsc100FdGetFrame: CRC Error\n" );
if (usStatusWord & RS_TOOLONG)
EdbgOutputDebugString ("Smsc100FdGetFrame: Frame Was Too Long\n" );
if (usStatusWord & RS_TOOSHORT)
EdbgOutputDebugString ("Smsc100FdGetFrame: Frame Was Too Short\n" );
#endif
#ifdef SMSC_DUMP_FRAMES
DumpEtherFrame (pbData, *pusLength);
#endif
//
// If the frame isn't filtered, return the data.
//
if (!fDropFrame)
{
// EdbgOutputDebugString ("Smsc100FdGetFrame: Returning %u bytes\n", *pusLength);
return (TRUE);
}
}
// EdbgOutputDebugString ("-Smsc100FdGetFrame\r\n");
return (FALSE);
}
//
// This routine should be called with a pointer to the ethernet frame data. It is the caller's
// responsibility to fill in all information including the destination and source addresses and
// the frame type. The length parameter gives the number of bytes in the ethernet frame.
// The routine will not return until the frame has been transmitted or an error has occured. If
// the frame transmits successfully, 0 is returned. If an error occured, a message is sent to
// the serial port and the routine returns non-zero.
UINT16
Smsc100FdSendFrame (BYTE *pbData, DWORD dwLength)
{
UINT16 wFrameHandle;
UINT16 cwBufferSize;
UINT16 wCompletionCode;
DWORD *pdwData;
DWORD dwStartTime;
BOOL bErr = FALSE;
UINT uiDwordCount;
UINT uiCount;
UINT uiRemainder;
USHORT usPhy;
// EdbgOutputDebugString ("+Smsc100FdSendFrame Length: %u\r\n", dwLength);
fTXEMPTY_INT = fTX_INT = 0;
#ifdef SMSC_DUMP_FRAMES
DumpEtherFrame (pbData, (USHORT)dwLength);
#endif
//
// Reset the Isolation bit in the PHY, and adjust the TCR based on the PHY autonegotiation.
//
usPhy = Smsc100FdReadPhy (PHY_CONTROL);
Smsc100FdWritePhy ((USHORT)PHY_CONTROL, (USHORT)(usPhy & ~PHY_CTRL_ISOLATION));
SelectBank (BANK0);
if (usPhy & PHY_CTRL_DUPLEX)
WriteWord (TCR, ReadWord (TCR) | TCR_SWFDUP);
else
WriteWord (TCR, ReadWord (TCR) & ~TCR_SWFDUP);
//
// Calculate the size of the buffer
//
cwBufferSize = 2 + 2 + (UINT16)dwLength + 1;
if (cwBufferSize & 1)
cwBufferSize++;
// Allocate memory in the buffer for the Frame
SelectBank (BANK2);
WriteWord (MMU_CMD, MC_ALLOC | (UINT16)(cwBufferSize >> 9)); // Number of 512 byte pages
//
// Loop here until the request is satisfied, or a timeout occurs.
//
dwStartTime = OEMEthGetSecs ();
while (!(ReadWord (INTERRUPT_REGISTER) & IS_ALLOC_INT))
{
if (OEMEthGetSecs () - dwStartTime > 2)
{
EdbgOutputDebugString ("!Smsc100FdSendFrame: Timed out waiting for SMSC91C100FD to allocate transmit memory.\r\n");
//
// Get the status word so that it can be returned.
//
WriteWord (POINTER, PTR_READ);
wCompletionCode = ReadWord (DATA_1);
return (wCompletionCode);
}
}
wFrameHandle = ReadWord (PNR_ARR) >> 8;
//
// Write the Frame into the buffer.
//
WriteWord (PNR_ARR, wFrameHandle);
WriteWord (POINTER, PTR_AUTOINC);
//
// Write the Status Word.
//
WriteWord (DATA_1, 0);
//
// Write the byte count = status word + byte count + data area + control byte
// This needs to be rounded up to an even number.
//
WriteWord (DATA_1, cwBufferSize);
//
// Now write all the DWORDS from the data
//
pdwData = (DWORD *)pbData;
uiDwordCount = dwLength >> 2; // Number of DWORDs to move
uiRemainder = dwLength & 0x3; // Number of bytes in last DWORD
for (uiCount = 0; uiCount < uiDwordCount; uiCount++)
WriteDWord (DATA_1, *pdwData++);
//
// Fix up the last WORD or DWORD, and the control byte
//
switch (uiRemainder)
{
case 0:
WriteWord (DATA_1, TC_APPENDCRC); // Create the last WORD, control word only
break;
case 1:
WriteWord (DATA_1, TC_APPENDCRC | TC_ODDFRAME | (*(PBYTE)pdwData & 0xff)); // Create the last WORD, control word plus last byte of data
break;
case 2:
WriteDWord (DATA_1, (TC_APPENDCRC << 16) | (*(PWORD)pdwData & 0xffff)); // Create the last DWORD, control word plus last two bytes of data
break;
case 3:
WriteDWord (DATA_1, ((TC_APPENDCRC | TC_ODDFRAME) << 16) | (*pdwData & 0xffffff)); // Create the last DWORD, control word plus last three bytes of data
break;
}
//
// Clear the IS_TX_INT and IS_TXEMPTY_INT before sending the frame.
//
WriteWord (INTERRUPT_REGISTER, wIntMask | IS_TX_INT | IS_TXEMPTY_INT);
//
// Enqueue the Frame number into the TX FIFO.
//
WriteWord (MMU_CMD, MC_ENQUEUE);
// Wait until either an error occurs or transmission completes successfully
dwStartTime = OEMEthGetSecs ();
while (!fTXEMPTY_INT && !fTX_INT)
{
Smsc100FdInterrupt ();
if (OEMEthGetSecs () - dwStartTime > 2)
{
EdbgOutputDebugString ("!Smsc100FdSendFrame: Timed out waiting for transmission to complete.\r\n");
bErr = TRUE;
break;
}
}
//
// If an error occured during transmission, IS_TX_INT will be generated, but IS_TXEMPTY_INT
// will not because the packet to be transmitted will not be automatically removed
// From the transmit FIFO. If this happens, delete the untransmitted Frame
// from the buffer. If no error occurred, this will be done by the chip because it's in
// AUTO RELEASE mode.
//
if (bErr || (fTX_INT && !fTXEMPTY_INT))
{
// Get the status word so that it can be returned.
WriteWord (POINTER, PTR_READ);
wCompletionCode = ReadWord (DATA_1);
#if 0
if (wCompletionCode & ES_TXOVERRUN)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Transmission Underrun\r\n");
if (wCompletionCode & ES_LINK_OK)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Link Test Failed\r\n");
if (wCompletionCode & ES_RXOVERRUN)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Receive Overrun\r\n");
if (wCompletionCode & TS_ROLLOVER)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Statistics Counter Roll Over\r\n");
if (wCompletionCode & TS_EXCESSIVE)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Excessive Deferral\r\n");
if (wCompletionCode & TS_LOSTCAR)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Lost Carrier\r\n");
if (wCompletionCode & TS_LATCOL)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Late Collision\r\n");
if (wCompletionCode & TS_DEFER)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Transmission Deferred\r\n");
if (wCompletionCode & TS_LTX_BROAD)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Last Frame Was Broadcast\r\n");
if (wCompletionCode & TS_SQET)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Signal Quality Error\r\n");
if (wCompletionCode & TS_16COL)
EdbgOutputDebugString ("!Smsc100FdSendFrame: 16 Collisions Reached\r\n");
if (wCompletionCode & TS_LTX_MULTI)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Last Frame Was Multicast\r\n");
if (wCompletionCode & TS_MULTIPLE)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Multiple Collisions Detected\r\n");
if (wCompletionCode & TS_SINGLE)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Single Collion Detected\r\n");
if (wCompletionCode & TS_SUCCESS)
EdbgOutputDebugString ("!Smsc100FdSendFrame: Transmit Successful\r\n");
#endif
//
// Clear the statistics registers.
//
SelectBank (BANK0);
ReadWord (COUNTER);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?