📄 ns8390.c
字号:
outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); else#endif outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);}/**************************************************************************NS8390_POLL - Wait for a frame**************************************************************************/static int ns8390_poll(struct nic *nic){ int ret = 0; unsigned char rstat, curr, next; unsigned short len, frag; unsigned short pktoff; unsigned char *p; struct ringbuffer pkthdr;#ifndef INCLUDE_3C503 /* avoid infinite recursion: see eth_rx_overrun() */ if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) { eth_rx_overrun(nic); return(0); }#endif /* INCLUDE_3C503 */ rstat = inb(eth_nic_base+D8390_P0_RSR); if (!(rstat & D8390_RSTAT_PRX)) return(0); next = inb(eth_nic_base+D8390_P0_BOUND)+1; if (next >= eth_memsize) next = eth_rx_start; outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND); curr = inb(eth_nic_base+D8390_P1_CURR); outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND); if (curr >= eth_memsize) curr=eth_rx_start; if (curr == next) return(0);#ifdef INCLUDE_WD if (eth_flags & FLAG_16BIT) { outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR); inb(0x84); } if (eth_flags & FLAG_790) { outb(WD_MSR_MENB, eth_asic_base + WD_MSR); inb(0x84); } inb(0x84);#endif pktoff = next << 8; if (eth_flags & FLAG_PIO) eth_pio_read(pktoff, (char *)&pkthdr, 4); else memcpy(&pkthdr, (char *)eth_rmem + pktoff, 4); pktoff += sizeof(pkthdr); /* incoming length includes FCS so must sub 4 */ len = pkthdr.len - 4; if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN || len > ETH_FRAME_LEN) { printf("Bogus packet, ignoring\n"); return (0); } else { p = nic->packet; nic->packetlen = len; /* available to caller */ frag = (eth_memsize << 8) - pktoff; if (len > frag) { /* We have a wrap-around */ /* read first part */ if (eth_flags & FLAG_PIO) eth_pio_read(pktoff, p, frag); else memcpy(p, (char *)eth_rmem + pktoff, frag); pktoff = eth_rx_start << 8; p += frag; len -= frag; } /* read second part */ if (eth_flags & FLAG_PIO) eth_pio_read(pktoff, p, len); else memcpy(p, (char *)eth_rmem + pktoff, len); ret = 1; }#ifdef INCLUDE_WD if (eth_flags & FLAG_790) { outb(0, eth_asic_base + WD_MSR); inb(0x84); } if (eth_flags & FLAG_16BIT) { outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR); inb(0x84); } inb(0x84);#endif next = pkthdr.next; /* frame number of next packet */ if (next == eth_rx_start) next = eth_memsize; outb(next-1, eth_nic_base+D8390_P0_BOUND); return(ret);}/**************************************************************************NS8390_DISABLE - Turn off adapter**************************************************************************/static void ns8390_disable(struct nic *nic){}/**************************************************************************ETH_PROBE - Look for an adapter**************************************************************************/#ifdef INCLUDE_NS8390struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs, struct pci_device *pci)#elsestruct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs)#endif{ int i; struct wd_board *brd; unsigned short chksum; unsigned char c; eth_vendor = VENDOR_NONE; eth_drain_receiver = 0;#ifdef INCLUDE_WD /****************************************************************** Search for WD/SMC cards ******************************************************************/ for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE; eth_asic_base += 0x20) { chksum = 0; for (i=8; i<16; i++) chksum += inb(eth_asic_base+i); /* Extra checks to avoid soundcard */ if ((chksum & 0xFF) == 0xFF && inb(eth_asic_base+8) != 0xFF && inb(eth_asic_base+9) != 0xFF) break; } if (eth_asic_base > WD_HIGH_BASE) return (0); /* We've found a board */ eth_vendor = VENDOR_WD; eth_nic_base = eth_asic_base + WD_NIC_ADDR; c = inb(eth_asic_base+WD_BID); /* Get board id */ for (brd = wd_boards; brd->name; brd++) if (brd->id == c) break; if (!brd->name) { printf("Unknown WD/SMC NIC type %hhX\n", c); return (0); /* Unknown type */ } eth_flags = brd->flags; eth_memsize = brd->memsize; eth_tx_start = 0; eth_rx_start = D8390_TXBUF_SIZE; if ((c == TYPE_WD8013EP) && (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) { eth_flags = FLAG_16BIT; eth_memsize = MEM_16384; } if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) { eth_bmem = (0x80000 | ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13)); } else eth_bmem = WD_DEFAULT_MEM; if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { *((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0; if (*((unsigned int *)(eth_bmem + 8192))) { brd += 2; eth_memsize = brd->memsize; } } outb(0x80, eth_asic_base + WD_MSR); /* Reset */ for (i=0; i<ETH_ALEN; i++) { nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR); } printf("\n%s base %#hx, memory %#hx, addr %!\n", brd->name, eth_asic_base, eth_bmem, nic->node_addr); if (eth_flags & FLAG_790) { outb(WD_MSR_MENB, eth_asic_base+WD_MSR); outb((inb(eth_asic_base+0x04) | 0x80), eth_asic_base+0x04); outb((((unsigned)eth_bmem >> 13) & 0x0F) | (((unsigned)eth_bmem >> 11) & 0x40) | (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B); outb((inb(eth_asic_base+0x04) & ~0x80), eth_asic_base+0x04); } else { outb((((unsigned)eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR); } if (eth_flags & FLAG_16BIT) { if (eth_flags & FLAG_790) { eth_laar = inb(eth_asic_base + WD_LAAR); outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR); } else { outb((eth_laar = WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);/* The previous line used to be WD_LAAR_M16EN | WD_LAAR_L16EN | 1)); jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made it work for WD8013s. This seems to work for my 8013 boards. I don't know what is really happening. I wish I had data sheets or more time to decode the Linux driver. - Ken*/ } inb(0x84); }#endif#ifdef INCLUDE_3C503 /****************************************************************** Search for 3Com 3c503 if no WD/SMC cards ******************************************************************/ if (eth_vendor == VENDOR_NONE) { int idx; int iobase_reg, membase_reg; static unsigned short base[] = { 0x300, 0x310, 0x330, 0x350, 0x250, 0x280, 0x2A0, 0x2E0, 0 }; /* Loop through possible addresses checking each one */ for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) { eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;/* * Note that we use the same settings for both 8 and 16 bit cards: * both have an 8K bank of memory at page 1 while only the 16 bit * cards have a bank at page 0. */ eth_memsize = MEM_16384; eth_tx_start = 32; eth_rx_start = 32 + D8390_TXBUF_SIZE; /* Check our base address. iobase and membase should */ /* both have a maximum of 1 bit set or be 0. */ iobase_reg = inb(eth_asic_base + _3COM_BCFR); membase_reg = inb(eth_asic_base + _3COM_PCFR); if ((iobase_reg & (iobase_reg - 1)) || (membase_reg & (membase_reg - 1))) continue; /* nope */ /* Now get the shared memory address */ eth_flags = 0; switch (membase_reg) { case _3COM_PCFR_DC000: eth_bmem = 0xdc000; break; case _3COM_PCFR_D8000: eth_bmem = 0xd8000; break; case _3COM_PCFR_CC000: eth_bmem = 0xcc000; break; case _3COM_PCFR_C8000: eth_bmem = 0xc8000; break; case _3COM_PCFR_PIO: eth_flags |= FLAG_PIO; eth_bmem = 0; break; default: continue; /* nope */ } break; } if (base[idx] == 0) /* not found */ return (0);#ifndef T503_SHMEM eth_flags |= FLAG_PIO; /* force PIO mode */ eth_bmem = 0;#endif eth_vendor = VENDOR_3COM; /* Need this to make ns8390_poll() happy. */ eth_rmem = eth_bmem - 0x2000; /* Reset NIC and ASIC */ outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR ); outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR ); /* Get our ethernet address */ outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR); printf("\n3Com 3c503 base %#hx, ", eth_nic_base); if (eth_flags & FLAG_PIO) printf("PIO mode"); else printf("memory %#hx", eth_bmem); for (i=0; i<ETH_ALEN; i++) { nic->node_addr[i] = inb(eth_nic_base+i); } printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr", nic->node_addr); outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR); /* * Initialize GA configuration register. Set bank and enable shared * mem. We always use bank 1. Disable interrupts. */ outb(_3COM_GACFR_RSEL | _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR); outb(0xff, eth_asic_base + _3COM_VPTR2); outb(0xff, eth_asic_base + _3COM_VPTR1); outb(0x00, eth_asic_base + _3COM_VPTR0); /* * Clear memory and verify that it worked (we use only 8K) */ if (!(eth_flags & FLAG_PIO)) { memset((char *)eth_bmem, 0, 0x2000); for(i = 0; i < 0x2000; ++i) if (*(((char *)eth_bmem)+i)) { printf ("Failed to clear 3c503 shared mem.\n"); return (0); } } /* * Initialize GA page/start/stop registers. */ outb(eth_tx_start, eth_asic_base + _3COM_PSTR); outb(eth_memsize, eth_asic_base + _3COM_PSPR); }#endif#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) /****************************************************************** Search for NE1000/2000 if no WD/SMC or 3com cards ******************************************************************/ if (eth_vendor == VENDOR_NONE) { char romdata[16], testbuf[32]; int idx; static char test[] = "NE*000 memory"; static unsigned short base[] = {#ifdef NE_SCAN NE_SCAN,#endif 0 }; /* if no addresses supplied, fall back on defaults */ if (probe_addrs == 0 || probe_addrs[0] == 0) probe_addrs = base; eth_bmem = 0; /* No shared memory */ for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) { eth_flags = FLAG_PIO; eth_asic_base = eth_nic_base + NE_ASIC_OFFSET; eth_memsize = MEM_16384; eth_tx_start = 32; eth_rx_start = 32 + D8390_TXBUF_SIZE; c = inb(eth_asic_base + NE_RESET); outb(c, eth_asic_base + NE_RESET); inb(0x84); outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND); outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR); outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); outb(MEM_8192, eth_nic_base + D8390_P0_PSTART); outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);#ifdef NS8390_FORCE_16BIT eth_flags |= FLAG_16BIT; /* force 16-bit mode */#endif eth_pio_write(test, 8192, sizeof(test)); eth_pio_read(8192, testbuf, sizeof(test)); if (!memcmp(test, testbuf, sizeof(test))) break; eth_flags |= FLAG_16BIT; eth_memsize = MEM_32768; eth_tx_start = 64; eth_rx_start = 64 + D8390_TXBUF_SIZE; outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); outb(MEM_16384, eth_nic_base + D8390_P0_PSTART); outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP); eth_pio_write(test, 16384, sizeof(test)); eth_pio_read(16384, testbuf, sizeof(test)); if (!memcmp(testbuf, test, sizeof(test))) break; } if (eth_nic_base == 0) return (0); if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */ eth_flags |= FLAG_16BIT; eth_vendor = VENDOR_NOVELL; eth_pio_read(0, romdata, sizeof(romdata)); for (i=0; i<ETH_ALEN; i++) { nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)]; } printf("\nNE%c000 base %#hx, addr %!\n", (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, nic->node_addr); }#endif if (eth_vendor == VENDOR_NONE) return(0); if (eth_vendor != VENDOR_3COM) eth_rmem = eth_bmem; ns8390_reset(nic); nic->reset = ns8390_reset; nic->poll = ns8390_poll; nic->transmit = ns8390_transmit; nic->disable = ns8390_disable; return(nic);}/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -