?? dwc_otg_hcd_intr.c
字號:
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 + -