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

📄 smc911x.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n",			dev->name, __FUNCTION__);		return -ETIMEDOUT;	}	return 0;}static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev,													int cmd, int addr){	unsigned long ioaddr = dev->base_addr;	int ret;	if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)		return ret;	SMC_SET_E2P_CMD(E2P_CMD_EPC_BUSY_ |		((cmd) & (0x7<<28)) |		((addr) & 0xFF));	return 0;}static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev,													u8 *data){	unsigned long ioaddr = dev->base_addr;	int ret;	if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)		return ret;	*data = SMC_GET_E2P_DATA();	return 0;}static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev,													 u8 data){	unsigned long ioaddr = dev->base_addr;	int ret;	if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)		return ret;	SMC_SET_E2P_DATA(data);	return 0;}static int smc911x_ethtool_geteeprom(struct net_device *dev,									  struct ethtool_eeprom *eeprom, u8 *data){	u8 eebuf[SMC911X_EEPROM_LEN];	int i, ret;	for(i=0;i<SMC911X_EEPROM_LEN;i++) {		if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ_, i ))!=0)			return ret;		if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0)			return ret;		}	memcpy(data, eebuf+eeprom->offset, eeprom->len);	return 0;}static int smc911x_ethtool_seteeprom(struct net_device *dev,									   struct ethtool_eeprom *eeprom, u8 *data){	int i, ret;	/* Enable erase */	if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN_, 0 ))!=0)		return ret;	for(i=eeprom->offset;i<(eeprom->offset+eeprom->len);i++) {		/* erase byte */		if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE_, i ))!=0)			return ret;		/* write byte */		if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0)			 return ret;		if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0)			return ret;		}	 return 0;}static int smc911x_ethtool_geteeprom_len(struct net_device *dev){	 return SMC911X_EEPROM_LEN;}static const struct ethtool_ops smc911x_ethtool_ops = {	.get_settings	 = smc911x_ethtool_getsettings,	.set_settings	 = smc911x_ethtool_setsettings,	.get_drvinfo	 = smc911x_ethtool_getdrvinfo,	.get_msglevel	 = smc911x_ethtool_getmsglevel,	.set_msglevel	 = smc911x_ethtool_setmsglevel,	.nway_reset = smc911x_ethtool_nwayreset,	.get_link	 = ethtool_op_get_link,	.get_regs_len	 = smc911x_ethtool_getregslen,	.get_regs	 = smc911x_ethtool_getregs,	.get_eeprom_len = smc911x_ethtool_geteeprom_len,	.get_eeprom = smc911x_ethtool_geteeprom,	.set_eeprom = smc911x_ethtool_seteeprom,};/* * smc911x_findirq * * This routine has a simple purpose -- make the SMC chip generate an * interrupt, so an auto-detect routine can detect it, and find the IRQ, */static int __init smc911x_findirq(unsigned long ioaddr){	int timeout = 20;	unsigned long cookie;	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);	cookie = probe_irq_on();	/*	 * Force a SW interrupt	 */	SMC_SET_INT_EN(INT_EN_SW_INT_EN_);	/*	 * Wait until positive that the interrupt has been generated	 */	do {		int int_status;		udelay(10);		int_status = SMC_GET_INT_EN();		if (int_status & INT_EN_SW_INT_EN_)			 break;		/* got the interrupt */	} while (--timeout);	/*	 * there is really nothing that I can do here if timeout fails,	 * as autoirq_report will return a 0 anyway, which is what I	 * want in this case.	 Plus, the clean up is needed in both	 * cases.	 */	/* and disable all interrupts again */	SMC_SET_INT_EN(0);	/* and return what I found */	return probe_irq_off(cookie);}/* * Function: smc911x_probe(unsigned long ioaddr) * * Purpose: *	 Tests to see if a given ioaddr points to an SMC911x chip. *	 Returns a 0 on success * * Algorithm: *	 (1) see if the endian word is OK *	 (1) see if I recognize the chip ID in the appropriate register * * Here I do typical initialization tasks. * * o  Initialize the structure if needed * o  print out my vanity message if not done so already * o  print out what type of hardware is detected * o  print out the ethernet address * o  find the IRQ * o  set up my private data * o  configure the dev structure with my subroutines * o  actually GRAB the irq. * o  GRAB the region */static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr){	struct smc911x_local *lp = netdev_priv(dev);	int i, retval;	unsigned int val, chip_id, revision;	const char *version_string;	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	/* First, see if the endian word is recognized */	val = SMC_GET_BYTE_TEST();	DBG(SMC_DEBUG_MISC, "%s: endian probe returned 0x%04x\n", CARDNAME, val);	if (val != 0x87654321) {		printk(KERN_ERR "Invalid chip endian 0x08%x\n",val);		retval = -ENODEV;		goto err_out;	}	/*	 * check if the revision register is something that I	 * recognize.	These might need to be added to later,	 * as future revisions could be added.	 */	chip_id = SMC_GET_PN();	DBG(SMC_DEBUG_MISC, "%s: id probe returned 0x%04x\n", CARDNAME, chip_id);	for(i=0;chip_ids[i].id != 0; i++) {		if (chip_ids[i].id == chip_id) break;	}	if (!chip_ids[i].id) {		printk(KERN_ERR "Unknown chip ID %04x\n", chip_id);		retval = -ENODEV;		goto err_out;	}	version_string = chip_ids[i].name;	revision = SMC_GET_REV();	DBG(SMC_DEBUG_MISC, "%s: revision = 0x%04x\n", CARDNAME, revision);	/* At this point I'll assume that the chip is an SMC911x. */	DBG(SMC_DEBUG_MISC, "%s: Found a %s\n", CARDNAME, chip_ids[i].name);	/* Validate the TX FIFO size requested */	if ((tx_fifo_kb < 2) || (tx_fifo_kb > 14)) {		printk(KERN_ERR "Invalid TX FIFO size requested %d\n", tx_fifo_kb);		retval = -EINVAL;		goto err_out;	}	/* fill in some of the fields */	dev->base_addr = ioaddr;	lp->version = chip_ids[i].id;	lp->revision = revision;	lp->tx_fifo_kb = tx_fifo_kb;	/* Reverse calculate the RX FIFO size from the TX */	lp->tx_fifo_size=(lp->tx_fifo_kb<<10) - 512;	lp->rx_fifo_size= ((0x4000 - 512 - lp->tx_fifo_size) / 16) * 15;	/* Set the automatic flow control values */	switch(lp->tx_fifo_kb) {		/*		 *	 AFC_HI is about ((Rx Data Fifo Size)*2/3)/64		 *	 AFC_LO is AFC_HI/2		 *	 BACK_DUR is about 5uS*(AFC_LO) rounded down		 */		case 2:/* 13440 Rx Data Fifo Size */			lp->afc_cfg=0x008C46AF;break;		case 3:/* 12480 Rx Data Fifo Size */			lp->afc_cfg=0x0082419F;break;		case 4:/* 11520 Rx Data Fifo Size */			lp->afc_cfg=0x00783C9F;break;		case 5:/* 10560 Rx Data Fifo Size */			lp->afc_cfg=0x006E374F;break;		case 6:/* 9600 Rx Data Fifo Size */			lp->afc_cfg=0x0064328F;break;		case 7:/* 8640 Rx Data Fifo Size */			lp->afc_cfg=0x005A2D7F;break;		case 8:/* 7680 Rx Data Fifo Size */			lp->afc_cfg=0x0050287F;break;		case 9:/* 6720 Rx Data Fifo Size */			lp->afc_cfg=0x0046236F;break;		case 10:/* 5760 Rx Data Fifo Size */			lp->afc_cfg=0x003C1E6F;break;		case 11:/* 4800 Rx Data Fifo Size */			lp->afc_cfg=0x0032195F;break;		/*		 *	 AFC_HI is ~1520 bytes less than RX Data Fifo Size		 *	 AFC_LO is AFC_HI/2		 *	 BACK_DUR is about 5uS*(AFC_LO) rounded down		 */		case 12:/* 3840 Rx Data Fifo Size */			lp->afc_cfg=0x0024124F;break;		case 13:/* 2880 Rx Data Fifo Size */			lp->afc_cfg=0x0015073F;break;		case 14:/* 1920 Rx Data Fifo Size */			lp->afc_cfg=0x0006032F;break;		 default:			 PRINTK("%s: ERROR -- no AFC_CFG setting found",				dev->name);			 break;	}	DBG(SMC_DEBUG_MISC | SMC_DEBUG_TX | SMC_DEBUG_RX,		"%s: tx_fifo %d rx_fifo %d afc_cfg 0x%08x\n", CARDNAME,		lp->tx_fifo_size, lp->rx_fifo_size, lp->afc_cfg);	spin_lock_init(&lp->lock);	/* Get the MAC address */	SMC_GET_MAC_ADDR(dev->dev_addr);	/* now, reset the chip, and put it into a known state */	smc911x_reset(dev);	/*	 * If dev->irq is 0, then the device has to be banged on to see	 * what the IRQ is.	 *	 * Specifying an IRQ is done with the assumption that the user knows	 * what (s)he is doing.  No checking is done!!!!	 */	if (dev->irq < 1) {		int trials;		trials = 3;		while (trials--) {			dev->irq = smc911x_findirq(ioaddr);			if (dev->irq)				break;			/* kick the card and try again */			smc911x_reset(dev);		}	}	if (dev->irq == 0) {		printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",			dev->name);		retval = -ENODEV;		goto err_out;	}	dev->irq = irq_canonicalize(dev->irq);	/* Fill in the fields of the device structure with ethernet values. */	ether_setup(dev);	dev->open = smc911x_open;	dev->stop = smc911x_close;	dev->hard_start_xmit = smc911x_hard_start_xmit;	dev->tx_timeout = smc911x_timeout;	dev->watchdog_timeo = msecs_to_jiffies(watchdog);	dev->set_multicast_list = smc911x_set_multicast_list;	dev->ethtool_ops = &smc911x_ethtool_ops;#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller = smc911x_poll_controller;#endif	INIT_WORK(&lp->phy_configure, smc911x_phy_configure);	lp->mii.phy_id_mask = 0x1f;	lp->mii.reg_num_mask = 0x1f;	lp->mii.force_media = 0;	lp->mii.full_duplex = 0;	lp->mii.dev = dev;	lp->mii.mdio_read = smc911x_phy_read;	lp->mii.mdio_write = smc911x_phy_write;	/*	 * Locate the phy, if any.	 */	smc911x_phy_detect(dev);	/* Set default parameters */	lp->msg_enable = NETIF_MSG_LINK;	lp->ctl_rfduplx = 1;	lp->ctl_rspeed = 100;	/* Grab the IRQ */	retval = request_irq(dev->irq, &smc911x_interrupt,			IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev);	if (retval)		goto err_out;#ifdef SMC_USE_DMA	lp->rxdma = SMC_DMA_REQUEST(dev, smc911x_rx_dma_irq);	lp->txdma = SMC_DMA_REQUEST(dev, smc911x_tx_dma_irq);	lp->rxdma_active = 0;	lp->txdma_active = 0;	dev->dma = lp->rxdma;#endif	retval = register_netdev(dev);	if (retval == 0) {		/* now, print out the card info, in a short format.. */		printk("%s: %s (rev %d) at %#lx IRQ %d",			dev->name, version_string, lp->revision,			dev->base_addr, dev->irq);#ifdef SMC_USE_DMA		if (lp->rxdma != -1)			printk(" RXDMA %d ", lp->rxdma);		if (lp->txdma != -1)			printk("TXDMA %d", lp->txdma);#endif		printk("\n");		if (!is_valid_ether_addr(dev->dev_addr)) {			printk("%s: Invalid ethernet MAC address. Please "					"set using ifconfig\n", dev->name);		} else {			/* Print the Ethernet address */			printk("%s: Ethernet addr: ", dev->name);			for (i = 0; i < 5; i++)				printk("%2.2x:", dev->dev_addr[i]);			printk("%2.2x\n", dev->dev_addr[5]);		}		if (lp->phy_type == 0) {			PRINTK("%s: No PHY found\n", dev->name);		} else if ((lp->phy_type & ~0xff) == LAN911X_INTERNAL_PHY_ID) {			PRINTK("%s: LAN911x Internal PHY\n", dev->name);		} else {			PRINTK("%s: External PHY 0x%08x\n", dev->name, lp->phy_type);		}	}err_out:#ifdef SMC_USE_DMA	if (retval) {		if (lp->rxdma != -1) {			SMC_DMA_FREE(dev, lp->rxdma);		}		if (lp->txdma != -1) {			SMC_DMA_FREE(dev, lp->txdma);		}	}#endif	return retval;}/* * smc911x_init(void) * *	  Output: *	 0 --> there is a device *	 anything else, error */static int smc911x_drv_probe(struct platform_device *pdev){	struct net_device *ndev;	struct resource *res;	struct smc911x_local *lp;	unsigned int *addr;	int ret;	DBG(SMC_DEBUG_FUNC, "--> %s\n",  __FUNCTION__);	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (!res) {		ret = -ENODEV;		goto out;	}	/*	 * Request the regions.	 */	if (!request_mem_region(res->start, SMC911X_IO_EXTENT, CARDNAME)) {		 ret = -EBUSY;		 goto out;	}	ndev = alloc_etherdev(sizeof(struct smc911x_local));	if (!ndev) {		printk("%s: could not allocate device.\n", CARDNAME);		ret = -ENOMEM;		goto release_1;	}	SET_NETDEV_DEV(ndev, &pdev->dev);	ndev->dma = (unsigned char)-1;	ndev->irq = platform_get_irq(pdev, 0);	lp = netdev_priv(ndev);	lp->netdev = ndev;	addr = ioremap(res->start, SMC911X_IO_EXTENT);	if (!addr) {		ret = -ENOMEM;		goto release_both;	}	platform_set_drvdata(pdev, ndev);	ret = smc911x_probe(ndev, (unsigned long)addr);	if (ret != 0) {		platform_set_drvdata(pdev, NULL);		iounmap(addr);release_both:		free_netdev(ndev);release_1:		release_mem_region(res->start, SMC911X_IO_EXTENT);out:		printk("%s: not found (%d).\n", CARDNAME, ret);	}#ifdef SMC_USE_DMA	else {		lp->physaddr = res->start;		lp->dev = &pdev->dev;	}#endif	return ret;}static int smc911x_drv_remove(struct platform_device *pdev){	struct net_device *ndev = platform_get_drvdata(pdev);	struct resource *res;	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);	platform_set_drvdata(pdev, NULL);	unregister_netdev(ndev);	free_irq(ndev->irq, ndev);#ifdef SMC_USE_DMA	{		struct smc911x_local *lp = netdev_priv(ndev);		if (lp->rxdma != -1) {			SMC_DMA_FREE(dev, lp->rxdma);		}		if (lp->txdma != -1) {			SMC_DMA_FREE(dev, lp->txdma);		}	}#endif	iounmap((void *)ndev->base_addr);	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	release_mem_region(res->start, SMC911X_IO_EXTENT);	free_netdev(ndev);	return 0;}static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state){	struct net_device *ndev = platform_get_drvdata(dev);	unsigned long ioaddr = ndev->base_addr;	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);	if (ndev) {		if (netif_running(ndev)) {			netif_device_detach(ndev);			smc911x_shutdown(ndev);#if POWER_DOWN			/* Set D2 - Energy detect only setting */			SMC_SET_PMT_CTRL(2<<12);#endif		}	}	return 0;}static int smc911x_drv_resume(struct platform_device *dev){	struct net_device *ndev = platform_get_drvdata(dev);	DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);	if (ndev) {		struct smc911x_local *lp = netdev_priv(ndev);		if (netif_running(ndev)) {			smc911x_reset(ndev);			smc911x_enable(ndev);			if (lp->phy_type != 0)				smc911x_phy_configure(&lp->phy_configure);			netif_device_attach(ndev);		}	}	return 0;}static struct platform_driver smc911x_driver = {	.probe		 = smc911x_drv_probe,	.remove	 = smc911x_drv_remove,	.suspend	 = smc911x_drv_suspend,	.resume	 = smc911x_drv_resume,	.driver	 = {		.name	 = CARDNAME,	},};static int __init smc911x_init(void){	return platform_driver_register(&smc911x_driver);}static void __exit smc911x_cleanup(void){	platform_driver_unregister(&smc911x_driver);}module_init(smc911x_init);module_exit(smc911x_cleanup);

⌨️ 快捷键说明

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