📄 p16_eth.c
字号:
}
/* Copy data from Rx to Tx buffers, return actual byte count */
WORD copy_rx_tx(WORD maxlen)
{
BYTE n, done=0;
WORD count=0;
save_txbuff();
while (load_rxbuff(0, RXBUFFLEN) || rxbuffin>0)
{
n = rxbuffin;
if (count+n >= maxlen)
{
done = 1;
n = (BYTE)(maxlen - count);
}
for (rxbuffout=0; rxbuffout<n; rxbuffout++)
put_byte(rxbuff[rxbuffout]);
rxout += n;
count += n;
if (done)
break;
}
net_txlen = MAX(txin, net_txlen);
return(count);
}
/* Initialise NIC, return 0 if error */
BOOL init_net(void)
{
BYTE i;
reset_ether();
delay_ms(2);
NIC_RESET = 0;
delay_ms(2);
outnic(NE_RESET, innic(NE_RESET)); /* Do reset */
delay_ms(2);
if ((innic(ISR) & 0x80) == 0) /* Report if failed */
{
put_ser("\nNIC init err ");
return(0);
}
outnic(CMDR, 0x21); /* Stop, DMA abort, page 0 */
delay_ms(2); /* ..wait to take effect */
outnic(DCR, DCRVAL);
outnic(RBCR0, 0); /* Clear remote byte count */
outnic(RBCR1, 0);
outnic(RCR, 0x20); /* Rx monitor mode */
outnic(TCR, 0x02); /* Tx internal loopback */
outnic(TPSR, TXSTART); /* Set Tx start page */
outnic(PSTART, RXSTART); /* Set Rx start, stop, boundary */
outnic(PSTOP, RXSTOP);
outnic(BNRY, (BYTE)(RXSTOP-1));
outnic(ISR, 0xff); /* Clear interrupt flags */
outnic(IMR, 0); /* Mask all interrupts */
outnic(CMDR, 0x61); /* Stop, DMA abort, page 1 */
delay_ms(2);
for (i=0; i<6; i++) /* Set Phys addr */
outnic(PAR0+i, myeth[i]);
for (i=0; i<8; i++) /* Multicast accept-all */
outnic(MAR0+i, 0xff);
outnic(CURRP, RXSTART+1); /* Set current Rx page */
next_page = RXSTART + 1;
// Set LED 0 to be a 'link' LED, not 'collision' LED
// It would be nice if the following code worked, but the upper bits of the
// RTL config3 register are obstinately read-only, so it doesn't!
// outnic(CMDR, 0xe0); /* DMA abort, page 3 */
// outnic(RTL9346CR, 0xc0); /* Write-enable config regs */
// outnic(RTL3, 0x10); /* Enable 'link' LED */
// outnic(RTL9346CR, 0x00); /* Write-protect config regs */
outnic(CMDR, 0x20); /* DMA abort, page 0 */
#if PROMISC
outnic(RCR, 0x14); /* Accept broadcasts and all packets!*/
#else
outnic(RCR, 0x04); /* Accept broadcasts */
#endif
outnic(TCR, 0); /* Normal Tx operation */
outnic(ISR, 0xff); /* Clear interrupt flags */
outnic(CMDR, 0x22); /* Start NIC */
return(1);
}
/* Set up the I/O ports, reset the NIC */
void reset_ether(void)
{
DATA_FROM_NIC;
NIC_ADDR = 0;
port_b_pullups(TRUE);
set_tris_b(TRISB_VAL);
NIC_IOW_ = NIC_IOR_ = 1;
NIC_RESET = 1;
set_tris_e(ALL_OUT);
}
/* Get packet into buffer, return 0 if none available */
BOOL get_net(void)
{
WORD curr;
BYTE bound;
net_rxin = 0;
if (innic(ISR) & 0x10) /* If Rx overrun.. */
{
put_ser(" NIC Rx overrun ");
init_net(); /* ..reset controller (drastic!) */
}
outnic(CMDR, 0x60); /* DMA abort, page 1 */
curr = innic(CURRP); /* Get current page */
outnic(CMDR, 0x20); /* DMA abort, page 0 */
if (curr != next_page) /* If Rx packet.. */
{
curr_rx_page = next_page;
curr_rx_addr = (WORD)next_page << 8;
init_rxbuff();
getnic_rxbuff(sizeof(host));
get_data((BYTE *)&host, sizeof(host));
curr_rx_addr += sizeof(host);
init_rxbuff();
net_rxin = host.nic.len; /* Take length from stored header */
if ((host.nic.stat&1) && net_rxin>=MINFRAMEC && net_rxin<=MAXFRAMEC)
{ /* If hdr is OK, get packet */
net_rxin -= ETHERHDR_LEN + CRCLEN;
host.eth.pcol = swapw(host.eth.pcol);
#if DEBUG
print_serial = TRUE; /* Diagnostic printout of pkt size */
print_net = print_lcd = FALSE;
put_ser(" Rx"); /* Include 14-byte MAC hdr in size */
disp_decword(net_rxin + ETHERHDR_LEN);
serial_putch('>');
#endif
}
else /* If not, no packet data */
{
net_rxin = 0;
put_ser(" NIC pkt err ");
} /* Update next packet ptr */
if (host.nic.next>=RXSTART && host.nic.next<RXSTOP)
next_page = host.nic.next;
else /* If invalid, use prev+1 */
{
net_rxin = 0;
put_ser(" NIC ptr err ");
next_page = nicwrap(next_page + 1);
} /* Update boundary register */
bound = nicwrap(next_page - 1);
outnic(BNRY, bound);
}
return(net_rxin != 0);
}
/* Transmit the Ethernet frame */
void transmit(void)
{
WORD dlen;
#if DROP_TX
static BYTE dropcount=0;
#endif
dlen = net_txlen;
save_txbuff();
setnic_tx(-ETHERHDR_LEN);
txbuffin = 0;
put_data(host.eth.srce, MACLEN); /* Destination addr */
put_data(myeth, MACLEN); /* Source addr */
put_byte((BYTE)(host.eth.pcol>>8)); /* Protocol */
put_byte((BYTE)host.eth.pcol);
dlen += ETHERHDR_LEN; /* Bump up length for MAC header */
putnic_txbuff();
if (dlen < MINFRAME)
dlen = MINFRAME; /* Constrain length */
#if NET_TXBUFFERS > 1
txbuff_lens[txbuffnum] = dlen;
outnic(TPSR, txbuffnum ? (TXSTART+TXPAGES) : TXSTART);
#endif
outnic(TBCR0, (BYTE)dlen); /* Set Tx length regs */
outnic(TBCR1, (BYTE)(dlen >> 8));
#if DROP_TX
if (++dropcount == DROP_TX)
{
dropcount = 0;
return;
}
#endif
outnic(CMDR, 0x24); /* Transmit the packet */
}
#if NET_TXBUFFERS > 1
/* Retransmit the Ethernet frame */
void retransmit(BYTE buffnum)
{
WORD dlen;
outnic(TPSR, buffnum ? (TXSTART+TXPAGES) : TXSTART);
dlen = txbuff_lens[buffnum];
outnic(TBCR0, (BYTE)dlen); /* Set Tx length regs */
outnic(TBCR1, (BYTE)(dlen >> 8));
outnic(CMDR, 0x24); /* Transmit the packet */
}
#endif
/* Set the 'remote DMA' address in the NIC's RAM to be accessed */
void setnic_addr(WORD addr)
{
outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */
outnic(RSAR0, addr&0xff); /* Data addr */
outnic(RSAR1, addr>>8);
}
/* Set the 'remote DMA' address in the NIC Tx packet buffer */
void setnic_tx(WORD addr)
{ /* Add on Tx buffer offset */
addr += (TXSTART << 8) + ETHERHDR_LEN;
#if NET_TXBUFFERS > 1
if (txbuffnum) /* ..additional offset if 2nd buffer */
addr += (TXPAGES << 8);
#endif
outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */
outnic(RSAR0, (BYTE)addr); /* Remote DMA addr */
outnic(RSAR1, (BYTE)(addr>>8));
nic_tx_transfer = 1;
}
/* Set the 'remote DMA' address in the current NIC Rx packet buffer */
void setnic_rx(WORD addr)
{
addr += curr_rx_addr;
if (addr >= RXSTOP*256)
addr += (RXSTART - RXSTOP)*256;
outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */
outnic(RSAR0, (BYTE)addr); /* Data addr */
outnic(RSAR1, (BYTE)(addr>>8));
nic_tx_transfer = 0;
}
/* Get data from NIC's RAM into the Rx buffer */
void getnic_rxbuff(BYTE len)
{
if (len == 0)
return;
outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */
outnic(RBCR0, len); /* Byte count */
outnic(RBCR1, 0);
outnic(CMDR, 0x0a); /* Start, DMA remote read */
NIC_ADDR = DATAPORT;
DATA_FROM_NIC;
while (len--) /* Get bytes */
{
NIC_IOR_ = 0;
rxbuff[rxbuffin++] = NIC_DATA;
NIC_IOR_ = 1;
}
}
/* Put the given data into the NIC's RAM from the Tx buffer */
void putnic_txbuff(void)
{
BYTE n=0, len;
if ((len = txbuffin) == 0)
return;
len += len & 1; /* Round length up to an even value */
outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */
outnic(RBCR0, len); /* Byte count */
outnic(RBCR1, 0);
outnic(CMDR, 0x12); /* Start, DMA remote write */
NIC_ADDR = DATAPORT;
DATA_TO_NIC;
while (len--) /* O/P bytes */
{
NIC_DATA = txbuff[n++];
NIC_IOW_ = 0;
DELAY_ONE_CYCLE;
NIC_IOW_ = 1;
}
DATA_FROM_NIC;
len = 255; /* Done: must ensure DMA complete */
while (len && (innic(ISR)&0x40)==0)
len--;
}
/* Wrap an NIC Rx page number */
BYTE nicwrap(BYTE page)
{
if (page >= RXSTOP)
page += RXSTART - RXSTOP;
else if (page < RXSTART)
page += RXSTOP - RXSTART;
return(page);
}
/* Input a byte from a NIC register */
BYTE innic(BYTE reg)
{
BYTE b;
DATA_FROM_NIC;
NIC_ADDR = reg;
NIC_IOR_ = 0;
b = NIC_DATA;
NIC_IOR_ = 1;
return(b);
}
/* Output a byte to a NIC register */
void outnic(BYTE reg, BYTE b)
{
NIC_ADDR = reg;
NIC_DATA = b;
DATA_TO_NIC;
NIC_IOW_ = 0;
DELAY_ONE_CYCLE;
NIC_IOW_ = 1;
DATA_FROM_NIC;
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -