📄 ne2000.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:
Routines for the NE2000 ethernet controller used for the Windows CE
debug ethernet services, and bootloaders.
Functions:
Notes:
These routines are called at system init and other times when system calls aren't allowed, so
they can't make any system calls.
--*/
#include <windows.h>
#include <halether.h>
#include <ceddk.h>
#include "ne2000hw.h"
#include "..\eboot\udp.h"
#include "ethdbg.h"
//
// List of multicast addresses currently set to h/w
//
#define MAX_MULTICAST_LIST 8
UCHAR g_pucMulticastList[MAX_MULTICAST_LIST][6];
DWORD g_dwMulticastListInUse;
//
// Default fitler is Broadcast & directed.
// Until this is changed via NE2000CurrentPacketFilter()
//
UCHAR ucFilter = NIC_RECEIVE_BROADCAST;
DWORD dwNdisFilter = 0x00;
//#define USE_ISA_PNP_STUFF
//#define DEBUG_SINGLE_CHAR 1
//
// Structure to track receive packets
//
#define RCV_Q_SIZE 32
typedef struct _RCV_ENTRY {
BYTE re_state;
BYTE re_next; // next card receive buffer
WORD re_len; // packet length
WORD re_ptr; // location in card's buffer
} RCV_ENTRY, *PRCV_ENTRY;
//
// re_state values
//
#define RCV_FREE 0
#define RCV_USED 1
static RCV_ENTRY g_rcv_list[RCV_Q_SIZE];
static DWORD g_rcv_index; // Next RCV_ENTRY to use
static DWORD g_rcv_next; // Next RCV_ENTRY to indicate
static DWORD g_rcv_cnt; // Number of packets to indicate
//
// Variables for remembering 8390 chip state
//
static BYTE command_reg;
static BYTE int_status;
static BYTE NextPage;
static BYTE overflowrestartflag;
static BYTE pstart;
static BYTE pstop;
static BYTE transmitting;
static DWORD srambase;
static DWORD sramsize;
static BYTE rcv_header[NIC_HEADER_LEN+16]; // NIC puts the current value of the Receive
#define rcv_status rcv_header[0] // Status Register in the frame header.
#define rcv_next_buff rcv_header[1] // Page number where next packet is/will be.
#define rcv_frame_len0 rcv_header[2]
#define rcv_frame_len1 rcv_header[3] // This can be ignored since in high speed systems
// it will be incorrect and can be calculated
// using the page variables.
#define rcv_dest_addr0 rcv_header[4]
#define rcv_dest_addr1 rcv_header[5]
static BYTE new_current_page;
static BYTE tbb_start;
static WORD curr_xmit_len;
static BYTE erase_header[20];
// Mask to use for interrupts
static BYTE bIntMask;
static BYTE volatile *pbEthernetBase;
static BYTE ethernetaddr[6];
// Bitmask for configuration options passed to us from bootloader/kernel.
static DWORD dwConfigOptions;
static void InitRcvQueue(void);
#ifdef USE_ISA_PNP_STUFF
//
// Use stuff from platform\cepc\kernel\hal\isapnp.c
//
extern ULONG ISAGetBusDataByOffset(IN ULONG BusNumber, IN ULONG SlotNumber,
IN PVOID Buffer, IN ULONG Offset, IN ULONG Length);
extern ULONG ISASetBusDataByOffset(IN ULONG BusNumber, IN ULONG SlotNumber,
IN PVOID Buffer, IN ULONG Offset, IN ULONG Length);
extern void ISAPNP_Sleep(DWORD ms);
BYTE * NE2000InitISAPNP(DWORD dwIOBase, DWORD dwIRQ);
#define DEFAULT_IOBASE 0x300
#define DEFAULT_IRQ 10
#endif // USE_ISA_PNP_STUFF
#ifdef x86
static void
NE2000_WRITE_PORT_UCHAR(volatile PUCHAR addr, UCHAR val)
{
__asm {
mov edx, addr
mov al, val
out dx, al
}
}
static UCHAR
NE2000_READ_PORT_UCHAR(volatile PUCHAR addr)
{
UCHAR val;
__asm {
mov edx, addr
in al, dx
mov val, al
}
return val;
}
static void
NE2000_WRITE_PORT_USHORT(volatile PUSHORT addr, USHORT val)
{
__asm {
mov edx, addr
mov ax, val
out dx, ax
}
}
static USHORT
NE2000_READ_PORT_USHORT(volatile PUSHORT addr)
{
USHORT val;
__asm {
mov edx, addr
in ax, dx
mov val, ax
}
return val;
}
#else
static void
NE2000_WRITE_PORT_UCHAR(volatile PUCHAR addr, UCHAR val)
{
*addr = val;
}
static UCHAR
NE2000_READ_PORT_UCHAR(volatile PUCHAR addr)
{
return *addr;
}
static void
NE2000_WRITE_PORT_USHORT(volatile PUSHORT addr, USHORT val)
{
*addr = val;
}
static USHORT
NE2000_READ_PORT_USHORT(volatile PUSHORT addr)
{
return *addr;
}
#endif
#define WriteByte(Offset, Value) NE2000_WRITE_PORT_UCHAR((volatile PUCHAR)(pbEthernetBase+Offset), Value)
#define ReadByte(Offset) NE2000_READ_PORT_UCHAR((volatile PUCHAR)(pbEthernetBase+Offset))
#define WriteWord(Offset, Value) NE2000_WRITE_PORT_USHORT((volatile PUSHORT)(pbEthernetBase+Offset), Value)
#define ReadWord(Offset) NE2000_READ_PORT_USHORT((volatile PUSHORT)(pbEthernetBase+Offset))
#define WriteCmd(Cmd) WriteByte(NIC_COMMAND, Cmd)
#define ReadCmd() ReadByte(NIC_COMMAND)
#define UsePage0() WriteCmd(NIC_Page0)
#define UsePage1() WriteCmd(NIC_Page1)
#define UsePage1Stop() WriteCmd(NIC_Page1Stop)
//#define NE2000_DUMP_FRAMES 1
#ifdef NE2000_DUMP_FRAMES
static void DumpEtherFrame( BYTE *pFrame, WORD cwFrameLength );
static void DumpNE2000Header(void);
#endif
static void iodelay(int delay);
static void HWAccess(WORD addr, WORD count, PWORD mem, BYTE direction);
#define INSB(addr, count, mem) HWAccess(((WORD)(addr)), ((WORD)(count)), (WORD *)mem, NIC_RemoteDmaRd)
#define OUTSB(addr, count, mem) HWAccess(((WORD)(addr)), ((WORD)(count)), (WORD *)mem, NIC_RemoteDmaWr)
///////////////////////////////////////////////////////////////////////////
//
// iodelay - Wait by polling the command register for "delay" iterations.
//
///////////////////////////////////////////////////////////////////////////
static void
iodelay(int delay)
{
while (delay) {
ReadCmd();
delay--;
}
} // iodelay
///////////////////////////////////////////////////////////////////////////
//
// insb/outsb - Read/Write bytes or words from/to adapter ram
//
// In word mode, the caller must ensure that adapter ram access starts
// on a word boundary.
//
///////////////////////////////////////////////////////////////////////////
static void
HWAccess(
WORD addr,
WORD count,
PWORD mem,
BYTE direction
)
{
WORD c;
PBYTE pb = (PBYTE)mem;
if (!count) {
EdbgOutputDebugString("EDBG:NE2000:HWAccess - skipping 0 byte access!!!\r\n");
return; // Skip 0 length reads
}
WriteByte(NIC_INTR_STATUS, NIC_ISR_DMA_COMPLETE);
// Set count, address, remote DMA address and direction,
UsePage0();
WriteByte(NIC_RMT_ADDR_LSB, (UCHAR)addr);
WriteByte(NIC_RMT_ADDR_MSB, (UCHAR)(addr>>8));
WriteByte(NIC_RMT_COUNT_LSB, (UCHAR)count);
WriteByte(NIC_RMT_COUNT_MSB, (UCHAR)(count>>8));
WriteCmd(direction);
if (addr & 1) { // Never start word IO on an odd adapter address
EdbgOutputDebugString("EDBG:NE2000:HWAccess SKIPPING ODD ADAPTER ADDRESS ACCESS!!!\r\n");
return;
}
c = count >> 1; // word count.
if (direction == NIC_RemoteDmaWr) {
while (c) {
WriteWord(NIC_RACK_NIC, *mem);
mem++;
c--;
}
if (count & 1) { // trailing odd data byte will be on even adapter address
WriteByte(NIC_RACK_NIC, *((PBYTE)mem));
}
} else {
while (c) {
*mem = ReadWord(NIC_RACK_NIC);
mem++;
c--;
}
if (count & 1) {
*((PBYTE)mem) = ReadByte(NIC_RACK_NIC);
}
}
c = 0;
while ((++c) &&
!(ReadByte(NIC_INTR_STATUS) & NIC_ISR_DMA_COMPLETE));
return;
} // HWAccess
/////////////////////////////////////////////////////////////////////////////
//
// HWStartAdapter - initialize the data size (BYTE or WORD), set up the
// receive configuration, and unmask the receive and
// transmit interrupts at the adapter.
//
/////////////////////////////////////////////////////////////////////////////
static void
HWStartAdapter(void)
{
UsePage0();
WriteByte(NIC_DATA_CONFIG, NIC_DCR_FIFO | NIC_DCR_NORMAL | NIC_DCR_WORD_XFER);
WriteByte(NIC_XMIT_CONFIG, 0); // Initialize transmit configuration for normal operation.
//WriteByte(NIC_RCV_CONFIG, NIC_RECEIVE_BROADCAST); // accept broadcast and directed packets.
WriteByte(NIC_RCV_CONFIG, ucFilter);
WriteByte(NIC_INTR_STATUS, 0xff ); // ack all interrupts
WriteCmd(NIC_CMD_ABORT | NIC_CMD_START ); // Put NIC in START mode.
} // HWStartAdapter
/////////////////////////////////////////////////////////////////////////////
//
// HWStopAdapter - shut down the adapter and leave it in loopback mode
// preparatory to a reset.
//
/////////////////////////////////////////////////////////////////////////////
static void
HWStopAdapter(void)
{
WORD closeTimeout;
WriteCmd(NIC_CMD_PAGE0 | NIC_CMD_ABORT | NIC_CMD_STOP); // Stop NIC from receiving or transmitting.
WriteByte(NIC_INTR_STATUS, 0 ); // mask all adapter interrupts
WriteByte(NIC_RMT_COUNT_LSB, 0 ); // Clear the remote byte count registers.
WriteByte(NIC_RMT_COUNT_MSB, 0 );
// Poll the card ISR for the RST bit.
closeTimeout = 0;
while ((++closeTimeout) &&
!(ReadByte(NIC_INTR_STATUS) & NIC_ISR_RESET_STATUS));
WriteByte(NIC_XMIT_CONFIG, 2); // Place NIC in internal loopback mode.
WriteCmd(NIC_CMD_PAGE0 | NIC_CMD_START ); // Issue a start command. The NIC is still in loopback mode.
} // HWStopAdapter
static void
HWReset(void)
{
HWStopAdapter();
WriteByte(NIC_PAGE_START, pstart);
WriteByte(NIC_BOUNDARY, (BYTE)(pstart+1));
WriteByte(NIC_PAGE_STOP, pstop);
UsePage1Stop();
WriteByte(NIC_CURRENT, (BYTE)(pstart+1));
WriteCmd(NIC_AbortDmaStop); // back to page0
NextPage = pstart+1;
HWStartAdapter();
}
// checkRam and ram_test are used at bind time.
#define RAMCHECK_SIZE 4 // RAM test pattern
static BYTE ramCheck[RAMCHECK_SIZE] = { 0xAA, 0x55, 0xCC, 0x66 };
//
// HWCheckRam - test adapter RAM by writing a test pattern and reading it.
//
// Inputs:
// addr - internal adapter RAM buffer address
// count - number of bytes to move
//
static BOOL
HWCheckRam(DWORD addr, DWORD count)
{
DWORD i,j;
BYTE buff[RAMCHECK_SIZE];
// write the test pattern in 4 byte chunks
for (i = 0; i < count; i += RAMCHECK_SIZE) {
OUTSB((addr+i), min(RAMCHECK_SIZE,count), ramCheck);
}
// read it back and compare against the checkRam pattern.
for (i = 0; i < count; i += RAMCHECK_SIZE) {
INSB((addr+i), min(RAMCHECK_SIZE,count), buff);
for (j = 0; j < min(RAMCHECK_SIZE,count); j++) {
if (buff[j] != ramCheck[j]) {
return FALSE;
}
}
}
return TRUE;
}
//
// HWRamTest - figure out how much adapter RAM there is.
//
static BOOL
HWRamTest(void)
{
DWORD ramEnd;
BOOL bRet;
#define MAX_RAM_BASE 0x10000
// find some RAM starting at 1K thru 64K. if it's greater then 64K, then
// assume it isn't there.
ramEnd = 0;
HWStopAdapter();
for (srambase = 1024; srambase < MAX_RAM_BASE; srambase += 1024) {
if (HWCheckRam(srambase, 4)) {
// found the starting point, now find out how much RAM there is.
// assume it will increase in 1K chunks.
for (ramEnd = srambase; !(ramEnd & 0xffff0000); ramEnd += 1024) {
// RAM ends at the first location that fails the RAM test.
if (!HWCheckRam(ramEnd, 4)) {
pstop = (BYTE)(ramEnd>>8);
break;
}
}
break;
}
}
// check for failure
if ((srambase > MAX_RAM_BASE) || (srambase == ramEnd) || (ramEnd == 0)) {
EdbgOutputDebugString("EDBG:NE2000:HWRamTest fail. srambase = 0x%X, ramEnd = 0x%X\r\n",
srambase, ramEnd);
bRet = FALSE;
goto hwrt_done;
}
// if ramEnd is >= 64K, then back off one 256 byte chunk to avoid the 16
// bit wrap around.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -