📄 ewrk3.c
字号:
outb(page, EWRK3_IOPR); } else if (lp->shmem_length == SHMEM_2K) { buf = lp->shmem_base; outb(page, EWRK3_MPR); } else if (lp->shmem_length == SHMEM_32K) { buf = ((((short) page << 11) & 0x7800) + lp->shmem_base); outb((page >> 4), EWRK3_MPR); } else if (lp->shmem_length == SHMEM_64K) { buf = ((((short) page << 11) & 0xf800) + lp->shmem_base); outb((page >> 5), EWRK3_MPR); } else { status = -1; printk("%s: Oops - your private data area is hosed!\n", dev->name); } if (!status) { char rx_status; int pkt_len; if (lp->shmem_length == IO_ONLY) { rx_status = inb(EWRK3_DATA); pkt_len = inb(EWRK3_DATA); pkt_len |= ((u_short) inb(EWRK3_DATA) << 8); } else { rx_status = readb(buf); buf += 1; pkt_len = readw(buf); buf += 3; } if (!(rx_status & R_ROK)) { /* There was an error. */ lp->stats.rx_errors++; /* Update the error stats. */ if (rx_status & R_DBE) lp->stats.rx_frame_errors++; if (rx_status & R_CRC) lp->stats.rx_crc_errors++; if (rx_status & R_PLL) lp->stats.rx_fifo_errors++; } else { struct sk_buff *skb; if ((skb = dev_alloc_skb(pkt_len + 2)) != NULL) { unsigned char *p; skb->dev = dev; skb_reserve(skb, 2); /* Align to 16 bytes */ p = skb_put(skb, pkt_len); if (lp->shmem_length == IO_ONLY) { *p = inb(EWRK3_DATA); /* dummy read */ for (i = 0; i < pkt_len; i++) { *p++ = inb(EWRK3_DATA); } } else { memcpy_fromio(p, buf, pkt_len); } /* ** Notify the upper protocol layers that there is another ** packet to handle */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* ** Update stats */ lp->stats.rx_packets++; for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) { if (pkt_len < i * EWRK3_PKT_BIN_SZ) { lp->pktStats.bins[i]++; i = EWRK3_PKT_STAT_SZ; } } p = skb->data; /* Look at the dest addr */ if (p[0] & 0x01) { /* Multicast/Broadcast */ if ((*(s32 *) & p[0] == -1) && (*(s16 *) & p[4] == -1)) { lp->pktStats.broadcast++; } else { lp->pktStats.multicast++; } } else if ((*(s32 *) & p[0] == *(s32 *) & dev->dev_addr[0]) && (*(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)); } } 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); if (tmpLock) { /* If a lock was preempted */ if (lp->shmem_length == IO_ONLY) { /* Replace old page */ outb(tmpPage, EWRK3_IOPR); } else { outb(tmpPage, EWRK3_MPR); } } lp->lock = 0; /* Unlock the page register */ } 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. */static int ewrk3_tx(struct 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 device *dev){ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; u_long iobase = dev->base_addr; u_char icr, csr; dev->start = 0; dev->tbusy = 1; 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); } MOD_DEC_USE_COUNT; return 0;}static struct net_device_stats *ewrk3_get_stats(struct 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 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 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, j, bit, byte; short *p = (short *) lp->mctbl; u16 hashcode; s32 crc, poly = CRC_POLYNOMIAL_LE; while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ 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 */ writew(0xffff, 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 { memset_io(lp->mctbl, 0, (HASH_TABLE_LEN >> 3)); writeb(0x80, (char *) (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 = 0xffffffff; /* init CRC for each address */ for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */ /* process each address bit */ for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); } } 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 { writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte); } } } } lp->lock = 0; /* Unlock the page register */ return;}/* ** ISA bus I/O device probe */__initfunc(static void isa_probe(struct device *dev, u_long ioaddr)){ int i = num_ewrk3s, maxSlots; u_long iobase; if (!ioaddr && autoprobed) return; /* Been here before ! */ if (ioaddr >= 0x400) return; /* Not ISA */ 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 (!check_region(iobase, EWRK3_TOTAL_SIZE)) { if (DevicePresent(iobase) == 0) { if ((dev = alloc_device(dev, iobase)) != NULL) { if (ewrk3_hw_init(dev, iobase) == 0) { num_ewrk3s++; } num_eth++; } } } else if (autoprobed) { printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); } } return;}/* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. */__initfunc(static void eisa_probe(struct device *dev, u_long ioaddr)){ int i, maxSlots; u_long iobase; char name[EWRK3_STRLEN]; if (!ioaddr && autoprobed) return; /* Been here before ! */ if (ioaddr < 0x1000) return; /* Not EISA */ 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 (!check_region(iobase, EWRK3_TOTAL_SIZE)) { if (DevicePresent(iobase) == 0) { if ((dev = alloc_device(dev, iobase)) != NULL) { if (ewrk3_hw_init(dev, iobase) == 0) { num_ewrk3s++; } num_eth++; } } } else if (autoprobed) { printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); } } } return;}/* ** Search the entire 'eth' device list for a fixed probe. If a match isn't ** found then check for an autoprobe or unused device location. If they ** are not available then insert a new device structure at the end of ** the current list. */__initfunc(static struct device * alloc_device(struct device *dev, u_long iobase)){ struct device *adev = NULL; int fixed = 0, new_dev = 0; num_eth = ewrk3_dev_index(dev->name); if (loading_module) return dev; while (1) { if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr == 0)) && !adev) { adev = dev; } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { fixed = 1; } else { if (dev->next == NULL) { new_dev = 1; } else if (strncmp(dev->next->name, "eth", 3) != 0) { new_dev = 1; } } if ((dev->next == NULL) || new_dev || fixed) break; dev = dev->next; num_eth++; } if (adev && !fixed) { dev = adev; num_eth = ewrk3_dev_index(dev->name); new_dev = 0; } if (((dev->next == NULL) && ((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) || new_dev) { num_eth++; /* New device */ dev = insert_device(dev, iobase, ewrk3_probe); } return dev;}/* ** If at end of eth device list and can't use current entry, malloc ** one up. If memory could not be allocated, print an error message. */__initfunc(static struct device * insert_device(struct device *dev, u_long iobase, int (*init) (struct device *))){ struct device *new; new = (struct device *) kmalloc(sizeof(struct device) + 8, GFP_KERNEL); if (new == NULL) { printk("eth%d: Device not initialised, insufficient memory\n", num_eth); return NULL; } else { new->next = dev->next; dev->next = new; dev = dev->next; /* point to the new device */ dev->name = (char *) (dev + 1); if (num_eth > 9999) { sprintf(dev->name, "eth????"); /* New device name */ } else { sprintf(dev->name, "eth%d", num_eth); /* New device name */ } dev->base_addr = iobase; /* assign the io address */ dev->init = init; /* initialisation routine */ } return dev;}__initfunc(static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -