📄 ne2000.c
字号:
/*++
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.
Copyright (c) 1998-2000 Microsoft Corporation. All rights reserved.
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 ".\udp.h"
//#define USE_ISA_PNP_STUFF
//#define DEBUG_SINGLE_CHAR 1
void msWait(unsigned msVal);
//
// 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 & 0x000000FF);
}
static UCHAR
NE2000_READ_PORT_UCHAR(volatile PUCHAR addr)
{
return *addr;
}
static void
NE2000_WRITE_PORT_USHORT(volatile PUSHORT addr, USHORT val)
{
*addr = (val & 0x0000FFFF);
}
static USHORT
NE2000_READ_PORT_USHORT(volatile PUSHORT addr)
{
return *addr;
}
static ULONG
NE2000_READ_PORT_ULONG(volatile PULONG 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 ReadLong(Offset) NE2000_READ_PORT_ULONG((volatile PULONG)(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;
int temp;
PBYTE pb = (PBYTE)mem;
if (!count) {
EdbgOutputDebugString("EDBG:NE2000:HWAccess - skipping 0 byte access!!!\r\n");
return; // Skip 0 length reads
}
/*
ReadByte(0x10);
ReadWord(0x10);
ReadLong(0x10);
while(1);
*/
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((count / 4) != 0)
{
temp = ReadLong(NIC_RACK_NIC);
*mem = (temp & 0x0000FFFF);
mem++;
*mem = ((temp & 0xFFFF0000) >> 16);
mem++;
count = count - 4;
}
if((count / 2) != 0)
{
temp = ReadLong(NIC_RACK_NIC);
*mem = (temp & 0x0000FFFF);
mem++;
if (count == 3) // count is either 2 or 3
{
*((PBYTE)mem) = ((temp & 0x00FF0000) >> 16);
count = count - 1;
}
count = count - 2;
}
if (count == 1)
{
temp = ReadLong(NIC_RACK_NIC);
*((PBYTE)mem) = (temp & 0x000000FF);
}
}
c = 0;
while ((++c) && !(ReadByte(NIC_INTR_STATUS) & NIC_ISR_DMA_COMPLETE));
return;
} // HWAccess
#if 0
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
}
/*
ReadByte(0x10);
ReadWord(0x10);
ReadLong(0x10);
while(1);
*/
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);
//EdbgOutputDebugString("W 0x%X \r\n", *mem);
mem++;
c--;
}
if (count & 1) {
*((PBYTE)mem) = ReadByte(NIC_RACK_NIC);
//EdbgOutputDebugString("B 0x%X \r\n", *((PBYTE)mem));
}
}
c = 0;
while ((++c) && !(ReadByte(NIC_INTR_STATUS) & NIC_ISR_DMA_COMPLETE));
return;
} // HWAccess
#endif
/////////////////////////////////////////////////////////////////////////////
//
// 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_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 };
static BYTE ramCheck2[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//
// 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -