📄 rtl8139.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.
//
/*++
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 Realtek RTL8139A.
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 <wdm.h>
#define PRINTF(cond, printf_exp) \
((void)((cond)?(EdbgOutputDebugString printf_exp) : 0))
#define NEXT(a, MAX) \
(++(a) >= MAX) ? (a = 0) : (0)
#define TO_REAL(Addr) (Addr & ~0x80000000)
#define TO_VIRT(Addr) (Addr | 0x80000000)
//
// Forward decl..
//
void
RTL8139HWSetMCRegs(PUCHAR pucMulticastRegs, BOOL bAllMulticast);
BOOL
RTL8139MulticastList(PUCHAR pucMulticastAddresses, DWORD dwNoOfAddresses);
//
// Multicast support ..
//
#define MAX_MULTICAST_LIST 8
UCHAR g_pucMulticastList[MAX_MULTICAST_LIST][6];
DWORD g_dwMulticastListInUse;
DWORD g_dwRCR;
DWORD g_dwNdisFilter;
enum RTL8139Register
{
RTL_IDR0_OFFSET = 0x00,
RTL_IDR1_OFFSET = 0x01,
RTL_IDR2_OFFSET = 0x02,
RTL_IDR3_OFFSET = 0x03,
RTL_IDR4_OFFSET = 0x04,
RTL_IDR5_OFFSET = 0x05,
RTL_MAR0_OFFSET = 0x08,
RTL_MAR1_OFFSET = 0x09,
RTL_MAR2_OFFSET = 0x0a,
RTL_MAR3_OFFSET = 0x0b,
RTL_MAR4_OFFSET = 0x0c,
RTL_MAR5_OFFSET = 0x0d,
RTL_MAR6_OFFSET = 0x0e,
RTL_MAR7_OFFSET = 0x0f,
RTL_TSD_BASE_OFFSET = 0x10,
RTL_TSAD_BASE_OFFSET = 0x20,
RTL_RBSTART_OFFSET = 0x30,
RTL_ERBCR_OFFSET = 0x34,
RTL_ERSR_OFFSET = 0x36,
RTL_CR_OFFSET = 0x37,
RTL_CAPR_OFFSET = 0x38,
RTL_CBR_OFFSET = 0x3a,
RTL_IMR_OFFSET = 0x3c,
RTL_ISR_OFFSET = 0x3e,
RTL_TCR_OFFSET = 0x40,
RTL_RCR_OFFSET = 0x44,
RTL_TCTR_OFFSET = 0x48,
RTL_MPC_OFFSET = 0x4c,
RTL_9346CR_OFFSET = 0x50,
RTL_CONFIG0_OFFSET = 0x51,
RTL_CONFIG1_OFFSET = 0x52,
RTL_TIMERINT_OFFSET = 0x54,
RTL_MSR_OFFSET = 0x58,
RTL_CONFIG3_OFFSET = 0x59,
RTL_MULINT_OFFSET = 0x5c,
RTL_RERID_OFFSET = 0x5e,
RTL_TSAD_OFFSET = 0x60,
RTL_BMCR_OFFSET = 0x62,
RTL_BMSR_OFFSET = 0x64,
RTL_ANAR_OFFSET = 0x66,
RTL_ANLPAR_OFFSET = 0x68,
RTL_ANER_OFFSET = 0x6a,
RTL_DIS_OFFSET = 0x6c,
RTL_FCSC_OFFSET = 0x6e,
RTL_NWAYTR_OFFSET = 0x70,
RTL_REC_OFFSET = 0x72,
RTL_CSCR_OFFSET = 0x74,
RTL_PHY1_PARAM_OFFSET = 0x78,
RTL_TW_PARAM_OFFSET = 0x7c,
RTL_PHY2_PARAM_OFFSET = 0x80
};
enum RTL8139CommandRegister
{
RTL8139_COMMAND_RESET = 0x10,
RTL8139_COMMAND_RX_ENABLE = 0x08,
RTL8139_COMMAND_TX_ENABLE = 0x04,
RTL8139_COMMAND_BUFFER_EMPTY = 0x01
};
enum RTL8139BMCRRegister
{
RTL_8139_PHY_REGISTERS_RESET = 0x8000,
RTL_100MBPS = 0x2000,
RTL_AUTO_NEGOTIATE_ENABLE = 0x1000,
RTl_RESTART_AUTO = 0x0200,
RTL_FULL_DUPLEX = 0x0100
};
#define TX_DMA_BURST_SIZE (0x007 << 8 ) // 2048 bytes. in TCR.
#define TX_CLEAR_ABORT (0x01) // Clear abort in TCR.
#define NUM_TX_DESC 4
#define ONE_BUFFER_SIZE 1536
#define RX_DMA_BURST_SIZE (0 << 8)
#define RX_ACCEPT_RUNT (1 << 4)
#define RX_BROADCAST (1 << 3)
#define RX_MULTICAST (1 << 2)
#define RX_UNICAST (1 << 1)
#define RX_PROMISCUOUS (1 << 0)
////////////////////////////////////////////////////////////////////////////////
// The packet header in RX buffer.
//
typedef struct
{
union
{
struct
{
USHORT ROK : 1; // Receive OK.
USHORT FAE : 1; // Frame Alignment Error.
USHORT CRC : 1; // CRC Error.
USHORT LONG: 1; // Long packet.
USHORT RUNT: 1; // Runt packet.
USHORT ISE : 1; // Invalid Symbol Err.
USHORT resv: 7;
USHORT BAR : 1; // Broadcast packet.
USHORT PAM : 1; // Mathcing unicast address.
USHORT MAR : 1; // Multicast address.
};
USHORT usPacketHeader;
};
USHORT usPacketLength;
} PACKET_HEADER, *PPACKET_HEADER;
typedef struct RTL8139
{
DWORD dwBaseIO;
DWORD dwMemOffset;
USHORT usMacAddr[3];
UCHAR *pucTxBuffer; // Start of the TX buffers.
DWORD dwCurrentTxDescriptor; // TX desc for next send.
DWORD dwCurrentHwTxDescriptor; // TX desc to get back from hw.
DWORD dwFreeTxDescriptors; // Curr no of free TX desc.
UCHAR *pucRxBuffer; // Start of the RX buffer.
UCHAR *puLastRxAddress; // The last byte of RX buffer.
DWORD dwCurrentRxOffset; // Next RX packet read from here.
} SRTL8139, *PSRTL8139;
////////////////////////////////////////////////////////////////////////////////
// Useful constants..
//
#define RTL_IDR0 (PULONG) (sRTL8139.dwBaseIO + RTL_IDR0_OFFSET)
#define RTL_IDR1 (PULONG) (sRTL8139.dwBaseIO + RTL_IDR1_OFFSET)
#define RTL_IDR2 (PULONG) (sRTL8139.dwBaseIO + RTL_IDR2_OFFSET)
#define RTL_IDR3 (PULONG) (sRTL8139.dwBaseIO + RTL_IDR3_OFFSET)
#define RTL_IDR4 (PULONG) (sRTL8139.dwBaseIO + RTL_IDR4_OFFSET)
#define RTL_IDR5 (PULONG) (sRTL8139.dwBaseIO + RTL_IDR5_OFFSET)
#define RTL_MAR0 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR0_OFFSET)
#define RTL_MAR1 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR1_OFFSET)
#define RTL_MAR2 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR2_OFFSET)
#define RTL_MAR3 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR3_OFFSET)
#define RTL_MAR4 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR4_OFFSET)
#define RTL_MAR5 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR5_OFFSET)
#define RTL_MAR6 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR6_OFFSET)
#define RTL_MAR7 (PULONG) (sRTL8139.dwBaseIO + RTL_MAR7_OFFSET)
#define RTL_RBSTART (PULONG) (sRTL8139.dwBaseIO + RTL_RBSTART_OFFSET)
#define RTL_ERBCR (PUSHORT)(sRTL8139.dwBaseIO + RTL_ERBCR_OFFSET)
#define RTL_ERSR (PUCHAR) (sRTL8139.dwBaseIO + RTL_ERSR_OFFSET)
#define RTL_CR (PUCHAR) (sRTL8139.dwBaseIO + RTL_CR_OFFSET)
#define RTL_CAPR (PUSHORT)(sRTL8139.dwBaseIO + RTL_CAPR_OFFSET)
#define RTL_CBR (PUSHORT)(sRTL8139.dwBaseIO + RTL_CBR_OFFSET)
#define RTL_IMR (PUSHORT)(sRTL8139.dwBaseIO + RTL_IMR_OFFSET)
#define RTL_ISR (PUSHORT)(sRTL8139.dwBaseIO + RTL_ISR_OFFSET)
#define RTL_TCR (PULONG) (sRTL8139.dwBaseIO + RTL_TCR_OFFSET)
#define RTL_RCR (PULONG) (sRTL8139.dwBaseIO + RTL_RCR_OFFSET)
#define RTL_TCTR (PULONG) (sRTL8139.dwBaseIO + RTL_TCTR_OFFSET)
#define RTL_MPC (PULONG) (sRTL8139.dwBaseIO + RTL_MPC_OFFSET)
#define RTL_9346CR (PUCHAR) (sRTL8139.dwBaseIO + RTL_9346CR_OFFSET)
#define RTL_CONFIG0 (PUCHAR) (sRTL8139.dwBaseIO + RTL_CONFIG0_OFFSET)
#define RTL_CONFIG1 (PUCHAR) (sRTL8139.dwBaseIO + RTL_CONFIG1_OFFSET)
#define RTL_TIMERINT (PULONG) (sRTL8139.dwBaseIO + RTL_TIMERINT_OFFSET)
#define RTL_MSR (PUCHAR) (sRTL8139.dwBaseIO + RTL_MSR_OFFSET)
#define RTL_CONFIG3 (PUCHAR) (sRTL8139.dwBaseIO + RTL_CONFIG3_OFFSET)
#define RTL_MULINT (PUSHORT)(sRTL8139.dwBaseIO + RTL_MULINT_OFFSET)
#define RTL_RERID (PUSHORT)(sRTL8139.dwBaseIO + RTL_RERID_OFFSET)
#define RTL_TSAD (PUSHORT)(sRTL8139.dwBaseIO + RTL_TSAD_OFFSET)
#define RTL_BMCR (PUSHORT)(sRTL8139.dwBaseIO + RTL_BMCR_OFFSET)
#define RTL_BMSR (PUSHORT)(sRTL8139.dwBaseIO + RTL_BMSR_OFFSET)
#define RTL_ANAR (PUSHORT)(sRTL8139.dwBaseIO + RTL_ANAR_OFFSET)
#define RTL_ANLPAR (PUSHORT)(sRTL8139.dwBaseIO + RTL_ANLPAR_OFFSET)
#define RTL_ANER (PUSHORT)(sRTL8139.dwBaseIO + RTL_ANER_OFFSET)
#define RTL_DIS (PUSHORT)(sRTL8139.dwBaseIO + RTL_DIS_OFFSET)
#define RTL_FCSC (PUSHORT)(sRTL8139.dwBaseIO + RTL_FCSC_OFFSET)
#define RTL_NWAYTR (PUSHORT)(sRTL8139.dwBaseIO + RTL_NWAYTR_OFFSET)
#define RTL_REC (PUSHORT)(sRTL8139.dwBaseIO + RTL_REC_OFFSET)
#define RTL_CSCR (PUSHORT)(sRTL8139.dwBaseIO + RTL_CSCR_OFFSET)
#define RTL_PHY1_PARM (PULONG) (sRTL8139.dwBaseIO + RTL_PHY1_PARAM_OFFSET)
#define RTL_TW_PARM (PULONG) (sRTL8139.dwBaseIO + RTL_TW_PARAM_OFFSET)
#define RTL_PHY2_PARM (PUCHAR) (sRTL8139.dwBaseIO + RTL_PHY2_PARAM_OFFSET)
#define RTL_TSD_X(x) (PULONG)(sRTL8139.dwBaseIO + RTL_TSD_BASE_OFFSET + x * 4)
#define RTL_TSAD_X(x) (PULONG)(sRTL8139.dwBaseIO + RTL_TSAD_BASE_OFFSET + x * 4)
////////////////////////////////////////////////////////////////////////////////
// Global var..
//
//#define BUFFER_START_ADDRESS 0x00200000 // TX/RX DMA Buffer..
// *** WARNING ***
// THIS IS HARDCODED UNTIL EDBG
// IS CHANGED TO CONTROL THIS..
//#define RX_BUFFER_LENGTH (64 * 1024)
//#define RX_BUFFER_LENGTH_BIT (3 << 11) // 64K + 16 bytes.
// SO WE NEED AROUND 70k OF
// BUFFER.. (64k + 6K for TX)
SRTL8139 sRTL8139;
DWORD dwTxStartAddress = 0x00;
DWORD dwRxStartAddress = 0x00;
DWORD dwRxLength = 0x00;
DWORD dwRxLengthBit = 0x00;
////////////////////////////////////////////////////////////////////////////////
// Misc utility functions.
//
void DisplayHex (BYTE data)
{
if (data < 0x10)
PRINTF(1, ("0"));
PRINTF (1, ("%x ", data));
} // DisplayHex()
void DumpMemory (PBYTE pSource, DWORD dwLength)
{
int i = 0;
PRINTF (1, ("+---- MEM DUMP (%d bytes)----+\r\n", dwLength));
PRINTF (1, ("0x%x: ", pSource));
while (dwLength--)
{
DisplayHex (*pSource++);
if (++i == 16)
{
i = 0;
PRINTF (1, ("\r\n0x%x: ", pSource));
}
}
PRINTF (1, ("\r\n\r\n"));
} // DumpMemory()
void
DumpAll8139Regs()
{
PRINTF (1,
("+------------------------------------------------------------+\r\n"));
PRINTF (1, ("IDR[0..5] = 0x[%x - %x - %x - %x - %x - %x]\r\n",
(UCHAR) READ_PORT_ULONG(RTL_IDR0),
(UCHAR) READ_PORT_ULONG(RTL_IDR1),
(UCHAR) READ_PORT_ULONG(RTL_IDR2),
(UCHAR) READ_PORT_ULONG(RTL_IDR3),
(UCHAR) READ_PORT_ULONG(RTL_IDR4),
(UCHAR) READ_PORT_ULONG(RTL_IDR5)));
PRINTF (1, ("MAR[0..7] = 0x[%x - %x - %x - %x - %x - %x - %x - %x]\r\n",
(UCHAR) READ_PORT_ULONG(RTL_MAR0),
(UCHAR) READ_PORT_ULONG(RTL_MAR1),
(UCHAR) READ_PORT_ULONG(RTL_MAR2),
(UCHAR) READ_PORT_ULONG(RTL_MAR3),
(UCHAR) READ_PORT_ULONG(RTL_MAR4),
(UCHAR) READ_PORT_ULONG(RTL_MAR5),
(UCHAR) READ_PORT_ULONG(RTL_MAR6),
(UCHAR) READ_PORT_ULONG(RTL_MAR7)));
PRINTF (1, ("TSD[0..3] = 0x[%x - %x - %x - %x]\r\n",
READ_PORT_ULONG(RTL_TSD_X(0)),
READ_PORT_ULONG(RTL_TSD_X(1)),
READ_PORT_ULONG(RTL_TSD_X(2)),
READ_PORT_ULONG(RTL_TSD_X(3))));
PRINTF (1, ("TSAD[0..3] = 0x[%x - %x - %x - %x]\r\n",
READ_PORT_ULONG(RTL_TSAD_X(0)),
READ_PORT_ULONG(RTL_TSAD_X(1)),
READ_PORT_ULONG(RTL_TSAD_X(2)),
READ_PORT_ULONG(RTL_TSAD_X(3))));
PRINTF (1, ("RBSTART [0x%x] \t ERBCR [0x%x] \t ERSR [0x%x] \t CR [0x%x]\r\n",
READ_PORT_ULONG(RTL_RBSTART),
READ_PORT_USHORT(RTL_ERBCR),
READ_PORT_UCHAR(RTL_ERSR),
READ_PORT_UCHAR(RTL_CR)));
PRINTF (1, ("CAPR [0x%x] \t CBR [0x%x] \t IMR [0x%x] \t ISR [0x%x]\r\n",
READ_PORT_USHORT(RTL_CAPR),
READ_PORT_USHORT(RTL_CBR),
READ_PORT_USHORT(RTL_IMR),
READ_PORT_USHORT(RTL_ISR)));
PRINTF (1, ("TCR [0x%x] \t RCR [0x%x] \t TCTR [0x%x] \t MPC [0x%x]\r\n",
READ_PORT_ULONG(RTL_TCR),
READ_PORT_ULONG(RTL_RCR),
READ_PORT_ULONG(RTL_TCTR),
READ_PORT_ULONG(RTL_MPC)));
PRINTF (1, ("9346CR [0x%x] \t CONFIG0 [0x%x] \t CONFIG1 [0x%x] \t TimerInt [0x%x]\r\n",
READ_PORT_UCHAR(RTL_9346CR),
READ_PORT_UCHAR(RTL_CONFIG0),
READ_PORT_UCHAR(RTL_CONFIG1),
READ_PORT_ULONG(RTL_TIMERINT)));
PRINTF (1, ("MSR [0x%x] \t CONFIG3 [0x%x] \t MULINT [0x%x] \t RERID [0x%x]\r\n",
READ_PORT_UCHAR(RTL_MSR),
READ_PORT_UCHAR(RTL_CONFIG3),
READ_PORT_USHORT(RTL_MULINT),
READ_PORT_USHORT(RTL_RERID)));
PRINTF (1, ("TSAD [0x%x] \t BMCR [0x%x] \t BMSR [0x%x] \t ANAR [0x%x]\r\n",
READ_PORT_USHORT(RTL_TSAD),
READ_PORT_USHORT(RTL_BMCR),
READ_PORT_USHORT(RTL_BMSR),
READ_PORT_USHORT(RTL_ANAR)));
PRINTF (1, ("ANLPAR [0x%x] \t ANER [0x%x] \t DIS [0x%x] \t FCSC [0x%x]\r\n",
READ_PORT_USHORT(RTL_ANLPAR),
READ_PORT_USHORT(RTL_ANER),
READ_PORT_USHORT(RTL_DIS),
READ_PORT_USHORT(RTL_FCSC)));
PRINTF (1, ("NWAYTR [0x%x] \t REC [0x%x] \t CSCR [0x%x] \t PHY1_PARM[0x%x]\r\n",
READ_PORT_USHORT(RTL_NWAYTR),
READ_PORT_USHORT(RTL_REC),
READ_PORT_USHORT(RTL_CSCR),
READ_PORT_ULONG(RTL_PHY1_PARM)));
PRINTF (1, ("TW_PARM [0x%x] \t PHY2PARM[0x%x] \r\n\r\n",
READ_PORT_ULONG(RTL_TW_PARM),
READ_PORT_UCHAR(RTL_PHY2_PARM)));
} // DumpAll8139Regs()
////////////////////////////////////////////////////////////////////////////////
// RTL8139InitDMABuffer()
// This function is used to inform this library on where the buffer for
// Tx/Rx DMA is.
//
BOOL
RTL8139InitDMABuffer(DWORD dwStartAddress, DWORD dwSize)
{
DWORD dwRxSize;
DWORD dwAlignedStart;
////////////////////////////////////////////////////////////////////////////
// We need at least:
// 4 TX buffers (4 * ONE_BUFFER_SIZE) ~ 6k
// 8K + 16 bytes of RX buffers.
// (64K Max) of RX buffer size is welcome!
// ** Note ** that ONE_BUFFER_SIZE is 1536 bytes which is in DWORD
// boundary!
//
#define MIN_DMA_SIZE ((NUM_TX_DESC * ONE_BUFFER_SIZE) + (8 * 1024 + 16))
dwAlignedStart = (dwStartAddress + 0x03) & 0xfffffffc;
dwSize -= (dwAlignedStart - dwStartAddress);
if (dwSize <= MIN_DMA_SIZE)
{
PRINTF (1, ("RTL8139InitDMABuffer():: DMA buffer is too small!!\r\n"));
PRINTF (1, ("Given:[0x%x] :: Minimun required [0x%x]\r\n",
dwSize,
MIN_DMA_SIZE));
return FALSE;
}
PRINTF (1,
("RTL8139InitDMABuffer():: Start[0x%x]-[0x%x] - Size[0x%x]\r\n",
dwStartAddress,
dwAlignedStart,
dwSize));
////////////////////////////////////////////////////////////////////////////
// Okay, so we are in business..
// TX is fixed, so see how much RX we have.
//
dwTxStartAddress = dwAlignedStart;
dwRxStartAddress = dwAlignedStart + (NUM_TX_DESC * ONE_BUFFER_SIZE);
dwRxSize = dwSize - NUM_TX_DESC * ONE_BUFFER_SIZE;
if (dwRxSize > (64 * 1024 + 16))
{
dwRxLength = 64 * 1024;
dwRxLengthBit = 3 << 11;
}
else
if (dwRxSize > (32 * 1024 + 16))
{
dwRxLength = 32 * 1024;
dwRxLengthBit = 2 << 11;
}
else
if (dwRxSize > (16 * 1024 + 16))
{
dwRxLength = 16 * 1024;
dwRxLengthBit = 1 << 11;
}
else
{
dwRxLength = 8 * 1024;
dwRxLengthBit = 0x00;
}
PRINTF (1, ("Tx[0x%x] - Rx[0x%x] - RxLength[0x%x] - RxLengthBit[0x%x]\r\n",
dwTxStartAddress,
dwRxStartAddress,
dwRxLength,
dwRxLengthBit));
return TRUE;
} // RTL8139InitDMABuffer()
#define AUTO_NEGOTIATE 1
////////////////////////////////////////////////////////////////////////////////
// RTL8139Init()
//
BOOL
RTL8139Init(BYTE *pbBaseAddress, ULONG dwMemOffset, USHORT MacAddr[3])
{
DWORD dwScrap;
#ifndef AUTO_NEGOTIATE
USHORT usScrap;
#endif
DWORD i;
if (dwTxStartAddress == 0x00)
{
////////////////////////////////////////////////////////////////////////
// Caller ** MUST ** call RTL8139InitDMABuffer() first!!
//
PRINTF (1,
("RTL8139():: Error!! RTL8139InitDMABuffer() was not called.\r\n"));
return FALSE;
}
PRINTF (1, ("RTL8139Init():: BaseIO[0x%x] : MemOffset[0x%x]\r\n",
pbBaseAddress,
dwMemOffset));
memset (&sRTL8139, 0x00, sizeof(SRTL8139));
sRTL8139.dwBaseIO = (DWORD)pbBaseAddress;
sRTL8139.dwMemOffset = dwMemOffset;
sRTL8139.dwFreeTxDescriptors = NUM_TX_DESC;
////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -