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

📄 am79c973.c

📁 可在VMWare workstation中的运行的wince 5 bsp
💻 C
字号:
//
// 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.
//
#include <windows.h>
#include <halether.h>

//------------------------------------------------------------------------------

#define Log                EdbgOutputDebugString

//------------------------------------------------------------------------------

#define BUFFER_SIZE        0x0600
#define DESC_SIZE          0x10
#define INIT_SIZE          0x20
#define ADDR_SIZE          6

#define TIMEOUT            2

#define RX_BUFFERS         32
#define TX_BUFFERS         4

//------------------------------------------------------------------------------

#define APROM              0x00
#define RDP                0x10
#define RAP                0x14
#define RESET              0x18
#define BDP                0x1C

//------------------------------------------------------------------------------

#define RMD1_OWN           0x80000000
#define RMD1_ERR           0x40000000
#define RMD1_FRAM          0x20000000
#define RMD1_OFLO          0x10000000
#define RMD1_CRC           0x08000000
#define RMD1_BUFF          0x04000000
#define RMD1_STP           0x02000000
#define RMD1_ENP           0x01000000
#define RMD1_BPE           0x00800000
#define RMD1_ONES          0x0000F000

#define TMD0_BUFF          0x80000000
#define TMD0_UFLO          0x40000000
#define TMD0_EXDEF         0x20000000
#define TMD0_LCOL          0x10000000
#define TMD0_LCAR          0x08000000
#define TMD0_RTRY          0x04000000

#define TMD1_OWN           0x80000000
#define TMD1_ERR           0x40000000
#define TMD1_ADD_FCS       0x20000000
#define TMD1_MORE          0x10000000
#define TMD1_LTINT         0x10000000
#define TMD1_ONE           0x08000000
#define TMD1_DEF           0x04000000
#define TMD1_STP           0x02000000
#define TMD1_ENP           0x01000000
#define TMD1_BPE           0x00800000
#define TMD1_ONES          0x0000F000

//------------------------------------------------------------------------------

#define INP32(x)           (*(volatile DWORD *)(x))
#define OUT32(x, y)        *(volatile DWORD *)(x)=(y)

#define V2P(a)             ((DWORD)(a) & ~0xE0000000)
#define C2U(a)             ((DWORD)(a) | 0xA0000000)

//------------------------------------------------------------------------------

static DWORD g_base = 0;               // The chip base address
static DWORD g_dmaAddress = 0;         // DMA buffer address
static ULONG g_dmaSize = 0;            // DMA buffer size

static ULONG *g_pInit;
static ULONG *g_pRxRing;
static ULONG *g_pTxRing;
static UCHAR *g_pRxBuffer;
static UCHAR *g_pTxBuffer;

static ULONG g_rxPos;
static ULONG g_txPos;

//------------------------------------------------------------------------------

static void  OEMSleep(DWORD delay)
{
	//	Simply loop...
	while (delay--)
		;
}

//------------------------------------------------------------------------------

static ULONG ReadCSR(DWORD address)
{
   OUT32(g_base + RAP, address);
   return INP32(g_base + RDP);
}

//------------------------------------------------------------------------------

static void WriteCSR(DWORD address, DWORD data)
{
   OUT32(g_base + RAP, address);
   OUT32(g_base + RDP, data);
}

//------------------------------------------------------------------------------

static ULONG ReadBCR(DWORD address)
{
   OUT32(g_base + RAP, address);
   return INP32(g_base + BDP);
}

//------------------------------------------------------------------------------

static void WriteBCR(DWORD address, DWORD data)
{
   OUT32(g_base + RAP, address);
   OUT32(g_base + BDP, data);
}

//------------------------------------------------------------------------------

static USHORT ReadMII(DWORD address)
{
   WriteBCR(33, (0x1e << 5) | (address & 0x1F));
   return (USHORT)ReadBCR(34);
}

//------------------------------------------------------------------------------

static void WriteMII(ULONG address, USHORT data)
{
   WriteBCR(33, (0x1e<<5) | (address & 0x1F));
   WriteBCR(34, data);
}

//------------------------------------------------------------------------------

static DWORD HashAddress(UCHAR* pAddress)
{
   ULONG crc, carry;
   UINT i, j;
   UCHAR uc;
   
   crc = 0xFFFFFFFF;
   for (i = 0; i < ADDR_SIZE; i++) {
      uc = pAddress[i];
      for (j = 0; j < 8; j++) {
         carry = ((crc & 0x80000000) ? 1 : 0) ^ (uc & 0x01);
         crc <<= 1;
         uc >>= 1;
         if (carry) crc = (crc ^ 0x04c11db6) | carry;
      }
   }
   return crc;
}

//------------------------------------------------------------------------------

BOOL AM79C973InitDMABuffer(DWORD address, ULONG size)
{
   ULONG offset, buffers;

   // Buffers must be aligned to 32 bytes boundary
   offset = address & 0x1F;
   if (offset != 0) {
      address = address + 0x20 - offset;
      size = size + 0x20 - offset;
   }

   // Check if buffer is big enough to accomodate all
   buffers = TX_BUFFERS + RX_BUFFERS;
   if (size < ((BUFFER_SIZE + DESC_SIZE) * buffers + INIT_SIZE)) return FALSE;

   // Store address and size
   g_dmaAddress = C2U(address);
   g_dmaSize = size;
   
   return TRUE;
}

//------------------------------------------------------------------------------

BOOL AM79C973Init(UCHAR *pAddress, ULONG offset, USHORT mac[3])
{
   ULONG i, pos;
   USHORT data;
   
   g_base = C2U(pAddress);

   // Switch to DWIO mode
   OUT32(g_base + RDP, 0);

   // Set software style to 3 (32bit software structure)
   WriteBCR(20, 0x0503);

   // Stop adapter
   WriteCSR(0, 0x0004);

   // Divide DMA buffer
   pos = g_dmaAddress;
   g_pInit = (ULONG*)pos;
   pos += INIT_SIZE;
   g_pRxRing = (ULONG*)pos;
   pos += RX_BUFFERS * DESC_SIZE;
   g_pTxRing = (ULONG*)pos;
   pos += TX_BUFFERS * DESC_SIZE;
   g_pRxBuffer = (UCHAR*)pos;
   pos += RX_BUFFERS * BUFFER_SIZE;
   g_pTxBuffer = (UCHAR*)pos;

   // Prepare initialization block
   g_pInit[0] = 0x20500180;
   g_pInit[1] = INP32(g_base);
   g_pInit[2] = INP32(g_base + 4);
   g_pInit[3] = 0;
   g_pInit[4] = 0;
   g_pInit[5] = V2P(g_pRxRing);
   g_pInit[6] = V2P(g_pTxRing);

   // Save MAC address
   memcpy(mac, &g_pInit[1], 6);

   // Initialize RX ring   
   for (i = 0; i < RX_BUFFERS; i++) {
      g_pRxRing[4 * i + 0] = 0;
      g_pRxRing[4 * i + 1] = RMD1_OWN | RMD1_ONES | (4096-BUFFER_SIZE);
      g_pRxRing[4 * i + 2] = V2P(g_pRxBuffer + i * BUFFER_SIZE);
      g_pRxRing[4 * i + 3] = (ULONG)(g_pRxBuffer + i * BUFFER_SIZE);
   }
   g_rxPos = 0;
   
   // Initialize TX ring   
   for (i = 0; i < TX_BUFFERS; i++) {
      g_pTxRing[4 * i + 0] = 0;
      g_pTxRing[4 * i + 1] = 0;
      g_pTxRing[4 * i + 2] = V2P(g_pTxBuffer + i * BUFFER_SIZE);
      g_pTxRing[4 * i + 3] = (ULONG)(g_pTxBuffer + i * BUFFER_SIZE);
   }
   g_txPos = 0;
   
   // Set initialization block address
   pos = V2P(g_pInit);
   WriteCSR(1, pos & 0xFFFF);
   WriteCSR(2, pos >> 16);

   // Connect internal PHY
   Log("Am79C973: Autonegotiation start...");
   WriteMII(0, 0x3100);
   OEMSleep(10);

   // Wait autonegotiation complete or link is up.
   while ((ReadMII(1) & 0x0020) == 0) OEMSleep(10);
   Log("  and completed, link mode ");

   data = ReadMII(24);
   if ((data & 0x0001) != 0) Log("100BASE-TX "); else Log("10BASE-T ");
   if ((data & 0x0004) != 0) Log("FD\n"); else Log("HD\n");

   // Mask everything
   WriteCSR(3, 0x1F40); // Enable DXSUFLO to let it recover from underflow
   WriteCSR(4, 0x0914);

   // Start initialization
   WriteCSR(0, 0x0001);

   // Wait for initialization complete
   while ((ReadCSR(0) & 0x0100) == 0) OEMSleep(10);

   // Enable Tx/Rx
   WriteCSR(0, 0x0002);

   return TRUE;
}

//------------------------------------------------------------------------------

USHORT AM79C973SendFrame(UCHAR *pData, ULONG length)
{
   ULONG start;
   volatile ULONG *pos;

   // Wait until buffer is done
   start = OEMEthGetSecs();
   pos = (volatile ULONG*)&g_pTxRing[g_txPos << 2];

   // Wait for transmit buffer available
   while ((pos[1] & TMD1_OWN) != 0) {
      OEMSleep(1);
      if ((OEMEthGetSecs() - start) > TIMEOUT) return 1;
   }

   // Copy data to buffer
   memcpy((VOID*)pos[3], pData, length);
   pos[0] = 0;
   pos[1] = TMD1_OWN|TMD1_STP|TMD1_ENP|TMD1_ONES|(4096 - length);

   // Force controller to read tx descriptor
   WriteCSR(0, (ReadCSR(0) & 0x0040) | 0x0008);

   // Wait for DMA to complete the transfer, otherwise we hang the bus
   while ((pos[1] & TMD1_OWN) != 0) OEMSleep(1);

   // Move to next possition
   if (++g_txPos == TX_BUFFERS) g_txPos = 0;

   return 0;
}

//------------------------------------------------------------------------------

USHORT AM79C973GetFrame(UCHAR *pData, USHORT *pLength)
{
   ULONG rmd1, rmd2, length;
   volatile ULONG *pos;

   pos = (volatile ULONG*)&g_pRxRing[g_rxPos << 2];
   length = 0;

   // When packet is in buffer hardware doesn own descriptor
   while (((rmd1 = pos[1]) & RMD1_OWN) == 0) {
      rmd2 = pos[0];
      // Is packet received ok?
      length = rmd2 & 0x0FFF;
      if (length > 4) length -= 4; 
      if ((rmd1 & RMD1_ERR) == 0 && length < *pLength) {
         // Copy packet if there is no problem
         memcpy(pData, (VOID*)pos[3], length);
      } else {
         Log("AM79C973GetFrame - %X/%X %d\n", rmd1, rmd2, *pLength);
         length = 0;
      }
      // Reinitialize descriptor
      pos[0] = 0;
      pos[1] = RMD1_OWN | RMD1_ONES | (4096 - BUFFER_SIZE);
      // Move to next possition
      if (++g_rxPos == RX_BUFFERS) g_rxPos = 0;
      // Calculate position
      pos = (volatile ULONG*)&g_pRxRing[g_rxPos << 2];
      // If this descriptor is owned by hardware clear interrupt
      if ((pos[1] & RMD1_OWN) != 0) {
         WriteCSR (0, (ReadCSR(0) & 0x40) | 0x0400);
      }         
      // If we get a packet break loop
      if (length > 0) break;
   }

   // Return size
   *pLength = (USHORT)length;
   return *pLength;
}

//------------------------------------------------------------------------------

void AM79C973EnableInts()
{
   WriteCSR (3, ReadCSR(3) & 0xFBFF);  // clear RINT mask
   WriteCSR (0, 0x40);
}

//------------------------------------------------------------------------------

void AM79C973DisableInts()
{
   WriteCSR(0, 0);
}

//------------------------------------------------------------------------------

void AM79C973CurrentPacketFilter(ULONG filter)
{
   ULONG exCtrl;

   // First we must go to suspend mode
   exCtrl = ReadCSR(5);
   exCtrl |= 0x0001;
   WriteCSR(5, exCtrl);
   // Wait until we get there
   while ((ReadCSR(5) & 0x0001) == 0) OEMSleep(1);

   // Just assume that we allways receive direct & broadcast packets
   if ((filter & PACKET_TYPE_ALL_MULTICAST) != 0) {
      WriteCSR (8, 0xFFFF);
      WriteCSR (9, 0xFFFF);
      WriteCSR (10, 0xFFFF);
      WriteCSR (11, 0xFFFF);
   } else if ((filter & PACKET_TYPE_MULTICAST) == 0) {
      WriteCSR (8, 0);
      WriteCSR (9, 0);
      WriteCSR (10, 0);
      WriteCSR (11, 0);
   }

   // It is time to leave suspend mode
   exCtrl = ReadCSR(5);
   exCtrl &= ~0x0001;
   WriteCSR(5, exCtrl);

   // Wait until we get there
   while ((ReadCSR(5) & 0x0001) != 0) OEMSleep(1);
}

//------------------------------------------------------------------------------

BOOL AM79C973MulticastList(UCHAR *pAddresses, ULONG count)
{
   ULONG exCtrl, crc;
   ULONG i, j, bit;
   USHORT h[4];

   // Calculate hash bits       
   h[0] = h[1] = h[2] = h[3] = 0;
   for (i = 0; i < count; i++) {
      crc = HashAddress(pAddresses);
      bit = 0;
      for (j = 0; j < 6; j++) bit = (bit << 1) + ((crc >> j) & 0x01);
      h[bit >> 4] |= 1 << (bit & 0x0F);
      pAddresses += ADDR_SIZE;
   }

   // Go to suspend mode
   exCtrl = ReadCSR(5);
   exCtrl |= 0x0001;
   WriteCSR(5, exCtrl);

   // Wait until we get there
   while ((ReadCSR(5) & 0x0001) == 0) OEMSleep(1);

   // And set hardware   
   WriteCSR(8, h[0]);
   WriteCSR(9, h[1]);
   WriteCSR(10, h[2]);
   WriteCSR(11, h[3]);

   // Leave suspend mode
   exCtrl = ReadCSR(5);
   exCtrl &= ~0x0001;
   WriteCSR(5, exCtrl);
   
   // Wait until we get there
   while ((ReadCSR(5) & 0x0001) != 0) OEMSleep(1);

   return TRUE;
}

//------------------------------------------------------------------------------

VOID   AM79C973PowerOff()
{
}
VOID   AM79C973PowerOn()
{
}

⌨️ 快捷键说明

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