📄 lance.c
字号:
(void)inw(ioaddr+LANCE_ADDR); outw(0x4, ioaddr+LANCE_DATA); /* stop */ outw(0x1, ioaddr+LANCE_DATA); /* init */ for (i = 10000; i > 0; --i) if (inw(ioaddr+LANCE_DATA) & 0x100) break;#ifdef DEBUG if (i <= 0) printf("Init timed out\n");#endif /* Apparently clearing the InitDone bit here triggers a bug in the '974. (Mark Stockton) */ outw(0x2, ioaddr+LANCE_DATA); /* start */}/**************************************************************************POLL - Wait for a frame***************************************************************************/static int lance_poll(struct nic *nic){ int status; status = lp->rx_ring[lp->rx_idx].u.base >> 24; if (status & 0x80) return (0);#ifdef DEBUG printf("LANCE packet received rx_ring.u.base %X mcnt %hX csr0 %hX\n", lp->rx_ring[lp->rx_idx].u.base, lp->rx_ring[lp->rx_idx].msg_length, inw(ioaddr+LANCE_DATA));#endif if (status == 0x3) memcpy(nic->packet, lp->rbuf[lp->rx_idx], nic->packetlen = lp->rx_ring[lp->rx_idx].msg_length); /* Andrew Boyd of QNX reports that some revs of the 79C765 clear the buffer length */ lp->rx_ring[lp->rx_idx].buf_length = -ETH_FRAME_LEN-4; lp->rx_ring[lp->rx_idx].u.addr[3] |= 0x80; /* prime for next receive */ /* I'm not sure if the following is still ok with multiple Rx buffers, but it works */ outw(0x0, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); outw(0x500, ioaddr+LANCE_DATA); /* clear receive + InitDone */ /* Switch to the next Rx ring buffer */ lp->rx_idx = (lp->rx_idx + 1) & RX_RING_MOD_MASK; return (status == 0x3);}/**************************************************************************TRANSMIT - Transmit a frame***************************************************************************/static void lance_transmit( struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */{ unsigned long time; /* copy the packet to ring buffer */ memcpy(lp->tbuf, d, ETH_ALEN); /* dst */ memcpy(&lp->tbuf[ETH_ALEN], nic->node_addr, ETH_ALEN); /* src */ lp->tbuf[ETH_ALEN+ETH_ALEN] = t >> 8; /* type */ lp->tbuf[ETH_ALEN+ETH_ALEN+1] = t; /* type */ memcpy(&lp->tbuf[ETH_HLEN], p, s); s += ETH_HLEN; if (chip_table[chip_version].flags & LANCE_MUST_PAD) while (s < ETH_ZLEN) /* pad to min length */ lp->tbuf[s++] = 0; lp->tx_ring.buf_length = -s; lp->tx_ring.misc = 0x0; /* OWN, STP, ENP */ lp->tx_ring.u.base = virt_to_bus(lp->tbuf) & 0xffffff; /* we set the top byte as the very last thing */ lp->tx_ring.u.addr[3] = 0x83; /* Trigger an immediate send poll */ outw(0x0, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); /* as in the datasheets... */ /* Klaus Espenlaub: the value below was 0x48, but that enabled the * interrupt line, causing a hang if for some reasone the interrupt * controller had the LANCE interrupt enabled. I have no idea why * nobody ran into this before... */ outw(0x08, ioaddr+LANCE_DATA); /* wait for transmit complete */ time = currticks() + TICKS_PER_SEC; /* wait one second */ while (currticks() < time && (lp->tx_ring.u.base & 0x80000000) != 0) ; if ((lp->tx_ring.u.base & 0x80000000) != 0) printf("LANCE timed out on transmit\n"); (void)inw(ioaddr+LANCE_ADDR); outw(0x200, ioaddr+LANCE_DATA); /* clear transmit + InitDone */#ifdef DEBUG printf("tx_ring.u.base %X tx_ring.buf_length %hX tx_ring.misc %hX csr0 %hX\n", lp->tx_ring.u.base, lp->tx_ring.buf_length, lp->tx_ring.misc, inw(ioaddr+LANCE_DATA));#endif}static void lance_disable(struct nic *nic){ (void)inw(ioaddr+LANCE_RESET); if (chip_table[lance_version].flags & LANCE_MUST_UNRESET) outw(0, ioaddr+LANCE_RESET); outw(0, ioaddr+LANCE_ADDR); outw(0x0004, ioaddr+LANCE_DATA); /* stop the LANCE */#ifndef INCLUDE_LANCE disable_dma(dma);#endif}#ifdef INCLUDE_LANCEstatic int lance_probe1(struct nic *nic, struct pci_device *pci)#elsestatic int lance_probe1(struct nic *nic)#endif{ int reset_val ; unsigned int i; Address l; short dma_channels;#ifndef INCLUDE_LANCE static const char dmas[] = { 5, 6, 7, 3 };#endif reset_val = inw(ioaddr+LANCE_RESET); outw(reset_val, ioaddr+LANCE_RESET);#if 1 /* Klaus Espenlaub -- was #ifdef INCLUDE_NE2100*/ outw(0x0, ioaddr+LANCE_ADDR); /* Switch to window 0 */ if (inw(ioaddr+LANCE_DATA) != 0x4) return (-1);#endif outw(88, ioaddr+LANCE_ADDR); /* Get the version of the chip */ if (inw(ioaddr+LANCE_ADDR) != 88) lance_version = 0; else { chip_version = inw(ioaddr+LANCE_DATA); outw(89, ioaddr+LANCE_ADDR); chip_version |= inw(ioaddr+LANCE_DATA) << 16; if ((chip_version & 0xfff) != 0x3) return (-1); chip_version = (chip_version >> 12) & 0xffff; for (lance_version = 1; chip_table[lance_version].id_number != 0; ++lance_version) if (chip_table[lance_version].id_number == chip_version) break; } /* make sure data structure is 8-byte aligned */ l = ((Address)lance + 7) & ~7; lp = (struct lance_interface *)l; lp->init_block.mode = 0x3; /* disable Rx and Tx */ lp->init_block.filter[0] = lp->init_block.filter[1] = 0x0; /* using multiple Rx buffer and a single Tx buffer */ lp->init_block.rx_ring = (virt_to_bus(&lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS; lp->init_block.tx_ring = virt_to_bus(&lp->tx_ring) & 0xffffff; l = virt_to_bus(&lp->init_block); outw(0x1, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); outw((unsigned short)l, ioaddr+LANCE_DATA); outw(0x2, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); outw((unsigned short)(l >> 16), ioaddr+LANCE_DATA); outw(0x4, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); outw(0x915, ioaddr+LANCE_DATA); outw(0x0, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); /* Get station address */ for (i = 0; i < ETH_ALEN; ++i) { nic->node_addr[i] = inb(ioaddr+LANCE_ETH_ADDR+i); }#ifndef INCLUDE_LANCE /* now probe for DMA channel */ dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0xf) | (inb(DMA2_STAT_REG) & 0xf0); /* need to fix when PCI provides DMA info */ for (i = 0; i < (sizeof(dmas)/sizeof(dmas[0])); ++i) { int j; dma = dmas[i]; /* Don't enable a permanently busy DMA channel, or the machine will hang */ if (dma_channels & (1 << dma)) continue; outw(0x7f04, ioaddr+LANCE_DATA); /* clear memory error bits */ set_dma_mode(dma, DMA_MODE_CASCADE); enable_dma(dma); outw(0x1, ioaddr+LANCE_DATA); /* init */ for (j = 100; j > 0; --j) if (inw(ioaddr+LANCE_DATA) & 0x900) break; if (inw(ioaddr+LANCE_DATA) & 0x100) break; else disable_dma(dma); } if (i >= (sizeof(dmas)/sizeof(dmas[0]))) dma = 0; printf("\n%s base %#X, DMA %d, addr %!\n", chip_table[lance_version].name, ioaddr, dma, nic->node_addr);#else printf(" %s base %#hX, addr %!\n", chip_table[lance_version].name, ioaddr, nic->node_addr);#endif if (chip_table[chip_version].flags & LANCE_ENABLE_AUTOSELECT) { /* Turn on auto-select of media (10baseT or BNC) so that the * user watch the LEDs. */ outw(0x0002, ioaddr+LANCE_ADDR); /* Don't touch 10base2 power bit. */ outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF); } return (lance_version);}/**************************************************************************PROBE - Look for an adapter, this routine's visible to the outside***************************************************************************/#ifdef INCLUDE_LANCEstruct nic *lancepci_probe(struct nic *nic, unsigned short *probe_addrs, struct pci_device *pci)#endif#ifdef INCLUDE_NE2100struct nic *ne2100_probe(struct nic *nic, unsigned short *probe_addrs)#endif#ifdef INCLUDE_NI6510struct nic *ni6510_probe(struct nic *nic, unsigned short *probe_addrs)#endif{ unsigned short *p;#ifndef INCLUDE_LANCE static unsigned short io_addrs[] = { 0x300, 0x320, 0x340, 0x360, 0 };#endif /* if probe_addrs is 0, then routine can use a hardwired default */ if (probe_addrs == 0) {#ifdef INCLUDE_LANCE return 0;#else probe_addrs = io_addrs;#endif } for (p = probe_addrs; (ioaddr = *p) != 0; ++p) { char offset15, offset14 = inb(ioaddr + 14); unsigned short pci_cmd;#ifdef INCLUDE_NE2100 if ((offset14 == 0x52 || offset14 == 0x57) && ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) if (lance_probe1(nic) >= 0) break;#endif#ifdef INCLUDE_NI6510 if ((offset14 == 0x00 || offset14 == 0x52) && ((offset15 = inb(ioaddr + 15)) == 0x55 || offset15 == 0x44)) if (lance_probe1(nic) >= 0) break;#endif#ifdef INCLUDE_LANCE adjust_pci_device(pci); if (lance_probe1(nic, pci) >= 0) break;#endif } /* if board found */ if (ioaddr != 0) { /* point to NIC specific routines */ lance_reset(nic); nic->reset = lance_reset; nic->poll = lance_poll; nic->transmit = lance_transmit; nic->disable = lance_disable; return nic; } /* no board found */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -