⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 am79c970.c

📁 可在VMWare workstation中的运行的wince 5 bsp
💻 C
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  

Abstract:  
	Plain Vanilla Routines for AMD Am79c970a NIC.
	This mainly supports initialization and Sending/Receiving Ethernet packets
	as well as interrupt handler.
	Minimum error handling is provided here...
    
Functions:
	
Notes: 
	Code is meant to be used for ethernet download and debugging only and 
	is expected to run in Kernel Mode...

    
--*/

#include <windows.h>
#include <halether.h>
#include <ceddk.h>
#include "am79c970.h"


/////////////////////////////////////////////////////////////////////////////////
//	External Functions that must be there...
//

#define localDEBUGMSG EdbgOutputDebugString
//extern	void	localDEBUGMSG(const unsigned char *sz, ...);
extern	DWORD	OEMEthGetMSecs (void);


/////////////////////////////////////////////////////////////////////////////////
//	Global Variables and defines...
//

#define		MAX_BUFFER_SIZE			1536	//	12*128(=max cache line size)

PBYTE		pbEthernetBase;					//	Ethernet IO Base Address...

DWORD		dwTRANSMIT_DESCRIPTORS_HEAD;	//	Start of TX descriptors.
DWORD		dwTRANSMIT_BUFFER_START;		//	Start of TX buffer linked to descriptors.
DWORD		dwTRANSMIT_RING_SIZE;			//	Size of the entire TX ring.

DWORD		dwRECEIVE_DESCRIPTORS_HEAD;		//	Start of RX descriptors.
DWORD		dwRECEIVE_BUFFER_START;			//	Start of RX buffer linked to descriptors.
DWORD		dwRECEIVE_RING_SIZE;			//	Size of the entire RX ring.


static		DWORD					dwMEM_OFFSET;			//	When NIC and CPU not having same offset to memory...

volatile	PRX_DESCRIPTOR_FORMAT	pCurrentRxDesc;			//	pointer to current RX Descriptor that Rx may use.
volatile	PRX_DESCRIPTOR_FORMAT	pLastRxDesc;			//	pointer to Last RX descriptor.

volatile	PTX_DESCRIPTOR_FORMAT	pCurrentTxDesc;			//	pointer to current TX Descriptor that Tx may use.
volatile	PTX_DESCRIPTOR_FORMAT	pLastTxDesc;			//	pointer to Last TX descriptor.


/////////////////////////////////////////////////////////////////////////////////
//	Forward decl...
//
void	DumpOneTxDescriptor (PTX_DESCRIPTOR_FORMAT	 pTxDesc);
void	DumpOneRxDescriptor (PRX_DESCRIPTOR_FORMAT	 pRxDesc);
void	DumpTxDescriptors ();
void	DumpRxDescriptors ();
void	DumpMemory (PBYTE pSource, DWORD dwLength);
void	DumpSenderAddr (PBYTE pSource);



/////////////////////////////////////////////////////////////////////////////////
//	Misc helper functions...
//

#define		SECOND_COMP(x)		((long) (0-(DWORD)x))
//#define		TO_REAL(Addr)		((Addr & 0x1fffffff) + dwMEM_OFFSET)
//#define		TO_VIRT(Addr)		((Addr | 0xA0000000) - dwMEM_OFFSET)
#define		TO_REAL(Addr)		(Addr)
#define		TO_VIRT(Addr)		(Addr)


void SleepLoop (DWORD dwCounter)
{
	//	Simply loop...
	while (dwCounter--)
		;
}	// SleepLoop()


void WriteCSR (DWORD dwIndex, DWORD dwValue)
{
	//localDEBUGMSG (">>> [%d] <-- 0x%x \r\n", dwIndex, dwValue);
	WRITE_PORT_ULONG(RAP, dwIndex);
	WRITE_PORT_ULONG(RDP, dwValue);
}

DWORD ReadCSR (DWORD dwIndex)
{
    DWORD dwRAP;

    WRITE_PORT_ULONG(RAP, dwIndex);
    dwRAP = READ_PORT_ULONG(RDP);
    return dwRAP;
}

void WriteBCR (DWORD dwIndex, DWORD dwValue)
{
    WRITE_PORT_ULONG(RAP, dwIndex);
    WRITE_PORT_ULONG(BDP, dwValue);
}

DWORD ReadBCR (DWORD dwIndex)
{
    DWORD dwBDP;
    
    WRITE_PORT_ULONG(RAP, dwIndex);
    dwBDP = READ_PORT_ULONG(BDP);
    return dwBDP;
}


PTX_DESCRIPTOR_FORMAT GetNextTxDesc (PTX_DESCRIPTOR_FORMAT pGivenTxDesc)
{
	if (pGivenTxDesc == pLastTxDesc)
		return (PTX_DESCRIPTOR_FORMAT) dwTRANSMIT_DESCRIPTORS_HEAD;		
	else
		return (PTX_DESCRIPTOR_FORMAT) (pGivenTxDesc + 1);
}


PRX_DESCRIPTOR_FORMAT GetNextRxDesc (PRX_DESCRIPTOR_FORMAT pGivenRxDesc)
{
	if (pGivenRxDesc == pLastRxDesc)
		return (PRX_DESCRIPTOR_FORMAT) dwRECEIVE_DESCRIPTORS_HEAD;		
	else
		return (PRX_DESCRIPTOR_FORMAT) (pGivenRxDesc + 1);
}



/////////////////////////////////////////////////////////////////////////////////
//	InitTxDescriptor initializes a given descriptor pointed to by pTxDesc to
//	use buffer pointed to by pBuffer...
//

void InitTxDescriptor (PTX_DESCRIPTOR_FORMAT pTxDesc, DWORD	pBuffer)
{
	//localDEBUGMSG ("Address: 0x%x --- Buffer 0x%x \r\n", pTxDesc, pBuffer);
								
	pTxDesc->TMD2.dwReg		= 0x00;							//	AMD controls the contents here...	
	
	pTxDesc->TMD1.dwReg		= 0x00;							//	Important one is the OWN bit settting.
	pTxDesc->TMD1.ALL_ONES  = 0xf;							//	And the MUST BE ONEs field.
	pTxDesc->TMD1.BCNT		= SECOND_COMP(MAX_BUFFER_SIZE);
	
	if (pBuffer)											//	Only point to buffer if pBuffer is avail...
		pTxDesc->TBADR		= TO_REAL(pBuffer);				//	TX buffer for this descriptor...

}	// InitTxDescriptor()


/////////////////////////////////////////////////////////////////////////////////
//	InitTxDescriptor initializes a given descriptor pointed to by pRxDesc to
//	use buffer pointed to by pBuffer...
//

void InitRxDescriptor (PRX_DESCRIPTOR_FORMAT pRxDesc, DWORD	pBuffer)
{
	//localDEBUGMSG ("Address: 0x%x --- Buffer 0x%x \r\n", pRxDesc, pBuffer);

	pRxDesc->RMD2.dwReg = 0x00;								//	AMD controls the fields in here...
	
	pRxDesc->RMD1.dwReg = RMD1_DEFAULT;						//	The goodies...
	pRxDesc->RMD1.BCNT	= SECOND_COMP(MAX_BUFFER_SIZE);		//	Main things are the size of buffer + OWN bit.
	
	if (pBuffer)
		pRxDesc->RBADR		= TO_REAL(pBuffer);					//	Rx buffer for this descriptor...

}	// InitRxDescriptor()


/////////////////////////////////////////////////////////////////////////////////
//	AM789C970Init()
//	Initializes the NIC.
//	pbBaseAddress = IO base address assigned to the NIC.
//	dwMemOffset	  = Can be used if the common memory (for descriptors and mem)
//					is not at the same offset as seen between host and NIC.
//	MacAddr		  = Contains the MAC address read from hardware upon successful
//					initialization.
//
//	Return value:
//		TRUE when NIC initialized successfully, FALSE otherwise.
//
//
//	Initialization procedure:
//	1.	BCR20 (or CSR58) bit 8 (SSIZE32) set to 1 for 32 bit accesses.	
//	2.	Use Alternative method for Initialization (Appendix C of am79c970a spec).
//	3.	Setup Transmit and Receive Descriptor Rings.
//
//	x.	Finally... Set INIT bit in CSR0 to get am789c970 to start reading the 
//		initialization block.
//


BOOL	AM79C970Init(BYTE *pbBaseAddress, ULONG	dwMemOffset, USHORT MacAddr[3])
{
	DWORD	i;	

    if (MacAddr == NULL) return FALSE;
    
	localDEBUGMSG ("AM79C970Init:: Init using i/o address: 0x%x - MEM Offset = 0x%x\r\n", 
		pbBaseAddress, dwMemOffset);

	pbEthernetBase = pbBaseAddress;	
	dwMEM_OFFSET   = dwMemOffset;


	/////////////////////////////////////////////////////////////////////////////
	//	Make sure all the tx and rx process stopped.
	//	I may get to this code because of jumping to reset vector from the 
	//	bootloader flash download...
	//	
	WriteCSR (0, 0x04);		
	SleepLoop(10000);



	/////////////////////////////////////////////////////////////////////////////
	//	The very first step is to soft reset the controller and invoke
	//	DWIO (DWord IO) mode (accomplished by writing 32 bit to RDP).
	//

	/////////////////////////////////////////////////////////////////////////////
	//	This causes the internal reset, and AMD PCI controller blocks further 
	//	accesses until its internal reset is done (around 1 uS).
	ReadWord (RESET_REGISTER);	
	WriteDword	(0x10, 0x00);
	SleepLoop(10000000);


	/////////////////////////////////////////////////////////////////////////////
	//	We are in business... First turn is to fix the MAC address required by 
	//	caller...
	//
	if( NULL != MacAddr ) {
		for (i = 0 ; i < 3 ; i++)	
			MacAddr[i] = ReadWord(i*2);	
	}

	
	localDEBUGMSG ("+--------------------- BEFORE -------------------------+\r\n");
	localDEBUGMSG ("CSR0 == 0x%x \r\n", ReadCSR(0));			
	localDEBUGMSG ("CSR04 == 0x%x \r\n", ReadCSR(4));		
	localDEBUGMSG ("CSR15 == 0x%x \r\n", ReadCSR(15));		
	localDEBUGMSG ("CSR58 == 0x%x \r\n", ReadCSR(58));		
	localDEBUGMSG ("BCR02 == 0x%x \r\n", ReadBCR(2));		
	localDEBUGMSG ("BCR9  == 0x%x \r\n", ReadBCR(9));
	

	/////////////////////////////////////////////////////////////////////////////
	//	Set the software style correctly then proceed with initialization 
	//	explained in appendix c of am79c970a manual.	
	//

	WriteCSR (58, CSR58_SSIZE32 | CSR58_SW_STYLE_PCNET_PCI_II_CONTROLLER);		// Software style.	
	WriteCSR (4, ReadCSR(4) | CSR4_DMA_PLUS | CSR4_APAD_XMIT | CSR4_TXSTRTM);	// Must be set for PCNET_PCI_II setting.		
	WriteBCR (2, ReadBCR(2) | BCR2_ASEL);										// Use auto select feature.

	WriteCSR (8, 0x00);		/////////////////////////////////////////////////////
	WriteCSR (9, 0x00);		// At this point we don't care about Logical adddr
	WriteCSR (10, 0x00);	// Filtering
	WriteCSR (11, 0x00);	//

								/////////////////////////////////////////////////////
	WriteCSR (12, MacAddr[0]);	//	Physical Address [15:00]
	WriteCSR (13, MacAddr[1]);	//	Physical Address [31:16]
	WriteCSR (14, MacAddr[2]);	//	Physical Address [47:32]

	WriteCSR (15, 0x00);		//	Turn off Promiscuous mode...

	WriteCSR (24, TO_REAL(dwRECEIVE_DESCRIPTORS_HEAD) & 0x0000ffff);			// RX descriptor starts...
	WriteCSR (25, (TO_REAL(dwRECEIVE_DESCRIPTORS_HEAD) & 0xffff0000) >> 16);

	WriteCSR (30, TO_REAL(dwTRANSMIT_DESCRIPTORS_HEAD) & 0x0000ffff);			// TX descriptor starts...
	WriteCSR (31, (TO_REAL(dwTRANSMIT_DESCRIPTORS_HEAD) & 0xffff0000) >> 16);

	WriteCSR (47, (DWORD) SECOND_COMP(0));								// Polling interval, use default...1.966ms
	WriteCSR (76, (DWORD) SECOND_COMP(dwRECEIVE_RING_SIZE));			// RX Ring Size...
	WriteCSR (78, (DWORD) SECOND_COMP(dwTRANSMIT_RING_SIZE));			// TX Ring Size...

	WriteBCR (9, ReadBCR(9) & 0xfffffffe);				// Make sure it is half duplex...
	WriteCSR (3, ReadCSR(3) | CSR3_MASK_ALL_INTS);		// Start off with all interrupt mask...EnableInts() will handle which one to turn on.


	/////////////////////////////////////////////////////////////////////////////
	//	Lets read 'em back for fun... :-)
	//	
	localDEBUGMSG ("+--------------------- AFTERWARDS -------------------------+\r\n");
	localDEBUGMSG ("CSR0 == 0x%x \r\n", ReadCSR(0));		
	localDEBUGMSG ("CSR3  == 0x%x \r\n", ReadCSR(3));
	localDEBUGMSG ("CSR04 == 0x%x \r\n", ReadCSR(4));		
	localDEBUGMSG ("CSR12 == 0x%x \r\n", ReadCSR(12));
	localDEBUGMSG ("CSR13 == 0x%x \r\n", ReadCSR(13));
	localDEBUGMSG ("CSR14 == 0x%x \r\n", ReadCSR(14));
	localDEBUGMSG ("CSR15 == 0x%x \r\n", ReadCSR(15));		
	localDEBUGMSG ("CSR24 == 0x%x \r\n", ReadCSR(24));		
	localDEBUGMSG ("CSR25 == 0x%x \r\n", ReadCSR(25));		
	localDEBUGMSG ("CSR30 == 0x%x \r\n", ReadCSR(30));		
	localDEBUGMSG ("CSR31 == 0x%x \r\n", ReadCSR(31));		
	localDEBUGMSG ("CSR47 == 0x%x \r\n", ReadCSR(47));
	localDEBUGMSG ("CSR58 == 0x%x \r\n", ReadCSR(58));		
	localDEBUGMSG ("CSR76 == 0x%x \r\n", ReadCSR(76));
	localDEBUGMSG ("CSR78 == 0x%x \r\n", ReadCSR(78));	
	localDEBUGMSG ("BCR02 == 0x%x \r\n", ReadBCR(2));		
	localDEBUGMSG ("BCR9  == 0x%x \r\n", ReadBCR(9));
	
	

	/////////////////////////////////////////////////////////////////////////////
	//	Initialize TX Descriptors...

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -