⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci-skeleton.c

📁 宋宝华的《Linux设备驱动开发详解》第一版的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))			break;		NETDRV_W8_F (ChipCmd,			  (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb);	}	/* G.S.: Re-enable receiver */	/* XXX temporary hack to work around receiver hang */	netdrv_set_rx_mode (dev);	if (tmp_work <= 0)		printk (KERN_WARNING PFX "tx/rx enable wait too long\n");}/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the   field alignments and semantics. */static void netdrv_rx_interrupt (struct net_device *dev,				  struct netdrv_private *tp, void *ioaddr){	unsigned char *rx_ring;	u16 cur_rx;	assert (dev != NULL);	assert (tp != NULL);	assert (ioaddr != NULL);	rx_ring = tp->rx_ring;	cur_rx = tp->cur_rx;	DPRINTK ("%s: In netdrv_rx(), current %4.4x BufAddr %4.4x,"		 " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,		 NETDRV_R16 (RxBufAddr),		 NETDRV_R16 (RxBufPtr), NETDRV_R8 (ChipCmd));	while ((NETDRV_R8 (ChipCmd) & RxBufEmpty) == 0) {		int ring_offset = cur_rx % RX_BUF_LEN;		u32 rx_status;		unsigned int rx_size;		unsigned int pkt_size;		struct sk_buff *skb;		/* read size+status of next frame from DMA ring buffer */		rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));		rx_size = rx_status >> 16;		pkt_size = rx_size - 4;		DPRINTK ("%s:  netdrv_rx() status %4.4x, size %4.4x,"			 " cur %4.4x.\n", dev->name, rx_status,			 rx_size, cur_rx);#if NETDRV_DEBUG > 2		{			int i;			DPRINTK ("%s: Frame contents ", dev->name);			for (i = 0; i < 70; i++)				printk (" %2.2x",					rx_ring[ring_offset + i]);			printk (".\n");		}#endif		/* If Rx err or invalid rx_size/rx_status received		 * (which happens if we get lost in the ring),		 * Rx process gets reset, so we abort any further		 * Rx processing.		 */		if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||		    (!(rx_status & RxStatusOK))) {			netdrv_rx_err (rx_status, dev, tp, ioaddr);			return;		}		/* Malloc up new buffer, compatible with net-2e. */		/* Omit the four octet CRC from the length. */		/* TODO: consider allocating skb's outside of		 * interrupt context, both to speed interrupt processing,		 * and also to reduce the chances of having to		 * drop packets here under memory pressure.		 */		skb = dev_alloc_skb (pkt_size + 2);		if (skb) {			skb->dev = dev;			skb_reserve (skb, 2);	/* 16 byte align the IP fields. */			eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);			skb_put (skb, pkt_size);			skb->protocol = eth_type_trans (skb, dev);			netif_rx (skb);			dev->last_rx = jiffies;			tp->stats.rx_bytes += pkt_size;			tp->stats.rx_packets++;		} else {			printk (KERN_WARNING				"%s: Memory squeeze, dropping packet.\n",				dev->name);			tp->stats.rx_dropped++;		}		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;		NETDRV_W16_F (RxBufPtr, cur_rx - 16);	}	DPRINTK ("%s: Done netdrv_rx(), current %4.4x BufAddr %4.4x,"		 " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,		 NETDRV_R16 (RxBufAddr),		 NETDRV_R16 (RxBufPtr), NETDRV_R8 (ChipCmd));	tp->cur_rx = cur_rx;}static void netdrv_weird_interrupt (struct net_device *dev,				     struct netdrv_private *tp,				     void *ioaddr,				     int status, int link_changed){	printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n",		dev->name, status);	assert (dev != NULL);	assert (tp != NULL);	assert (ioaddr != NULL);	/* Update the error count. */	tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);	NETDRV_W32 (RxMissed, 0);	if ((status & RxUnderrun) && link_changed &&	    (tp->drv_flags & HAS_LNK_CHNG)) {		/* Really link-change on new chips. */		int lpar = NETDRV_R16 (NWayLPAR);		int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040				|| tp->duplex_lock;		if (tp->full_duplex != duplex) {			tp->full_duplex = duplex;			NETDRV_W8 (Cfg9346, Cfg9346_Unlock);			NETDRV_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);			NETDRV_W8 (Cfg9346, Cfg9346_Lock);		}		status &= ~RxUnderrun;	}	/* XXX along with netdrv_rx_err, are we double-counting errors? */	if (status &	    (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))		tp->stats.rx_errors++;	if (status & (PCSTimeout))		tp->stats.rx_length_errors++;	if (status & (RxUnderrun | RxFIFOOver))		tp->stats.rx_fifo_errors++;	if (status & RxOverflow) {		tp->stats.rx_over_errors++;		tp->cur_rx = NETDRV_R16 (RxBufAddr) % RX_BUF_LEN;		NETDRV_W16_F (RxBufPtr, tp->cur_rx - 16);	}	if (status & PCIErr) {		u16 pci_cmd_status;		pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);		printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",			dev->name, pci_cmd_status);	}}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static irqreturn_t netdrv_interrupt (int irq, void *dev_instance,			       struct pt_regs *regs){	struct net_device *dev = (struct net_device *) dev_instance;	struct netdrv_private *tp = dev->priv;	int boguscnt = max_interrupt_work;	void *ioaddr = tp->mmio_addr;	int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */	int handled = 0;	spin_lock (&tp->lock);	do {		status = NETDRV_R16 (IntrStatus);		/* h/w no longer present (hotplug?) or major error, bail */		if (status == 0xFFFF)			break;		handled = 1;		/* Acknowledge all of the current interrupt sources ASAP */		NETDRV_W16_F (IntrStatus, status);		DPRINTK ("%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",				dev->name, status,				NETDRV_R16 (IntrStatus));		if ((status &		     (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |		      RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)			break;		/* Check uncommon events with one test. */		if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |		  	      RxFIFOOver | TxErr | RxErr))			netdrv_weird_interrupt (dev, tp, ioaddr,						 status, link_changed);		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */			netdrv_rx_interrupt (dev, tp, ioaddr);		if (status & (TxOK | TxErr))			netdrv_tx_interrupt (dev, tp, ioaddr);		boguscnt--;	} while (boguscnt > 0);	if (boguscnt <= 0) {		printk (KERN_WARNING			"%s: Too much work at interrupt, "			"IntrStatus=0x%4.4x.\n", dev->name,			status);		/* Clear all interrupt sources. */		NETDRV_W16 (IntrStatus, 0xffff);	}	spin_unlock (&tp->lock);	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",		 dev->name, NETDRV_R16 (IntrStatus));	return IRQ_RETVAL(handled);}static int netdrv_close (struct net_device *dev){	struct netdrv_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	unsigned long flags;	DPRINTK ("ENTER\n");	netif_stop_queue (dev);	DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",			dev->name, NETDRV_R16 (IntrStatus));	del_timer_sync (&tp->timer);	spin_lock_irqsave (&tp->lock, flags);	/* Stop the chip's Tx and Rx DMA processes. */	NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear));	/* Disable interrupts by clearing the interrupt mask. */	NETDRV_W16 (IntrMask, 0x0000);	/* Update the error counts. */	tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);	NETDRV_W32 (RxMissed, 0);	spin_unlock_irqrestore (&tp->lock, flags);	synchronize_irq ();	free_irq (dev->irq, dev);	netdrv_tx_clear (tp);	pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,			    tp->rx_ring, tp->rx_ring_dma);	pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,			    tp->tx_bufs, tp->tx_bufs_dma);	tp->rx_ring = NULL;	tp->tx_bufs = NULL;	/* Green! Put the chip in low-power mode. */	NETDRV_W8 (Cfg9346, Cfg9346_Unlock);	NETDRV_W8 (Config1, 0x03);	NETDRV_W8 (Cfg9346, Cfg9346_Lock);	DPRINTK ("EXIT\n");	return 0;}static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){	struct netdrv_private *tp = dev->priv;	struct mii_ioctl_data *data = if_mii(rq);	unsigned long flags;	int rc = 0;	DPRINTK ("ENTER\n");	switch (cmd) {	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */		data->phy_id = tp->phys[0] & 0x3f;		/* Fall Through */	case SIOCGMIIREG:		/* Read MII PHY register. */		spin_lock_irqsave (&tp->lock, flags);		data->val_out = mdio_read (dev, data->phy_id & 0x1f, data->reg_num & 0x1f);		spin_unlock_irqrestore (&tp->lock, flags);		break;	case SIOCSMIIREG:		/* Write MII PHY register. */		if (!capable (CAP_NET_ADMIN)) {			rc = -EPERM;			break;		}		spin_lock_irqsave (&tp->lock, flags);		mdio_write (dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);		spin_unlock_irqrestore (&tp->lock, flags);		break;	default:		rc = -EOPNOTSUPP;		break;	}	DPRINTK ("EXIT, returning %d\n", rc);	return rc;}static struct net_device_stats *netdrv_get_stats (struct net_device *dev){	struct netdrv_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	DPRINTK ("ENTER\n");	assert (tp != NULL);	if (netif_running(dev)) {		unsigned long flags;		spin_lock_irqsave (&tp->lock, flags);		tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);		NETDRV_W32 (RxMissed, 0);		spin_unlock_irqrestore (&tp->lock, flags);	}	DPRINTK ("EXIT\n");	return &tp->stats;}/* Set or clear the multicast filter for this adaptor.   This routine is not state sensitive and need not be SMP locked. */static void netdrv_set_rx_mode (struct net_device *dev){	struct netdrv_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	u32 mc_filter[2];	/* Multicast hash filter */	int i, rx_mode;	u32 tmp;	DPRINTK ("ENTER\n");	DPRINTK ("%s:   netdrv_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",			dev->name, dev->flags, NETDRV_R32 (RxConfig));	/* Note: do not reorder, GCC is clever about common statements. */	if (dev->flags & IFF_PROMISC) {		/* Unconditionally log net taps. */		printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",			dev->name);		rx_mode =		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |		    AcceptAllPhys;		mc_filter[1] = mc_filter[0] = 0xffffffff;	} else if ((dev->mc_count > multicast_filter_limit)		   || (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter perfectly -- accept all multicasts. */		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;		mc_filter[1] = mc_filter[0] = 0xffffffff;	} else {		struct dev_mc_list *mclist;		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;		mc_filter[1] = mc_filter[0] = 0;		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;		     i++, mclist = mclist->next) {			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);		}	}	/* if called from irq handler, lock already acquired */	if (!in_irq ())		spin_lock_irq (&tp->lock);	/* We can safely update without stopping the chip. */	tmp = netdrv_rx_config | rx_mode |		(NETDRV_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);	NETDRV_W32_F (RxConfig, tmp);	NETDRV_W32_F (MAR0 + 0, mc_filter[0]);	NETDRV_W32_F (MAR0 + 4, mc_filter[1]);	if (!in_irq ())		spin_unlock_irq (&tp->lock);	DPRINTK ("EXIT\n");}#ifdef CONFIG_PMstatic int netdrv_suspend (struct pci_dev *pdev, pm_message_t state){	struct net_device *dev = pci_get_drvdata (pdev);	struct netdrv_private *tp = dev->priv;	void *ioaddr = tp->mmio_addr;	unsigned long flags;	if (!netif_running(dev))		return 0;	netif_device_detach (dev);	spin_lock_irqsave (&tp->lock, flags);	/* Disable interrupts, stop Tx and Rx. */	NETDRV_W16 (IntrMask, 0x0000);	NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear));	/* Update the error counts. */	tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);	NETDRV_W32 (RxMissed, 0);	spin_unlock_irqrestore (&tp->lock, flags);	pci_save_state (pdev);	pci_set_power_state (pdev, PCI_D3hot);	return 0;}static int netdrv_resume (struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata (pdev);	struct netdrv_private *tp = dev->priv;	if (!netif_running(dev))		return 0;	pci_set_power_state (pdev, PCI_D0);	pci_restore_state (pdev);	netif_device_attach (dev);	netdrv_hw_start (dev);	return 0;}#endif /* CONFIG_PM */static struct pci_driver netdrv_pci_driver = {	.name		= MODNAME,	.id_table	= netdrv_pci_tbl,	.probe		= netdrv_init_one,	.remove		= __devexit_p(netdrv_remove_one),#ifdef CONFIG_PM	.suspend	= netdrv_suspend,	.resume		= netdrv_resume,#endif /* CONFIG_PM */};static int __init netdrv_init_module (void){/* when a module, this is printed whether or not devices are found in probe */#ifdef MODULE	printk(version);#endif	return pci_module_init (&netdrv_pci_driver);}static void __exit netdrv_cleanup_module (void){	pci_unregister_driver (&netdrv_pci_driver);}module_init(netdrv_init_module);module_exit(netdrv_cleanup_module);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -