📄 ns8390.c
字号:
/*
* 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 + -