📄 ether3.c
字号:
priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; } else priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);}static void ether3_timeout(struct net_device *dev){ unsigned long flags; del_timer(&priv(dev)->timer); local_irq_save(flags); printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name, ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR)); printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name, priv(dev)->tx_head, priv(dev)->tx_tail); ether3_setbuffer(dev, buffer_read, priv(dev)->tx_tail); printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); local_irq_restore(flags); priv(dev)->regs.config2 |= CFG2_CTRLO; priv(dev)->stats.tx_errors += 1; ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); priv(dev)->tx_head = priv(dev)->tx_tail = 0; netif_wake_queue(dev);}/* * Transmit a packet */static intether3_sendpacket(struct sk_buff *skb, struct net_device *dev){ unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int ptr, next_ptr; if (priv(dev)->broken) { dev_kfree_skb(skb); priv(dev)->stats.tx_dropped ++; netif_start_queue(dev); return 0; } length = (length + 1) & ~1; if (length != skb->len) { skb = skb_padto(skb, length); if (skb == NULL) goto out; } next_ptr = (priv(dev)->tx_head + 1) & 15; local_irq_save(flags); if (priv(dev)->tx_tail == next_ptr) { local_irq_restore(flags); return 1; /* unable to queue */ } dev->trans_start = jiffies; ptr = 0x600 * priv(dev)->tx_head; priv(dev)->tx_head = next_ptr; next_ptr *= 0x600;#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) ether3_setbuffer(dev, buffer_write, next_ptr); ether3_writelong(dev, 0); ether3_setbuffer(dev, buffer_write, ptr); ether3_writelong(dev, 0); ether3_writebuffer(dev, skb->data, length); ether3_writeword(dev, htons(next_ptr)); ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); ether3_setbuffer(dev, buffer_write, ptr); ether3_writeword(dev, htons((ptr + length + 4))); ether3_writeword(dev, TXHDR_FLAGS >> 16); ether3_ledon(dev); if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { ether3_outw(ptr, REG_TRANSMITPTR); ether3_outw(priv(dev)->regs.command | CMD_TXON, REG_COMMAND); } next_ptr = (priv(dev)->tx_head + 1) & 15; local_irq_restore(flags); dev_kfree_skb(skb); if (priv(dev)->tx_tail == next_ptr) netif_stop_queue(dev); out: return 0;}static irqreturn_tether3_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *)dev_id; unsigned int status, handled = IRQ_NONE;#if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("eth3irq: %d ", irq);#endif status = ether3_inw(REG_STATUS); if (status & STAT_INTRX) { ether3_outw(CMD_ACKINTRX | priv(dev)->regs.command, REG_COMMAND); ether3_rx(dev, 12); handled = IRQ_HANDLED; } if (status & STAT_INTTX) { ether3_outw(CMD_ACKINTTX | priv(dev)->regs.command, REG_COMMAND); ether3_tx(dev); handled = IRQ_HANDLED; }#if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("done\n");#endif return handled;}/* * If we have a good packet(s), get it/them out of the buffers. */static int ether3_rx(struct net_device *dev, unsigned int maxcnt){ unsigned int next_ptr = priv(dev)->rx_head, received = 0; ether3_ledon(dev); do { unsigned int this_ptr, status; unsigned char addrs[16]; /* * read the first 16 bytes from the buffer. * This contains the status bytes etc and ethernet addresses, * and we also check the source ethernet address to see if * it originated from us. */ { unsigned int temp_ptr; ether3_setbuffer(dev, buffer_read, next_ptr); temp_ptr = ether3_readword(dev); status = ether3_readword(dev); if ((status & (RXSTAT_DONE | RXHDR_CHAINCONTINUE | RXHDR_RECEIVE)) != (RXSTAT_DONE | RXHDR_CHAINCONTINUE) || !temp_ptr) break; this_ptr = next_ptr + 4; next_ptr = ntohs(temp_ptr); } ether3_setbuffer(dev, buffer_read, this_ptr); ether3_readbuffer(dev, addrs+2, 12);if (next_ptr < RX_START || next_ptr >= RX_END) { int i; printk("%s: bad next pointer @%04X: ", dev->name, priv(dev)->rx_head); printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8); for (i = 2; i < 14; i++) printk("%02X ", addrs[i]); printk("\n"); next_ptr = priv(dev)->rx_head; break;} /* * ignore our own packets... */ if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) && !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) { maxcnt ++; /* compensate for loopedback packet */ ether3_outw(next_ptr >> 8, REG_RECVEND); } else if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) { unsigned int length = next_ptr - this_ptr; struct sk_buff *skb; if (next_ptr <= this_ptr) length += RX_END - RX_START; skb = dev_alloc_skb(length + 2); if (skb) { unsigned char *buf; skb->dev = dev; skb_reserve(skb, 2); buf = skb_put(skb, length); ether3_readbuffer(dev, buf + 12, length - 12); ether3_outw(next_ptr >> 8, REG_RECVEND); *(unsigned short *)(buf + 0) = *(unsigned short *)(addrs + 2); *(unsigned long *)(buf + 2) = *(unsigned long *)(addrs + 4); *(unsigned long *)(buf + 6) = *(unsigned long *)(addrs + 8); *(unsigned short *)(buf + 10) = *(unsigned short *)(addrs + 12); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); received ++; } else goto dropping; } else { struct net_device_stats *stats = &priv(dev)->stats; ether3_outw(next_ptr >> 8, REG_RECVEND); if (status & RXSTAT_OVERSIZE) stats->rx_over_errors ++; if (status & RXSTAT_CRCERROR) stats->rx_crc_errors ++; if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++; if (status & RXSTAT_SHORTPACKET) stats->rx_length_errors ++; stats->rx_errors++; } } while (-- maxcnt);done: priv(dev)->stats.rx_packets += received; priv(dev)->rx_head = next_ptr; /* * If rx went off line, then that means that the buffer may be full. We * have dropped at least one packet. */ if (!(ether3_inw(REG_STATUS) & STAT_RXON)) { priv(dev)->stats.rx_dropped ++; ether3_outw(next_ptr, REG_RECVPTR); ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND); } return maxcnt;dropping:{ static unsigned long last_warned; ether3_outw(next_ptr >> 8, REG_RECVEND); /* * Don't print this message too many times... */ if (time_after(jiffies, last_warned + 10 * HZ)) { last_warned = jiffies; printk("%s: memory squeeze, dropping packet.\n", dev->name); } priv(dev)->stats.rx_dropped ++; goto done; }}/* * Update stats for the transmitted packet(s) */static void ether3_tx(struct net_device *dev){ unsigned int tx_tail = priv(dev)->tx_tail; int max_work = 14; do { unsigned long status; /* * Read the packet header */ ether3_setbuffer(dev, buffer_read, tx_tail * 0x600); status = ether3_readlong(dev); /* * Check to see if this packet has been transmitted */ if ((status & (TXSTAT_DONE | TXHDR_TRANSMIT)) != (TXSTAT_DONE | TXHDR_TRANSMIT)) break; /* * Update errors */ if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS))) priv(dev)->stats.tx_packets++; else { priv(dev)->stats.tx_errors ++; if (status & TXSTAT_16COLLISIONS) priv(dev)->stats.collisions += 16; if (status & TXSTAT_BABBLED) priv(dev)->stats.tx_fifo_errors ++; } tx_tail = (tx_tail + 1) & 15; } while (--max_work); if (priv(dev)->tx_tail != tx_tail) { priv(dev)->tx_tail = tx_tail; netif_wake_queue(dev); }}static void __init ether3_banner(void){ static unsigned version_printed = 0; if (net_debug && version_printed++ == 0) printk(KERN_INFO "%s", version);}static int __devinitether3_probe(struct expansion_card *ec, const struct ecard_id *id){ const struct ether3_data *data = id->data; struct net_device *dev; int i, bus_type, ret; ether3_banner(); ret = ecard_request_resources(ec); if (ret) goto out; dev = alloc_etherdev(sizeof(struct dev_priv)); if (!dev) { ret = -ENOMEM; goto release; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &ec->dev); priv(dev)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), ecard_resource_len(ec, ECARD_RES_MEMC)); if (!priv(dev)->base) { ret = -ENOMEM; goto free; } ec->irqaddr = priv(dev)->base + data->base_offset; ec->irqmask = 0xf0; priv(dev)->seeq = priv(dev)->base + data->base_offset; dev->irq = ec->irq; ether3_addr(dev->dev_addr, ec); init_timer(&priv(dev)->timer); /* Reset card... */ ether3_outb(0x80, REG_CONFIG2 + 4); bus_type = BUS_UNKNOWN; udelay(4); /* Test using Receive Pointer (16-bit register) to find out * how the ether3 is connected to the bus... */ if (ether3_probe_bus_8(dev, 0x100) && ether3_probe_bus_8(dev, 0x201)) bus_type = BUS_8; if (bus_type == BUS_UNKNOWN && ether3_probe_bus_16(dev, 0x101) && ether3_probe_bus_16(dev, 0x201)) bus_type = BUS_16; switch (bus_type) { case BUS_UNKNOWN: printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); ret = -ENODEV; goto free; case BUS_8: printk(KERN_ERR "%s: %s found, but is an unsupported " "8-bit card\n", dev->name, data->name); ret = -ENODEV; goto free; default: break; } if (ether3_init_2(dev)) { ret = -ENODEV; goto free; } dev->open = ether3_open; dev->stop = ether3_close; dev->hard_start_xmit = ether3_sendpacket; dev->get_stats = ether3_getstats; dev->set_multicast_list = ether3_setmulticastlist; dev->tx_timeout = ether3_timeout; dev->watchdog_timeo = 5 * HZ / 100; ret = register_netdev(dev); if (ret) goto free; printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); ecard_set_drvdata(ec, dev); return 0; free: if (priv(dev)->base) iounmap(priv(dev)->base); free_netdev(dev); release: ecard_release_resources(ec); out: return ret;}static void __devexit ether3_remove(struct expansion_card *ec){ struct net_device *dev = ecard_get_drvdata(ec); ecard_set_drvdata(ec, NULL); unregister_netdev(dev); iounmap(priv(dev)->base); free_netdev(dev); ecard_release_resources(ec);}static struct ether3_data ether3 = { .name = "ether3", .base_offset = 0,};static struct ether3_data etherb = { .name = "etherb", .base_offset = 0x800,};static const struct ecard_id ether3_ids[] = { { MANU_ANT2, PROD_ANT_ETHER3, ðer3 }, { MANU_ANT, PROD_ANT_ETHER3, ðer3 }, { MANU_ANT, PROD_ANT_ETHERB, ðerb }, { 0xffff, 0xffff }};static struct ecard_driver ether3_driver = { .probe = ether3_probe, .remove = __devexit_p(ether3_remove), .id_table = ether3_ids, .drv = { .name = "ether3", },};static int __init ether3_init(void){ return ecard_register_driver(ðer3_driver);}static void __exit ether3_exit(void){ ecard_remove_driver(ðer3_driver);}module_init(ether3_init);module_exit(ether3_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -