📄 ns8390.c
字号:
/* stop the nic */
NS8390_WR_CR(ns8390, 0
| NS8390_CR_PAGE0
| NS8390_CR_RD_AB
| NS8390_CR_STP
) ;
}
/********************************************************************/
static int
ns8390_send (NIF *nif,
HWA_ADDR_P eth_dest,
HWA_ADDR_P eth_src,
uint16 eth_type,
NBUF *pNbuf)
{
/*
* This routine transmits one frame. This routine only accepts
* 6-byte Ethernet addresses.
*/
int mod_data_length, index;
NS8390 *ns8390;
uint8 old_ipl;
ns8390 = nif->nic;
/*
* The format of an Ethernet frame looks like:
*
* 00 01 02 03 04 05
* +--+--+--+--+--+--+
* | | | | | | | destination ethernet address
* +--+--+--+--+--+--+
* 06 07 08 09 0A 0B
* +--+--+--+--+--+--+
* | | | | | | | source ethernet address
* +--+--+--+--+--+--+
* 0C 0D
* +--+--+
* | | | type (IP = 0x0800)
* +--+--+
* 0E 0F ...
* +--+--+--+--+--+--+
* | | | | | | | data (min of 46 octets, max of 1500)
* +--+--+--+--+--+--+
*
* +--+--+--+--+
* | | | | | 32-bit CRC (generated by hardware)
* +--+--+--+--+
*
* NOTE: The NS8390 takes care of pre-amble, and is programmed
* to generate the 32-bit CRC.
*
* NOTE: The minimum size of data transmitted in an ethernet
* frame is 46 octets (bytes).
*/
/*
* Check for valid length of data.
*/
if ((pNbuf->length > nif->mtu) || (pNbuf->length <= 0))
{
return 0;
}
mod_data_length = pNbuf->length;
if (mod_data_length < ETH_MIN_SIZE)
mod_data_length = ETH_MIN_SIZE;
#if (defined(NS8390_16BIT))
if (mod_data_length & 0x0001)
++mod_data_length; /* make it align to 16 bits */
#endif
/*
* During the course of loading a frame into the NS8390, we
* can not have interrupts occur, especially those from the
* NS8390 receiver!
*/
old_ipl = asm_set_ipl(6);
/*
* Load starting address and length into the DMA registers.
*/
set_dma_write_at (ns8390,(DEFAULT_TPSR << 8), mod_data_length+14);
/*
* Write destination ethernet address.
*/
#if (defined(NS8390_8BIT))
NS8390_WR_DATA8(ns8390, eth_dest[0]);
NS8390_WR_DATA8(ns8390, eth_dest[1]);
NS8390_WR_DATA8(ns8390, eth_dest[2]);
NS8390_WR_DATA8(ns8390, eth_dest[3]);
NS8390_WR_DATA8(ns8390, eth_dest[4]);
NS8390_WR_DATA8(ns8390, eth_dest[5]);
#elif (defined(NS8390_16BIT))
NS8390_WR_DATA16(ns8390, *((uint16 *)ð_dest[0]));
NS8390_WR_DATA16(ns8390, *((uint16 *)ð_dest[2]));
NS8390_WR_DATA16(ns8390, *((uint16 *)ð_dest[4]));
#else
#error
#endif
/*
* Write source ethernet address.
*/
#if (defined(NS8390_8BIT))
NS8390_WR_DATA8(ns8390, eth_src[0]);
NS8390_WR_DATA8(ns8390, eth_src[1]);
NS8390_WR_DATA8(ns8390, eth_src[2]);
NS8390_WR_DATA8(ns8390, eth_src[3]);
NS8390_WR_DATA8(ns8390, eth_src[4]);
NS8390_WR_DATA8(ns8390, eth_src[5]);
#elif (defined(NS8390_16BIT))
NS8390_WR_DATA16(ns8390, *((uint16 *)ð_src[0]));
NS8390_WR_DATA16(ns8390, *((uint16 *)ð_src[2]));
NS8390_WR_DATA16(ns8390, *((uint16 *)ð_src[4]));
#else
#error
#endif
/*
* Write frame type.
*/
#if (defined(NS8390_8BIT))
NS8390_WR_DATA8(ns8390, ((eth_type & 0x0000FF00) >> 8));
NS8390_WR_DATA8(ns8390, (eth_type & 0x000000FF));
#elif (defined(NS8390_16BIT))
NS8390_WR_DATA16(ns8390, eth_type);
#else
#error
#endif
/*
* Write the data.
*/
#if (defined(NS8390_8BIT))
for (index = 0; index < pNbuf->length; ++index)
{
NS8390_WR_DATA8(ns8390, pNbuf->data[ETH_HDR_SIZE + index]);
}
for (index = pNbuf->length; index < ETH_MIN_SIZE; ++index)
{
NS8390_WR_DATA8(ns8390, 0);
}
#elif (defined(NS8390_16BIT))
for (index = 0; (index + 1) < pNbuf->length; index += 2)
{
NS8390_WR_DATA16(ns8390, *((uint16 *)&pNbuf->data[ETH_HDR_SIZE + index]));
}
if (pNbuf->length & 0x0001)
{
/* odd number of bytes to transmit */
NS8390_WR_DATA16(ns8390, (pNbuf->data[ETH_HDR_SIZE + pNbuf->length - 1]<<8));
++pNbuf->length; /* for zero pad below */
}
for (index = pNbuf->length; index < ETH_MIN_SIZE; index += 2)
{
NS8390_WR_DATA16(ns8390, 0);
}
#else
#error
#endif
/*
* Load Transmit Start Pointer Register and Transmit Byte Count
* Registers.
*/
NS8390_WR_P0_TPSR(ns8390, DEFAULT_TPSR);
NS8390_WR_P0_TBCR0(ns8390, ((mod_data_length + 14) & 0x000000FF));
NS8390_WR_P0_TBCR1(ns8390,
(((mod_data_length + 14) & 0x0000FF00) >> 8));
/*
* Turn the transmitter on! We're done!
*/
NS8390_WR_CR(ns8390, 0
| NS8390_CR_PAGE0
| NS8390_CR_STA
| NS8390_CR_TXP
| NS8390_CR_RD_AB
) ;
/* Free the network buffer */
nif->tx_free(pNbuf);
/* We can allow interrupts again */
asm_set_ipl(old_ipl);
return TRUE;
}
/********************************************************************/
static void
ns8390_receive (NS8390 *ns8390, NIF *nif)
{
/*
* This command pulls one frame from the card.
*/
int index, current, receive_status, np_pointer, a,b, receive_count;
eth_frame_hdr *ethframe;
NBUF *pNbuf;
/* Prepare to read from the local buffer memory */
current = nif->next_receive;
set_dma_read_at (ns8390, current, 4);
/*
* Read the Status bytes and Ethernet frame from the
* local buffer memory. The DMA hardware automatically
* increments the DMA pointers.
*/
#if (defined(NS8390_8BIT))
receive_status = NS8390_RD_DATA8(ns8390) & 0x00FF;
np_pointer = NS8390_RD_DATA8(ns8390) & 0x00FF;
a = (NS8390_DATAPORT(ns8390) & 0x00FF);
b = (NS8390_DATAPORT(ns8390) & 0x00FF);
receive_count = ((b << 8) | a);
#elif (defined(NS8390_16BIT))
a = NS8390_RD_DATA16(ns8390);
b = NS8390_RD_DATA16(ns8390);
#if (defined(NS8390_ENDIAN_BIG))
receive_status = (a & 0x00FF);
np_pointer = ((a & 0xFF00)>>8);
receive_count = (((b & 0x00FF) << 8) | ((b&0xFF00)>>8));
#elif (defined(NS8390_ENDIAN_LITTLE))
np_pointer = (a & 0x00FF);
receive_status = ((a & 0xFF00)>>8);
receive_count = (((b & 0x00FF) << 8) | ((b&0xFF00)>>8));
#else
#error "ENDIAN"
#endif
#else
#error
#endif
/* Record next packet pointer and adjust circular queue */
nif->next_receive = (np_pointer << 8);
if ((np_pointer-1) <= DEFAULT_PSTART)
NS8390_WR_P0_BNRY(ns8390, DEFAULT_PSTOP-1);
else
NS8390_WR_P0_BNRY(ns8390, np_pointer-1);
/* This frame has errors! */
if ((receive_status & NS8390_RSR_PRX) != NS8390_RSR_PRX)
{
++nif->f_rx_err;
return;
}
/* Process the frame */
set_dma_read_at(ns8390, current+4, 6 + 6 + 2);
/* Obtain system RAM buffer for the frame */
if ((pNbuf = nif->rx_alloc()) == NULL)
return;
ethframe = (eth_frame_hdr *)&pNbuf->data[ETH_HDR_OFFSET];
/* Read the frame from the local buffer */
#if (defined(NS8390_8BIT))
ethframe->dest[0] = NS8390_RD_DATA8(ns8390);
ethframe->dest[1] = NS8390_RD_DATA8(ns8390);
ethframe->dest[2] = NS8390_RD_DATA8(ns8390);
ethframe->dest[3] = NS8390_RD_DATA8(ns8390);
ethframe->dest[4] = NS8390_RD_DATA8(ns8390);
ethframe->dest[5] = NS8390_RD_DATA8(ns8390);
ethframe->src[0] = NS8390_RD_DATA8(ns8390);
ethframe->src[1] = NS8390_RD_DATA8(ns8390);
ethframe->src[2] = NS8390_RD_DATA8(ns8390);
ethframe->src[3] = NS8390_RD_DATA8(ns8390);
ethframe->src[4] = NS8390_RD_DATA8(ns8390);
ethframe->src[5] = NS8390_RD_DATA8(ns8390);
a = (NS8390_RD_DATA8(ns8390) & 0x00FF);
b = (NS8390_RD_DATA8(ns8390) & 0x00FF);
ethframe->type = (uint16)((a << 8) | b);
#elif (defined(NS8390_16BIT))
*(uint16 *)ðframe->dest[0] = NS8390_RD_DATA16(ns8390);
*(uint16 *)ðframe->dest[2] = NS8390_RD_DATA16(ns8390);
*(uint16 *)ðframe->dest[4] = NS8390_RD_DATA16(ns8390);
*(uint16 *)ðframe->src[0] = NS8390_RD_DATA16(ns8390);
*(uint16 *)ðframe->src[2] = NS8390_RD_DATA16(ns8390);
*(uint16 *)ðframe->src[4] = NS8390_RD_DATA16(ns8390);
ethframe->type = NS8390_RD_DATA16(ns8390);
#else
#error
#endif
if (!nif_protocol_exist(nif,ethframe->type))
{
nif->rx_free(pNbuf);
return;
}
pNbuf->length = receive_count - (4 + 6 + 6 + 2);
set_dma_read_at(ns8390, current+18, pNbuf->length);
#if (defined(NS8390_8BIT))
for (index = 0; index < pNbuf->length; ++index)
{
ethframe->data[index] = NS8390_RD_DATA8(ns8390);
}
#elif (defined(NS8390_16BIT))
for (index = 0; index < pNbuf->length; index += 2)
{
*(uint16 *)ðframe->data[index] = NS8390_RD_DATA16(ns8390);
}
#else
#error
#endif
/* Call the appriopriate handler */
nif_protocol_handler(nif, ethframe->type,pNbuf);
/****************************************************************
Higher level protocols must save off the data if they need to
keep it around for processing.
*****************************************************************/
nif->rx_free(pNbuf);
}
/********************************************************************/
int
ns8390_handler (NS8390 *ns8390, NIF *nif)
{
/* This is the Interrupt Service Routine for the NS 8390 */
int isr;
NS8390_WR_CR(ns8390, 0
| NS8390_CR_PAGE0
| NS8390_CR_RD_AB
| NS8390_CR_STA
) ;
/* Verify part has interrupts pending */
isr = NS8390_RD_P0_ISR(ns8390) & 0x00FF;
if (!isr)
{
return FALSE;
}
/* Check the source of interrupts, and handle it */
if (isr & NS8390_ISR_PRX)
{
/* Ack as soon as possible so more RX IRQs recognized */
NS8390_WR_P0_ISR(ns8390, NS8390_ISR_PRX);
ns8390_receive(ns8390, nif);
++nif->f_rx;
}
if (isr & NS8390_ISR_PTX)
{
NS8390_WR_P0_ISR(ns8390, NS8390_ISR_PTX);
++nif->f_tx;
}
if (isr & NS8390_ISR_RXE)
{
printf("NS8390 RXE Receiver Error\n");
/* ns8390_receive(ns8390, nif); */
NS8390_WR_P0_ISR(ns8390, NS8390_ISR_RXE);
}
if (isr & NS8390_ISR_TXE)
{
printf("NS8390 TXE Transmitter Error\n");
NS8390_WR_P0_ISR(ns8390, NS8390_ISR_TXE);
++nif->f_tx_err;
}
if (isr & NS8390_ISR_OVW)
{
printf("NS8390 OVW Buffer Overflow\n");
NS8390_WR_P0_ISR(ns8390, NS8390_ISR_OVW);
++nif->f_rx_err;
}
if (isr & NS8390_ISR_CNT)
{
printf("NS8390 CNT\n");
NS8390_WR_P0_ISR(ns8390, NS8390_ISR_CNT);
}
if (isr & NS8390_ISR_RDC)
{
NS8390_WR_P0_ISR(ns8390, NS8390_ISR_RDC);
}
return TRUE;
}
/********************************************************************/
int
ns8390_init (NIF *nif, void *base, int vector)
{
nif_init(nif, "ns8390");
nif->nic = base;
nif->vector = vector;
read_eth_addr(nif->nic,&nif->hwa[0]);
nif->hwa_size = 6;
nif->mtu = 1500;
nif->reset = ns8390_reset;
nif->start = ns8390_start;
nif->stop = ns8390_stop;
nif->send = ns8390_send;
nif->receive = (void *)&ns8390_receive;
nif->rx_alloc = nbuf_rx_allocate;
nif->tx_alloc = nbuf_tx_allocate;
nif->rx_free = nbuf_rx_release;
nif->tx_free = nbuf_tx_release;
return TRUE;
}
/********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -