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

📄 smc91x.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/*	 * Wait until positive that the interrupt has been generated	 */	do {		int int_status;		udelay(10);		int_status = SMC_GET_INT();		if (int_status & IM_ALLOC_INT)			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_MASK(0);	/* and return what I found */	return probe_irq_off(cookie);}/* * Function: smc_probe(unsigned long ioaddr) * * Purpose: *	Tests to see if a given ioaddr points to an SMC91x chip. *	Returns a 0 on success * * Algorithm: *	(1) see if the high byte of BANK_SELECT is 0x33 * 	(2) compare the ioaddr with the base register's address *	(3) 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 smc_probe(struct net_device *dev, void __iomem *ioaddr){	struct smc_local *lp = netdev_priv(dev);	static int version_printed = 0;	int retval;	unsigned int val, revision_register;	const char *version_string;	DECLARE_MAC_BUF(mac);	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);	/* First, see if the high byte is 0x33 */	val = SMC_CURRENT_BANK();	DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val);	if ((val & 0xFF00) != 0x3300) {		if ((val & 0xFF) == 0x33) {			printk(KERN_WARNING				"%s: Detected possible byte-swapped interface"				" at IOADDR %p\n", CARDNAME, ioaddr);		}		retval = -ENODEV;		goto err_out;	}	/*	 * The above MIGHT indicate a device, but I need to write to	 * further test this.	 */	SMC_SELECT_BANK(0);	val = SMC_CURRENT_BANK();	if ((val & 0xFF00) != 0x3300) {		retval = -ENODEV;		goto err_out;	}	/*	 * well, we've already written once, so hopefully another	 * time won't hurt.  This time, I need to switch the bank	 * register to bank 1, so I can access the base address	 * register	 */	SMC_SELECT_BANK(1);	val = SMC_GET_BASE();	val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;	if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) {		printk("%s: IOADDR %p doesn't match configuration (%x).\n",			CARDNAME, ioaddr, val);	}	/*	 * check if the revision register is something that I	 * recognize.  These might need to be added to later,	 * as future revisions could be added.	 */	SMC_SELECT_BANK(3);	revision_register = SMC_GET_REV();	DBG(2, "%s: revision = 0x%04x\n", CARDNAME, revision_register);	version_string = chip_ids[ (revision_register >> 4) & 0xF];	if (!version_string || (revision_register & 0xff00) != 0x3300) {		/* I don't recognize this chip, so... */		printk("%s: IO %p: Unrecognized revision register 0x%04x"			", Contact author.\n", CARDNAME,			ioaddr, revision_register);		retval = -ENODEV;		goto err_out;	}	/* At this point I'll assume that the chip is an SMC91x. */	if (version_printed++ == 0)		printk("%s", version);	/* fill in some of the fields */	dev->base_addr = (unsigned long)ioaddr;	lp->base = ioaddr;	lp->version = revision_register & 0xff;	spin_lock_init(&lp->lock);	/* Get the MAC address */	SMC_SELECT_BANK(1);	SMC_GET_MAC_ADDR(dev->dev_addr);	/* now, reset the chip, and put it into a known state */	smc_reset(dev);	/*	 * If dev->irq is 0, then the device has to be banged on to see	 * what the IRQ is. 	 *	 * This banging doesn't always detect the IRQ, for unknown reasons.	 * a workaround is to reset the chip and try again.	 *	 * Interestingly, the DOS packet driver *SETS* the IRQ on the card to	 * be what is requested on the command line.   I don't do that, mostly	 * because the card that I have uses a non-standard method of accessing	 * the IRQs, and because this _should_ work in most configurations.	 *	 * 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 = smc_findirq(ioaddr);			if (dev->irq)				break;			/* kick the card and try again */			smc_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 = smc_open;	dev->stop = smc_close;	dev->hard_start_xmit = smc_hard_start_xmit;	dev->tx_timeout = smc_timeout;	dev->watchdog_timeo = msecs_to_jiffies(watchdog);	dev->set_multicast_list = smc_set_multicast_list;	dev->ethtool_ops = &smc_ethtool_ops;#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller = smc_poll_controller;#endif	tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev);	INIT_WORK(&lp->phy_configure, smc_phy_configure);	lp->dev = dev;	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 = smc_phy_read;	lp->mii.mdio_write = smc_phy_write;	/*	 * Locate the phy, if any.	 */	if (lp->version >= (CHIP_91100 << 4))		smc_phy_detect(dev);	/* then shut everything down to save power */	smc_shutdown(dev);	smc_phy_powerdown(dev);	/* Set default parameters */	lp->msg_enable = NETIF_MSG_LINK;	lp->ctl_rfduplx = 0;	lp->ctl_rspeed = 10;	if (lp->version >= (CHIP_91100 << 4)) {		lp->ctl_rfduplx = 1;		lp->ctl_rspeed = 100;	}	/* Grab the IRQ */      	retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev);      	if (retval)      		goto err_out;#ifdef SMC_USE_PXA_DMA	{		int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,					  smc_pxa_dma_irq, NULL);		if (dma >= 0)			dev->dma = dma;	}#endif	retval = register_netdev(dev);	if (retval == 0) {		/* now, print out the card info, in a short format.. */		printk("%s: %s (rev %d) at %p IRQ %d",			dev->name, version_string, revision_register & 0x0f,			lp->base, dev->irq);		if (dev->dma != (unsigned char)-1)			printk(" DMA %d", dev->dma);		printk("%s%s\n", nowait ? " [nowait]" : "",			THROTTLE_TX_PKTS ? " [throttle_tx]" : "");		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: %s\n",			       dev->name, print_mac(mac, dev->dev_addr));		}		if (lp->phy_type == 0) {			PRINTK("%s: No PHY found\n", dev->name);		} else if ((lp->phy_type & 0xfffffff0) == 0x0016f840) {			PRINTK("%s: PHY LAN83C183 (LAN91C111 Internal)\n", dev->name);		} else if ((lp->phy_type & 0xfffffff0) == 0x02821c50) {			PRINTK("%s: PHY LAN83C180\n", dev->name);		}	}err_out:#ifdef SMC_USE_PXA_DMA	if (retval && dev->dma != (unsigned char)-1)		pxa_free_dma(dev->dma);#endif	return retval;}static int smc_enable_device(struct platform_device *pdev){	unsigned long flags;	unsigned char ecor, ecsr;	void __iomem *addr;	struct resource * res;	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");	if (!res)		return 0;	/*	 * Map the attribute space.  This is overkill, but clean.	 */	addr = ioremap(res->start, ATTRIB_SIZE);	if (!addr)		return -ENOMEM;	/*	 * Reset the device.  We must disable IRQs around this	 * since a reset causes the IRQ line become active.	 */	local_irq_save(flags);	ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET;	writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT));	readb(addr + (ECOR << SMC_IO_SHIFT));	/*	 * Wait 100us for the chip to reset.	 */	udelay(100);	/*	 * The device will ignore all writes to the enable bit while	 * reset is asserted, even if the reset bit is cleared in the	 * same write.  Must clear reset first, then enable the device.	 */	writeb(ecor, addr + (ECOR << SMC_IO_SHIFT));	writeb(ecor | ECOR_ENABLE, addr + (ECOR << SMC_IO_SHIFT));	/*	 * Set the appropriate byte/word mode.	 */	ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8;	if (!SMC_CAN_USE_16BIT)		ecsr |= ECSR_IOIS8;	writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT));	local_irq_restore(flags);	iounmap(addr);	/*	 * Wait for the chip to wake up.  We could poll the control	 * register in the main register space, but that isn't mapped	 * yet.  We know this is going to take 750us.	 */	msleep(1);	return 0;}static int smc_request_attrib(struct platform_device *pdev){	struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");	if (!res)		return 0;	if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME))		return -EBUSY;	return 0;}static void smc_release_attrib(struct platform_device *pdev){	struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");	if (res)		release_mem_region(res->start, ATTRIB_SIZE);}static inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev){	if (SMC_CAN_USE_DATACS) {		struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");		struct smc_local *lp = netdev_priv(ndev);		if (!res)			return;		if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) {			printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME);			return;		}		lp->datacs = ioremap(res->start, SMC_DATA_EXTENT);	}}static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev){	if (SMC_CAN_USE_DATACS) {		struct smc_local *lp = netdev_priv(ndev);		struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");		if (lp->datacs)			iounmap(lp->datacs);		lp->datacs = NULL;		if (res)			release_mem_region(res->start, SMC_DATA_EXTENT);	}}/* * smc_init(void) *   Input parameters: *	dev->base_addr == 0, try to find all possible locations *	dev->base_addr > 0x1ff, this is the address to check *	dev->base_addr == <anything else>, return failure code * *   Output: *	0 --> there is a device *	anything else, error */static int smc_drv_probe(struct platform_device *pdev){	struct net_device *ndev;	struct resource *res;	unsigned int __iomem *addr;	int ret;	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");	if (!res)		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (!res) {		ret = -ENODEV;		goto out;	}	if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {		ret = -EBUSY;		goto out;	}	ndev = alloc_etherdev(sizeof(struct smc_local));	if (!ndev) {		printk("%s: could not allocate device.\n", CARDNAME);		ret = -ENOMEM;		goto out_release_io;	}	SET_NETDEV_DEV(ndev, &pdev->dev);	ndev->dma = (unsigned char)-1;	ndev->irq = platform_get_irq(pdev, 0);	if (ndev->irq < 0) {		ret = -ENODEV;		goto out_free_netdev;	}	ret = smc_request_attrib(pdev);	if (ret)		goto out_free_netdev;#if defined(CONFIG_SA1100_ASSABET)	NCR_0 |= NCR_ENET_OSC_EN;#endif	ret = smc_enable_device(pdev);	if (ret)		goto out_release_attrib;	addr = ioremap(res->start, SMC_IO_EXTENT);	if (!addr) {		ret = -ENOMEM;		goto out_release_attrib;	}#ifdef SMC_USE_PXA_DMA	{		struct smc_local *lp = netdev_priv(ndev);		lp->device = &pdev->dev;		lp->physaddr = res->start;	}#endif	platform_set_drvdata(pdev, ndev);	ret = smc_probe(ndev, addr);	if (ret != 0)		goto out_iounmap;	smc_request_datacs(pdev, ndev);	return 0; out_iounmap:	platform_set_drvdata(pdev, NULL);	iounmap(addr); out_release_attrib:	smc_release_attrib(pdev); out_free_netdev:	free_netdev(ndev); out_release_io:	release_mem_region(res->start, SMC_IO_EXTENT); out:	printk("%s: not found (%d).\n", CARDNAME, ret);	return ret;}static int smc_drv_remove(struct platform_device *pdev){	struct net_device *ndev = platform_get_drvdata(pdev);	struct smc_local *lp = netdev_priv(ndev);	struct resource *res;	platform_set_drvdata(pdev, NULL);	unregister_netdev(ndev);	free_irq(ndev->irq, ndev);#ifdef SMC_USE_PXA_DMA	if (ndev->dma != (unsigned char)-1)		pxa_free_dma(ndev->dma);#endif	iounmap(lp->base);	smc_release_datacs(pdev,ndev);	smc_release_attrib(pdev);	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");	if (!res)		platform_get_resource(pdev, IORESOURCE_MEM, 0);	release_mem_region(res->start, SMC_IO_EXTENT);	free_netdev(ndev);	return 0;}static int smc_drv_suspend(struct platform_device *dev, pm_message_t state){	struct net_device *ndev = platform_get_drvdata(dev);	if (ndev) {		if (netif_running(ndev)) {			netif_device_detach(ndev);			smc_shutdown(ndev);			smc_phy_powerdown(ndev);		}	}	return 0;}static int smc_drv_resume(struct platform_device *dev){	struct net_device *ndev = platform_get_drvdata(dev);	if (ndev) {		struct smc_local *lp = netdev_priv(ndev);		smc_enable_device(dev);		if (netif_running(ndev)) {			smc_reset(ndev);			smc_enable(ndev);			if (lp->phy_type != 0)				smc_phy_configure(&lp->phy_configure);			netif_device_attach(ndev);		}	}	return 0;}static struct platform_driver smc_driver = {	.probe		= smc_drv_probe,	.remove		= smc_drv_remove,	.suspend	= smc_drv_suspend,	.resume		= smc_drv_resume,	.driver		= {		.name	= CARDNAME,	},};static int __init smc_init(void){#ifdef MODULE#ifdef CONFIG_ISA	if (io == -1)		printk(KERN_WARNING			"%s: You shouldn't use auto-probing with insmod!\n",			CARDNAME);#endif#endif	return platform_driver_register(&smc_driver);}static void __exit smc_cleanup(void){	platform_driver_unregister(&smc_driver);}module_init(smc_init);module_exit(smc_cleanup);

⌨️ 快捷键说明

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