📄 nmclan_cs.c
字号:
if (link->open) { nmclan_reset(dev); netif_device_attach(dev); } } break; case CS_EVENT_RESET_REQUEST: return 1; break; } return 0;} /* nmclan_event *//* ----------------------------------------------------------------------------nmclan_reset Reset and restore all of the Xilinx and MACE registers.---------------------------------------------------------------------------- */static void nmclan_reset(struct net_device *dev){ mace_private *lp = netdev_priv(dev);#if RESET_XILINX dev_link_t *link = &lp->link; conf_reg_t reg; u_long OrigCorValue; /* Save original COR value */ reg.Function = 0; reg.Action = CS_READ; reg.Offset = CISREG_COR; reg.Value = 0; pcmcia_access_configuration_register(link->handle, ®); OrigCorValue = reg.Value; /* Reset Xilinx */ reg.Action = CS_WRITE; reg.Offset = CISREG_COR; DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n", OrigCorValue); reg.Value = COR_SOFT_RESET; pcmcia_access_configuration_register(link->handle, ®); /* Need to wait for 20 ms for PCMCIA to finish reset. */ /* Restore original COR configuration index */ reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK); pcmcia_access_configuration_register(link->handle, ®); /* Xilinx is now completely reset along with the MACE chip. */ lp->tx_free_frames=AM2150_MAX_TX_FRAMES;#endif /* #if RESET_XILINX */ /* Xilinx is now completely reset along with the MACE chip. */ lp->tx_free_frames=AM2150_MAX_TX_FRAMES; /* Reinitialize the MACE chip for operation. */ mace_init(lp, dev->base_addr, dev->dev_addr); mace_write(lp, dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT); /* Restore the multicast list and enable TX and RX. */ restore_multicast_list(dev);} /* nmclan_reset *//* ----------------------------------------------------------------------------mace_config [Someone tell me what this is supposed to do? Is if_port a defined standard? If so, there should be defines to indicate 1=10Base-T, 2=10Base-2, etc. including limited automatic detection.]---------------------------------------------------------------------------- */static int mace_config(struct net_device *dev, struct ifmap *map){ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (map->port <= 2) { dev->if_port = map->port; printk(KERN_INFO "%s: switched to %s port\n", dev->name, if_names[dev->if_port]); } else return -EINVAL; } return 0;} /* mace_config *//* ----------------------------------------------------------------------------mace_open Open device driver.---------------------------------------------------------------------------- */static int mace_open(struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; mace_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; if (!DEV_OK(link)) return -ENODEV; link->open++; MACEBANK(0); netif_start_queue(dev); nmclan_reset(dev); return 0; /* Always succeed */} /* mace_open *//* ----------------------------------------------------------------------------mace_close Closes device driver.---------------------------------------------------------------------------- */static int mace_close(struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; mace_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); /* Mask off all interrupts from the MACE chip. */ outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR); link->open--; netif_stop_queue(dev); return 0;} /* mace_close */static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);}#ifdef PCMCIA_DEBUGstatic u32 netdev_get_msglevel(struct net_device *dev){ return pc_debug;}static void netdev_set_msglevel(struct net_device *dev, u32 level){ pc_debug = level;}#endif /* PCMCIA_DEBUG */static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo,#ifdef PCMCIA_DEBUG .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel,#endif /* PCMCIA_DEBUG */};/* ----------------------------------------------------------------------------mace_start_xmit This routine begins the packet transmit function. When completed, it will generate a transmit interrupt. According to /usr/src/linux/net/inet/dev.c, if _start_xmit returns 0, the "packet is now solely the responsibility of the driver." If _start_xmit returns non-zero, the "transmission failed, put skb back into a list."---------------------------------------------------------------------------- */static void mace_tx_timeout(struct net_device *dev){ mace_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);#if RESET_ON_TIMEOUT printk("resetting card\n"); pcmcia_reset_card(link->handle, NULL);#else /* #if RESET_ON_TIMEOUT */ printk("NOT resetting card\n");#endif /* #if RESET_ON_TIMEOUT */ dev->trans_start = jiffies; netif_wake_queue(dev);}static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev){ mace_private *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; netif_stop_queue(dev); DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n", dev->name, (long)skb->len);#if (!TX_INTERRUPTABLE) /* Disable MACE TX interrupts. */ outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT, ioaddr + AM2150_MACE_BASE + MACE_IMR); lp->tx_irq_disabled=1;#endif /* #if (!TX_INTERRUPTABLE) */ { /* This block must not be interrupted by another transmit request! mace_tx_timeout will take care of timer-based retransmissions from the upper layers. The interrupt handler is guaranteed never to service a transmit interrupt while we are in here. */ lp->linux_stats.tx_bytes += skb->len; lp->tx_free_frames--; /* WARNING: Write the _exact_ number of bytes written in the header! */ /* Put out the word header [must be an outw()] . . . */ outw(skb->len, ioaddr + AM2150_XMT); /* . . . and the packet [may be any combination of outw() and outb()] */ outsw(ioaddr + AM2150_XMT, skb->data, skb->len >> 1); if (skb->len & 1) { /* Odd byte transfer */ outb(skb->data[skb->len-1], ioaddr + AM2150_XMT); } dev->trans_start = jiffies;#if MULTI_TX if (lp->tx_free_frames > 0) netif_start_queue(dev);#endif /* #if MULTI_TX */ }#if (!TX_INTERRUPTABLE) /* Re-enable MACE TX interrupts. */ lp->tx_irq_disabled=0; outb(MACE_IMR_DEFAULT, ioaddr + AM2150_MACE_BASE + MACE_IMR);#endif /* #if (!TX_INTERRUPTABLE) */ dev_kfree_skb(skb); return 0;} /* mace_start_xmit *//* ----------------------------------------------------------------------------mace_interrupt The interrupt handler.---------------------------------------------------------------------------- */static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; mace_private *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; int status; int IntrCnt = MACE_MAX_IR_ITERATIONS; if (dev == NULL) { DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n", irq); return IRQ_NONE; } if (lp->tx_irq_disabled) { printk( (lp->tx_irq_disabled? KERN_NOTICE "%s: Interrupt with tx_irq_disabled " "[isr=%02X, imr=%02X]\n": KERN_NOTICE "%s: Re-entering the interrupt handler " "[isr=%02X, imr=%02X]\n"), dev->name, inb(ioaddr + AM2150_MACE_BASE + MACE_IR), inb(ioaddr + AM2150_MACE_BASE + MACE_IMR) ); /* WARNING: MACE_IR has been read! */ return IRQ_NONE; } if (!netif_device_present(dev)) { DEBUG(2, "%s: interrupt from dead card\n", dev->name); return IRQ_NONE; } do { /* WARNING: MACE_IR is a READ/CLEAR port! */ status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); if (status & MACE_IR_RCVINT) { mace_rx(dev, MACE_MAX_RX_ITERATIONS); } if (status & MACE_IR_XMTINT) { unsigned char fifofc; unsigned char xmtrc; unsigned char xmtfs; fifofc = inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC); if ((fifofc & MACE_FIFOFC_XMTFC)==0) { lp->linux_stats.tx_errors++; outb(0xFF, ioaddr + AM2150_XMT_SKIP); } /* Transmit Retry Count (XMTRC, reg 4) */ xmtrc = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC); if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++; lp->mace_stats.xmtrc += (xmtrc & MACE_XMTRC_XMTRC); if ( (xmtfs = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) & MACE_XMTFS_XMTSV /* Transmit Status Valid */ ) { lp->mace_stats.xmtsv++; if (xmtfs & ~MACE_XMTFS_XMTSV) { if (xmtfs & MACE_XMTFS_UFLO) { /* Underflow. Indicates that the Transmit FIFO emptied before the end of frame was reached. */ lp->mace_stats.uflo++; } if (xmtfs & MACE_XMTFS_LCOL) { /* Late Collision */ lp->mace_stats.lcol++; } if (xmtfs & MACE_XMTFS_MORE) { /* MORE than one retry was needed */ lp->mace_stats.more++; } if (xmtfs & MACE_XMTFS_ONE) { /* Exactly ONE retry occurred */ lp->mace_stats.one++; } if (xmtfs & MACE_XMTFS_DEFER) { /* Transmission was defered */ lp->mace_stats.defer++; } if (xmtfs & MACE_XMTFS_LCAR) { /* Loss of carrier */ lp->mace_stats.lcar++; } if (xmtfs & MACE_XMTFS_RTRY) { /* Retry error: transmit aborted after 16 attempts */ lp->mace_stats.rtry++; } } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */ } /* if (xmtfs & MACE_XMTFS_XMTSV) */ lp->linux_stats.tx_packets++; lp->tx_free_frames++; netif_wake_queue(dev); } /* if (status & MACE_IR_XMTINT) */ if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) { if (status & MACE_IR_JAB) { /* Jabber Error. Excessive transmit duration (20-150ms). */ lp->mace_stats.jab++; } if (status & MACE_IR_BABL) { /* Babble Error. >1518 bytes transmitted. */ lp->mace_stats.babl++; } if (status & MACE_IR_CERR) { /* Collision Error. CERR indicates the absence of the Signal Quality Error Test message after a packet transmission. */ lp->mace_stats.cerr++; } if (status & MACE_IR_RCVCCO) { /* Receive Collision Count Overflow; */ lp->mace_stats.rcvcco++; } if (status & MACE_IR_RNTPCO) { /* Runt Packet Count Overflow */ lp->mace_stats.rntpco++; } if (status & MACE_IR_MPCO) { /* Missed Packet Count Overflow */ lp->mace_stats.mpco++; } } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) */ } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt)); return IRQ_HANDLED;} /* mace_interrupt *//* ----------------------------------------------------------------------------mace_rx Receives packets.---------------------------------------------------------------------------- */static int mace_rx(struct net_device *dev, unsigned char RxCnt){ mace_private *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; unsigned char rx_framecnt; unsigned short rx_status; while ( ((rx_framecnt = inb(ioaddr + AM2150_RCV_FRAME_COUNT)) > 0) && (rx_framecnt <= 12) && /* rx_framecnt==0xFF if card is extracted. */ (RxCnt--) ) { rx_status = inw(ioaddr + AM2150_RCV); DEBUG(3, "%s: in mace_rx(), framecnt 0x%X, rx_status" " 0x%X.\n", dev->name, rx_framecnt, rx_status); if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */ lp->linux_stats.rx_errors++; if (rx_status & MACE_RCVFS_OFLO) { lp->mace_stats.oflo++; } if (rx_status & MACE_RCVFS_CLSN) { lp->mace_stats.clsn++; } if (rx_status & MACE_RCVFS_FRAM) { lp->mace_stats.fram++; } if (rx_status & MACE_RCVFS_FCS) { lp->mace_stats.fcs++; } } else { short pkt_len = (rx_status & ~MACE_RCVFS_RCVSTS) - 4; /* Auto Strip is off, always subtract 4 */ struct sk_buff *skb; lp->mace_stats.rfs_rntpc += inb(ioaddr + AM2150_RCV); /* runt packet count */ lp->mace_stats.rfs_rcvcc += inb(ioaddr + AM2150_RCV); /* rcv collision count */ DEBUG(3, " receiving packet size 0x%X rx_status"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -