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

📄 3c505.c

📁 linux设备驱动开发详解(书代码)
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************** * * open the board * ******************************************************/static int elp_open(struct net_device *dev){	elp_device *adapter;	int retval;	adapter = dev->priv;	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: request to open device\n", dev->name);	/*	 * make sure we actually found the device	 */	if (adapter == NULL) {		printk(KERN_ERR "%s: Opening a non-existent physical device\n", dev->name);		return -EAGAIN;	}	/*	 * disable interrupts on the board	 */	outb_control(0, dev);	/*	 * clear any pending interrupts	 */	inb_command(dev->base_addr);	adapter_reset(dev);	/*	 * no receive PCBs active	 */	adapter->rx_active = 0;	adapter->busy = 0;	adapter->send_pcb_semaphore = 0;	adapter->rx_backlog.in = 0;	adapter->rx_backlog.out = 0;		spin_lock_init(&adapter->lock);	/*	 * install our interrupt service routine	 */	if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) {		printk(KERN_ERR "%s: could not allocate IRQ%d\n", dev->name, dev->irq);		return retval;	}	if ((retval = request_dma(dev->dma, dev->name))) {		free_irq(dev->irq, dev);		printk(KERN_ERR "%s: could not allocate DMA%d channel\n", dev->name, dev->dma);		return retval;	}	adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);	if (!adapter->dma_buffer) {		printk(KERN_ERR "%s: could not allocate DMA buffer\n", dev->name);		free_dma(dev->dma);		free_irq(dev->irq, dev);		return -ENOMEM;	}	adapter->dmaing = 0;	/*	 * enable interrupts on the board	 */	outb_control(CMDE, dev);	/*	 * configure adapter memory: we need 10 multicast addresses, default==0	 */	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: sending 3c505 memory configuration command\n", dev->name);	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;	adapter->tx_pcb.data.memconf.cmd_q = 10;	adapter->tx_pcb.data.memconf.rcv_q = 20;	adapter->tx_pcb.data.memconf.mcast = 10;	adapter->tx_pcb.data.memconf.frame = 20;	adapter->tx_pcb.data.memconf.rcv_b = 20;	adapter->tx_pcb.data.memconf.progs = 0;	adapter->tx_pcb.length = sizeof(struct Memconf);	adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;	if (!send_pcb(dev, &adapter->tx_pcb))		printk(KERN_ERR "%s: couldn't send memory configuration command\n", dev->name);	else {		unsigned long timeout = jiffies + TIMEOUT;		while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));		if (time_after_eq(jiffies, timeout))			TIMEOUT_MSG(__LINE__);	}	/*	 * configure adapter to receive broadcast messages and wait for response	 */	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name);	adapter->tx_pcb.command = CMD_CONFIGURE_82586;	adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;	adapter->tx_pcb.length = 2;	adapter->got[CMD_CONFIGURE_82586] = 0;	if (!send_pcb(dev, &adapter->tx_pcb))		printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name);	else {		unsigned long timeout = jiffies + TIMEOUT;		while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));		if (time_after_eq(jiffies, timeout))			TIMEOUT_MSG(__LINE__);	}	/* enable burst-mode DMA */	/* outb(0x1, dev->base_addr + PORT_AUXDMA); */	/*	 * queue receive commands to provide buffering	 */	prime_rx(dev);	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: %d receive PCBs active\n", dev->name, adapter->rx_active);	/*	 * device is now officially open!	 */	netif_start_queue(dev);	return 0;}/****************************************************** * * send a packet to the adapter * ******************************************************/static int send_packet(struct net_device *dev, struct sk_buff *skb){	elp_device *adapter = dev->priv;	unsigned long target;	unsigned long flags;	/*	 * make sure the length is even and no shorter than 60 bytes	 */	unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);	if (test_and_set_bit(0, (void *) &adapter->busy)) {		if (elp_debug >= 2)			printk(KERN_DEBUG "%s: transmit blocked\n", dev->name);		return FALSE;	}	adapter->stats.tx_bytes += nlen;		/*	 * send the adapter a transmit packet command. Ignore segment and offset	 * and make sure the length is even	 */	adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;	adapter->tx_pcb.length = sizeof(struct Xmit_pkt);	adapter->tx_pcb.data.xmit_pkt.buf_ofs	    = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0;	/* Unused */	adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;	if (!send_pcb(dev, &adapter->tx_pcb)) {		adapter->busy = 0;		return FALSE;	}	/* if this happens, we die */	if (test_and_set_bit(0, (void *) &adapter->dmaing))		printk(KERN_DEBUG "%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);	adapter->current_dma.direction = 1;	adapter->current_dma.start_time = jiffies;	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {		memcpy(adapter->dma_buffer, skb->data, nlen);		memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);		target = isa_virt_to_bus(adapter->dma_buffer);	}	else {		target = isa_virt_to_bus(skb->data);	}	adapter->current_dma.skb = skb;	flags=claim_dma_lock();	disable_dma(dev->dma);	clear_dma_ff(dev->dma);	set_dma_mode(dev->dma, 0x48);	/* dma memory -> io */	set_dma_addr(dev->dma, target);	set_dma_count(dev->dma, nlen);	outb_control(adapter->hcr_val | DMAE | TCEN, dev);	enable_dma(dev->dma);	release_dma_lock(flags);		if (elp_debug >= 3)		printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name);	return TRUE;}/* *	The upper layer thinks we timed out */ static void elp_timeout(struct net_device *dev){	elp_device *adapter = dev->priv;	int stat;	stat = inb_status(dev->base_addr);	printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");	if (elp_debug >= 1)		printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat);	dev->trans_start = jiffies;	adapter->stats.tx_dropped++;	netif_wake_queue(dev);}/****************************************************** * * start the transmitter *    return 0 if sent OK, else return 1 * ******************************************************/static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev){	unsigned long flags;	elp_device *adapter = dev->priv;		spin_lock_irqsave(&adapter->lock, flags);	check_3c505_dma(dev);	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: request to send packet of length %d\n", dev->name, (int) skb->len);	netif_stop_queue(dev);		/*	 * send the packet at skb->data for skb->len	 */	if (!send_packet(dev, skb)) {		if (elp_debug >= 2) {			printk(KERN_DEBUG "%s: failed to transmit packet\n", dev->name);		}		spin_unlock_irqrestore(&adapter->lock, flags);		return 1;	}	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: packet of length %d sent\n", dev->name, (int) skb->len);	/*	 * start the transmit timeout	 */	dev->trans_start = jiffies;	prime_rx(dev);	spin_unlock_irqrestore(&adapter->lock, flags);	netif_start_queue(dev);	return 0;}/****************************************************** * * return statistics on the board * ******************************************************/static struct net_device_stats *elp_get_stats(struct net_device *dev){	elp_device *adapter = (elp_device *) dev->priv;	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: request for stats\n", dev->name);	/* If the device is closed, just return the latest stats we have,	   - we cannot ask from the adapter without interrupts */	if (!netif_running(dev))		return &adapter->stats;	/* send a get statistics command to the board */	adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;	adapter->tx_pcb.length = 0;	adapter->got[CMD_NETWORK_STATISTICS] = 0;	if (!send_pcb(dev, &adapter->tx_pcb))		printk(KERN_ERR "%s: couldn't send get statistics command\n", dev->name);	else {		unsigned long timeout = jiffies + TIMEOUT;		while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));		if (time_after_eq(jiffies, timeout)) {			TIMEOUT_MSG(__LINE__);			return &adapter->stats;		}	}	/* statistics are now up to date */	return &adapter->stats;}static void netdev_get_drvinfo(struct net_device *dev,			       struct ethtool_drvinfo *info){	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);}static u32 netdev_get_msglevel(struct net_device *dev){	return debug;}static void netdev_set_msglevel(struct net_device *dev, u32 level){	debug = level;}static struct ethtool_ops netdev_ethtool_ops = {	.get_drvinfo		= netdev_get_drvinfo,	.get_msglevel		= netdev_get_msglevel,	.set_msglevel		= netdev_set_msglevel,};/****************************************************** * * close the board * ******************************************************/static int elp_close(struct net_device *dev){	elp_device *adapter;	adapter = dev->priv;	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: request to close device\n", dev->name);	netif_stop_queue(dev);	/* Someone may request the device statistic information even when	 * the interface is closed. The following will update the statistics	 * structure in the driver, so we'll be able to give current statistics.	 */	(void) elp_get_stats(dev);	/*	 * disable interrupts on the board	 */	outb_control(0, dev);	/*	 * release the IRQ	 */	free_irq(dev->irq, dev);	free_dma(dev->dma);	free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));	return 0;}/************************************************************ * * Set multicast list * num_addrs==0: clear mc_list * num_addrs==-1: set promiscuous mode * num_addrs>0: set mc_list * ************************************************************/static void elp_set_mc_list(struct net_device *dev){	elp_device *adapter = (elp_device *) dev->priv;	struct dev_mc_list *dmi = dev->mc_list;	int i;	unsigned long flags;	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: request to set multicast list\n", dev->name);	spin_lock_irqsave(&adapter->lock, flags);		if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {		/* send a "load multicast list" command to the board, max 10 addrs/cmd */		/* if num_addrs==0 the list will be cleared */		adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;		adapter->tx_pcb.length = 6 * dev->mc_count;		for (i = 0; i < dev->mc_count; i++) {			memcpy(adapter->tx_pcb.data.multicast[i], dmi->dmi_addr, 6);			dmi = dmi->next;		}		adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;		if (!send_pcb(dev, &adapter->tx_pcb))			printk(KERN_ERR "%s: couldn't send set_multicast command\n", dev->name);		else {			unsigned long timeout = jiffies + TIMEOUT;			while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));			if (time_after_eq(jiffies, timeout)) {				TIMEOUT_MSG(__LINE__);			}		}		if (dev->mc_count)			adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;		else		/* num_addrs == 0 */			adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;	} else		adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;	/*	 * configure adapter to receive messages (as specified above)	 * and wait for response	 */	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name);

⌨️ 快捷键说明

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