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

📄 dwc_otg_hcd_intr.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 4 页
字号:
	hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);	if (!_hc->ep_is_in || hctsiz.b.pktcnt == 0) {		/* Core halts channel in these cases. */		release_channel(_hcd, _hc, _qtd, _halt_status);	} else {		/* Flush any outstanding requests from the Tx queue. */		halt_channel(_hcd, _hc, _qtd, _halt_status);	}}/** * Handles a host channel Transfer Complete interrupt. This handler may be * called in either DMA mode or Slave mode. */static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * _hcd,				       dwc_hc_t * _hc,				       dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd){	int urb_xfer_done;	dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;	struct urb *urb = _qtd->urb;	int pipe_type = usb_pipetype(urb->pipe);	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "Transfer Complete--\n", _hc->hc_num);	/*	 * Handle xfer complete on CSPLIT.	 */	if (_hc->qh->do_split) {		_qtd->complete_split = 0;	}	/* Update the QTD and URB states. */	switch (pipe_type) {	case PIPE_CONTROL:		switch (_qtd->control_phase) {		case DWC_OTG_CONTROL_SETUP:			if (urb->transfer_buffer_length > 0) {				_qtd->control_phase = DWC_OTG_CONTROL_DATA;			} else {				_qtd->control_phase = DWC_OTG_CONTROL_STATUS;			}			DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction done\n");			halt_status = DWC_OTG_HC_XFER_COMPLETE;			break;		case DWC_OTG_CONTROL_DATA:{				urb_xfer_done =					update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd);				if (urb_xfer_done) {					_qtd->control_phase = DWC_OTG_CONTROL_STATUS;					DWC_DEBUGPL(DBG_HCDV, "  Control data transfer done\n");				} else {					save_data_toggle(_hc, _hc_regs, _qtd);				}				halt_status = DWC_OTG_HC_XFER_COMPLETE;				break;			}		case DWC_OTG_CONTROL_STATUS:			DWC_DEBUGPL(DBG_HCDV, "  Control transfer complete\n");			if (urb->status == -EINPROGRESS) {				urb->status = 0;			}			dwc_otg_hcd_complete_urb(_hcd, urb, urb->status);			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;			break;		}		complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status);		_hcd->core_if->xfr_done[0]++;		break;	case PIPE_BULK:		DWC_DEBUGPL(DBG_HCDV, "  Bulk transfer complete\n");		urb_xfer_done = update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd);		if (urb_xfer_done) {			dwc_otg_hcd_complete_urb(_hcd, urb, urb->status);			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;		} else {			halt_status = DWC_OTG_HC_XFER_COMPLETE;		}		save_data_toggle(_hc, _hc_regs, _qtd);		complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status);		_hcd->core_if->xfr_done[1]++;		break;	case PIPE_INTERRUPT:		DWC_DEBUGPL(DBG_HCDV, "  Interrupt transfer complete\n");		update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd);		/*		 * Interrupt URB is done on the first transfer complete		 * interrupt.		 */		dwc_otg_hcd_complete_urb(_hcd, urb, urb->status);		save_data_toggle(_hc, _hc_regs, _qtd);		complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, DWC_OTG_HC_XFER_URB_COMPLETE);		_hcd->core_if->xfr_done[2]++;		break;	case PIPE_ISOCHRONOUS:		DWC_DEBUGPL(DBG_HCDV, "  Isochronous transfer complete\n");		if (_qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {			halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,							    DWC_OTG_HC_XFER_COMPLETE);		}		complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status);		_hcd->core_if->xfr_done[3]++;		break;	}	disable_hc_int(_hc_regs, xfercompl);	return 1;}/** * Handles a host channel STALL interrupt. This handler may be called in * either DMA mode or Slave mode. */static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * _hcd,				    dwc_hc_t * _hc,				    dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd){	struct urb *urb = _qtd->urb;	int pipe_type = usb_pipetype(urb->pipe);	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "STALL Received--\n", _hc->hc_num);	if (pipe_type == PIPE_CONTROL) {		dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE);	}	if (pipe_type == PIPE_BULK || pipe_type == PIPE_INTERRUPT) {		dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE);		/*		 * USB protocol requires resetting the data toggle for bulk		 * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)		 * setup command is issued to the endpoint. Anticipate the		 * CLEAR_FEATURE command since a STALL has occurred and reset		 * the data toggle now.		 */		_hc->qh->data_toggle = 0;	}	halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_STALL);	disable_hc_int(_hc_regs, stall);	return 1;}/* * Updates the state of the URB when a transfer has been stopped due to an * abnormal condition before the transfer completes. Modifies the * actual_length field of the URB to reflect the number of bytes that have * actually been transferred via the host channel. */static void update_urb_state_xfer_intr(dwc_hc_t * _hc,				       dwc_otg_hc_regs_t * _hc_regs,				       struct urb *_urb,				       dwc_otg_qtd_t * _qtd, dwc_otg_halt_status_e _halt_status){	uint32_t bytes_transferred = get_actual_xfer_length(_hc, _hc_regs, _qtd,							    _halt_status, NULL);	_urb->actual_length += bytes_transferred;#ifdef DEBUG	{		hctsiz_data_t hctsiz;		hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);		DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",			    __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num);		DWC_DEBUGPL(DBG_HCDV, "  _hc->start_pkt_count %d\n", _hc->start_pkt_count);		DWC_DEBUGPL(DBG_HCDV, "  hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);		DWC_DEBUGPL(DBG_HCDV, "  _hc->max_packet %d\n", _hc->max_packet);		DWC_DEBUGPL(DBG_HCDV, "  bytes_transferred %d\n", bytes_transferred);		DWC_DEBUGPL(DBG_HCDV, "  _urb->actual_length %d\n", _urb->actual_length);		DWC_DEBUGPL(DBG_HCDV, "  _urb->transfer_buffer_length %d\n",			    _urb->transfer_buffer_length);	}#endif}/** * Handles a host channel NAK interrupt. This handler may be called in either * DMA mode or Slave mode. */static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * _hcd,				  dwc_hc_t * _hc,				  dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd){	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "NAK Received--\n", _hc->hc_num);	/*	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and	 * interrupt.  Re-start the SSPLIT transfer.	 */	if (_hc->do_split) {		if (_hc->complete_split) {			_qtd->error_count = 0;		}		_qtd->complete_split = 0;		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);		goto handle_nak_done;	}	switch (usb_pipetype(_qtd->urb->pipe)) {	case PIPE_CONTROL:	case PIPE_BULK:		if (_hcd->core_if->dma_enable && _hc->ep_is_in) {			/*			 * NAK interrupts are enabled on bulk/control IN			 * transfers in DMA mode for the sole purpose of			 * resetting the error count after a transaction error			 * occurs. The core will continue transferring data.			 */			_qtd->error_count = 0;			goto handle_nak_done;		}		/*		 * NAK interrupts normally occur during OUT transfers in DMA		 * or Slave mode. For IN transfers, more requests will be		 * queued as request queue space is available.		 */		_qtd->error_count = 0;		if (!_hc->qh->ping_state) {			update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb,						   _qtd, DWC_OTG_HC_XFER_NAK);			save_data_toggle(_hc, _hc_regs, _qtd);			if (_qtd->urb->dev->speed == USB_SPEED_HIGH) {				_hc->qh->ping_state = 1;			}		}		/*		 * Halt the channel so the transfer can be re-started from		 * the appropriate point or the PING protocol will		 * start/continue.		 */		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);		break;	case PIPE_INTERRUPT:		_qtd->error_count = 0;		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);		break;	case PIPE_ISOCHRONOUS:		/* Should never get called for isochronous transfers. */		BUG();		break;	}      handle_nak_done:	disable_hc_int(_hc_regs, nak);	return 1;}/** * Handles a host channel ACK interrupt. This interrupt is enabled when * performing the PING protocol in Slave mode, when errors occur during * either Slave mode or DMA mode, and during Start Split transactions. */static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * _hcd,				  dwc_hc_t * _hc,				  dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd){	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "ACK Received--\n", _hc->hc_num);	if (_hc->do_split) {		/*		 * Handle ACK on SSPLIT.		 * ACK should not occur in CSPLIT.		 */		if ((!_hc->ep_is_in) && (_hc->data_pid_start != DWC_OTG_HC_PID_SETUP)) {			_qtd->ssplit_out_xfer_count = _hc->xfer_len;		}		if (!(_hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !_hc->ep_is_in)) {			/* Don't need complete for isochronous out transfers. */			_qtd->complete_split = 1;		}		/* ISOC OUT */		if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && !_hc->ep_is_in) {			switch (_hc->xact_pos) {			case DWC_HCSPLIT_XACTPOS_ALL:				break;			case DWC_HCSPLIT_XACTPOS_END:				_qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;				_qtd->isoc_split_offset = 0;				break;			case DWC_HCSPLIT_XACTPOS_BEGIN:			case DWC_HCSPLIT_XACTPOS_MID:				/*				 * For BEGIN or MID, calculate the length for				 * the next microframe to determine the correct				 * SSPLIT token, either MID or END.				 */				do {					struct usb_iso_packet_descriptor *frame_desc;					frame_desc =						&_qtd->urb->iso_frame_desc[_qtd->isoc_frame_index];					_qtd->isoc_split_offset += 188;					if ((frame_desc->length - _qtd->isoc_split_offset) <= 188) {						_qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_END;					} else {						_qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_MID;					}				} while (0);				break;			}		} else {			halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK);		}	} else {		_qtd->error_count = 0;		if (_hc->qh->ping_state) {			_hc->qh->ping_state = 0;			/*			 * Halt the channel so the transfer can be re-started			 * from the appropriate point. This only happens in			 * Slave mode. In DMA mode, the ping_state is cleared			 * when the transfer is started because the core			 * automatically executes the PING, then the transfer.			 */			halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK);		}	}	/*	 * If the ACK occurred when _not_ in the PING state, let the channel	 * continue transferring data after clearing the error count.	 */	disable_hc_int(_hc_regs, ack);	return 1;}/** * Handles a host channel NYET interrupt. This interrupt should only occur on * Bulk and Control OUT endpoints and for complete split transactions. If a * NYET occurs at the same time as a Transfer Complete interrupt, it is * handled in the xfercomp interrupt handler, not here. This handler may be * called in either DMA mode or Slave mode. */static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * _hcd,				   dwc_hc_t * _hc,				   dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd){	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "NYET Received--\n", _hc->hc_num);	/*	 * NYET on CSPLIT	 * re-do the CSPLIT immediately on non-periodic	 */	if ((_hc->do_split) && (_hc->complete_split)) {		if ((_hc->ep_type == DWC_OTG_EP_TYPE_INTR) ||		    (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {			int frnum = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd));			if (dwc_full_frame_num(frnum) != dwc_full_frame_num(_hc->qh->sched_frame)) {				/*				 * No longer in the same full speed frame.				 * Treat this as a transaction error.				 */#if 0				/** @todo Fix system performance so this can				 * be treated as an error. Right now complete				 * splits cannot be scheduled precisely enough				 * due to other system activity, so this error				 * occurs regularly in Slave mode.				 */				_qtd->error_count++;#endif				_qtd->complete_split = 0;				halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR);				/** @todo add support for isoc release */				goto handle_nyet_done;			}		}		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET);		goto handle_nyet_done;	}	_hc->qh->ping_state = 1;	_qtd->error_count = 0;	update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, _qtd, DWC_OTG_HC_XFER_NYET);	save_data_toggle(_hc, _hc_regs, _qtd);	/*	 * Halt the channel and re-start the transfer so the PING	 * protocol will start.	 */	halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET);      handle_nyet_done:	disable_hc_int(_hc_regs, nyet);	return 1;}/** * Handles a host channel babble interrupt. This handler may be called in * either DMA mode or Slave mode. */static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * _hcd,				     dwc_hc_t * _hc,				     dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd){	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "Babble Error--\n", _hc->hc_num);	if (_hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {		dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EOVERFLOW);		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_BABBLE_ERR);	} else {		dwc_otg_halt_status_e halt_status;		halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,						    DWC_OTG_HC_XFER_BABBLE_ERR);		halt_channel(_hcd, _hc, _qtd, halt_status);	}	disable_hc_int(_hc_regs, bblerr);	return 1;}/** * Handles a host channel AHB error interrupt. This handler is only called in * DMA mode. */static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * _hcd,				     dwc_hc_t * _hc,				     dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd){	hcchar_data_t hcchar;	hcsplt_data_t hcsplt;	hctsiz_data_t hctsiz;	uint32_t hcdma;	struct urb *urb = _qtd->urb;	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "AHB Error--\n", _hc->hc_num);

⌨️ 快捷键说明

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