ewrk3.c
字号:
lp->pktStats.multicast++; } } else if ((*(s16 *) & p[0] == *(s16 *) & dev->dev_addr[0]) && (*(s16 *) & p[2] == *(s16 *) & dev->dev_addr[2]) && (*(s16 *) & p[4] == *(s16 *) & dev->dev_addr[4])) { lp->pktStats.unicast++; } lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ if (lp->pktStats.bins[0] == 0) { /* Reset counters */ memset(&lp->pktStats, 0, sizeof(lp->pktStats)); } /* ** Notify the upper protocol layers that there is another ** packet to handle */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* ** Update stats */ dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } else { printk("%s: Insufficient memory; nuking packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ break; } } } /* ** Return the received buffer to the free memory queue */ outb(page, EWRK3_FMQ); } else { printk("ewrk3_rx(): Illegal page number, page %d\n", page); printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC)); } } return status;}/*** Buffer sent - check for TX buffer errors.** Called with lp->hw_lock held*/static int ewrk3_tx(struct net_device *dev){ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; u_long iobase = dev->base_addr; u_char tx_status; while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */ if (tx_status & T_VSTS) { /* The status is valid */ if (tx_status & T_TXE) { lp->stats.tx_errors++; if (tx_status & T_NCL) lp->stats.tx_carrier_errors++; if (tx_status & T_LCL) lp->stats.tx_window_errors++; if (tx_status & T_CTU) { if ((tx_status & T_COLL) ^ T_XUR) { lp->pktStats.tx_underruns++; } else { lp->pktStats.excessive_underruns++; } } else if (tx_status & T_COLL) { if ((tx_status & T_COLL) ^ T_XCOLL) { lp->stats.collisions++; } else { lp->pktStats.excessive_collisions++; } } } else { lp->stats.tx_packets++; } } } return 0;}static int ewrk3_close(struct net_device *dev){ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; u_long iobase = dev->base_addr; u_char icr, csr; netif_stop_queue(dev); if (ewrk3_debug > 1) { printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inb(EWRK3_CSR)); } /* ** We stop the EWRK3 here... mask interrupts and stop TX & RX */ DISABLE_IRQs; STOP_EWRK3; /* ** Clean out the TX and RX queues here (note that one entry ** may get added to either the TXD or RX queues if the TX or RX ** just starts processing a packet before the STOP_EWRK3 command ** is received. This will be flushed in the ewrk3_open() call). */ while (inb(EWRK3_TQ)); while (inb(EWRK3_TDQ)); while (inb(EWRK3_RQ)); if (!lp->hard_strapped) { free_irq(dev->irq, dev); } return 0;}static struct net_device_stats *ewrk3_get_stats(struct net_device *dev){ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; /* Null body since there is no framing error counter */ return &lp->stats;}/* ** Set or clear the multicast filter for this adapter. */static void set_multicast_list(struct net_device *dev){ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; u_long iobase = dev->base_addr; u_char csr; csr = inb(EWRK3_CSR); if (lp->shmem_length == IO_ONLY) { lp->mctbl = (char *) PAGE0_HTE; } else { lp->mctbl = (char *) (lp->shmem_base + PAGE0_HTE); } csr &= ~(CSR_PME | CSR_MCE); if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ csr |= CSR_PME; outb(csr, EWRK3_CSR); } else { SetMulticastFilter(dev); csr |= CSR_MCE; outb(csr, EWRK3_CSR); }}/* ** Calculate the hash code and update the logical address filter ** from a list of ethernet multicast addresses. ** Little endian crc one liner from Matt Thomas, DEC. ** ** Note that when clearing the table, the broadcast bit must remain asserted ** to receive broadcast messages. */static void SetMulticastFilter(struct net_device *dev){ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; struct dev_mc_list *dmi = dev->mc_list; u_long iobase = dev->base_addr; int i; char *addrs, bit, byte; short *p = (short *) lp->mctbl; u16 hashcode; u32 crc; spin_lock_irq(&lp->hw_lock); if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); outw(EEPROM_OFFSET(lp->mctbl), EWRK3_PIR1); } else { outb(0, EWRK3_MPR); } if (dev->flags & IFF_ALLMULTI) { for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) { if (lp->shmem_length == IO_ONLY) { outb(0xff, EWRK3_DATA); } else { /* memset didn't work here */ isa_writew(0xffff, (int) p); p++; i++; } } } else { /* Clear table except for broadcast bit */ if (lp->shmem_length == IO_ONLY) { for (i = 0; i < (HASH_TABLE_LEN >> 4) - 1; i++) { outb(0x00, EWRK3_DATA); } outb(0x80, EWRK3_DATA); i++; /* insert the broadcast bit */ for (; i < (HASH_TABLE_LEN >> 3); i++) { outb(0x00, EWRK3_DATA); } } else { isa_memset_io((int) lp->mctbl, 0, (HASH_TABLE_LEN >> 3)); isa_writeb(0x80, (int) (lp->mctbl + (HASH_TABLE_LEN >> 4) - 1)); } /* Update table */ for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ addrs = dmi->dmi_addr; dmi = dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ crc = ether_crc_le(ETH_ALEN, addrs); hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */ byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ if (lp->shmem_length == IO_ONLY) { u_char tmp; outw((short) ((long) lp->mctbl) + byte, EWRK3_PIR1); tmp = inb(EWRK3_DATA); tmp |= bit; outw((short) ((long) lp->mctbl) + byte, EWRK3_PIR1); outb(tmp, EWRK3_DATA); } else { isa_writeb(isa_readb((int)(lp->mctbl + byte)) | bit, (int)(lp->mctbl + byte)); } } } } spin_unlock_irq(&lp->hw_lock);}/* ** ISA bus I/O device probe */static int __init isa_probe(struct net_device *dev, u_long ioaddr){ int i = num_ewrks3s, maxSlots; int ret = -ENODEV; u_long iobase; if (ioaddr >= 0x400) goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EWRK3_IO_BASE; /* Get the first slot address */ maxSlots = 24; } else { /* Probe a specific location */ iobase = ioaddr; maxSlots = i + 1; } for (; (i < maxSlots) && (dev != NULL); iobase += EWRK3_IOP_INC, i++) { if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME)) { if (DevicePresent(iobase) == 0) { int irq = dev->irq; ret = ewrk3_hw_init(dev, iobase); if (!ret) break; dev->irq = irq; } release_region(iobase, EWRK3_TOTAL_SIZE); } } out: return ret;}/* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. */static int __init eisa_probe(struct net_device *dev, u_long ioaddr){ int i, maxSlots; u_long iobase; int ret = -ENODEV; if (ioaddr < 0x1000) goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EISA_SLOT_INC; /* Get the first slot address */ i = 1; maxSlots = MAX_EISA_SLOTS; } else { /* Probe a specific location */ iobase = ioaddr; i = (ioaddr >> 12); maxSlots = i + 1; } for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { if (EISA_signature(name, EISA_ID) == 0) { if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME) && DevicePresent(iobase) == 0) { int irq = dev->irq; ret = ewrk3_hw_init(dev, iobase); if (!ret) break; dev->irq = irq; } release_region(iobase, EWRK3_TOTAL_SIZE); } } out: return ret;}/* ** Read the EWRK3 EEPROM using this routine */static int Read_EEPROM(u_long iobase, u_char eaddr){ int i; outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */ outb(EEPROM_RD, EWRK3_IOPR); /* issue read command */ for (i = 0; i < 5000; i++) inb(EWRK3_CSR); /* wait 1msec */ return inw(EWRK3_EPROM1); /* 16 bits data return */}/* ** Write the EWRK3 EEPROM using this routine */static int Write_EEPROM(short data, u_long iobase, u_char eaddr){ int i; outb(EEPROM_WR_EN, EWRK3_IOPR); /* issue write enable command */ for (i = 0; i < 5000; i++) inb(EWRK3_CSR); /* wait 1msec */ outw(data, EWRK3_EPROM1); /* write data to register */ outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */ outb(EEPROM_WR, EWRK3_IOPR); /* issue write command */ for (i = 0; i < 75000; i++) inb(EWRK3_CSR); /* wait 15msec */ outb(EEPROM_WR_DIS, EWRK3_IOPR); /* issue write disable command */ for (i = 0; i < 5000; i++) inb(EWRK3_CSR); /* wait 1msec */ return 0;}/* ** Look for a particular board name in the on-board EEPROM. */static void __init EthwrkSignature(char *name, char *eeprom_image){ int i; char *signatures[] = EWRK3_SIGNATURE; for (i=0; *signatures[i] != '\0'; i++) if( !strncmp(eeprom_image+EEPROM_PNAME7, signatures[i], strlen(signatures[i])) ) break; if (*signatures[i] != '\0') { memcpy(name, eeprom_image+EEPROM_PNAME7, EWRK3_STRLEN); name[EWRK3_STRLEN] = '\0'; } else name[0] = '\0'; return;}/* ** Look for a special sequence in the Ethernet station address PROM that ** is common across all EWRK3 products. ** ** Search the Ethernet address ROM for the signature. Since the ROM address ** counter can start at an arbitrary point, the search must include the entire ** probe sequence length plus the (length_of_the_signature - 1). ** Stop the search IMMEDIATELY after the signature is found so that the ** PROM address counter is correctly positioned at the start of the ** ethernet address for later read out. */static int __init DevicePresent(u_long iobase){ union { struct { u32 a; u32 b; } llsig; char Sig[sizeof(u32) << 1]; } dev; short sigLength; char data; int i, j, status = 0; dev.llsig.a = ETH_PROM_SIG; dev.llsig.b = ETH_PROM_SIG; sigLength = sizeof(u32) << 1; for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) { data = inb(EWRK3_APROM); if (dev.Sig[j] == data) { /* track signature */ j++; } else { /* lost signature; begin search again */ if (data == dev.Sig[0]) { j = 1; } else { j = 0; } } } if (j != sigLength) { status = -ENODEV; /* search failed */ } return status;}static u_char __init get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType){ int i, j, k; u_short chksum; u_char crc, lfsr, sd, status = 0; u_long iobase = dev->base_addr; u16 tmp; if (chipType == LeMAC2) { for (crc = 0x6a, j = 0; j < ETH_ALEN; j++) { sd = dev->dev_addr[j] = eeprom_image[EEPROM_PADDR0 + j]; outb(dev->dev_addr[j], EWRK3_PAR0 + j); for (k = 0; k < 8; k++, sd >>= 1) { lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7; crc = (crc >> 1) + lfsr; } } if (crc != eeprom_image[EEPROM_PA_CRC]) status = -1; } else { for (i = 0, k = 0; i < ETH_ALEN;) { k <<= 1; if (k > 0xffff) k -= 0xffff; k += (u_char) (tmp = inb(EWRK3_APROM)); dev->dev_addr[i] = (u_char) tmp; outb(dev->dev_addr[i], EWRK3_PAR0 + i); i++; k += (u_short) ((tmp = inb(EWRK3_APROM)) << 8); dev->dev_addr[i] = (u_char) tmp; outb(dev->dev_addr[i], EWRK3_PAR0 + i); i++; if (k > 0xffff) k -= 0xffff; } if (k == 0xffff) k = 0; chksum = inb(EWRK3_APROM); chksum |= (inb(EWRK3_APROM) << 8); if (k != chksum) status = -1; } return status;}/* ** Look for a particular board name in the EISA configuration space */static int __init EISA_signature(char *name, s32 eisa_id){ u_long i; char *signatures[] = EWRK3_SIGNATURE; char ManCode[EWRK3_STRLEN]; union { s32 ID; char Id[4]; } Eisa; int status = 0; *name = '\0'; for (i = 0; i < 4; i++) { Eisa.Id[i] = inb(eisa_id + i); } ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40); ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40); ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30); ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30); ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30); ManCode[5] = '\0'; for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) { if (strstr(ManCode, signatures[i]) != NULL) { strcpy(name, ManCode); status = 1; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -