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

📄 smc9194.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
		 * Force byte mode.		 */		writel(readl(addr + ECSR) | ECSR_IOIS8, addr + ECSR);		local_irq_restore(flags);		iounmap(addr);		/*		 * Wait for the chip to wake up.		 */		mdelay(1);		/*		 * Map the real registers.		 */		addr = ioremap(0x18000000, 8 * 1024);		if (!addr)			return -ENOMEM;		ret = smc_probe(dev, (int)addr);		if (ret)			iounmap(addr);	}#elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_GRAPHICSMASTER)	if (machine_is_graphicsclient() || machine_is_graphicsmaster()) {		int base_addr = ADS_ETHERNET;		// Max recovery timing		MSC1 &= ~0xFFFF;		MSC1 |= 0x8649;		ret = smc_probe(dev, base_addr);	}#elif defined(CONFIG_SA1100_FLEXANET)	if (machine_is_flexanet()) {		volatile unsigned *attaddr;		int ioaddr;		unsigned flags;		/* Get the I/O and attribute base addresses		 * declared in flexanet.h */		ioaddr  = FHH_ETH_IOBASE;		attaddr = (unsigned *) FHH_ETH_MMBASE;		/* Ethernet IRQ setup (GPIO is input, falling edge) */		GPDR &= ~(GPIO_ETH_IRQ);		set_GPIO_IRQ_edge( GPIO_ETH_IRQ, GPIO_FALLING_EDGE );		dev->irq = IRQ_GPIO_ETH;		local_irq_save(flags);		/* first reset, then enable the device. Sequence is critical */		attaddr[ECOR] |= ECOR_RESET;		udelay(100);		attaddr[ECOR] &= ~ECOR_RESET;		attaddr[ECOR] |= ECOR_ENABLE;		local_irq_restore(flags);		/* force 16-bit mode */		attaddr[ECSR] &= ~ECSR_IOIS8;		ret = smc_probe(dev, ioaddr);	}#elif defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP)	if (machine_is_lubbock() || machine_is_pxa_idp()) {		int ioaddr = machine_is_lubbock() ? 			LUBBOCK_ETH_BASE : IDP_ETH_BASE;		volatile unsigned *attaddr = (unsigned *) (ioaddr + 0x100000);		unsigned flags;		/* first reset, then enable the device. Sequence is critical */		local_irq_save(flags);		attaddr[ECOR] |= ECOR_RESET;		udelay(100);		attaddr[ECOR] &= ~ECOR_RESET;		attaddr[ECOR] |= ECOR_ENABLE;		/* force 16-bit mode */		attaddr[ECSR] &= ~ECSR_IOIS8;		mdelay(1);		local_irq_restore(flags);		dev->irq = LUBBOCK_ETH_IRQ;			ret = smc_probe(dev, ioaddr);	}#elif defined(CONFIG_ISA)	int i;	int base_addr = dev->base_addr;	SET_MODULE_OWNER(dev);	/*  try a specific location */	if (base_addr > 0x1ff)		return smc_probe(dev, base_addr);	else if (base_addr != 0)		return -ENXIO;	/* check every ethernet address */	for (i = 0; smc_portlist[i]; i++)		if (smc_probe(dev, smc_portlist[i]) == 0)			return 0;	/* couldn't find anything */#endif	return ret;}/*---------------------------------------------------------------------- . 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 __init smc_findirq(struct net_device *dev){	int	timeout = 20;	unsigned long cookie;	u_int ioaddr = dev->base_addr;	/* I have to do a STI() here, because this is called from	   a routine that does an CLI during this process, making it	   rather difficult to get interrupts for auto detection */	sti();	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(IM_ALLOC_INT);	/* 	 . Allocate 512 bytes of memory.  Note that the chip was just	 . reset so all the memory is available	*/	smc_outw(MC_ALLOC | 1, ioaddr, MMU_CMD);	/*	 . Wait until positive that the interrupt has been generated	*/	while (timeout) {		byte	int_status;		int_status = smc_inb(ioaddr, INTERRUPT);		if (int_status & IM_ALLOC_INT)			break;		/* got the interrupt */		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.  */	/* DELAY HERE!	   On a fast machine, the status might change before the interrupt	   is given to the processor.  This means that the interrupt was	   never detected, and autoirq_report fails to report anything.	   This should fix autoirq_* problems.	*/	SMC_DELAY();	SMC_DELAY();	/* and disable all interrupts again */	SMC_SET_INT(0);	/* clear hardware interrupts again, because that's how it	   was when I was called... */	cli();	/* and return what I found */	return probe_irq_off(cookie);}static int __init smc_probe_chip(struct net_device *dev, int ioaddr){	unsigned int temp;	/* First, see if the high byte is 0x33 */	temp = smc_inw(ioaddr, BANK_SELECT);	if ((temp & 0xFF00) != 0x3300)		return -ENODEV;	/* The above MIGHT indicate a device, but I need to write to further 	   test this.  */	smc_outw(0, ioaddr, BANK_SELECT);	temp = smc_inw(ioaddr, BANK_SELECT);	if ((temp & 0xFF00) != 0x3300)		return -ENODEV;#ifdef CONFIG_ISA	/* 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);	temp = smc_inw(ioaddr, BASE);	if (ioaddr != (temp >> 3 & 0x3E0)) {		printk("%s: IOADDR %x doesn't match configuration (%x)."			"Probably not a SMC chip\n", dev->name,			ioaddr, (base_address_register >> 3) & 0x3E0);		/* well, the base address register didn't match.  Must not have		   been a SMC chip after all. */		return -ENODEV;	}#endif	return 0;}/* . 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!!!! .*/static int __init smc_probe_irq(struct net_device *dev){	if (dev->irq < 2) {		int	trials;		trials = 3;		while (trials--) {			dev->irq = smc_findirq(dev);			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);		return -ENODEV;	}	/*	 * Some machines (eg, PCs) need to cannonicalize their IRQs.	 */	dev->irq = irq_cannonicalize(dev->irq);	return 0;}/*---------------------------------------------------------------------- . Function: smc_probe(struct net_device *dev, int ioaddr) . . Purpose: .	Tests to see if a given ioaddr points to an SMC9xxx 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, int ioaddr){	struct smc_local *smc;	int i, memory, retval;	static unsigned version_printed;	const char *version_string;	/* registers */	word revision_register;	word configuration_register;	word memory_info_register;	word memory_cfg_register;	/* Grab the region so that no one else tries to probe our ioports. */	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))		return -EBUSY;	/*	 * Do the basic probes.	 */	retval = smc_probe_chip(dev, ioaddr);	if (retval)		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.  */	SMC_SELECT_BANK(3);	revision_register = smc_inw(ioaddr, REVISION);	version_string = chip_ids[(revision_register >> 4) & 15];	if (!version_string) {		/* I don't recognize this chip, so... */		printk("%s: IO %x: unrecognized revision register: %x, "			"contact author.\n", dev->name, ioaddr,			revision_register);		retval = -ENODEV;		goto err_out;	}	/* at this point I'll assume that the chip is an SMC9xxx.	   It might be prudent to check a listing of MAC addresses	   against the hardware address, or do some other tests. */	if (version_printed++ == 0)		printk(KERN_INFO "%s", version);	/* fill in some of the fields */	dev->base_addr = ioaddr;	/* 	 . Get the MAC address (bank 1, regs 4 - 9)	*/	SMC_SELECT_BANK(1);	for (i = 0; i < 6; i += 2) {		word	address;		address = smc_inw(ioaddr, ADDR0 + i);		dev->dev_addr[i + 1] = address >> 8;		dev->dev_addr[i] = address & 0xFF;	}	if (dev->dev_addr[0] != 0) {		/*		 * Possibly a multicast MAC which is not good.		 * Some people apparently defined it backwards in the eprom.		 */		for (i = 0; i < 3; i++) {			unsigned char tmp = dev->dev_addr[i];			dev->dev_addr[i] = dev->dev_addr[5-i];			dev->dev_addr[5-i] = tmp;		}	}	if (!is_valid_ether_addr(dev->dev_addr))		printk("%s: Invalid ethernet MAC address.  Please set using "			"ifconfig\n", dev->name);	/* get the memory information */	SMC_SELECT_BANK(0);	memory_info_register = smc_inw(ioaddr, MIR);	memory_cfg_register = smc_inw(ioaddr, MCR);	memory = (memory_cfg_register >> 9) & 0x7;  /* multiplier */	memory *= 256 * (memory_info_register & 0xFF);	/* now, reset the chip, and put it into a known state */	smc_reset(dev);	/*	 * Ok, now that we have everything in a	 * sane state, probe for the interrupt.	 */	retval = smc_probe_irq(dev);	if (retval)		goto err_out;	/* Initialize the private structure. */	if (dev->priv == NULL) {		dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL);		if (dev->priv == NULL) {			retval = -ENOMEM;			goto err_out;		}	}	smc = dev->priv;	/* set the private data to zero by default */	memset(smc, 0, sizeof(struct smc_local));	/*	 * Get the interface characteristics.	 * is it using AUI or 10BaseT ?	 */	switch (dev->if_port) {	case IF_PORT_10BASET:		smc->port = PORT_TP;		break;	case IF_PORT_AUI:		smc->port = PORT_AUI;		break;	default:		SMC_SELECT_BANK(1);		configuration_register = smc_inw(ioaddr, CONFIG);		if (configuration_register & CFG_AUI_SELECT) {			dev->if_port = IF_PORT_AUI;			smc->port = PORT_AUI;		} else {			dev->if_port = IF_PORT_10BASET;			smc->port = PORT_TP;		}		break;	}	/* all interfaces are half-duplex by default */	smc->duplex = DUPLEX_HALF;	/* now, print out the card info, in a short format.. */	printk("%s: %s (rev %d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name,		version_string, revision_register & 15, ioaddr, dev->irq,		interfaces[smc->port], memory);	/*	 . Print the Ethernet address	*/	printk("ADDR: ");	for (i = 0; i < 5; i++)		printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x\n", dev->dev_addr[5]);	/* Fill in the fields of the device structure with ethernet values. */	ether_setup(dev);	/* Grab the IRQ */	retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);	if (retval) {		printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,			dev->irq, retval);		kfree(dev->priv);		dev->priv = NULL;		goto err_out;	}	dev->open		= smc_open;	dev->stop		= smc_close;	dev->hard_start_xmit	= smc_wait_to_send_packet;	dev->tx_timeout 	= smc_timeout;	dev->watchdog_timeo	= HZ/20;	dev->get_stats		= smc_query_statistics;	dev->set_multicast_list = smc_set_multicast_list;	dev->do_ioctl		= smc_ioctl;	return 0;err_out:	release_region(ioaddr, SMC_IO_EXTENT);	return retval;}/* * This is responsible for setting the chip appropriately * for the interface type.  This should only be called while * the interface is up and running. */static void smc_set_port(struct net_device *dev){	struct smc_local *smc = dev->priv;	u_int ioaddr = dev->base_addr;	u_int val;	SMC_SELECT_BANK(1);	val = smc_inw(ioaddr, CONFIG);	switch (smc->port) {	case PORT_TP:		val &= ~CFG_AUI_SELECT;		break;	case PORT_AUI:		val |= CFG_AUI_SELECT;		break;	}	smc_outw(val, ioaddr, CONFIG);	SMC_SELECT_BANK(0);	val = smc_inw(ioaddr, TCR);	switch (smc->duplex) {	case DUPLEX_HALF:		val &= ~TCR_FDSE;		break;	case DUPLEX_FULL:		val |= TCR_FDSE;		break;	}	smc_outw(val, ioaddr, TCR);}/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_open(struct net_device *dev){	struct smc_local *smc = dev->priv;	u_int ioaddr = dev->base_addr;	int i;	/*	 * Check that the address is valid.  If its not, refuse	 * to bring the device up.  The user must specify an	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx	 */	if (!is_valid_ether_addr(dev->dev_addr))		return -EINVAL;	/* clear out all the junk that was put here before... */	smc->saved_skb = NULL;	smc->packets_waiting = 0;	/* reset the hardware */	smc_reset(dev);	smc_enable(dev);	/* Select which interface to use */	smc_set_port(dev);	/*		According to Becker, I have to set the hardware address		at this point, because the (l)user can set it with an		ioctl.  Easily done...	*/	SMC_SELECT_BANK(1);	for (i = 0; i < 6; i += 2) {		word	address;		address = dev->dev_addr[i + 1] << 8 ;		address |= dev->dev_addr[i];		smc_outw(address, ioaddr, ADDR0 + i);	}		netif_start_queue(dev);	return 0;

⌨️ 快捷键说明

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