📄 etherne.c
字号:
#endif
cp = &configs[dtype & NETNUM_MASK];
ebase = cp->ebase;
if (innic(ISR) & 0x10) /* If Rx overrun.. */
{
printf(" NIC Rx overrun\n");
resetnic(cp, 0); /* ..reset controller (drastic!) */
}
outnic(CMDR, 0x60); /* DMA abort, page 1 */
curr = innic(CURR); /* Get current page */
outnic(CMDR, 0x20); /* DMA abort, page 0 */
if (curr != cp->next_pkt) /* If Rx packet.. */
{
memset(&nichdr, 0xee, sizeof(nichdr)); /* ..get NIC header */
getnic((WORD)(cp->next_pkt<<8), (BYTE *)&nichdr, sizeof(nichdr));
#if STARHACK
hilen = nichdr.next - cp->next_pkt - 1;
lolen = nichdr.len & 0xff;
if (hilen < 0) /* Do len calc from NIC datasheet */
hilen = RXSTOP - cp->next_pkt + nichdr.next - RXSTART - 1;
if (lolen > 0xfc)
hilen++;
len = (hilen<<8) + lolen;
if (len != nichdr.len) /* ..and compare with actual value */
{
if (netdebug)
printf(" NIC length mismatch %Xh - %Xh\n", len, nichdr.len);
}
#else
len = nichdr.len; /* Take length from stored header */
#endif
if ((nichdr.stat&1) && len>=MINFRAMEC && len<=MAXFRAMEC)
{ /* If hdr is OK, get packet */
len -= CRCLEN; /* ..without CRC! */
if (pkt)
getnic((WORD)((cp->next_pkt<<8)+sizeof(nichdr)), pkt, len);
}
else /* If not, no packet data */
{
printf(" NIC packet error\n");
} /* Update next packet ptr */
if (nichdr.next>=RXSTART && nichdr.next<RXSTOP)
cp->next_pkt = nichdr.next;
else /* If invalid, use prev+1 */
{
printf(" NIC pointer error\n");
cp->next_pkt = nicwrap(cp->next_pkt + 1);
} /* Update boundary register */
bnry = nicwrap(cp->next_pkt - 1);
outnic(BNRY, bnry);
}
return(len); /* Return length excl. CRC */
}
/* Send Ethernet packet given len excl. CRC, return 0 if NIC is busy */
WORD put_etherne(WORD dtype, void *pkt, WORD len)
{
CONFIGNE *cp;
cp = &configs[dtype & NETNUM_MASK];
ebase = cp->ebase;
if (!ebase || innic(CMDR) & 4) /* If still Txing, return 0 */
len = 0;
else if (pkt)
{ /* If last Tx is complete.. */
len = minw(MAXFRAME, maxw(MINFRAME, len)); /* Constrain length */
memcpy((BYTE *)pkt+MACLEN, cp->myeth, MACLEN); /* Set source addr */
outnic(ISR, 0x0a); /* Clear interrupt flags */
outnic(TBCR0, len & 0xff); /* Set Tx length regs */
outnic(TBCR1, len >> 8);
putnic(TXSTART<<8, pkt, len);
outnic(CMDR, 0x24); /* Transmit the packet */
}
return(len);
}
/* Reset the Ethernet card, if 'cold' start, get my 6-byte address */
void resetnic(CONFIGNE *cp, char cold)
{
int i;
BYTE temp[MACLEN*2];
outnic(CMDR, 0x21); /* Stop, DMA abort, page 0 */
delay(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 */
if (cold)
{
outnic(CMDR, 0x22); /* Start NIC, DMA abort */
getnic(0, temp, 12); /* Get 6-byte addr */
for (i=0; i<MACLEN; i++) /* Convert addr words to bytes */
cp->myeth[i] = temp[WORDMODE ? i+i : i];
}
outnic(CMDR, 0x61); /* Stop, DMA abort, page 1 */
delay(2);
for (i=0; i<6; i++) /* Set Phys addr */
outnic(PAR0+i, cp->myeth[i]);
for (i=0; i<8; i++) /* Multicast accept-all */
outnic(MAR0+i, 0xff);
outnic(CURR, RXSTART+1); /* Set current Rx page */
cp->next_pkt = RXSTART + 1;
outnic(CMDR, 0x20); /* DMA abort, page 0 */
outnic(RCR, promisc ? 0x14 : 0x04); /* Allow broadcasts, maybe all pkts */
outnic(TCR, 0); /* Normal Tx operation */
outnic(ISR, 0xff); /* Clear interrupt flags */
outnic(CMDR, 0x22); /* Start NIC */
}
/* Get a packet from a given address in the NIC's RAM */
void getnic(WORD addr, BYTE data[], WORD len)
{
register int count;
register WORD *dataw, dataport;
count = WORDMODE ? len>>1 : len; /* Halve byte count if word I/P */
dataport = ebase + DATAPORT; /* Address of NIC data port */
outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */
outnic(RBCR0, len&0xff); /* Byte count */
outnic(RBCR1, len>>8);
outnic(RSAR0, addr&0xff); /* Data addr */
outnic(RSAR1, addr>>8);
outnic(CMDR, 0x0a); /* Start, DMA remote read */
#if WORDMODE
dataw = (WORD *)data; /* Use pointer for speed */
while(count--) /* Get words */
*dataw++ = inpw(dataport);
if (len & 1) /* If odd length, do last byte */
*(BYTE *)dataw = inp(dataport);
#else
while(count--) /* Get bytes */
*data++ = inp(dataport);
#endif
}
/* Put a packet into a given address in the NIC's RAM */
void putnic(WORD addr, BYTE data[], WORD len)
{
register int count;
register WORD *dataw, dataport;
len += len & 1; /* Round length up to an even value */
count = WORDMODE ? len>>1 : len; /* Halve byte count if word O/P */
dataport = ebase + DATAPORT; /* Address of NIC data port */
outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */
outnic(RBCR0, len&0xff); /* Byte count */
outnic(RBCR1, len>>8);
outnic(RSAR0, addr&0xff); /* Data addr */
outnic(RSAR1, addr>>8);
outnic(CMDR, 0x12); /* Start, DMA remote write */
#if WORDMODE /* Word transfer? */
dataw = (WORD *)data;
while(count--)
outpw(dataport, *dataw++); /* O/P words */
#else
while(count--) /* O/P bytes */
outp(dataport, *data++);
#endif
count = 10000; /* Done: must ensure DMA complete */
while(count && (innic(ISR)&0x40)==0)
count--;
}
/* Wrap an NIC Rx page number */
BYTE nicwrap(int 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(int reg)
{
return(inp((WORD)(ebase+reg)));
}
/* Output a byte to a NIC register */
void outnic(int reg, int b)
{
outp((WORD)(ebase+reg), b);
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -