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

📄 dwc_otg_hcd_intr.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 4 页
字号:
	hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar);	hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt);	hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);	hcdma = dwc_read_reg32(&_hc_regs->hcdma);	DWC_ERROR("AHB ERROR, Channel %d\n", _hc->hc_num);	DWC_ERROR("  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);	DWC_ERROR("  hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");	DWC_ERROR("  Device address: %d\n", usb_pipedevice(urb->pipe));	DWC_ERROR("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),		  (usb_pipein(urb->pipe) ? "IN" : "OUT"));	DWC_ERROR("  Endpoint type: %s\n", ( {					    char *pipetype; switch (usb_pipetype(urb->pipe)) {case PIPE_CONTROL:pipetype = "CONTROL"; break; case PIPE_BULK:pipetype = "BULK"; break; case PIPE_INTERRUPT:pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:pipetype = "ISOCHRONOUS"; break; default:					    pipetype = "UNKNOWN"; break;};					    pipetype;}		  ));	DWC_ERROR("  Speed: %s\n", ( {				    char *speed; switch (urb->dev->speed) {case USB_SPEED_HIGH:speed = "HIGH"; break; case USB_SPEED_FULL:speed = "FULL"; break; case USB_SPEED_LOW:speed = "LOW"; break; default:				    speed = "UNKNOWN"; break;};				    speed;}		  ));	DWC_ERROR("  Max packet size: %d\n",		  usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));	DWC_ERROR("  Data buffer length: %d\n", urb->transfer_buffer_length);	DWC_ERROR("  Transfer buffer: %p, Transfer DMA: %p\n",		  urb->transfer_buffer, (void *) urb->transfer_dma);	DWC_ERROR("  Setup buffer: %p, Setup DMA: %p\n",		  urb->setup_packet, (void *) urb->setup_dma);	DWC_ERROR("  Interval: %d\n", urb->interval);	dwc_otg_hcd_complete_urb(_hcd, urb, -EIO);	/*	 * Force a channel halt. Don't call halt_channel because that won't	 * write to the HCCHARn register in DMA mode to force the halt.	 */	dwc_otg_hc_halt(_hcd->core_if, _hc, DWC_OTG_HC_XFER_AHB_ERR);	disable_hc_int(_hc_regs, ahberr);	return 1;}/** * Handles a host channel transaction error interrupt. This handler may be * called in either DMA mode or Slave mode. */static int32_t handle_hc_xacterr_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: " "Transaction Error--\n", _hc->hc_num);	switch (usb_pipetype(_qtd->urb->pipe)) {	case PIPE_CONTROL:	case PIPE_BULK:		_qtd->error_count++;		if (!_hc->qh->ping_state) {			update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb,						   _qtd, DWC_OTG_HC_XFER_XACT_ERR);			save_data_toggle(_hc, _hc_regs, _qtd);			if (!_hc->ep_is_in && _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.		 */		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR);		break;	case PIPE_INTERRUPT:		_qtd->error_count++;		if ((_hc->do_split) && (_hc->complete_split)) {			_qtd->complete_split = 0;		}		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR);		break;	case PIPE_ISOCHRONOUS:		{			dwc_otg_halt_status_e halt_status;			halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,							    DWC_OTG_HC_XFER_XACT_ERR);			halt_channel(_hcd, _hc, _qtd, halt_status);		}		break;	}	disable_hc_int(_hc_regs, xacterr);	return 1;}/** * Handles a host channel frame overrun interrupt. This handler may be called * in either DMA mode or Slave mode. */static int32_t handle_hc_frmovrun_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: " "Frame Overrun--\n", _hc->hc_num);	switch (usb_pipetype(_qtd->urb->pipe)) {	case PIPE_CONTROL:	case PIPE_BULK:		break;	case PIPE_INTERRUPT:		halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);		break;	case PIPE_ISOCHRONOUS:		{			dwc_otg_halt_status_e halt_status;			halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,							    DWC_OTG_HC_XFER_FRAME_OVERRUN);			halt_channel(_hcd, _hc, _qtd, halt_status);		}		break;	}	disable_hc_int(_hc_regs, frmovrun);	return 1;}/** * Handles a host channel data toggle error interrupt. This handler may be * called in either DMA mode or Slave mode. */static int32_t handle_hc_datatglerr_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: " "Data Toggle Error--\n", _hc->hc_num);	if (_hc->ep_is_in) {		_qtd->error_count = 0;	} else {		DWC_ERROR("Data Toggle Error on OUT transfer," "channel %d\n", _hc->hc_num);	}	disable_hc_int(_hc_regs, datatglerr);	return 1;}#ifdef DEBUG/** * This function is for debug only. It checks that a valid halt status is set * and that HCCHARn.chdis is clear. If there's a problem, corrective action is * taken and a warning is issued. * @return 1 if halt status is ok, 0 otherwise. */static inline int halt_status_ok(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;	hctsiz_data_t hctsiz;	hcint_data_t hcint;	hcintmsk_data_t hcintmsk;	hcsplt_data_t hcsplt;	if (_hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {		/*		 * This code is here only as a check. This condition should		 * never happen. Ignore the halt if it does occur.		 */		hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar);		hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);		hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);		hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk);		hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt);		DWC_WARN("%s: _hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "			 "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "			 "hcint 0x%08x, hcintmsk 0x%08x, "			 "hcsplt 0x%08x, qtd->complete_split %d\n",			 __func__, _hc->hc_num, hcchar.d32, hctsiz.d32,			 hcint.d32, hcintmsk.d32, hcsplt.d32, _qtd->complete_split);		DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",			 __func__, _hc->hc_num);		DWC_WARN("\n");		clear_hc_int(_hc_regs, chhltd);		return 0;	}	/*	 * This code is here only as a check. hcchar.chdis should	 * never be set when the halt interrupt occurs. Halt the	 * channel again if it does occur.	 */	hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar);	if (hcchar.b.chdis) {		DWC_WARN("%s: hcchar.chdis set unexpectedly, "			 "hcchar 0x%08x, trying to halt again\n", __func__, hcchar.d32);		clear_hc_int(_hc_regs, chhltd);		_hc->halt_pending = 0;		halt_channel(_hcd, _hc, _qtd, _hc->halt_status);		return 0;	}	return 1;}#endif/** * Handles a host Channel Halted interrupt in DMA mode. This handler * determines the reason the channel halted and proceeds accordingly. */static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * _hcd,				      dwc_hc_t * _hc,				      dwc_otg_hc_regs_t * _hc_regs,				      dwc_otg_qtd_t * _qtd){	hcint_data_t hcint;	hcintmsk_data_t hcintmsk;	if (_hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||	    _hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR) {		/*		 * Just release the channel. A dequeue can happen on a		 * transfer timeout. In the case of an AHB Error, the channel		 * was forced to halt because there's no way to gracefully		 * recover.		 */		release_channel(_hcd, _hc, _qtd, _hc->halt_status);		return;	}	/* Read the HCINTn register to determine the cause for the halt. */	hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);	hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk);	if (hcint.b.xfercomp) {		/** @todo This is here because of a possible hardware bug.  Spec		 * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT		 * interrupt w/ACK bit set should occur, but I only see the		 * XFERCOMP bit, even with it masked out.  This is a workaround		 * for that behavior.  Should fix this when hardware is fixed.		 */		if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!_hc->ep_is_in)) {			handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd);		}		handle_hc_xfercomp_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[0]++;	} else if (hcint.b.stall) {		handle_hc_stall_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[1]++;	} else if (hcint.b.xacterr) {		/*		 * Must handle xacterr before nak or ack. Could get a xacterr		 * at the same time as either of these on a BULK/CONTROL OUT		 * that started with a PING. The xacterr takes precedence.		 */		handle_hc_xacterr_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[2]++;	} else if (hcint.b.nyet) {		/*		 * Must handle nyet before nak or ack. Could get a nyet at the		 * same time as either of those on a BULK/CONTROL OUT that		 * started with a PING. The nyet takes precedence.		 */		handle_hc_nyet_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[3]++;	} else if (hcint.b.bblerr) {		handle_hc_babble_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[4]++;	} else if (hcint.b.frmovrun) {		handle_hc_frmovrun_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[5]++;	} else if (hcint.b.nak && !hcintmsk.b.nak) {		/*		 * If nak is not masked, it's because a non-split IN transfer		 * is in an error state. In that case, the nak is handled by		 * the nak interrupt handler, not here. Handle nak here for		 * BULK/CONTROL OUT transfers, which halt on a NAK to allow		 * rewinding the buffer pointer.		 */		handle_hc_nak_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[6]++;	} else if (hcint.b.ack && !hcintmsk.b.ack) {		/*		 * If ack is not masked, it's because a non-split IN transfer		 * is in an error state. In that case, the ack is handled by		 * the ack interrupt handler, not here. Handle ack here for		 * split transfers. Start splits halt on ACK.		 */		handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd);		_hcd->core_if->irq_hlt[7]++;	} else {		if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {			/*			 * A periodic transfer halted with no other channel			 * interrupts set. Assume it was halted by the core			 * because it could not be completed in its scheduled			 * (micro)frame.			 */#ifdef DEBUG			DWC_PRINT("%s: Halt channel %d (assume incomplete periodic transfer)\n",				  __func__, _hc->hc_num);#endif			halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);		} else {			DWC_ERROR("%s: Channel %d, DMA Mode -- ChHltd set, but reason "				  "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",				  __func__, _hc->hc_num, hcint.d32,				  dwc_read_reg32(&_hcd->core_if->core_global_regs->gintsts));		}		_hcd->core_if->irq_hlt[8]++;	}}/** * Handles a host channel Channel Halted interrupt. * * In slave mode, this handler is called only when the driver specifically * requests a halt. This occurs during handling other host channel interrupts * (e.g. nak, xacterr, stall, nyet, etc.). * * In DMA mode, this is the interrupt that occurs when the core has finished * processing a transfer on a channel. Other host channel interrupts (except * ahberr) are disabled in DMA mode. */static inline int32_t handle_hc_chhltd_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: " "Channel Halted--\n", _hc->hc_num);	if (_hcd->core_if->dma_enable) {		handle_hc_chhltd_intr_dma(_hcd, _hc, _hc_regs, _qtd);	} else {#ifdef DEBUG		if (!halt_status_ok(_hcd, _hc, _hc_regs, _qtd)) {			return 1;		}#endif		release_channel(_hcd, _hc, _qtd, _hc->halt_status);	}	return 1;}/** Handles interrupt for a specific Host Channel */int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * _dwc_otg_hcd, uint32_t _num){	int retval = 0;	hcint_data_t hcint;	hcintmsk_data_t hcintmsk;	dwc_hc_t *hc;	dwc_otg_hc_regs_t *hc_regs;	dwc_otg_qtd_t *qtd;	DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num);	hc = _dwc_otg_hcd->hc_ptr_array[_num];	hc_regs = _dwc_otg_hcd->core_if->host_if->hc_regs[_num];	qtd = list_entry(hc->qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry);	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);	hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);	DWC_DEBUGPL(DBG_HCDV, "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",		    hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));	hcint.d32 = hcint.d32 & hcintmsk.d32;	if (!_dwc_otg_hcd->core_if->dma_enable) {		printk("DO NOT OCCUR.... ERROR in IRQ in dma enabled\n");		if ((hcint.b.chhltd) && (hcint.d32 != 0x2)) {			hcint.b.chhltd = 0;		}	}	if (hcint.b.xfercomp) {		_dwc_otg_hcd->core_if->irq_hcd[0]++;		retval |= handle_hc_xfercomp_intr(_dwc_otg_hcd, hc, hc_regs, qtd);		/*		 * If NYET occurred at same time as Xfer Complete, the NYET is		 * handled by the Xfer Complete interrupt handler. Don't want		 * to call the NYET interrupt handler in this case.		 */		hcint.b.nyet = 0;	}	if (hcint.b.chhltd) {		_dwc_otg_hcd->core_if->irq_hcd[1]++;		retval |= handle_hc_chhltd_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.ahberr) {		_dwc_otg_hcd->core_if->irq_hcd[2]++;		retval |= handle_hc_ahberr_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.stall) {		_dwc_otg_hcd->core_if->irq_hcd[3]++;		retval |= handle_hc_stall_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.nak) {		_dwc_otg_hcd->core_if->irq_hcd[4]++;		retval |= handle_hc_nak_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.ack) {		_dwc_otg_hcd->core_if->irq_hcd[5]++;		retval |= handle_hc_ack_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.nyet) {		_dwc_otg_hcd->core_if->irq_hcd[6]++;		retval |= handle_hc_nyet_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.xacterr) {		_dwc_otg_hcd->core_if->irq_hcd[7]++;		retval |= handle_hc_xacterr_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.bblerr) {		_dwc_otg_hcd->core_if->irq_hcd[8]++;		retval |= handle_hc_babble_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.frmovrun) {		_dwc_otg_hcd->core_if->irq_hcd[9]++;		retval |= handle_hc_frmovrun_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	if (hcint.b.datatglerr) {		_dwc_otg_hcd->core_if->irq_hcd[10]++;		retval |= handle_hc_datatglerr_intr(_dwc_otg_hcd, hc, hc_regs, qtd);	}	return retval;}#endif				/* DWC_DEVICE_ONLY */

⌨️ 快捷键说明

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