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

📄 ns8390.c

📁 Coldfire MCF5282 DBug bootloader
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * File:		ns8390.c
 * Purpose:		Device driver for the National Semiconductor 8390
 *				Ethernet chipset used in NE2000 type NICs.
 *
 * Notes:		This driver was actually developed on a Winbond
 *				W89C906 chipset, a reportedly-identical clone.
 *
 */

#include "src/include/dbug.h"
#include "src/include/dev/ns8390.h"
#include "src/uif/net/net.h"
#include "src/dev/ethernet/ns8390p.h"

#ifndef NS8390_8BIT
#define NS8390_16BIT
#endif

#ifdef NS8390_16BIT
#if		(!defined(NS8390_ENDIAN_BIG) && !defined(NS8390_ENDIAN_LITTLE))
#error "Must define NS8390_ENDIAN"
#endif
#endif

/********************************************************************/

/*
 * The local buffer memory management algorithms treat the
 * buffer as a circular queue with blocks of size 256 bytes.
 * The following define regions of the local buffer memory
 * in terms of blocks.  Thus the values given below are
 * actually the MSB of a 16-bit address into the local
 * buffer memory.  For most cards, there is 16Kbytes of local
 * buffer memory starting at 0x4000 and ending at 0x7FFF.
 * In addition, there is 32 bytes of EEPROM residing at 0x0000
 * which contains the Ethernet Address and some manufacturer
 * information.
 */

/*
 * 256 * 6 = 1536 which is enough room for one packet for TX.
 * This scheme gives TX enough buffer space for transmitting
 * one packet, and the rest to the receiver logic.  This
 * simplifies the code necessary to manage the queue.
 */
#if (defined(NS8390_8BIT))
#define DEFAULT_TPSR	(0x40)
#define DEFAULT_PSTART	(0x46)
#define DEFAULT_PSTOP	(0x60)
#elif (defined(NS8390_16BIT))
#define DEFAULT_TPSR	(0x40)
#define DEFAULT_PSTART	(0x46)
#define DEFAULT_PSTOP	(0x80)
#else
#error "Unsupported NS8390_WIDTH in ns8390.c"
#endif

/********************************************************************/
static void
set_dma_read_at (NS8390 *ns8390, int addr, int size)
{
	/*
	 * Prepare to do a Remote DMA read.  When this routine exits,
	 * it leaves the CR in Page 0.
	 */
	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_RD_AB
		| NS8390_CR_STA
		) ;

	NS8390_WR_P0_RBCR1(ns8390, ((size & 0x0000FF00) >> 8));
	NS8390_WR_P0_RBCR0(ns8390, ((size & 0x000000FF)));

	NS8390_WR_P0_RSAR1(ns8390, ((addr & 0x0000FF00) >> 8));
	NS8390_WR_P0_RSAR0(ns8390, ((addr & 0x000000FF)));

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_RD_RD
		| NS8390_CR_STA
		) ;
}

/********************************************************************/
static void
set_dma_write_at (NS8390 *ns8390, int addr, int size)
{
	/*
	 * Initialize the Remote DMA Write sequence properly. (See National
	 * Semiconductor documentation.)  When this routine exists, it
	 * leaves the CR at Page 0.
	 */
	volatile int dummy_read;

	set_dma_read_at(ns8390, DEFAULT_PSTART, 2);
#if		(defined(NS8390_8BIT))
	dummy_read = NS8390_RD_DATA8(ns8390);
	/* dummy_read = NS8390_RD_DATA8(ns8390); */
#elif	(defined(NS8390_16BIT))
	dummy_read = NS8390_RD_DATA16(ns8390);
#else
#error
#endif

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_RD_AB
		| NS8390_CR_STA
		) ;

	NS8390_WR_P0_RBCR1(ns8390, ((size & 0x0000FF00) >> 8));
	NS8390_WR_P0_RBCR0(ns8390, ((size & 0x000000FF)));

	NS8390_WR_P0_RSAR1(ns8390, ((addr & 0x0000FF00) >> 8));
	NS8390_WR_P0_RSAR0(ns8390, ((addr & 0x000000FF)));

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_RD_WR
		| NS8390_CR_STA
		) ;
}

/********************************************************************/
static void
read_eth_addr(NS8390 *ns8390, unsigned char *hwa)
{
	int i;
	unsigned char eeprom[32];

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_STP
		| NS8390_CR_RD_AB	/* No DMA */
		) ;

	NS8390_WR_P0_DCR(ns8390, 0
		| NS8390_DCR_FT_8B
		) ;

	NS8390_WR_P0_RBCR1(ns8390, 0);
	NS8390_WR_P0_RBCR0(ns8390, 0);

	NS8390_WR_P0_IMR(ns8390, 0);	/* mask irqs */
	NS8390_WR_P0_ISR(ns8390, ~0);

	NS8390_WR_P0_RCR(ns8390, 0
		| NS8390_RCR_MON
		) ;

	NS8390_WR_P0_TCR(ns8390, 0
		| NS8390_TCR_LOOP_I0
		) ;

	NS8390_WR_P0_RBCR0(ns8390, 32);	/* EEPROM size */
	NS8390_WR_P0_RBCR1(ns8390, 0);

	NS8390_WR_P0_RSAR0(ns8390, 0);	/* EEPROM address */
	NS8390_WR_P0_RSAR1(ns8390, 0);

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_STA		/* Start   */
		| NS8390_CR_RD_RD	/* Read DMA */
		) ;

	for (i = 0; i < 32; ++i)
	{
		eeprom[i] = NS8390_RD_DATA8(ns8390);
	}

	for (i = 0; i < 6; ++i)
	{
		hwa[i] = eeprom[(i*2)];
	}

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_STP		/* Stop   */
		| NS8390_CR_RD_AB	/* No DMA */
		) ;
}

/********************************************************************/
static int
ns8390_reset (NIF *nif)
{
	/*
	 * This routine sets up the chipset for use.  The procedure
	 * implemented below is *mandatory*, as stated by National.
	 */
	NS8390 *ns8390;

	ns8390 = nif->nic;

	/*
	 * Step 1)  Select register page 0.  Stop the part.
	 */
	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_STP
		| NS8390_CR_RD_AB
		) ;

	/*
	 * Step 2)  Configure the DCR for 8 or 16-bit mode, normal operation.
	 */
#if (defined(NS8390_8BIT))
	NS8390_WR_P0_DCR(ns8390, 0
		| NS8390_DCR_FT_8B
		) ;
#elif (defined(NS8390_16BIT))

#if (defined(NS8390_ENDIAN_BIG))
	NS8390_WR_P0_DCR(ns8390, 0
		| NS8390_DCR_WTS
		| NS8390_DCR_BOS
		| NS8390_DCR_FT_8B
		) ;
#elif (defined(NS8390_ENDIAN_LITTLE))
	NS8390_WR_P0_DCR(ns8390, 0
		| NS8390_DCR_WTS
		| NS8390_DCR_FT_8B
		) ;
#else
#error "ENDIAN"
#endif

#else
#error
#endif

	/*
	 * Step 3)  Clear Remote Byte Counter Registers.
	 */
	NS8390_WR_P0_RBCR0(ns8390, 0);
	NS8390_WR_P0_RBCR1(ns8390, 0);

	/*
	 * Step 4)  Initalize RCR.  Allow Broadcasts.
	 */
	NS8390_WR_P0_RCR(ns8390, 0
/*		| NS8390_RCR_AB*/		/* FIX !!!! */
/*		| NS8390_RCR_PRO */
		) ;

	/*
	 * Step 5)  Place NIC in loopback mode 1 or 2.
	 */
	NS8390_WR_P0_TCR(ns8390, 0
		| NS8390_TCR_LOOP_I0
		) ;

	/*
	 * Step 6)  Initialize BNDRY, PSTART, and PSTOP.
	 */
	NS8390_WR_P0_BNRY(ns8390, DEFAULT_PSTART);
	NS8390_WR_P0_PSTART(ns8390, DEFAULT_PSTART);
	NS8390_WR_P0_PSTOP(ns8390, DEFAULT_PSTOP);

	/*
	 * Step 7)  Clear ISR.
	 */
	NS8390_WR_P0_ISR(ns8390, 0
		| NS8390_ISR_PRX
		| NS8390_ISR_PTX
		| NS8390_ISR_RXE
		| NS8390_ISR_TXE
		| NS8390_ISR_OVW
		| NS8390_ISR_CNT
		| NS8390_ISR_RDC
		| NS8390_ISR_RST
		) ;

	/*
	 * Step 8)  Initialize IMR.
	 */
	NS8390_WR_P0_IMR(ns8390, 0
		| NS8390_IMR_PRXE
/*		| NS8390_IMR_PTXE */
		| NS8390_IMR_RXEE
		| NS8390_IMR_TXEE
		| NS8390_IMR_OVWE
		| NS8390_IMR_CNTE
/*		| NS8390_IMR_RDCE */
		) ;

	/*
	 * Step 9)  Program CR for Register Page 1.  Initialize the
	 * Station Physical Address, Multicast address, and CURR.
	 */
	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE1
		| NS8390_CR_STP
		| NS8390_CR_RD_AB
		) ;

	NS8390_WR_P1_PAR0(ns8390, nif->hwa[0]);
	NS8390_WR_P1_PAR1(ns8390, nif->hwa[1]);
	NS8390_WR_P1_PAR2(ns8390, nif->hwa[2]);
	NS8390_WR_P1_PAR3(ns8390, nif->hwa[3]);
	NS8390_WR_P1_PAR4(ns8390, nif->hwa[4]);
	NS8390_WR_P1_PAR5(ns8390, nif->hwa[5]);

	NS8390_WR_P1_CURR(ns8390, (DEFAULT_PSTART + 1));
	nif->next_receive = ((DEFAULT_PSTART + 1) << 8);

	/* No Multicasts */
	NS8390_WR_P1_MAR0(ns8390, 0);
	NS8390_WR_P1_MAR1(ns8390, 0);
	NS8390_WR_P1_MAR2(ns8390, 0);
	NS8390_WR_P1_MAR3(ns8390, 0);
	NS8390_WR_P1_MAR4(ns8390, 0);
	NS8390_WR_P1_MAR5(ns8390, 0);
	NS8390_WR_P1_MAR6(ns8390, 0);
	NS8390_WR_P1_MAR7(ns8390, 0);

	/*
	 * Step 10)  Put NIC in START mode (NIC still in Loopback).
	 */
	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_STA
		| NS8390_CR_RD_AB
		) ;

	/*
	 * Step 11)  Initialize TCR.  NIC now ready.  NS recommends
	 * placing the NIC in normal operation from loopback here.
	 * This isn't done here so that an explict ns8390_start() is
	 * needed to start receiving ethernet frames.
	 */

	return TRUE;
}

/********************************************************************/
static void
ns8390_start (NIF *nif)
{
	/*
	 * This routine allows the chipset to start receiving frames.
	 */
	NS8390 *ns8390;

	ns8390 = nif->nic;

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_STA
		| NS8390_CR_RD_AB
		) ;

	NS8390_WR_P0_TCR(ns8390, 0
		| NS8390_TCR_LOOP_NO
		) ;

#if (defined(NS8390_8BIT))
	NS8390_WR_P0_DCR(ns8390, 0
		| NS8390_DCR_LS
		| NS8390_DCR_FT_8B
		) ;
#elif (defined(NS8390_16BIT))

#if (defined(NS8390_ENDIAN_BIG))
	NS8390_WR_P0_DCR(ns8390, 0
		| NS8390_DCR_LS
		| NS8390_DCR_WTS
		| NS8390_DCR_BOS
		| NS8390_DCR_FT_8B
		) ;
#elif (defined(NS8390_ENDIAN_LITTLE))
	NS8390_WR_P0_DCR(ns8390, 0
		| NS8390_DCR_LS
		| NS8390_DCR_WTS
		| NS8390_DCR_FT_8B
		) ;
#else
#error "ENDIAN"
#endif

#else
#error
#endif
}

/********************************************************************/
static void
ns8390_stop (NIF *nif)
{
	/*
	 * This routine masks out all NS8390 interrupts, thereby
	 * letting any remaining TX frames transmit, and preventing
	 * the NS8390 from interrupting the host processor.  Because
	 * there isn't any clean way of shutting this part down, this
	 * is how we do it.  The NS8390 may continue to receive frames,
	 * and fill its buffers, but the host won't know it.
	 */
	int loop;
	NS8390 *ns8390 = nif->nic;

	NS8390_WR_CR(ns8390, 0
		| NS8390_CR_PAGE0
		| NS8390_CR_RD_AB
		| NS8390_CR_STA
		) ;

	NS8390_WR_P0_IMR(ns8390, 0);
	NS8390_WR_P0_ISR(ns8390, ~0);

	/* hope this is long enough for 1 TX frame time */
	for (loop = 0; loop < 0x000010000; ++loop)
		;

⌨️ 快捷键说明

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