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

📄 smc91x.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	.get_link	= ethtool_op_get_link,//	.get_eeprom	= smc_ethtool_geteeprom,//	.set_eeprom	= smc_ethtool_seteeprom,};/*---------------------------------------------------------------------- . smc_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, ------------------------------------------------------------------------*/int __initsmc_findirq( unsigned long ioaddr ){	int timeout = 20;	unsigned long cookie;	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);	cookie = probe_irq_on();	/*	 * What I try to do here is trigger an ALLOC_INT. This is done	 * by allocating a small chunk of memory, which will give an interrupt	 * when done.	 */	/* enable ALLOCation interrupts ONLY */	SMC_SELECT_BANK(2);	SMC_SET_INT_MASK( IM_ALLOC_INT );	/* 	 . Allocate 512 bytes of memory.  Note that the chip was just	 . reset so all the memory is available	*/	SMC_SET_MMU_CMD( MC_ALLOC | 1 );	/*	 . 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 __initsmc_probe(struct net_device *dev, unsigned long ioaddr){	struct smc_local *lp = (struct smc_local *)dev->priv;	static int version_printed = 0;	int i, retval;	unsigned int val, revision_register;	const char *version_string;	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);#if defined(CONFIG_ARCH_PXA_PNP2110)	/* MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x1010 */	volatile unsigned char *pnp2110_mac = ioremap_nocache(0x00021000, 0x1000);	if (!pnp2110_mac)		return -ENODEV;	pnp2110_mac += 0x10;	ioaddr = SMC_IOADDR; /* HACK ALERT!! FIXME (RSC) */	dev->irq = SMC_IRQ;#endif	PRINTK2("%s: ioaddr=%08x\n", CARDNAME, ioaddr);	/* First, see if the high byte is 0x33 */	val = SMC_CURRENT_BANK();	PRINTK2("%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 0x%lx\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 ( (ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val ) {		printk( "%s: IOADDR %lx 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();	PRINTK2("%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 0x%lx: 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);	/* set the private data to zero by default */	memset(lp, 0, sizeof(struct smc_local));	/* fill in some of the fields */	dev->base_addr = ioaddr;	lp->version = revision_register & 0xff;	/* Get the MAC address */	SMC_SELECT_BANK( 1 );#if defined(CONFIG_ARCH_PXA_PNP2110)	SMC_SET_MAC_ADDR(pnp2110_mac);#elif defined(CONFIG_ARCH_FS_PXA255)	{		char smc91xx_mac[6] = {0x00,0x12,0x34,0x56,0x80,0x48};		SMC_SET_MAC_ADDR(smc91xx_mac);	}#endif	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		= HZ/10;	dev->get_stats			= smc_query_statistics;	dev->set_multicast_list 	= smc_set_multicast_list;	dev->ethtool_ops		= &smc_ethtool_ops;	spin_lock_init(&lp->lock);	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_detect_phy(dev);	/* Set default parameters */	lp->msg_enable = NETIF_MSG_LINK;	lp->ctl_rfduplx = 0;	lp->ctl_rspeed = 10;#ifndef CONFIG_ARCH_RAMSES	if (lp->version >= (CHIP_91100 << 4)) {		lp->ctl_rfduplx = 1;		lp->ctl_rspeed = 100;	}#endif	/* Grab the IRQ */      	retval = request_irq(dev->irq, &smc_interrupt, 0, 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 %#lx IRQ %d",			dev->name, version_string, revision_register & 0x0f,			dev->base_addr, 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: ", dev->name);			for (i = 0; i < 5; i++)				printk("%2.2x:", dev->dev_addr[i]);			printk("%2.2x\n", dev->dev_addr[5]);		}	}err_out:#ifdef SMC_USE_PXA_DMA	if (retval && dev->dma != -1)		pxa_free_dma(dev->dma);#endif	return retval;}/*------------------------------------------------------------------------- | | 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_enable_device(unsigned long attrib_phys){	unsigned long flags;	unsigned char ecor, ecsr;	void *addr;	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);	/*	 * Map the attribute space.  This is overkill, but clean.	 */	addr = ioremap(attrib_phys, ATTRIB_SIZE);	if (!addr)		return -ENOMEM;	/*	 * Reset the device.  We must disable IRQs around this.	 */	local_irq_save(flags);	ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET;	writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT));	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;#ifndef SMC_CAN_USE_16BIT	ecsr |= ECSR_IOIS8;#endif	writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT));	local_irq_restore(flags);	iounmap(addr);	/*	 * Wait for the chip to wake up.	 */	mdelay(1);	return 0;}static int smc_drv_probe(struct device *dev){	struct platform_device *pdev = to_platform_device(dev);	struct net_device *ndev;	unsigned long base, ext_base = 0;	unsigned int *addr = NULL;	int ret = -ENODEV;	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);	ndev = alloc_etherdev(sizeof(struct smc_local));	if (!ndev) {		printk("%s: could not allocate device.\n", CARDNAME);		return -ENOMEM;	}	SET_MODULE_OWNER(ndev);	SET_NETDEV_DEV(ndev, dev);	ndev->dma = (unsigned char)-1;	if (pdev->num_resources < 2 || pdev->num_resources > 3) {		ret = -ENODEV;		goto out;	}	base = pdev->resource[0].start;	ndev->irq = pdev->resource[1].start;	/*	 * Request the regions.	 */	if (!request_mem_region(base, SMC_IO_EXTENT, ndev->name)) {		ret = -EBUSY;		goto out;	}	if (pdev->num_resources == 3) {		ext_base = pdev->resource[2].start;		if (!request_mem_region(ext_base, ATTRIB_SIZE, ndev->name)) {			ret = -EBUSY;			goto release_1;		}#if defined(CONFIG_SA1100_ASSABET)		NCR_0 |= NCR_ENET_OSC_EN;#endif		ret = smc_enable_device(ext_base);		if (ret)			goto release_both;	}	addr = ioremap(base, SMC_IO_EXTENT);	if (!addr) {		ret = -ENOMEM;		goto release_both;	}	dev_set_drvdata(dev, ndev);	ret = smc_probe(ndev, (unsigned long)addr);	if (ret != 0) {		dev_set_drvdata(dev, NULL);		iounmap(addr); release_both:		if (pdev->num_resources == 3)			release_mem_region(ext_base, ATTRIB_SIZE); release_1:		release_mem_region(base, SMC_IO_EXTENT); out:		printk("%s: not found (%d).\n", CARDNAME, ret);		kfree(ndev);	}	return ret;}static int smc_drv_remove(struct device *dev){	struct platform_device *pdev = to_platform_device(dev);	struct net_device *ndev = dev_get_drvdata(dev);	dev_set_drvdata(dev, NULL);	unregister_netdev(ndev);	free_irq(ndev->irq, ndev);#ifdef SMC_USE_PXA_DMA	if (ndev->dma != -1)		pxa_free_dma(ndev->dma);#endif	iounmap((void *)ndev->base_addr);	if (pdev->num_resources == 3)		release_mem_region(pdev->resource[2].start, ATTRIB_SIZE);	release_mem_region(pdev->resource[0].start, SMC_IO_EXTENT);	kfree(ndev);	return 0;}static int smc_drv_suspend(struct device *dev, u32 state, u32 level){	struct net_device *ndev = dev_get_drvdata(dev);	if (ndev && level == SUSPEND_DISABLE) {		if (netif_running(ndev)) {			netif_device_detach(ndev);			smc_shutdown(ndev->base_addr);		}	}	return 0;}static int smc_drv_resume(struct device *dev, u32 level){	struct platform_device *pdev = to_platform_device(dev);	struct net_device *ndev = dev_get_drvdata(dev);	if (ndev && level == RESUME_ENABLE) {		struct smc_local *lp = (struct smc_local *)ndev->priv;		unsigned long ioaddr = ndev->base_addr;		if (pdev->num_resources == 3)			smc_enable_device(pdev->resource[2].start);		if (netif_running(ndev)) {			smc_reset(ndev);			smc_enable(ndev);			SMC_SELECT_BANK(1);			SMC_SET_MAC_ADDR(ndev->dev_addr);			if (lp->phy_type != 0)				smc_phy_configure(ndev);			netif_device_attach(ndev);		}	}	return 0;}static struct device_driver smc_driver = {	.name		= CARDNAME,	.bus		= &platform_bus_type,	.probe		= smc_drv_probe,	.remove		= smc_drv_remove,	.suspend	= smc_drv_suspend,	.resume		= smc_drv_resume,};static int __init smc_init(void){	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);	DEBUG_DIR(15);	DEBUG_CLR(15);#ifdef MODULE	if (io == -1)		printk( KERN_WARNING 			"%s: You shouldn't use auto-probing with insmod!\n",			CARDNAME );#endif	return driver_register(&smc_driver);}static void __exit smc_cleanup(void){	driver_unregister(&smc_driver);}module_init(smc_init);module_exit(smc_cleanup);MODULE_DESCRIPTION("SM91Cxxx Net Card Interface Driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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