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

📄 3c505.c

📁 linux设备驱动开发详解(书代码)
💻 C
📖 第 1 页 / 共 4 页
字号:
	adapter->tx_pcb.command = CMD_CONFIGURE_82586;	adapter->tx_pcb.length = 2;	adapter->got[CMD_CONFIGURE_82586] = 0;	if (!send_pcb(dev, &adapter->tx_pcb))	{		spin_unlock_irqrestore(&adapter->lock, flags);		printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name);	}	else {		unsigned long timeout = jiffies + TIMEOUT;		spin_unlock_irqrestore(&adapter->lock, flags);		while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));		if (time_after_eq(jiffies, timeout))			TIMEOUT_MSG(__LINE__);	}}/************************************************************ * * A couple of tests to see if there's 3C505 or not * Called only by elp_autodetect ************************************************************/static int __init elp_sense(struct net_device *dev){	int addr = dev->base_addr;	const char *name = dev->name;	byte orig_HSR;	if (!request_region(addr, ELP_IO_EXTENT, "3c505"))		return -ENODEV;	orig_HSR = inb_status(addr);	if (elp_debug > 0)		printk(search_msg, name, addr);	if (orig_HSR == 0xff) {		if (elp_debug > 0)			printk(notfound_msg, 1);		goto out;	}	/* Wait for a while; the adapter may still be booting up */	if (elp_debug > 0)		printk(stilllooking_msg);	if (orig_HSR & DIR) {		/* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */		outb(0, dev->base_addr + PORT_CONTROL);		msleep(300);		if (inb_status(addr) & DIR) {			if (elp_debug > 0)				printk(notfound_msg, 2);			goto out;		}	} else {		/* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */		outb(DIR, dev->base_addr + PORT_CONTROL);		msleep(300);		if (!(inb_status(addr) & DIR)) {			if (elp_debug > 0)				printk(notfound_msg, 3);			goto out;		}	}	/*	 * It certainly looks like a 3c505.	 */	if (elp_debug > 0)		printk(found_msg);	return 0;out:	release_region(addr, ELP_IO_EXTENT);	return -ENODEV;}/************************************************************* * * Search through addr_list[] and try to find a 3C505 * Called only by eplus_probe *************************************************************/static int __init elp_autodetect(struct net_device *dev){	int idx = 0;	/* if base address set, then only check that address	   otherwise, run through the table */	if (dev->base_addr != 0) {	/* dev->base_addr == 0 ==> plain autodetect */		if (elp_sense(dev) == 0)			return dev->base_addr;	} else		while ((dev->base_addr = addr_list[idx++])) {			if (elp_sense(dev) == 0)				return dev->base_addr;		}	/* could not find an adapter */	if (elp_debug > 0)		printk(couldnot_msg, dev->name);	return 0;		/* Because of this, the layer above will return -ENODEV */}/****************************************************** * * probe for an Etherlink Plus board at the specified address * ******************************************************//* There are three situations we need to be able to detect here: *  a) the card is idle *  b) the card is still booting up *  c) the card is stuck in a strange state (some DOS drivers do this) * * In case (a), all is well.  In case (b), we wait 10 seconds to see if the * card finishes booting, and carry on if so.  In case (c), we do a hard reset, * loop round, and hope for the best. * * This is all very unpleasant, but hopefully avoids the problems with the old * probe code (which had a 15-second delay if the card was idle, and didn't * work at all if it was in a weird state). */static int __init elplus_setup(struct net_device *dev){	elp_device *adapter = dev->priv;	int i, tries, tries1, okay;	unsigned long timeout;	unsigned long cookie = 0;	int err = -ENODEV;	SET_MODULE_OWNER(dev);	/*	 *  setup adapter structure	 */	dev->base_addr = elp_autodetect(dev);	if (!dev->base_addr)		return -ENODEV;	adapter->send_pcb_semaphore = 0;	for (tries1 = 0; tries1 < 3; tries1++) {		outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);		/* First try to write just one byte, to see if the card is		 * responding at all normally.		 */		timeout = jiffies + 5*HZ/100;		okay = 0;		while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));		if ((inb_status(dev->base_addr) & HCRE)) {			outb_command(0, dev->base_addr);	/* send a spurious byte */			timeout = jiffies + 5*HZ/100;			while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));			if (inb_status(dev->base_addr) & HCRE)				okay = 1;		}		if (!okay) {			/* Nope, it's ignoring the command register.  This means that			 * either it's still booting up, or it's died.			 */			printk(KERN_ERR "%s: command register wouldn't drain, ", dev->name);			if ((inb_status(dev->base_addr) & 7) == 3) {				/* If the adapter status is 3, it *could* still be booting.				 * Give it the benefit of the doubt for 10 seconds.				 */				printk("assuming 3c505 still starting\n");				timeout = jiffies + 10*HZ;				while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));				if (inb_status(dev->base_addr) & 7) {					printk(KERN_ERR "%s: 3c505 failed to start\n", dev->name);				} else {					okay = 1;  /* It started */				}			} else {				/* Otherwise, it must just be in a strange				 * state.  We probably need to kick it.				 */				printk("3c505 is sulking\n");			}		}		for (tries = 0; tries < 5 && okay; tries++) {			/*			 * Try to set the Ethernet address, to make sure that the board			 * is working.			 */			adapter->tx_pcb.command = CMD_STATION_ADDRESS;			adapter->tx_pcb.length = 0;			cookie = probe_irq_on();			if (!send_pcb(dev, &adapter->tx_pcb)) {				printk(KERN_ERR "%s: could not send first PCB\n", dev->name);				probe_irq_off(cookie);				continue;			}			if (!receive_pcb(dev, &adapter->rx_pcb)) {				printk(KERN_ERR "%s: could not read first PCB\n", dev->name);				probe_irq_off(cookie);				continue;			}			if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||			    (adapter->rx_pcb.length != 6)) {				printk(KERN_ERR "%s: first PCB wrong (%d, %d)\n", dev->name, adapter->rx_pcb.command, adapter->rx_pcb.length);				probe_irq_off(cookie);				continue;			}			goto okay;		}		/* It's broken.  Do a hard reset to re-initialise the board,		 * and try again.		 */		printk(KERN_INFO "%s: resetting adapter\n", dev->name);		outb_control(adapter->hcr_val | FLSH | ATTN, dev);		outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);	}	printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name);	goto out;      okay:	if (dev->irq) {		/* Is there a preset IRQ? */		int rpt = probe_irq_off(cookie);		if (dev->irq != rpt) {			printk(KERN_WARNING "%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);		}		/* if dev->irq == probe_irq_off(cookie), all is well */	} else		       /* No preset IRQ; just use what we can detect */		dev->irq = probe_irq_off(cookie);	switch (dev->irq) {    /* Legal, sane? */	case 0:		printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n",		       dev->name);		goto out;	case 1:	case 6:	case 8:	case 13:		printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n",		       dev->name, dev->irq);		       goto out;	}	/*	 *  Now we have the IRQ number so we can disable the interrupts from	 *  the board until the board is opened.	 */	outb_control(adapter->hcr_val & ~CMDE, dev);	/*	 * copy Ethernet address into structure	 */	for (i = 0; i < 6; i++)		dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];	/* find a DMA channel */	if (!dev->dma) {		if (dev->mem_start) {			dev->dma = dev->mem_start & 7;		}		else {			printk(KERN_WARNING "%s: warning, DMA channel not specified, using default\n", dev->name);			dev->dma = ELP_DMA;		}	}	/*	 * print remainder of startup message	 */	printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, ",	       dev->name, dev->base_addr, dev->irq, dev->dma);	printk("addr %02x:%02x:%02x:%02x:%02x:%02x, ",	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);	/*	 * read more information from the adapter	 */	adapter->tx_pcb.command = CMD_ADAPTER_INFO;	adapter->tx_pcb.length = 0;	if (!send_pcb(dev, &adapter->tx_pcb) ||	    !receive_pcb(dev, &adapter->rx_pcb) ||	    (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||	    (adapter->rx_pcb.length != 10)) {		printk("not responding to second PCB\n");	}	printk("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers, adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);	/*	 * reconfigure the adapter memory to better suit our purposes	 */	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;	adapter->tx_pcb.length = 12;	adapter->tx_pcb.data.memconf.cmd_q = 8;	adapter->tx_pcb.data.memconf.rcv_q = 8;	adapter->tx_pcb.data.memconf.mcast = 10;	adapter->tx_pcb.data.memconf.frame = 10;	adapter->tx_pcb.data.memconf.rcv_b = 10;	adapter->tx_pcb.data.memconf.progs = 0;	if (!send_pcb(dev, &adapter->tx_pcb) ||	    !receive_pcb(dev, &adapter->rx_pcb) ||	    (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||	    (adapter->rx_pcb.length != 2)) {		printk(KERN_ERR "%s: could not configure adapter memory\n", dev->name);	}	if (adapter->rx_pcb.data.configure) {		printk(KERN_ERR "%s: adapter configuration failed\n", dev->name);	}	dev->open = elp_open;				/* local */	dev->stop = elp_close;				/* local */	dev->get_stats = elp_get_stats;			/* local */	dev->hard_start_xmit = elp_start_xmit;		/* local */	dev->tx_timeout = elp_timeout;			/* local */	dev->watchdog_timeo = 10*HZ;	dev->set_multicast_list = elp_set_mc_list;	/* local */	dev->ethtool_ops = &netdev_ethtool_ops;		/* local */	memset(&(adapter->stats), 0, sizeof(struct net_device_stats));	dev->mem_start = dev->mem_end = 0;	err = register_netdev(dev);	if (err)		goto out;	return 0;out:	release_region(dev->base_addr, ELP_IO_EXTENT);	return err;}#ifndef MODULEstruct net_device * __init elplus_probe(int unit){	struct net_device *dev = alloc_etherdev(sizeof(elp_device));	int err;	if (!dev)		return ERR_PTR(-ENOMEM);	sprintf(dev->name, "eth%d", unit);	netdev_boot_setup_check(dev);	err = elplus_setup(dev);	if (err) {		free_netdev(dev);		return ERR_PTR(err);	}	return dev;}#elsestatic struct net_device *dev_3c505[ELP_MAX_CARDS];static int io[ELP_MAX_CARDS];static int irq[ELP_MAX_CARDS];static int dma[ELP_MAX_CARDS];module_param_array(io, int, NULL, 0);module_param_array(irq, int, NULL, 0);module_param_array(dma, int, NULL, 0);MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");int init_module(void){	int this_dev, found = 0;	for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {		struct net_device *dev = alloc_etherdev(sizeof(elp_device));		if (!dev)			break;		dev->irq = irq[this_dev];		dev->base_addr = io[this_dev];		if (dma[this_dev]) {			dev->dma = dma[this_dev];		} else {			dev->dma = ELP_DMA;			printk(KERN_WARNING "3c505.c: warning, using default DMA channel,\n");		}		if (io[this_dev] == 0) {			if (this_dev) {				free_netdev(dev);				break;			}			printk(KERN_NOTICE "3c505.c: module autoprobe not recommended, give io=xx.\n");		}		if (elplus_setup(dev) != 0) {			printk(KERN_WARNING "3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);			free_netdev(dev);			break;		}		dev_3c505[this_dev] = dev;		found++;	}	if (!found)		return -ENODEV;	return 0;}void cleanup_module(void){	int this_dev;	for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {		struct net_device *dev = dev_3c505[this_dev];		if (dev) {			unregister_netdev(dev);			release_region(dev->base_addr, ELP_IO_EXTENT);			free_netdev(dev);		}	}}#endif				/* MODULE */MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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