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

📄 hc_crisv10.c

📁 usb driver for 2.6.17
💻 C
📖 第 1 页 / 共 5 页
字号:
}static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data){	usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data;	struct urb *urb;	int epid;	int epid_done;	etrax_urb_priv_t *urb_priv;	DBFENTER;	dbg_isoc("dma8_sub3_descr (ISOC) bottom half.");	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {		unsigned long flags;		save_flags(flags);		cli();		epid_done = 0;		/* The descriptor interrupt handler has marked all transmitted isoch. out		   URBs with TRANSFER_DONE.  Now we traverse all epids and for all that 		   have isoch. out traffic traverse its URB list and complete the		   transmitted URB.		*/		while (!epid_done) {			/* Get the first urb (if any). */			urb = urb_list_first(epid);			if (urb == 0) {				epid_done = 1;				continue;			}			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {					epid_done = 1;					continue;			}			if (!usb_pipeout(urb->pipe)) {				/* descr interrupts are generated only for out pipes. */				epid_done = 1;				continue;			}			dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub);			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;			assert(urb_priv);			if (urb_priv->urb_state == TRANSFER_DONE) {				int i;				struct usb_iso_packet_descriptor *packet;				/* This urb has been sent. */				dbg_isoc("Completing isoc out URB 0x%p", urb);				for (i = 0; i < urb->number_of_packets; i++) {					packet = &urb->iso_frame_desc[i];					packet->status = 0;					packet->actual_length = packet->length;				}				etrax_usb_complete_isoc_urb(urb, 0);				if (urb_list_empty(epid)) {					etrax_usb_free_epid(epid);					epid_done = 1;				}			} else {				epid_done = 1;			}		}		restore_flags(flags);	}	kmem_cache_free(isoc_compl_cache, comp_data);	DBFEXIT;}static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs){	struct urb *urb;	etrax_urb_priv_t *urb_priv;	int epid = 0;	unsigned long flags;	/* Isoc diagnostics. */	static int curr_fm = 0;	static int prev_fm = 0;	DBFENTER;	/* Clear this interrupt. */	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);	/* Note that this while loop assumes that all packets span only	   one rx descriptor. */	/* The reason we cli here is that we call the driver's callback functions. */	save_flags(flags);	cli();	while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {		epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);		urb = urb_list_first(epid);		//printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);		if (!urb) {			err("No urb for epid %d in rx interrupt", epid);			__dump_ept_data(epid);			goto skip_out;		}		/* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since		   ctrl pipes are not. */		if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {			__u32 r_usb_ept_data;			int no_error = 0;			assert(test_bit(epid, (void *)&epid_usage_bitmask));			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);			nop();			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {				r_usb_ept_data = *R_USB_EPT_DATA_ISO;				if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&				    (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {					/* Not an error, just a failure to receive an expected iso					   in packet in this frame.  This is not documented					   in the designers reference.					*/					no_error++;				} else {					warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data);				}			} else {				r_usb_ept_data = *R_USB_EPT_DATA;				warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);			}			if (!no_error){				warn("error in rx desc->status, epid %d, first urb = 0x%lx",				     epid, (unsigned long)urb);				__dump_in_desc(myNextRxDesc);				warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);				/* Check that ept was disabled when error occurred. */				switch (usb_pipetype(urb->pipe)) {				case PIPE_BULK:					assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));					break;				case PIPE_CONTROL:					assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));					break;				case PIPE_INTERRUPT:					assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable)));					break;				case PIPE_ISOCHRONOUS:					assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)));					break;				default:					warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p",					     usb_pipetype(urb->pipe),					     urb);				}				etrax_usb_complete_urb(urb, -EPROTO);				goto skip_out;			}		}		urb_priv = (etrax_urb_priv_t *)urb->hcpriv;		assert(urb_priv);		if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||		    (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||		    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {				/* We get nodata for empty data transactions, and the rx descriptor's				   hw_len field is not valid in that case. No data to copy in other				   words. */			} else {				/* Make sure the data fits in the buffer. */				assert(urb_priv->rx_offset + myNextRxDesc->hw_len				       <= urb->transfer_buffer_length);				memcpy(urb->transfer_buffer + urb_priv->rx_offset,				       phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);				urb_priv->rx_offset += myNextRxDesc->hw_len;			}			if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {				if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) &&				    ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) ==				     IO_STATE(USB_EP_command, enable, yes))) {					/* The EP is still enabled, so the OUT packet used to ack					   the in data is probably not processed yet.  If the EP					   sub pointer has not moved beyond urb_priv->last_sb mark					   it for a descriptor interrupt and complete the urb in					   the descriptor interrupt handler.					*/					USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0;					while ((sub != NULL) && (sub != urb_priv->last_sb)) {						sub = sub->next ? phys_to_virt(sub->next) : 0;					}					if (sub != NULL) {						/* The urb has not been fully processed. */						urb_priv->urb_state = WAITING_FOR_DESCR_INTR;					} else {						warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub);						etrax_usb_complete_urb(urb, 0);					}				} else {					etrax_usb_complete_urb(urb, 0);				}			}		} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {			struct usb_iso_packet_descriptor *packet;			if (urb_priv->urb_state == UNLINK) {				info("Ignoring rx data for urb being unlinked.");				goto skip_out;			} else if (urb_priv->urb_state == NOT_STARTED) {				info("What? Got rx data for urb that isn't started?");				goto skip_out;			}			packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];			packet->status = 0;			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {				/* We get nodata for empty data transactions, and the rx descriptor's				   hw_len field is not valid in that case. We copy 0 bytes however to				   stay in synch. */				packet->actual_length = 0;			} else {				packet->actual_length = myNextRxDesc->hw_len;				/* Make sure the data fits in the buffer. */				assert(packet->actual_length <= packet->length);				memcpy(urb->transfer_buffer + packet->offset,				       phys_to_virt(myNextRxDesc->buf), packet->actual_length);			}			/* Increment the packet counter. */			urb_priv->isoc_packet_counter++;			/* Note that we don't care about the eot field in the rx descriptor's status.			   It will always be set for isoc traffic. */			if (urb->number_of_packets == urb_priv->isoc_packet_counter) {				/* Out-of-synch diagnostics. */				curr_fm = (*R_USB_FM_NUMBER & 0x7ff);				if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {					/* This test is wrong, if there is more than one isoc					   in endpoint active it will always calculate wrong					   since prev_fm is shared by all endpoints.					   FIXME Make this check per URB using urb->start_frame.					*/					dbg_isoc("Out of synch? Previous frame = %d, current frame = %d",						 prev_fm, curr_fm);				}				prev_fm = curr_fm;				/* Complete the urb with status OK. */				etrax_usb_complete_isoc_urb(urb, 0);			}		}	skip_out:		/* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr		   has the same layout as USB_IN_Desc for the relevant fields.) */		prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);		myPrevRxDesc = myNextRxDesc;		myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);		myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);		myLastRxDesc = myPrevRxDesc;		myNextRxDesc->status = 0;		myNextRxDesc = phys_to_virt(myNextRxDesc->next);	}	restore_flags(flags);	DBFEXIT;        return IRQ_HANDLED;}/* This function will unlink the SB descriptors associated with this urb. */static int etrax_remove_from_sb_list(struct urb *urb){	USB_SB_Desc_t *next_sb, *first_sb, *last_sb;	etrax_urb_priv_t *urb_priv;	int i = 0;	DBFENTER;	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;	assert(urb_priv);	/* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor	   doesn't really need to be disabled, it's just that we expect it to be. */	if (usb_pipetype(urb->pipe) == PIPE_BULK) {		assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {		assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));	}	first_sb = urb_priv->first_sb;	last_sb = urb_priv->last_sb;	assert(first_sb);	assert(last_sb);	while (first_sb != last_sb) {		next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);		kmem_cache_free(usb_desc_cache, first_sb);		first_sb = next_sb;		i++;	}	kmem_cache_free(usb_desc_cache, last_sb);	i++;	dbg_sb("%d SB descriptors freed", i);	/* Compare i with urb->number_of_packets for Isoc traffic.	   Should be same when calling unlink_urb */	DBFEXIT;	return i;}static int etrax_usb_submit_bulk_urb(struct urb *urb){	int epid;	int empty;	unsigned long flags;	etrax_urb_priv_t *urb_priv;	DBFENTER;	/* Epid allocation, empty check and list add must be protected.	   Read about this in etrax_usb_submit_ctrl_urb. */	spin_lock_irqsave(&urb_list_lock, flags);	epid = etrax_usb_setup_epid(urb);	if (epid == -1) {		DBFEXIT;		spin_unlock_irqrestore(&urb_list_lock, flags);		return -ENOMEM;	}	empty = urb_list_empty(epid);	urb_list_add(urb, epid);	spin_unlock_irqrestore(&urb_list_lock, flags);	dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",		 usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);	/* Mark the urb as being in progress. */	urb->status = -EINPROGRESS;	/* Setup the hcpriv data. */	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);	assert(urb_priv != NULL);	/* This sets rx_offset to 0. */	urb_priv->urb_state = NOT_STARTED;	urb->hcpriv = urb_priv;	if (empty) {		etrax_usb_add_to_bulk_sb_list(urb, epid);	}	DBFEXIT;	return 0;}static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid){	USB_SB_Desc_t *sb_desc;	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;	unsigned long flags;	char maxlen;	DBFENTER;	dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));	sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);	assert(sb_desc != NULL);	memset(sb_desc, 0, sizeof(USB_SB_Desc_t));	if (usb_pipeout(urb->pipe)) {		dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);		/* This is probably a sanity check of the bulk transaction length		   not being larger than 64 kB. */		if (urb->transfer_buffer_length > 0xffff) {			panic("urb->transfer_buffer_length > 0xffff");		}		sb_desc->sw_len = urb->transfer_buffer_length;		/* The rem field is don't care if it's not a full-length transfer, so setting		   it shouldn't hurt. Also, rem isn't used for OUT traffic. */		sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |				    IO_STATE(USB_SB_command, tt, out) |				    IO_STATE(USB_SB_command, eot, yes) |				    IO_STATE(USB_SB_command, eol, yes));		/* The full field is set to yes, even if we don't actually check tha

⌨️ 快捷键说明

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