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

📄 usb-ohci.c

📁 周立功2410开发板USB键盘与鼠标应用开发源程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/*-------------------------------------------------------------------------*/ /* prepare all TDs of a transfer *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static void td_submit_urb (urb_t * urb){ 	urb_priv_t * urb_priv = urb->hcpriv;	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;	dma_addr_t data;	int data_len = urb->transfer_buffer_length;	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));	int cnt = 0; 	__u32 info = 0;  	unsigned int toggle = 0;	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */  	if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {  		toggle = TD_T_TOGGLE;	} else {  		toggle = TD_T_DATA0;		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);	}		urb_priv->td_cnt = 0;	if (data_len) {		data = pci_map_single (ohci->ohci_dev,			urb->transfer_buffer, data_len,			usb_pipeout (urb->pipe)				? PCI_DMA_TODEVICE				: PCI_DMA_FROMDEVICE			);	} else		data = 0;		switch (usb_pipetype (urb->pipe)) {		case PIPE_BULK:			info = usb_pipeout (urb->pipe)? 				TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;			while(data_len > 4096) {						td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);				data += 4096; data_len -= 4096; cnt++;			}			info = usb_pipeout (urb->pipe)?				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);			cnt++;			/* If the transfer size is multiple of the pipe mtu,			 * we may need an extra TD to create a empty frame			 * Note : another way to check this condition is			 * to test if(urb_priv->length > cnt) - Jean II */			if ((urb->transfer_flags & USB_ZERO_PACKET) &&			    usb_pipeout (urb->pipe) &&			    (urb->transfer_buffer_length != 0) && 			    ((urb->transfer_buffer_length % maxps) == 0)) {				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);				cnt++;			}			if (!ohci->sleeping) {// BUSHI				wmb();				writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */			}			break;		case PIPE_INTERRUPT:			info = usb_pipeout (urb->pipe)? 				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;			td_fill (ohci, info, data, data_len, urb, cnt++);			break;		case PIPE_CONTROL:			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;			td_fill (ohci, info,				pci_map_single (ohci->ohci_dev,					urb->setup_packet, 8,					PCI_DMA_TODEVICE),				8, urb, cnt++); 			if (data_len > 0) {  				info = usb_pipeout (urb->pipe)? 					TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;				/* NOTE:  mishandles transfers >8K, some >4K */				td_fill (ohci, info, data, data_len, urb, cnt++);  			} 			info = usb_pipeout (urb->pipe)?  				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;			td_fill (ohci, info, data, 0, urb, cnt++);			if (!ohci->sleeping) {				// BUSHI				wmb();				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */			}			break;		case PIPE_ISOCHRONOUS:			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {				td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 					data + urb->iso_frame_desc[cnt].offset, 					urb->iso_frame_desc[cnt].length, urb, cnt); 			}			break;	} //	if (urb_priv->length != cnt) //		dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);}/*-------------------------------------------------------------------------* * Done List handling functions *-------------------------------------------------------------------------*//* calculate the transfer length and update the urb */static void dl_transfer_length(td_t * td){	__u32 tdINFO, tdBE, tdCBP; 	__u16 tdPSW; 	urb_t * urb = td->urb; 	urb_priv_t * urb_priv = urb->hcpriv;	int dlen = 0;	int cc = 0;		tdINFO = le32_to_cpup (&td->hwINFO);  	tdBE   = le32_to_cpup (&td->hwBE);  	tdCBP  = le32_to_cpup (&td->hwCBP);  	if (tdINFO & TD_ISO) { 		tdPSW = le16_to_cpu (td->hwPSW[0]); 		cc = (tdPSW >> 12) & 0xF;		if (cc < 0xE)  {			if (usb_pipeout(urb->pipe)) {				dlen = urb->iso_frame_desc[td->index].length;			} else {				dlen = tdPSW & 0x3ff;			}			urb->actual_length += dlen;			urb->iso_frame_desc[td->index].actual_length = dlen;			if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))				cc = TD_CC_NOERROR;					 			urb->iso_frame_desc[td->index].status = cc_to_error[cc];		}	} else { /* BULK, INT, CONTROL DATA */		if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL && 				((td->index == 0) || (td->index == urb_priv->length - 1)))) { 			if (tdBE != 0) { 				if (td->hwCBP == 0)					urb->actual_length += tdBE - td->data_dma + 1;  				else					urb->actual_length += tdCBP - td->data_dma;			}  		}  	}}/* handle an urb that is being unlinked *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static void dl_del_urb (urb_t * urb){	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;	urb_rm_priv_locked (urb);	if (urb->transfer_flags & USB_ASYNC_UNLINK) {		urb->status = -ECONNRESET;		if (urb->complete)			urb->complete (urb);	} else {		urb->status = -ENOENT;		/* unblock sohci_unlink_urb */		if (wait_head)			wake_up (wait_head);	}}/*-------------------------------------------------------------------------*//* replies to the request have to be on a FIFO basis so * we reverse the reversed done-list */// 返转链表项顺序 static td_t * dl_reverse_done_list (ohci_t * ohci){	__u32 td_list_hc;	td_t * td_rev = NULL;	td_t * td_list = NULL;  	urb_priv_t * urb_priv = NULL;  	unsigned long flags;  	  	spin_lock_irqsave (&usb_ed_lock, flags);  		td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;	ohci->hcca->done_head = 0;		while (td_list_hc) {				td_list = dma_to_td (ohci, td_list_hc);			// 从传输描述符列表中找到		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {	// 获取完成代码,正常完成代码为0,其它值为出错			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;		// URB块中的私有数据		//	dbg(" USB-error/status: %x : %p", 		//			TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);			if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {				if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {					td_list->ed->hwHeadP = 						(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |									(td_list->ed->hwHeadP & cpu_to_le32 (0x2));					urb_priv->td_cnt += urb_priv->length - td_list->index - 1;				} else 					td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);			}		}		td_list->next_dl_td = td_rev;			td_rev = td_list;		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	// 获取下一个传输描述符指针	}		spin_unlock_irqrestore (&usb_ed_lock, flags);	return td_list;}/*-------------------------------------------------------------------------*//* there are some pending requests to remove  * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev) * - some URBs/TDs if urb_priv->state == URB_DEL *//*********************************************************************************************************** Function name: ** Descriptions: ** Input:** Output :** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/ static void dl_del_list (ohci_t  * ohci, unsigned int frame){	unsigned long flags;	ed_t * ed;	__u32 edINFO;	__u32 tdINFO;	td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;	__u32 * td_p;	int ctrl = 0, bulk = 0;	spin_lock_irqsave (&usb_ed_lock, flags);	for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);		edINFO = le32_to_cpup (&ed->hwINFO);		td_p = &ed->hwHeadP;		for (td = tdHeadP; td != tdTailP; td = td_next) { 			urb_t * urb = td->urb;			urb_priv_t * urb_priv = td->urb->hcpriv;						td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {				tdINFO = le32_to_cpup (&td->hwINFO);				if (TD_CC_GET (tdINFO) < 0xE)					dl_transfer_length (td);				*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));				/* URB is done; clean up */				if (++(urb_priv->td_cnt) == urb_priv->length)					dl_del_urb (urb);			} else {				td_p = &td->hwNextTD;			}		}		if (ed->state & ED_DEL) { /* set by sohci_free_dev */			struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);			td_free (ohci, tdTailP); /* free dummy td */   	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 			ed->state = ED_NEW;			hash_free_ed(ohci, ed);   	 		/* if all eds are removed wake up sohci_free_dev */   	 		if (!--dev->ed_cnt) {				wait_queue_head_t *wait_head = dev->wait;				dev->wait = 0;				if (wait_head)					wake_up (wait_head);			}   	 	} else {   	 		ed->state &= ~ED_URB_DEL;			tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);			if (tdHeadP == tdTailP) {				if (ed->state == ED_OPER)					ep_unlink(ohci, ed);				td_free (ohci, tdTailP);				ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);				ed->state = ED_NEW;				hash_free_ed(ohci, ed);				--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;			} else   	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);   	 	}		switch (ed->type) {			case PIPE_CONTROL:				ctrl = 1;				break;			case PIPE_BULK:				bulk = 1;				break;		}   	}   		/* maybe reenable control and bulk lists */ 	if (!ohci->disabled) {		if (ctrl) 	/* reset control list */			writel (0, &ohci->regs->ed_controlcurrent);		if (bulk)	/* reset bulk list */			writel (0, &ohci->regs->ed_bulkcurrent);		if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {			if (ohci->ed_controltail)				ohci->hc_control |= OHCI_CTRL_CLE;			if (ohci->ed_bulktail)				ohci->hc_control |= OHCI_CTRL_BLE;			writel (ohci->hc_control, &ohci->regs->control);   		}	}   	ohci->ed_rm_list[frame] = NULL;   	spin_unlock_irqrestore (&usb_ed_lock, flags);}  		/*-------------------------------------------------------------------------*//* td done list */// 已完成的传输描述符处理/*********************************************************************************************************** Function name: dl_done_list** Descriptions: 已完成的传输描述符处理** Input:* ohci:**       * td_list:** Output 0:**        1:** Created by:** Created Date: **-------------------------------------------------------------------------------------------------------** Modified by:** Modified Date: **------------------------------------------------------------------------------------------------------********************************************************************************************************/static void dl_done_list (ohci_t * ohci, td_t * td_list){  	td_t * td_list_next = NULL;	ed_t * ed;	int cc = 0;	urb_t * urb;	urb_priv_t * urb_priv; 	__u32 tdINFO, edHeadP, edTailP; 	 	unsigned long flags; 	  	while (td_list) {   		td_list_next = td_list->next_dl_td;				// 获取下一个已完成的传输列表项   		  		urb = td_list->urb;												// 获取URB块描述数据结构指针  		urb_priv = urb->hcpriv;										// 获取URB与系统相关的私有数据指针  		tdINFO = le32_to_cpup (&td_list->hwINFO);	// 传输描述符的状态信息  		   		ed = td_list->ed;													// 传输描述符对应的端点描述符指针   		   		dl_transfer_length(td_list);								// ********************************* 			  		/* error code of transfer */  		cc = TD_CC_GET (tdINFO);  		if (cc == TD_CC_STALL)							// 端点停止			usb_endpoint_halt(urb->dev,					// 执行端点停止处理函数				usb_pipeendpoint(urb->pipe),				usb_pipeout(urb->pipe));  		  		if (!(

⌨️ 快捷键说明

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