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

📄 ax88796.c

📁 PXA255 WINCE 4.2 BSP ,该BSP是商用的。
💻 C
字号:

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

//#define DEBUG_INIT
//#define DEBUG_SENDFRAME
//#define DEBUG_GETFRAME

#define NE_DATAPORT     EI_SHIFT(0x10)  /* NatSemi-defined port window offset. */
#define NE_RESET        EI_SHIFT(0x1f)  /* Issue a read to reset, a write to clear. */

static unsigned E8390_BASE = 0x400;

static unsigned char inb( unsigned addr)
{
	return (unsigned char) *((volatile unsigned short *) addr);
}

static void insw( unsigned addr, unsigned short* buffer, int count)
{
	while( count-- > 0)
		*buffer++ = *((volatile unsigned short *)addr);
}

static void outb( unsigned char c, unsigned addr)
{
	*((volatile unsigned short *)addr) = c;
}

static void outsw( unsigned addr, unsigned short* buffer, int count)
{
	while( count-- > 0)
		*((volatile unsigned short *)addr) = *buffer++;
}

void NE2000DisableInts(void)
{
#ifdef DEBUG_INIT
	EdbgOutputDebugString( "ax88796: eth_halt\r\n");
#endif
	outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_BASE + E8390_CMD);       // switch to page 0 + stop
}

void NE2000EnableInts(void)
{
#ifdef DEBUG_INIT
	EdbgOutputDebugString( "ax88796: eth_start\r\n");
#endif
	// clear the pending interrupts and mask
	outb( 0xff, E8390_BASE + EN0_ISR);
	outb( ENISR_ALL, E8390_BASE + EN0_IMR);

	outb(E8390_NODMA+E8390_PAGE0+E8390_START, E8390_BASE + E8390_CMD);      // switch to page 0 + start
}

DWORD NE2000GetPendingInts(void)
{
	unsigned char curr_page, this_page;
#ifdef DEBUG_INIT
	EdbgOutputDebugString( "ax88796: get_interrupts\r\n");
#endif
	// get the rx page (incoming packet pointer)
	outb(E8390_NODMA+E8390_PAGE1, E8390_BASE + E8390_CMD);	// switch to page 1, get curr page register
	curr_page = inb( E8390_BASE + EN1_CURPAG);
	outb(E8390_NODMA+E8390_PAGE0, E8390_BASE + E8390_CMD);	// switch to page 0
#ifdef DEBUG_INIT
	EdbgOutputDebugString( "curr_page=0x%x\r\n", curr_page);
#endif
	// remove one frame from the ring, boundary is always a page behind
	this_page = inb( E8390_BASE + EN0_BOUNDARY) + 1;
	if (this_page >= 0x80)
		this_page = 0x46;	// wrap around page register
#ifdef DEBUG_INIT
	EdbgOutputDebugString( "this_page=0x%x\r\n", this_page);
#endif
	if (this_page == curr_page)   // read all the frames
		return 0;

	return INTR_TYPE_RX;
}

extern void msWait(unsigned msVal);

static int ax88796_reset(unsigned ioaddr)
{
	unsigned rto = 500;		// reset timeout 5*5ms

	// reset card, who knows what brain-damaged state it was left in
	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);

	while( (inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
	{
		if( rto-- == 0)		// reset timeout ?
			return -1;

		msWait(5);	// wait 5ms
	}
	outb(0xff, ioaddr + EN0_ISR);		// ack all intr
	return 0;
}

static int ax88796_probe( int ioaddr)
{
	// verify chip present
	if( inb(E8390_BASE) == 0xff)
		return -1;

	// Do a preliminary verification that we have a 8390 chipset
	outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);	// set page 1 registers
	outb(0xff, ioaddr + EN0_COUNTER0);	// set 0xff at offset of EN0_COUNTER0(page0)
	outb(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);	// switch to page 0
	inb(ioaddr + EN0_COUNTER0);	// clear the counter by reading
	if( inb(ioaddr + EN0_COUNTER0) != 0)
		return -1;

	return 0;
}

BOOL NE2000Init( BYTE *pbBaseAddress, DWORD dwMultiplier, USHORT macAddr[3])
{
	E8390_BASE = (unsigned) pbBaseAddress;

#ifdef DEBUG_INIT
	EdbgOutputDebugString( "ax88796: eth_init chip at 0x%X\r\n", E8390_BASE);
#endif

	if( ax88796_probe(E8390_BASE) < 0)
	{
		EdbgOutputDebugString("ax88796: ethernet chip not found\r\n");
		return FALSE;
	}
#ifdef DEBUG_INIT
	EdbgOutputDebugString("ax88796: found at 0x%X\r\n", E8390_BASE);
#endif
	if( ax88796_reset(E8390_BASE) < 0)
	{
		EdbgOutputDebugString("ax88796: reset failed (no reset ack)\r\n");
		return FALSE;
	}

	// follow ax88796 init procedure
	outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_BASE + E8390_CMD);	// switch to page 0
	outb( 0x01, E8390_BASE + EN0_DCFG);	// select word wide transfer
	outb( E8390_RXCONFIG, E8390_BASE + EN0_RXCR);   // irq high active, accept broadcasts

	// clear the remote byte count registers
	outb( 0x00, E8390_BASE + EN0_RCNTLO);
	outb( 0x00, E8390_BASE + EN0_RCNTHI);

	// set the transmit page and receive ring
	outb( 0x40, E8390_BASE + EN0_TPSR);		// tx start page register
	outb( 0x46, E8390_BASE + EN0_STARTPG);		// start page register
	outb( 0x80, E8390_BASE + EN0_STOPPG);		// stop page register
	outb( 0x46, E8390_BASE + EN0_BOUNDARY);

	// clear the pending interrupts and mask
	outb( 0xff, E8390_BASE + EN0_ISR);
	outb( ENISR_ALL, E8390_BASE + EN0_IMR);

	{
		int i;
		unsigned char* pmac = (unsigned char*) macAddr;
		// set mac address
		outb(E8390_NODMA + E8390_PAGE1 + E8390_STOP, E8390_BASE + E8390_CMD);	// switch to page 1

		for(i = 0; i < ETHER_ADDR_LEN; i++)
		{
			outb( pmac[i], E8390_BASE + EN1_PHYS_SFT(i));
			if( inb( E8390_BASE + EN1_PHYS_SFT(i)) != pmac[i])
				EdbgOutputDebugString( "ax88796: mac address read/write mismap %d\r\n", i);
		}
	}
	outb( 0x47, E8390_BASE + EN1_CURPAG);		// set current page register
	outb(E8390_NODMA+E8390_PAGE0+E8390_START, E8390_BASE + E8390_CMD);      // switch to page 0 + start

	if( inb( E8390_BASE + EN0_GPI) & 0x02)		// set to full duplex mode
		outb( 0x80 | E8390_TXCONFIG, E8390_BASE + EN0_TXCR);
	else
		outb( E8390_TXCONFIG, E8390_BASE + EN0_TXCR);

	return TRUE;
}

// Send a data block via Ethernet
UINT16 NE2000SendFrame( BYTE *packet, DWORD length )
{
	unsigned txto;
#ifdef DEBUG_SENDFRAME
	EdbgOutputDebugString( "ax88796: +eth_send\r\n");
#endif
	outb(E8390_PAGE0+E8390_START+E8390_NODMA, E8390_BASE + E8390_CMD);	// switch to page 0
	outb(ENISR_RDC, E8390_BASE + EN0_ISR);		// set remote dma complete

	if( length & 0x01)	// round the length up for word writes
		length++;

	// setup remote dma transfer
	outb( (unsigned char) (length & 0xff), E8390_BASE + EN0_RCNTLO);
	outb( (unsigned char) (length >> 8), E8390_BASE + EN0_RCNTHI);
	outb( 0x00, E8390_BASE + EN0_RSARLO);
	outb( 0x40, E8390_BASE + EN0_RSARHI);

	//start data transfer
	outb( E8390_RWRITE+E8390_START, E8390_BASE + E8390_CMD);
	outsw( E8390_BASE + NE_DATAPORT, (unsigned short*)packet, length>>1);

	// write packet tx length
        outb( (unsigned char) (length & 0xff), E8390_BASE + EN0_TCNTLO);
	outb( (unsigned char) (length >> 8), E8390_BASE + EN0_TCNTHI);

	// trigger tx
	outb( E8390_NODMA+E8390_TRANS+E8390_START, E8390_BASE + E8390_CMD);

	txto = 20;	// tx timeout 20*10ms

	while( (inb( E8390_BASE + EN0_ISR) & (ENISR_RDC|ENISR_TX)) == 0)
	{
		if( txto-- == 0)
		{
			EdbgOutputDebugString("ax88796: tramsmit timeout\r\n");
//			ax88796_reset(E8390_BASE);
			break;
		}
		msWait(10);
	}

//	outb( (ENISR_RDC|ENISR_ALL), E8390_BASE + EN0_ISR);  // ack intr

#ifdef DEBUG_SENDFRAME
	EdbgOutputDebugString( "ax88796: -eth_send\r\n");
#endif
	return 0;
}

static void ax88796_read( unsigned char* buffer, int count, unsigned ring_addr)
{
#ifdef DEBUG_GETFRAME
	EdbgOutputDebugString( "ax88796: reading %d bytes from ring at 0x%x\r\n", count, ring_addr);
#endif
	outb( E8390_NODMA+E8390_PAGE0+E8390_START, E8390_BASE + E8390_CMD);  // switch to page 0

	outb( count & 0xff, E8390_BASE + EN0_RCNTLO);	// write count of bytes
	outb( count >> 8, E8390_BASE + EN0_RCNTHI);
	outb( ring_addr & 0xff, E8390_BASE + EN0_RSARLO);	// set read start address
	outb( ring_addr >> 8, E8390_BASE + EN0_RSARHI);

	// read data from rx buffer
	outb( E8390_RREAD+E8390_START, E8390_BASE + E8390_CMD);
	insw( E8390_BASE + NE_DATAPORT, (unsigned short*)buffer, count>>1);

	if (count & 0x01)
		buffer[count-1] = inb( E8390_BASE + NE_DATAPORT);
}

#ifdef DEBUG_GETFRAME
static void DumpEtherFrame( BYTE *pFrame, WORD cwFrameLength )
{
    int i,j;

    EdbgOutputDebugString( "Frame Buffer Address: 0x%X\r\n", pFrame );
    EdbgOutputDebugString( "To: %B:%B:%B:%B:%B:%B  From: %B:%B:%B:%B:%B:%B  Type: 0x%H  Length: %u\r\n",
        pFrame[0], pFrame[1], pFrame[2], pFrame[3], pFrame[4], pFrame[5],
        pFrame[6], pFrame[7], pFrame[8], pFrame[9], pFrame[10], pFrame[11],
        ntohs(*((UINT16 *)(pFrame + 12))), cwFrameLength );
    for( i = 0; i < cwFrameLength / 16; i++ ) {
        for( j = 0; j < 16; j++ )
            EdbgOutputDebugString( " %B", pFrame[i*16 + j] );
        EdbgOutputDebugString( "\r\n" );
    }
    for( j = 0; j < cwFrameLength % 16; j++ )
        EdbgOutputDebugString( " %B", pFrame[i*16 + j] );
    EdbgOutputDebugString( "\r\n" );
}
#endif

// Get a data block via Ethernet
UINT16 NE2000GetFrame(BYTE *pbData, UINT16 *pwLength )
{
	int rxlen = *pwLength;
	unsigned char curr_page, this_page;
	struct e8390_pkt_hdr rx_frame;
#ifdef DEBUG_GETFRAME
	EdbgOutputDebugString( "ax88796: +eth_rx\r\n");
#endif
	outb( 0, E8390_BASE + EN0_IMR);		// mask interrupts
	outb( ENISR_ALL, E8390_BASE + EN0_ISR);  // ack interrupts

	*pwLength = 0;
	// get the rx page (incoming packet pointer)
	outb(E8390_NODMA+E8390_PAGE1, E8390_BASE + E8390_CMD);	// switch to page 1, get curr page register
	curr_page = inb( E8390_BASE + EN1_CURPAG);
	outb(E8390_NODMA+E8390_PAGE0, E8390_BASE + E8390_CMD);	// switch to page 0
#ifdef DEBUG_GETFRAME
	EdbgOutputDebugString( "curr_page=0x%x\r\n", curr_page);
#endif
	// remove one frame from the ring, boundary is always a page behind
	this_page = inb( E8390_BASE + EN0_BOUNDARY) + 1;
	if (this_page >= 0x80)
		this_page = 0x46;	// wrap around page register
#ifdef DEBUG_GETFRAME
	EdbgOutputDebugString( "this_page=0x%x\r\n", this_page);
#endif
	if (this_page != curr_page)   // read all the frames
	{
		// read page aligned packet header
		ax88796_read( (unsigned char*) &rx_frame, sizeof(struct e8390_pkt_hdr), this_page<<8);
	#ifdef DEBUG_GETFRAME
		EdbgOutputDebugString( "8390hdr: status=0x%x, next=0x%x, count=0x%x\r\n", rx_frame.status, rx_frame.next, rx_frame.count);
	#endif
		*pwLength = rx_frame.count - sizeof(struct e8390_pkt_hdr);

		// read packet data
		if(*pwLength > rxlen)
			EdbgOutputDebugString( "ax88796: bogus packet size %d\r\n", *pwLength);

		if( (rx_frame.status & 0x0F) == ENRSR_RXOK)
			ax88796_read( pbData, min(*pwLength,rxlen), (this_page<<8) + sizeof(rx_frame));

		if( rx_frame.next > 0x80 && rx_frame.next <= 0x46)	// set boundary register
			rx_frame.next = 0x80;

		outb( rx_frame.next-1, E8390_BASE + EN0_BOUNDARY);
	#ifdef DEBUG_GETFRAME
		EdbgOutputDebugString( "setting boundary to 0x%x\r\n", inb( E8390_BASE + EN0_BOUNDARY));

		DumpEtherFrame( pbData, *pwLength);

		EdbgOutputDebugString( "ax88796: -eth_rx\r\n");
	#endif
	}

	outb( ENISR_ALL, E8390_BASE + EN0_IMR);		// enable interrupts

	return *pwLength;
}


⌨️ 快捷键说明

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