📄 ns8390.c
字号:
static int ns8390_poll(struct nic *nic);#ifndef INCLUDE_3C503/**************************************************************************ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun**************************************************************************/static void eth_rx_overrun(struct nic *nic){ int start_time;#ifdef INCLUDE_WD if (eth_flags & FLAG_790) outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); else#endif outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); /* wait for at least 1.6ms - we wait one timer tick */ start_time = currticks(); while (currticks() - start_time <= 1) /* Nothing */; outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */ outb(0, eth_nic_base+D8390_P0_RBCR1); /* * Linux driver checks for interrupted TX here. This is not necessary, * because the transmit routine waits until the frame is sent. */ /* enter loopback mode and restart NIC */ outb(2, eth_nic_base+D8390_P0_TCR);#ifdef INCLUDE_WD if (eth_flags & FLAG_790) outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); else#endif outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); /* clear the RX ring, acknowledge overrun interrupt */ eth_drain_receiver = 1; while (ns8390_poll(nic)) /* Nothing */; eth_drain_receiver = 0; outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR); /* leave loopback mode - no packets to be resent (see Linux driver) */ outb(0, eth_nic_base+D8390_P0_TCR);}#endif /* INCLUDE_3C503 *//**************************************************************************NS8390_TRANSMIT - Transmit a frame**************************************************************************/static void ns8390_transmit( struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */{#if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO)) Address eth_vmem = bus_to_virt(eth_bmem);#endif#ifdef INCLUDE_3C503 if (!(eth_flags & FLAG_PIO)) { memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */ memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ *((char *)eth_vmem+12) = t>>8; /* type */ *((char *)eth_vmem+13) = t; memcpy((char *)eth_vmem+ETH_HLEN, p, s); s += ETH_HLEN; while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0; }#endif#ifdef INCLUDE_WD if (eth_flags & FLAG_16BIT) { outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR); inb(0x84); }#ifndef WD_790_PIO /* Memory interface */ if (eth_flags & FLAG_790) { outb(WD_MSR_MENB, eth_asic_base + WD_MSR); inb(0x84); } inb(0x84); memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */ memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ *((char *)eth_vmem+12) = t>>8; /* type */ *((char *)eth_vmem+13) = t; memcpy((char *)eth_vmem+ETH_HLEN, p, s); s += ETH_HLEN; while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0; if (eth_flags & FLAG_790) { outb(0, eth_asic_base + WD_MSR); inb(0x84); }#else inb(0x84);#endif#endif#if defined(INCLUDE_3C503) if (eth_flags & FLAG_PIO)#endif#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO)) { /* Programmed I/O */ unsigned short type; type = (t >> 8) | (t << 8); eth_pio_write(d, eth_tx_start<<8, ETH_ALEN); eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN); /* bcc generates worse code without (const+const) below */ eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2); eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s); s += ETH_HLEN; if (s < ETH_ZLEN) s = ETH_ZLEN; }#endif#if defined(INCLUDE_3C503)#endif#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(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); else#endif outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR); outb(s, eth_nic_base+D8390_P0_TBCR0); outb(s>>8, eth_nic_base+D8390_P0_TBCR1);#ifdef INCLUDE_WD if (eth_flags & FLAG_790) 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); }#ifndef WD_790_PIO if (eth_flags & FLAG_790) { outb(WD_MSR_MENB, eth_asic_base + WD_MSR); inb(0x84); }#endif inb(0x84);#endif pktoff = next << 8; if (eth_flags & FLAG_PIO) eth_pio_read(pktoff, (char *)&pkthdr, 4); else memcpy(&pkthdr, bus_to_virt(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, bus_to_virt(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, bus_to_virt(eth_rmem + pktoff), len); ret = 1; }#ifdef INCLUDE_WD#ifndef WD_790_PIO if (eth_flags & FLAG_790) { outb(0, eth_asic_base + WD_MSR); inb(0x84); }#endif 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 dev *dev){ struct nic *nic = (struct nic *)dev; /* reset and disable merge */ ns8390_reset(nic);}/**************************************************************************ETH_PROBE - Look for an adapter**************************************************************************/#ifdef INCLUDE_NS8390static int eth_probe (struct dev *dev, struct pci_device *pci)#elsestatic int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)#endif{ struct nic *nic = (struct nic *)dev; int i;#ifdef INCLUDE_NS8390 unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 }; unsigned short *probe_addrs = pci_probe_addrs;#endif eth_vendor = VENDOR_NONE; eth_drain_receiver = 0;#ifdef INCLUDE_WD{ /****************************************************************** Search for WD/SMC cards ******************************************************************/ struct wd_board *brd; unsigned short chksum; unsigned char c; 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) { /* from Linux driver, 8416BT detects as 8216 sometimes */ unsigned int addr = inb(eth_asic_base + 0xb); if (((addr >> 4) & 3) == 0) { brd += 2; eth_memsize = brd->memsize; } } outb(0x80, eth_asic_base + WD_MSR); /* Reset */ for (i=0; i<ETH_ALEN; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -