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

📄 3c505.c

📁 linux设备驱动开发详解(书代码)
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))			goto sti_abort;	}	outb_control(adapter->hcr_val | 3, dev);	/* signal end of PCB */	outb_command(2 + pcb->length, dev->base_addr);	/* now wait for the acknowledgement */	spin_unlock_irqrestore(&adapter->lock, flags);	for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {		switch (GET_ASF(dev->base_addr)) {		case ASF_PCB_ACK:			adapter->send_pcb_semaphore = 0;			return TRUE;		case ASF_PCB_NAK:#ifdef ELP_DEBUG			printk(KERN_DEBUG "%s: send_pcb got NAK\n", dev->name);#endif			goto abort;		}	}	if (elp_debug >= 1)		printk(KERN_DEBUG "%s: timeout waiting for PCB acknowledge (status %02x)\n", dev->name, inb_status(dev->base_addr));	goto abort;      sti_abort:	spin_unlock_irqrestore(&adapter->lock, flags);      abort:	adapter->send_pcb_semaphore = 0;	return FALSE;}/***************************************************************** * * receive_pcb *   Read a PCB from the adapter * *	wait for ACRF to be non-zero        ---<---+ *	input a byte                               | *	if ASF1 and ASF2 were not both one         | *		before byte was read, loop      --->---+ *	set HSF1 and HSF2 for ack * *****************************************************************/static int receive_pcb(struct net_device *dev, pcb_struct * pcb){	int i, j;	int total_length;	int stat;	unsigned long timeout;	unsigned long flags;	elp_device *adapter = dev->priv;	set_hsf(dev, 0);	/* get the command code */	timeout = jiffies + 2*HZ/100;	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));	if (time_after_eq(jiffies, timeout)) {		TIMEOUT_MSG(__LINE__);		return FALSE;	}	pcb->command = inb_command(dev->base_addr);	/* read the data length */	timeout = jiffies + 3*HZ/100;	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));	if (time_after_eq(jiffies, timeout)) {		TIMEOUT_MSG(__LINE__);		printk(KERN_INFO "%s: status %02x\n", dev->name, stat);		return FALSE;	}	pcb->length = inb_command(dev->base_addr);	if (pcb->length > MAX_PCB_DATA) {		INVALID_PCB_MSG(pcb->length);		adapter_reset(dev);		return FALSE;	}	/* read the data */	spin_lock_irqsave(&adapter->lock, flags);	i = 0;	do {		j = 0;		while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && j++ < 20000);		pcb->data.raw[i++] = inb_command(dev->base_addr);		if (i > MAX_PCB_DATA)			INVALID_PCB_MSG(i);	} while ((stat & ASF_PCB_MASK) != ASF_PCB_END && j < 20000);	spin_unlock_irqrestore(&adapter->lock, flags);	if (j >= 20000) {		TIMEOUT_MSG(__LINE__);		return FALSE;	}	/* woops, the last "data" byte was really the length! */	total_length = pcb->data.raw[--i];	/* safety check total length vs data length */	if (total_length != (pcb->length + 2)) {		if (elp_debug >= 2)			printk(KERN_WARNING "%s: mangled PCB received\n", dev->name);		set_hsf(dev, HSF_PCB_NAK);		return FALSE;	}	if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {		if (test_and_set_bit(0, (void *) &adapter->busy)) {			if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {				set_hsf(dev, HSF_PCB_NAK);				printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name);				pcb->command = 0;				return TRUE;			} else {				pcb->command = 0xff;			}		}	}	set_hsf(dev, HSF_PCB_ACK);	return TRUE;}/****************************************************** * *  queue a receive command on the adapter so we will get an *  interrupt when a packet is received. * ******************************************************/static int start_receive(struct net_device *dev, pcb_struct * tx_pcb){	int status;	elp_device *adapter = dev->priv;	if (elp_debug >= 3)		printk(KERN_DEBUG "%s: restarting receiver\n", dev->name);	tx_pcb->command = CMD_RECEIVE_PACKET;	tx_pcb->length = sizeof(struct Rcv_pkt);	tx_pcb->data.rcv_pkt.buf_seg	    = tx_pcb->data.rcv_pkt.buf_ofs = 0;		/* Unused */	tx_pcb->data.rcv_pkt.buf_len = 1600;	tx_pcb->data.rcv_pkt.timeout = 0;	/* set timeout to zero */	status = send_pcb(dev, tx_pcb);	if (status)		adapter->rx_active++;	return status;}/****************************************************** * * extract a packet from the adapter * this routine is only called from within the interrupt * service routine, so no cli/sti calls are needed * note that the length is always assumed to be even * ******************************************************/static void receive_packet(struct net_device *dev, int len){	int rlen;	elp_device *adapter = dev->priv;	void *target;	struct sk_buff *skb;	unsigned long flags;	rlen = (len + 1) & ~1;	skb = dev_alloc_skb(rlen + 2);	if (!skb) {		printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name);		target = adapter->dma_buffer;		adapter->current_dma.target = NULL;		/* FIXME: stats */		return;	}	skb_reserve(skb, 2);	target = skb_put(skb, rlen);	if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {		adapter->current_dma.target = target;		target = adapter->dma_buffer;	} else {		adapter->current_dma.target = NULL;	}	/* if this happens, we die */	if (test_and_set_bit(0, (void *) &adapter->dmaing))		printk(KERN_ERR "%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction);	skb->dev = dev;	adapter->current_dma.direction = 0;	adapter->current_dma.length = rlen;	adapter->current_dma.skb = skb;	adapter->current_dma.start_time = jiffies;	outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);	flags=claim_dma_lock();	disable_dma(dev->dma);	clear_dma_ff(dev->dma);	set_dma_mode(dev->dma, 0x04);	/* dma read */	set_dma_addr(dev->dma, isa_virt_to_bus(target));	set_dma_count(dev->dma, rlen);	enable_dma(dev->dma);	release_dma_lock(flags);	if (elp_debug >= 3) {		printk(KERN_DEBUG "%s: rx DMA transfer started\n", dev->name);	}	if (adapter->rx_active)		adapter->rx_active--;	if (!adapter->busy)		printk(KERN_WARNING "%s: receive_packet called, busy not set.\n", dev->name);}/****************************************************** * * interrupt handler * ******************************************************/static irqreturn_t elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr){	int len;	int dlen;	int icount = 0;	struct net_device *dev;	elp_device *adapter;	unsigned long timeout;	dev = dev_id;	adapter = (elp_device *) dev->priv;		spin_lock(&adapter->lock);	do {		/*		 * has a DMA transfer finished?		 */		if (inb_status(dev->base_addr) & DONE) {			if (!adapter->dmaing) {				printk(KERN_WARNING "%s: phantom DMA completed\n", dev->name);			}			if (elp_debug >= 3) {				printk(KERN_DEBUG "%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr));			}			outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);			if (adapter->current_dma.direction) {				dev_kfree_skb_irq(adapter->current_dma.skb);			} else {				struct sk_buff *skb = adapter->current_dma.skb;				if (skb) {					if (adapter->current_dma.target) {				  	/* have already done the skb_put() */				  	memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);					}					skb->protocol = eth_type_trans(skb,dev);					adapter->stats.rx_bytes += skb->len;					netif_rx(skb);					dev->last_rx = jiffies;				}			}			adapter->dmaing = 0;			if (adapter->rx_backlog.in != adapter->rx_backlog.out) {				int t = adapter->rx_backlog.length[adapter->rx_backlog.out];				adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);				if (elp_debug >= 2)					printk(KERN_DEBUG "%s: receiving backlogged packet (%d)\n", dev->name, t);				receive_packet(dev, t);			} else {				adapter->busy = 0;			}		} else {			/* has one timed out? */			check_3c505_dma(dev);		}		/*		 * receive a PCB from the adapter		 */		timeout = jiffies + 3*HZ/100;		while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {			if (receive_pcb(dev, &adapter->irx_pcb)) {				switch (adapter->irx_pcb.command) 				{				case 0:					break;					/*					 * received a packet - this must be handled fast					 */				case 0xff:				case CMD_RECEIVE_PACKET_COMPLETE:					/* if the device isn't open, don't pass packets up the stack */					if (!netif_running(dev))						break;					len = adapter->irx_pcb.data.rcv_resp.pkt_len;					dlen = adapter->irx_pcb.data.rcv_resp.buf_len;					if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {						printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name);					} else {						if (elp_debug >= 3) {							printk(KERN_DEBUG "%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);						}						if (adapter->irx_pcb.command == 0xff) {							if (elp_debug >= 2)								printk(KERN_DEBUG "%s: adding packet to backlog (len = %d)\n", dev->name, dlen);							adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;							adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);						} else {							receive_packet(dev, dlen);						}						if (elp_debug >= 3)							printk(KERN_DEBUG "%s: packet received\n", dev->name);					}					break;					/*					 * 82586 configured correctly					 */				case CMD_CONFIGURE_82586_RESPONSE:					adapter->got[CMD_CONFIGURE_82586] = 1;					if (elp_debug >= 3)						printk(KERN_DEBUG "%s: interrupt - configure response received\n", dev->name);					break;					/*					 * Adapter memory configuration					 */				case CMD_CONFIGURE_ADAPTER_RESPONSE:					adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;					if (elp_debug >= 3)						printk(KERN_DEBUG "%s: Adapter memory configuration %s.\n", dev->name,						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");					break;					/*					 * Multicast list loading					 */				case CMD_LOAD_MULTICAST_RESPONSE:					adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;					if (elp_debug >= 3)						printk(KERN_DEBUG "%s: Multicast address list loading %s.\n", dev->name,						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");					break;					/*					 * Station address setting					 */				case CMD_SET_ADDRESS_RESPONSE:					adapter->got[CMD_SET_STATION_ADDRESS] = 1;					if (elp_debug >= 3)						printk(KERN_DEBUG "%s: Ethernet address setting %s.\n", dev->name,						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");					break;					/*					 * received board statistics					 */				case CMD_NETWORK_STATISTICS_RESPONSE:					adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;					adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;					adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;					adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;					adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;					adapter->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;					adapter->got[CMD_NETWORK_STATISTICS] = 1;					if (elp_debug >= 3)						printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name);					break;					/*					 * sent a packet					 */				case CMD_TRANSMIT_PACKET_COMPLETE:					if (elp_debug >= 3)						printk(KERN_DEBUG "%s: interrupt - packet sent\n", dev->name);					if (!netif_running(dev))						break;					switch (adapter->irx_pcb.data.xmit_resp.c_stat) {					case 0xffff:						adapter->stats.tx_aborted_errors++;						printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name);						break;					case 0xfffe:						adapter->stats.tx_fifo_errors++;						printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);						break;					}					netif_wake_queue(dev);					break;					/*					 * some unknown PCB					 */				default:					printk(KERN_DEBUG "%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command);					break;				}			} else {				printk(KERN_WARNING "%s: failed to read PCB on interrupt\n", dev->name);				adapter_reset(dev);			}		}	} while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));	prime_rx(dev);	/*	 * indicate no longer in interrupt routine	 */	spin_unlock(&adapter->lock);	return IRQ_HANDLED;}

⌨️ 快捷键说明

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