📄 atp.c
字号:
} else if (status & ((ISR_TxErr + ISR_TxOK)<<3)) { if (net_debug > 6) printk("handling Tx done.."); /* Clear the Tx interrupt. We should check for too many failures and reinitialize the adapter. */ write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK); if (status & (ISR_TxErr<<3)) { lp->stats.collisions++; if (++lp->re_tx > 15) { lp->stats.tx_aborted_errors++; hardware_init(dev); break; } /* Attempt to retransmit. */ if (net_debug > 6) printk("attempting to ReTx"); write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit); } else { /* Finish up the transmit. */ lp->stats.tx_packets++; lp->pac_cnt_in_tx_buf--; if ( lp->saved_tx_size) { trigger_send(ioaddr, lp->saved_tx_size); lp->saved_tx_size = 0; lp->re_tx = 0; } else lp->tx_unit_busy = 0; netif_wake_queue(dev); /* Inform upper layers. */ } num_tx_since_rx++; } else if (num_tx_since_rx > 8 && jiffies > dev->last_rx + HZ) { if (net_debug > 2) printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and " "%ld jiffies status %02x CMR1 %02x.\n", dev->name, num_tx_since_rx, jiffies - dev->last_rx, status, (read_nibble(ioaddr, CMR1) >> 3) & 15); lp->stats.rx_missed_errors++; hardware_init(dev); num_tx_since_rx = 0; break; } else break; } /* This following code fixes a rare (and very difficult to track down) problem where the adapter forgets its ethernet address. */ { int i; for (i = 0; i < 6; i++) write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);#if 0 && defined(TIMED_CHECKER) mod_timer(&lp->timer, RUN_AT(TIMED_CHECKER));#endif } /* Tell the adapter that it can go back to using the output line as IRQ. */ write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Enable the physical interrupt line, which is sure to be low until.. */ outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); /* .. we enable the interrupt sources. */ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); write_reg_high(ioaddr, IMR, ISRh_RxErr); /* Hmmm, really needed? */ spin_unlock(&lp->lock); if (net_debug > 5) printk("exiting interrupt.\n"); return;}#ifdef TIMED_CHECKER/* This following code fixes a rare (and very difficult to track down) problem where the adapter forgets its ethernet address. */static void atp_timed_checker(unsigned long data){ struct net_device *dev = (struct net_device *)data; long ioaddr = dev->base_addr; struct net_local *lp = (struct net_local *)dev->priv; int tickssofar = jiffies - lp->last_rx_time; int i; spin_lock(&lp->lock); if (tickssofar > 2*HZ) {#if 1 for (i = 0; i < 6; i++) write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); lp->last_rx_time = jiffies;#else for (i = 0; i < 6; i++) if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i]) { struct net_local *lp = (struct net_local *)atp_timed_dev->priv; write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); if (i == 2) lp->stats.tx_errors++; else if (i == 3) lp->stats.tx_dropped++; else if (i == 4) lp->stats.collisions++; else lp->stats.rx_errors++; }#endif } spin_unlock(&lp->lock); lp->timer.expires = RUN_AT(TIMED_CHECKER); add_timer(&lp->timer);}#endif/* We have a good packet(s), get it/them out of the buffers. */static void net_rx(struct net_device *dev){ struct net_local *lp = (struct net_local *)dev->priv; long ioaddr = dev->base_addr; struct rx_header rx_head; /* Process the received packet. */ outb(EOC+MAR, ioaddr + PAR_DATA); read_block(ioaddr, 8, (unsigned char*)&rx_head, dev->if_port); if (net_debug > 5) printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad, rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr); if ((rx_head.rx_status & 0x77) != 0x01) { lp->stats.rx_errors++; if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++; else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++; if (net_debug > 3) printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n", dev->name, rx_head.rx_status); if (rx_head.rx_status & 0x0020) { lp->stats.rx_fifo_errors++; write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE); write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); } else if (rx_head.rx_status & 0x0050) hardware_init(dev); return; } else { /* Malloc up new buffer. The "-4" omits the FCS (CRC). */ int pkt_len = (rx_head.rx_count & 0x7ff) - 4; struct sk_buff *skb; skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) { printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; goto done; } skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ read_block(ioaddr, pkt_len, skb_put(skb,pkt_len), dev->if_port); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } done: write_reg(ioaddr, CMR1, CMR1_NextPkt); lp->last_rx_time = jiffies; return;}static void read_block(long ioaddr, int length, unsigned char *p, int data_mode){ if (data_mode <= 3) { /* Mode 0 or 1 */ outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); outb(length == 8 ? RdAddr | HNib | MAR : RdAddr | MAR, ioaddr + PAR_DATA); if (data_mode <= 1) { /* Mode 0 or 1 */ do *p++ = read_byte_mode0(ioaddr); while (--length > 0); } else /* Mode 2 or 3 */ do *p++ = read_byte_mode2(ioaddr); while (--length > 0); } else if (data_mode <= 5) do *p++ = read_byte_mode4(ioaddr); while (--length > 0); else do *p++ = read_byte_mode6(ioaddr); while (--length > 0); outb(EOC+HNib+MAR, ioaddr + PAR_DATA); outb(Ctrl_SelData, ioaddr + PAR_CONTROL);}/* The inverse routine to net_open(). */static intnet_close(struct net_device *dev){ struct net_local *lp = (struct net_local *)dev->priv; long ioaddr = dev->base_addr; netif_stop_queue(dev); del_timer_sync(&lp->timer); /* Flush the Tx and disable Rx here. */ lp->addr_mode = CMR2h_OFF; write_reg_high(ioaddr, CMR2, CMR2h_OFF); /* Free the IRQ line. */ outb(0x00, ioaddr + PAR_CONTROL); free_irq(dev->irq, dev); /* Reset the ethernet hardware and activate the printer pass-through. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); return 0;}/* Get the current statistics. This may be called with the card open or closed. */static struct net_device_stats *net_get_stats(struct net_device *dev){ struct net_local *lp = (struct net_local *)dev->priv; return &lp->stats;}/* * Set or clear the multicast filter for this adapter. *//* The little-endian AUTODIN32 ethernet CRC calculation. This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){ unsigned int crc = 0xffffffff; /* Initial value. */ while(--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 8; --bit >= 0; current_octet >>= 1) { if ((crc ^ current_octet) & 1) { crc >>= 1; crc ^= ethernet_polynomial_le; } else crc >>= 1; } } return crc;}static void set_rx_mode_8002(struct net_device *dev){ struct net_local *lp = (struct net_local *)dev->priv; long ioaddr = dev->base_addr; if ( dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) { /* We must make the kernel realise we had to move * into promisc mode or we start all out war on * the cable. - AC */ dev->flags|=IFF_PROMISC; lp->addr_mode = CMR2h_PROMISC; } else lp->addr_mode = CMR2h_Normal; write_reg_high(ioaddr, CMR2, lp->addr_mode);}static void set_rx_mode_8012(struct net_device *dev){ struct net_local *lp = (struct net_local *)dev->priv; long ioaddr = dev->base_addr; unsigned char new_mode, mc_filter[8]; /* Multicast hash filter */ int i; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ new_mode = CMR2h_PROMISC; } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); new_mode = CMR2h_Normal; } else { struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, mc_filter); new_mode = CMR2h_Normal; } lp->addr_mode = new_mode; write_reg(ioaddr, CMR2, CMR2_IRQOUT | 0x04); /* Switch to page 1. */ for (i = 0; i < 8; i++) write_reg_byte(ioaddr, i, mc_filter[i]); if (net_debug > 2 || 1) { lp->addr_mode = 1; printk(KERN_DEBUG "%s: Mode %d, setting multicast filter to", dev->name, lp->addr_mode); for (i = 0; i < 8; i++) printk(" %2.2x", mc_filter[i]); printk(".\n"); } write_reg_high(ioaddr, CMR2, lp->addr_mode); write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Switch back to page 0 */}static int __init atp_init_module(void) { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); return atp_init(NULL);}static void __exit atp_cleanup_module(void) { struct net_device *next_dev; while (root_atp_dev) { next_dev = ((struct net_local *)root_atp_dev->priv)->next_module; unregister_netdev(root_atp_dev); /* No need to release_region(), since we never snarf it. */ kfree(root_atp_dev); root_atp_dev = next_dev; }}module_init(atp_init_module);module_exit(atp_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -