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

📄 pci-skeleton.c

📁 宋宝华的《Linux设备驱动开发详解》第一版的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static int read_eeprom (void *ioaddr, int location, int addr_len);static int netdrv_open (struct net_device *dev);static int mdio_read (struct net_device *dev, int phy_id, int location);static void mdio_write (struct net_device *dev, int phy_id, int location,			int val);static void netdrv_timer (unsigned long data);static void netdrv_tx_timeout (struct net_device *dev);static void netdrv_init_ring (struct net_device *dev);static int netdrv_start_xmit (struct sk_buff *skb,			       struct net_device *dev);static irqreturn_t netdrv_interrupt (int irq, void *dev_instance,			       struct pt_regs *regs);static int netdrv_close (struct net_device *dev);static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);static struct net_device_stats *netdrv_get_stats (struct net_device *dev);static void netdrv_set_rx_mode (struct net_device *dev);static void netdrv_hw_start (struct net_device *dev);#ifdef USE_IO_OPS#define NETDRV_R8(reg)		inb (((unsigned long)ioaddr) + (reg))#define NETDRV_R16(reg)		inw (((unsigned long)ioaddr) + (reg))#define NETDRV_R32(reg)		((unsigned long) inl (((unsigned long)ioaddr) + (reg)))#define NETDRV_W8(reg, val8)	outb ((val8), ((unsigned long)ioaddr) + (reg))#define NETDRV_W16(reg, val16)	outw ((val16), ((unsigned long)ioaddr) + (reg))#define NETDRV_W32(reg, val32)	outl ((val32), ((unsigned long)ioaddr) + (reg))#define NETDRV_W8_F		NETDRV_W8#define NETDRV_W16_F		NETDRV_W16#define NETDRV_W32_F		NETDRV_W32#undef readb#undef readw#undef readl#undef writeb#undef writew#undef writel#define readb(addr) inb((unsigned long)(addr))#define readw(addr) inw((unsigned long)(addr))#define readl(addr) inl((unsigned long)(addr))#define writeb(val,addr) outb((val),(unsigned long)(addr))#define writew(val,addr) outw((val),(unsigned long)(addr))#define writel(val,addr) outl((val),(unsigned long)(addr))#else/* write MMIO register, with flush *//* Flush avoids rtl8139 bug w/ posted MMIO writes */#define NETDRV_W8_F(reg, val8)	do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0)#define NETDRV_W16_F(reg, val16)	do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0)#define NETDRV_W32_F(reg, val32)	do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)#if MMIO_FLUSH_AUDIT_COMPLETE/* write MMIO register */#define NETDRV_W8(reg, val8)	writeb ((val8), ioaddr + (reg))#define NETDRV_W16(reg, val16)	writew ((val16), ioaddr + (reg))#define NETDRV_W32(reg, val32)	writel ((val32), ioaddr + (reg))#else/* write MMIO register, then flush */#define NETDRV_W8		NETDRV_W8_F#define NETDRV_W16		NETDRV_W16_F#define NETDRV_W32		NETDRV_W32_F#endif /* MMIO_FLUSH_AUDIT_COMPLETE *//* read MMIO register */#define NETDRV_R8(reg)		readb (ioaddr + (reg))#define NETDRV_R16(reg)		readw (ioaddr + (reg))#define NETDRV_R32(reg)		((unsigned long) readl (ioaddr + (reg)))#endif /* USE_IO_OPS */static const u16 netdrv_intr_mask =	PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |	TxErr | TxOK | RxErr | RxOK;static const unsigned int netdrv_rx_config =	  RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap |	  (RX_FIFO_THRESH << RxCfgFIFOShift) |	  (RX_DMA_BURST << RxCfgDMAShift);static int __devinit netdrv_init_board (struct pci_dev *pdev,					 struct net_device **dev_out,					 void **ioaddr_out){	void *ioaddr = NULL;	struct net_device *dev;	struct netdrv_private *tp;	int rc, i;	u32 pio_start, pio_end, pio_flags, pio_len;	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;	u32 tmp;	DPRINTK ("ENTER\n");	assert (pdev != NULL);	assert (ioaddr_out != NULL);	*ioaddr_out = NULL;	*dev_out = NULL;	/* dev zeroed in alloc_etherdev */	dev = alloc_etherdev (sizeof (*tp));	if (dev == NULL) {		printk (KERN_ERR PFX "unable to alloc new ethernet\n");		DPRINTK ("EXIT, returning -ENOMEM\n");		return -ENOMEM;	}	SET_MODULE_OWNER(dev);	SET_NETDEV_DEV(dev, &pdev->dev);	tp = dev->priv;	/* enable device (incl. PCI PM wakeup), and bus-mastering */	rc = pci_enable_device (pdev);	if (rc)		goto err_out;	pio_start = pci_resource_start (pdev, 0);	pio_end = pci_resource_end (pdev, 0);	pio_flags = pci_resource_flags (pdev, 0);	pio_len = pci_resource_len (pdev, 0);	mmio_start = pci_resource_start (pdev, 1);	mmio_end = pci_resource_end (pdev, 1);	mmio_flags = pci_resource_flags (pdev, 1);	mmio_len = pci_resource_len (pdev, 1);	/* set this immediately, we need to know before	 * we talk to the chip directly */	DPRINTK("PIO region size == 0x%02X\n", pio_len);	DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);	/* make sure PCI base addr 0 is PIO */	if (!(pio_flags & IORESOURCE_IO)) {		printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");		rc = -ENODEV;		goto err_out;	}	/* make sure PCI base addr 1 is MMIO */	if (!(mmio_flags & IORESOURCE_MEM)) {		printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");		rc = -ENODEV;		goto err_out;	}	/* check for weird/broken PCI region reporting */	if ((pio_len < NETDRV_MIN_IO_SIZE) ||	    (mmio_len < NETDRV_MIN_IO_SIZE)) {		printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");		rc = -ENODEV;		goto err_out;	}	rc = pci_request_regions (pdev, "pci-skeleton");	if (rc)		goto err_out;	pci_set_master (pdev);#ifdef USE_IO_OPS	ioaddr = (void *) pio_start;#else	/* ioremap MMIO region */	ioaddr = ioremap (mmio_start, mmio_len);	if (ioaddr == NULL) {		printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");		rc = -EIO;		goto err_out_free_res;	}#endif /* USE_IO_OPS */	/* Soft reset the chip. */	NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear) | CmdReset);	/* Check that the chip has finished the reset. */	for (i = 1000; i > 0; i--)		if ((NETDRV_R8 (ChipCmd) & CmdReset) == 0)			break;		else			udelay (10);	/* Bring the chip out of low-power mode. */	/* <insert device-specific code here> */#ifndef USE_IO_OPS	/* sanity checks -- ensure PIO and MMIO registers agree */	assert (inb (pio_start+Config0) == readb (ioaddr+Config0));	assert (inb (pio_start+Config1) == readb (ioaddr+Config1));	assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig));	assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));#endif /* !USE_IO_OPS */	/* identify chip attached to board */	tmp = NETDRV_R8 (ChipVersion);	for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--)		if (tmp == rtl_chip_info[i].version) {			tp->chipset = i;			goto match;		}	/* if unknown chip, assume array element #0, original RTL-8139 in this case */	printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n",		pci_name(pdev));	printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pci_name(pdev), NETDRV_R32 (TxConfig));	tp->chipset = 0;match:	DPRINTK ("chipset id (%d) == index %d, '%s'\n",		tmp,		tp->chipset,		rtl_chip_info[tp->chipset].name);	i = register_netdev (dev);	if (i)		goto err_out_unmap;	DPRINTK ("EXIT, returning 0\n");	*ioaddr_out = ioaddr;	*dev_out = dev;	return 0;err_out_unmap:#ifndef USE_IO_OPS	iounmap(ioaddr);err_out_free_res:#endif	pci_release_regions (pdev);err_out:	free_netdev (dev);	DPRINTK ("EXIT, returning %d\n", rc);	return rc;}static int __devinit netdrv_init_one (struct pci_dev *pdev,				       const struct pci_device_id *ent){	struct net_device *dev = NULL;	struct netdrv_private *tp;	int i, addr_len, option;	void *ioaddr = NULL;	static int board_idx = -1;/* when built into the kernel, we only print version if device is found */#ifndef MODULE	static int printed_version;	if (!printed_version++)		printk(version);#endif	DPRINTK ("ENTER\n");	assert (pdev != NULL);	assert (ent != NULL);	board_idx++;	i = netdrv_init_board (pdev, &dev, &ioaddr);	if (i < 0) {		DPRINTK ("EXIT, returning %d\n", i);		return i;	}	tp = dev->priv;	assert (ioaddr != NULL);	assert (dev != NULL);	assert (tp != NULL);	addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;	for (i = 0; i < 3; i++)		((u16 *) (dev->dev_addr))[i] =		    le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));	/* The Rtl8139-specific entries in the device structure. */	dev->open = netdrv_open;	dev->hard_start_xmit = netdrv_start_xmit;	dev->stop = netdrv_close;	dev->get_stats = netdrv_get_stats;	dev->set_multicast_list = netdrv_set_rx_mode;	dev->do_ioctl = netdrv_ioctl;	dev->tx_timeout = netdrv_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	dev->irq = pdev->irq;	dev->base_addr = (unsigned long) ioaddr;	/* dev->priv/tp zeroed and aligned in alloc_etherdev */	tp = dev->priv;	/* note: tp->chipset set in netdrv_init_board */	tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |			PCI_COMMAND_MASTER | NETDRV_CAPS;	tp->pci_dev = pdev;	tp->board = ent->driver_data;	tp->mmio_addr = ioaddr;	spin_lock_init(&tp->lock);	pci_set_drvdata(pdev, dev);	tp->phys[0] = 32;	printk (KERN_INFO "%s: %s at 0x%lx, "		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "		"IRQ %d\n",		dev->name,		board_info[ent->driver_data].name,		dev->base_addr,		dev->dev_addr[0], dev->dev_addr[1],		dev->dev_addr[2], dev->dev_addr[3],		dev->dev_addr[4], dev->dev_addr[5],		dev->irq);	printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",		dev->name, rtl_chip_info[tp->chipset].name);	/* Put the chip into low-power mode. */	NETDRV_W8_F (Cfg9346, Cfg9346_Unlock);	/* The lower four bits are the media type. */	option = (board_idx > 7) ? 0 : media[board_idx];	if (option > 0) {		tp->full_duplex = (option & 0x200) ? 1 : 0;		tp->default_port = option & 15;		if (tp->default_port)			tp->medialock = 1;	}	if (tp->full_duplex) {		printk (KERN_INFO			"%s: Media type forced to Full Duplex.\n",			dev->name);		mdio_write (dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL);		tp->duplex_lock = 1;	}	DPRINTK ("EXIT - returning 0\n");	return 0;}static void __devexit netdrv_remove_one (struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata (pdev);	struct netdrv_private *np;	DPRINTK ("ENTER\n");	assert (dev != NULL);	np = dev->priv;	assert (np != NULL);	unregister_netdev (dev);#ifndef USE_IO_OPS	iounmap (np->mmio_addr);#endif /* !USE_IO_OPS */	pci_release_regions (pdev);	free_netdev (dev);	pci_set_drvdata (pdev, NULL);	pci_disable_device (pdev);	DPRINTK ("EXIT\n");}/* Serial EEPROM section. *//*  EEPROM_Ctrl bits. */#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */#define EE_CS			0x08	/* EEPROM chip select. */#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */#define EE_WRITE_0		0x00#define EE_WRITE_1		0x02#define EE_DATA_READ	0x01	/* EEPROM chip data out. */#define EE_ENB			(0x80 | EE_CS)/* Delay between EEPROM clock transitions.   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */#define eeprom_delay()	readl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD	(5)#define EE_READ_CMD		(6)#define EE_ERASE_CMD	(7)static int __devinit read_eeprom (void *ioaddr, int location, int addr_len){	int i;	unsigned retval = 0;	void *ee_addr = ioaddr + Cfg9346;	int read_cmd = location | (EE_READ_CMD << addr_len);	DPRINTK ("ENTER\n");	writeb (EE_ENB & ~EE_CS, ee_addr);	writeb (EE_ENB, ee_addr);	eeprom_delay ();	/* Shift the read command bits out. */	for (i = 4 + addr_len; i >= 0; i--) {		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;		writeb (EE_ENB | dataval, ee_addr);		eeprom_delay ();		writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);		eeprom_delay ();	}	writeb (EE_ENB, ee_addr);	eeprom_delay ();	for (i = 16; i > 0; i--) {		writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);		eeprom_delay ();		retval =		    (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :				     0);		writeb (EE_ENB, ee_addr);		eeprom_delay ();	}	/* Terminate the EEPROM access. */	writeb (~EE_CS, ee_addr);	eeprom_delay ();	DPRINTK ("EXIT - returning %d\n", retval);	return retval;}/* MII serial management: mostly bogus for now. *//* Read and write the MII management registers using software-generated   serial MDIO protocol.   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually   met by back-to-back PCI I/O cycles, but we insert a delay to avoid   "overclocking" issues. */#define MDIO_DIR		0x80#define MDIO_DATA_OUT	0x04#define MDIO_DATA_IN	0x02#define MDIO_CLK		0x01#define MDIO_WRITE0 (MDIO_DIR)#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)#define mdio_delay()	readb(mdio_addr)static char mii_2_8139_map[8] = {	BasicModeCtrl,	BasicModeStatus,	0,	0,	NWayAdvert,	NWayLPAR,	NWayExpansion,	0};/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_sync (void *mdio_addr){	int i;	DPRINTK ("ENTER\n");	for (i = 32; i >= 0; i--) {		writeb (MDIO_WRITE1, mdio_addr);		mdio_delay ();		writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);		mdio_delay ();	}	DPRINTK ("EXIT\n");}static int mdio_read (struct net_device *dev, int phy_id, int location){	struct netdrv_private *tp = dev->priv;	void *mdio_addr = tp->mmio_addr + Config4;	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int retval = 0;	int i;

⌨️ 快捷键说明

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