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 + -
显示快捷键?