📄 ne2000.c
字号:
#if EI_DEBUG > 0
printf("\n");
#endif
neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
dlink = (SA_prom[0] == 0x00 && SA_prom[1] == 0xDE && SA_prom[2] == 0x01);
dfi = (SA_prom[0] == 'D' && SA_prom[1] == 'F' && SA_prom[2] == 'I');
#if EI_DEBUG > 0
if ( neX000 )
printf("neX000");
#endif
/* Set up the rest of the parameters. */
if (neX000 || dlink || dfi) {
if (wordlength == 2) {
name = dlink ? "DE200" : "NE2000";
start_page = NESM_START_PG;
stop_page = NESM_STOP_PG;
} else {
name = dlink ? "DE100" : "NE1000";
start_page = NE1SM_START_PG;
stop_page = NE1SM_STOP_PG;
}
} else if (ctron) {
name = "Cabletron";
start_page = 0x01;
stop_page = (wordlength == 2) ? 0x40 : 0x20;
} else {
printf(" not found.\n");
return 0;
}
dev->base_addr = ioaddr;
dev->name = name;
#if EI_DEBUG > 0
printf(" %s: %s found at %x, using IRQ %x.\n",
dev->name, name, ioaddr, dev->irq);
#endif
ei_status.name = name;
ei_status.tx_start_page = start_page;
ei_status.stop_page = stop_page;
ei_status.word16 = (wordlength == 2);
ei_status.rx_start_page = start_page + TX_PAGES;
#ifdef PACKETBUF_MEMSIZE
/* Allow the packet buffer size to be overridden by know-it-alls. */
ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
#endif
NS8390_init(dev, 1);
return dev->base_addr;
}
#if 0 /* not used now */
/*
* void ne_reset_8390(struct device *dev)
*
* Resets the board associated with DEV, including a hardware
* reset of the 8390. This would only be called when there is a
* transmit timeout, which is currently not implemented.
*/
void ne_reset_8390(struct device *dev)
{
int tmp = INPB(dev->base_addr + NE_RESET);
#if EI_DEBUG > 1
printf("resetting the 8390 ...\n");
#endif
ei_status.txing = 0;
OUTB(dev->base_addr + NE_RESET, tmp);
/* This check _should_not_ be necessary, omit eventually. */
while ((INPB(dev->base_addr+EN0_ISR) & ENISR_RESET) == 0) ;
}
#endif /* 0 */
/*
* int
* block_input(struct device *dev, int count, char *buf, int ring_offset)
*
* Read COUNT bytes from the packet buffer into BUF. Start
* reading from RING_OFFSET, the address as the 8390 sees it.
* The first read will always be the 4 byte, page aligned 8390
* header. *If* there is a subsequent read, it will be of the
* rest of the packet.
*/
int
ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int xfer_count = count;
int nic_base = dev->base_addr;
ENTRY("ne_block_input");
if (ei_status.dmaing) {
#if EI_DEBUG > 0
printf("%s: DMAing conflict in ne_block_input."
"[DMAstat:%1x][irqlock:%1x]\n",
dev->name, ei_status.dmaing, ei_status.irqlock);
#endif
EXIT("ne_block_input");
return 0;
}
ei_status.dmaing |= 0x01;
OUTB(nic_base + NE_CMD, E8390_NODMA+E8390_PAGE0+E8390_START);
OUTB(nic_base + EN0_RCNTLO, count & 0xff);
OUTB(nic_base + EN0_RCNTHI, count >> 8);
OUTB(nic_base + EN0_RSARLO, ring_offset & 0xff);
OUTB(nic_base + EN0_RSARHI, ring_offset >> 8);
OUTB(nic_base + NE_CMD, E8390_RREAD+E8390_START);
if (ei_status.word16) {
_insw(nic_base + NE_DATAPORT, (short *)buf, count>>1);
if (count & 0x01)
buf[count-1] = INPB(nic_base + NE_DATAPORT), xfer_count++;
} else {
_insb(nic_base + NE_DATAPORT, buf, count);
}
/* This was for the ALPHA version only, but enough people have
encountering problems that it is still here. If you see
this message you either 1) have an slightly imcompatible clone
or 2) have noise/speed problems with your bus. */
#if EI_DEBUG > 1
{ /* DMA termination address check... */
int addr, tries = 20;
do {
/* Check the DMA address. */
int high = INPB(nic_base + EN0_RSARHI);
int low = INPB(nic_base + EN0_RSARLO);
addr = (high << 8) + low;
if (((ring_offset + xfer_count) & 0xff) == low)
break;
} while (--tries > 0);
if (tries <= 0)
printf("%s: RX transfer address mismatch,"
"%x (expected) vs. %x (actual).\n",
dev->name, ring_offset + xfer_count, addr);
}
#endif
ei_status.dmaing &= ~0x01;
EXIT("ne_block_input");
return ring_offset + count;
}
/*
* void
* ne_block_output(struct device *dev, int count, char *buf, int start_offset)
*
* Write COUNT bytes of BUF to the packet buffer at START_OFFSET.
*/
void
ne_block_output(struct device *dev, int count, char *buf, int start_offset)
{
#if EI_DEBUG > 1
int retries = 0;
#endif
int nic_base = dev->base_addr;
ENTRY("ne_block_output");
#if EI_DEBUG > 1
printf("ne_block_output(%x,%x,%x,%x)\n", dev, count, buf, start_offset);
printf(" base_addr=%x\n", dev->base_addr);
dump(buf, count);
#endif
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
if (ei_status.word16 && (count & 0x01))
count++;
if (ei_status.dmaing) {
#if EI_DEBUG > 0
printf("%s: DMAing conflict in ne_block_output."
"[DMAstat:%1x][irqlock:%1x]\n",
dev->name, ei_status.dmaing, ei_status.irqlock);
#endif
EXIT("ne_block_output");
return;
}
ei_status.dmaing |= 0x02;
/* We should already be in page 0, but to be safe... */
OUTB(nic_base + NE_CMD, E8390_PAGE0+E8390_START+E8390_NODMA);
retry:
#define NE8390_RW_BUGFIX
#ifdef NE8390_RW_BUGFIX
/*
Dummy read-before-write bug fix from Linux ne.c driver.
This appears to prevent crashes on some fast machines.
*/
OUTB(nic_base + EN0_RCNTLO, count & 0xff);
OUTB(nic_base + EN0_RCNTHI, count >> 8);
OUTB(nic_base + EN0_RSARLO, start_offset & 0xff);
OUTB(nic_base + EN0_RSARHI, start_offset >> 8);
OUTB(nic_base + NE_CMD, E8390_RREAD+E8390_START);
/* make sure the dummy read has enough time to complete */
INPB(nic_base + NE_CMD);
#endif
OUTB(nic_base + EN0_RCNTLO, count & 0xff);
OUTB(nic_base + EN0_RCNTHI, count >> 8);
OUTB(nic_base + EN0_RSARLO, start_offset & 0xff);
OUTB(nic_base + EN0_RSARHI, start_offset >> 8);
#if EI_DEBUG > 1 /* debug */
printf("block_output: reading back EN0_RSARs: %x %x\n",
INPB(nic_base + EN0_RSARHI),
INPB(nic_base + EN0_RSARLO));
#endif
OUTB(nic_base + NE_CMD, E8390_RWRITE+E8390_START);
if (ei_status.word16)
_outsw(nic_base + NE_DATAPORT, (short *) buf, count>>1);
else
_outsb(nic_base + NE_DATAPORT, buf, count);
#if EI_DEBUG > 1
{ /* DMA termination address check... */
int addr, tries = 20;
do {
/* Check the DMA address. */
int high = INPB(nic_base + EN0_RSARHI);
int low = INPB(nic_base + EN0_RSARLO);
addr = (high << 8) + low;
if (((start_offset + count) & 0xff) == low)
break;
} while (--tries > 0);
if (tries <= 0) {
printf("%s: Tx packet transfer address mismatch,"
"%x (expected) vs. %x (actual).\n",
dev->name, start_offset + count, addr);
if (retries++ == 0)
goto retry;
}
}
#endif
ei_status.dmaing &= ~0x02;
EXIT("ne_block_output");
}
#if 0
/*
* NOTE: These two functions, OUTB() and INPB() are required
* to guarantee adequate timing of ISA bus I/O to the
* ne2000. Due to the argument passing and the call/ret
* instructions required to get into and exit from these
* functions, sufficient delays are introduced.
*
* If these are replaced with the intrinsics OUTB() and
* INPB() throughout the code, then there may not be sufficient
* time between two back-to-back I/O instructions for the second
* I/O to work.
* If you suspect a problem, use these functions
*/
void
outb(int port, int data)
{
_outb(port, data);
}
int
inb(int port)
{
return(_inb(port));
}
#endif
#ifdef NEDEBUG
/*
* Support for debugging macros ENTRY(), EXIT(), etc.
*/
static indent = 0;
#define INDENT_AMT 1
void
nedebug_entry(char *name)
{
int i;
for (i = indent; i-- > 0; printf(" ")) ;
printf("%s\n", name);
indent += INDENT_AMT;
}
void
nedebug_exit(char *name)
{
int i;
if ((indent -= INDENT_AMT) < 0)
indent = 0;
for (i = indent; i-- > 0; printf(" ")) ;
printf("%s }\n", name);
}
void
nedebug_exit2(char *name, int rv)
{
int i;
if ((indent -= INDENT_AMT) < 0)
indent = 0;
for (i = indent; i-- > 0; printf(" ")) ;
printf("%s 0x%x}\n", name, rv);
}
#endif /* NEDEBUG */
#if EI_DEBUG > 0
/*
* DEBUG support routines
*/
void
dump(char *d, int size)
{
int x = 0;
if (!size)
return;
while(size--) {
if ((x % 16) == 0)
printf("\n%08.8x: ", d);
printf("%02.2x ",*((unsigned char *)d));
d++;
x++;
}
printf("\n");
}
#endif /* NEDEBUG */
#if RWS /* debug */
#define IOLOGSZ 128
short ne2000_iolog[ IOLOGSZ + 4 ];
#define IOLOGIDX ne2000_iolog[IOLOGSZ+1]
#define COUNTDOWN ne2000_iolog[IOLOGSZ+2]
void
outb_log(int port, int data)
{
ne2000_iolog[ IOLOGIDX ] = ((port & 0xf) << 8) | (data & 0xFF);
if (++IOLOGIDX >= IOLOGSZ) IOLOGIDX = 0;
ne2000_iolog[ IOLOGIDX ] = 0xFFFF;
_outb(port, data);
}
int
inb_log(int port)
{
int data = _inb(port);
ne2000_iolog[ IOLOGIDX ] = 0x8000 | ((port & 0xf) << 8) | (data & 0xFF);
if (++IOLOGIDX >= IOLOGSZ) IOLOGIDX = 0;
ne2000_iolog[ IOLOGIDX ] = 0xFFFF;
return data;
}
void
dumpiolog()
{
int i, cnt = 0;
short s;
printf("\nINPB/OUTB LOG:\n");
i = IOLOGIDX + 1;
do {
s = ne2000_iolog[ i ];
printf("%s %x %02x ",
(s & 0x8000)? "IN: ": "OUT: ",
(s >> 8) & 0xF,
s & 0xFF);
if (++cnt % 4 == 0)
printf("\n");
if (++i >= IOLOGSZ)
i = 0;
} while (i != IOLOGIDX);
printf("\n");
}
#define CRMASK 0x3B /* cmd reg: RD2|RD1|RD0|STA|STP */
/*
* Save the state of the 8390 (read) registers.
*/
void
savestate(int cmdreg, unsigned char *buf)
{
/* NOTE: don't change _inb/_outb to INPB/OUTB! */
int cr;
int i = 0;
cr = _inb(cmdreg); /* save command reg */
/* PAGE 0 */
buf[i++] = (unsigned char)cr;
_outb(cmdreg, ((cr & CRMASK) | E8390_PAGE0));
do
buf[i] = (unsigned char) _inb(cmdreg + i);
while (++i < 16);
/* PAGE 1 */
buf[i++] = (unsigned char)cr;
_outb(cmdreg, ((cr & CRMASK) | E8390_PAGE1));
do
buf[i] = (unsigned char) _inb(cmdreg + (i % 16));
while (++i < 32);
/* PAGE 2 */
buf[i++] = (unsigned char)cr;
_outb(cmdreg, ((cr & CRMASK) | E8390_PAGE2));
do
buf[i] = (unsigned char) _inb(cmdreg + (i % 16));
while (++i < 48);
_outb(cmdreg, (cr & ~E8390_TRANS)); /* restore all but TXP */
}
void
dumpstate(unsigned char *buf)
{
int i;
printf("\n8390 REGISTERS:\n ");
for (i = 0; i < 16; i++)
printf(" %02x", i);
for (i = 0; i < 48; i++) {
if ((i % 16) == 0)
printf("\n%d - ", i / 16);
printf(" %02x", buf[i]);
}
printf("\n");
}
#endif /* RWS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -