📄 ewrk3.c
字号:
/* ** Set up shared memory window and pointer into the window */ if (lp->shmem_length == IO_ONLY) { 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 intewrk3_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 intewrk3_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, NULL); irq2dev_map[dev->irq] = 0; } MOD_DEC_USE_COUNT; return 0;}static struct enet_statistics *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 voidset_multicast_list(struct device *dev){ struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; u_long iobase = dev->base_addr; u_char csr; if (irq2dev_map[dev->irq] != NULL) { 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 (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*/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.*/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.*/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.*/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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -