📄 usbtcdpdiusbd12evallib.c
字号:
/* If this ERP is awaiting status, check the status. If the ERP * is not awaiting status, then the status must be stale, so * discard it. */ if (pTarget->transPending [pEndpoint->endpointId]) { /* "consume" the last status read for this endpoint */ tStatus = pTarget->transStatus [pEndpoint->endpointId]; pTarget->transPending [pEndpoint->endpointId] = FALSE; if (pWork->inStatusPending) { /* If the last transaction failed, fail the ERP. */#ifdef D12_CHECK_DATA_SUCCESS_BIT if ((tStatus & D12_CMD_RLTS_DATA_SUCCESS) == 0) { finishErp (pTarget, pErp, S_usbTcdLib_COMM_FAULT); return; }#endif /* #ifdef D12_CHECK_DATA_SUCCESS_BIT */ pWork->inStatusPending = FALSE; /* Is the ERP complete? */ if (pWork->curBfr == pErp->bfrCount || (pErp->bfrList [0].pBfr == NULL && pErp->bfrList [0].bfrLen == 0)) { finishErp (pTarget, pErp, OK); return; } } } /* If the endpoint can accept data, put data into it now. */ if ((d12SelectEndpoint (pTarget, pErp->endpointId) & D12_CMD_SE_FULL_EMPTY) != 0) return; d12WriteBfr (pTarget, pEndpoint, pErp, pWork); pWork->inStatusPending = TRUE; }/***************************************************************************** processOutEndpoint - update an ERP for an OUT endpoint** Validates data received by the device on an OUT endpoint and puts the* data into the indicated ERP. If the ERP completes (successfully or with* an error), this function sets the ERP status.** RETURNS: N/A*/LOCAL VOID processOutEndpoint ( pTARGET pTarget, pUSB_TARG_ENDPOINT_INFO pEndpoint, pUSB_ERP pErp, pERP_WORKSPACE pWork ) { UINT8 tStatus; /* Check if this ERP/endpoint is handled via DMA */ if (checkDma (pTarget, pEndpoint, pErp, pWork)) return; /* Is there a pending transaction for this endpoint? */ if (!pTarget->transPending [pEndpoint->endpointId]) return; /* Pick up the last status read for this endpoint */ tStatus = pTarget->transStatus [pEndpoint->endpointId]; /* Check the incoming data against the expected PID. */ if (pErp->transferType == USB_XFRTYPE_CONTROL) { if (((tStatus & D12_CMD_RLTS_SETUP_PACKET) != 0 && pErp->bfrList [0].pid != USB_PID_SETUP) || ((tStatus & D12_CMD_RLTS_SETUP_PACKET) == 0 && pErp->bfrList [0].pid != USB_PID_OUT)) { /* PID mismatch */ stallEndpoint (pTarget, pEndpoint->endpointId); finishErp (pTarget, pErp, S_usbTcdLib_PID_MISMATCH); return; } } /* Now that we're sure we're processing the expected kind of packet, * "consume" the endpoint status. */ pTarget->transPending [pEndpoint->endpointId] = FALSE; /* If this was a setup packet, let the D12 know we acknowledge it. */ if ((tStatus & D12_CMD_RLTS_SETUP_PACKET) != 0) { d12AckSetup (pTarget, D12_ENDPOINT_CONTROL_IN); d12AckSetup (pTarget, D12_ENDPOINT_CONTROL_OUT); } /* Was the last transaction successful? If not, fail the ERP. */#ifdef D12_CHECK_DATA_SUCCESS_BIT if ((tStatus & D12_CMD_RLTS_DATA_SUCCESS) == 0) { finishErp (pTarget, pErp, S_usbTcdLib_COMM_FAULT); return; }#endif /* #ifdef D12_CHECK_DATA_SUCCESS_BIT */ /* Check the DATA0/DATA1 flag against the expected flag */ if (((tStatus & D12_CMD_RLTS_DATA1) == 0) != (pErp->dataToggle == USB_DATA0)) { /* Data toggle mismatch */ stallEndpoint (pTarget, pEndpoint->endpointId); finishErp (pTarget, pErp, S_usbTcdLib_DATA_TOGGLE_FAULT); return; } pErp->dataToggle = (pErp->dataToggle == USB_DATA0) ? USB_DATA1 : USB_DATA0; /* Read data into the ERP. */ d12ReadBfr (pTarget, pEndpoint, pErp, pWork); /* Is the ERP complete? */ if (pWork->curBfr == pErp->bfrCount || (pErp->bfrList [0].pBfr == NULL && pErp->bfrList [0].bfrLen == 0)) { finishErp (pTarget, pErp, OK); } }/***************************************************************************** processErpQueue - See if we can update the queue for an endpoint** This function examines the ERP queue for the specified <endpointId>.* If the queue can be updated - that is, if data can be transferred to/* from the queue or an error condition can be logged - then we update* the queue.** RETURNS: N/A*/LOCAL VOID processErpQueue ( pTARGET pTarget, UINT16 endpointId ) { pUSB_TARG_ENDPOINT_INFO pEndpoint = &pTarget->pEndpoints [endpointId]; pUSB_ERP pErp; pERP_WORKSPACE pWork; /* Process the next ERP */ if ((pErp = usbListFirst (&pTarget->erps [endpointId])) != NULL) { /* Get ERP_WORKSPACE for this ERP/endpoint. */ pWork = &pTarget->workspace [endpointId]; if (!((BOOL) pErp->tcdPtr)) { pErp->tcdPtr = (pVOID) TRUE; memset (pWork, 0, sizeof (*pWork)); } /* Fan-out based on OUT or IN endpoint. */ switch (pErp->endpointId) { case D12_ENDPOINT_CONTROL_OUT: case D12_ENDPOINT_1_OUT: case D12_ENDPOINT_2_OUT: processOutEndpoint (pTarget, pEndpoint, pErp, pWork); break; case D12_ENDPOINT_CONTROL_IN: case D12_ENDPOINT_1_IN: case D12_ENDPOINT_2_IN: processInEndpoint (pTarget, pEndpoint, pErp, pWork); break; } } else { /* There is an interrupt pending, but the ERP queue is empty. If * this is the default control OUT pipe, and if the newly received * packet is a setup packet, then we need to abort any pending * transfers on the default control IN pipe. */ if (endpointId == D12_ENDPOINT_CONTROL_OUT && pTarget->transPending [endpointId] && (pTarget->transStatus [endpointId] & D12_CMD_RLTS_SETUP_PACKET) != 0 && (pErp = usbListFirst (&pTarget->erps [D12_ENDPOINT_CONTROL_IN])) != NULL) { finishErp (pTarget, pErp, S_usbTcdLib_NEW_SETUP_PACKET); } } }/***************************************************************************** processErpQueueInt - Reads interrupt status and invokes processErpQueue()** RETURNS: N/A*/LOCAL VOID processErpQueueInt ( pTARGET pTarget, UINT16 endpointId ) { /* Select the endpoint and read the last transaction status. * * NOTE: Reading the transaction status clears the interrupt condition * associated with a pipe. */ pTarget->transStatus [endpointId] = d12ReadLastTransStatus (pTarget, endpointId); pTarget->transPending [endpointId] = TRUE; processErpQueue (pTarget, endpointId); }/***************************************************************************** processBusReset - Processes a bus reset event** RETURNS: N/A*/LOCAL VOID processBusReset ( pTARGET pTarget ) { UINT8 ginByte = IN_EVAL_GIN (); /* The D12 has reported a bus reset. */ pTarget->deviceAddress = 0; /* reverts to power-ON default */ /* Report the bus reset to our caller. */ MNGMT_CALLBACK (pTarget, TCD_MNGMT_BUS_RESET); /* Follow-up by determining if Vbus is present or not */ if ((ginByte & D12EVAL_BUS_POWER) == 0) MNGMT_CALLBACK (pTarget, TCD_MNGMT_VBUS_LOST); else MNGMT_CALLBACK (pTarget, TCD_MNGMT_VBUS_DETECT); }/***************************************************************************** processSuspendChange - Interprets a change in the bus SUSPEND state** RETURNS: N/A*/LOCAL VOID processSuspendChange ( pTARGET pTarget ) { UINT8 ginByte = IN_EVAL_GIN (); /* The D12 has reported a change in the suspend state. Reflect the * current suspend state to the caller. */ if ((ginByte & D12EVAL_SUSPEND) == 0) MNGMT_CALLBACK (pTarget, TCD_MNGMT_RESUME); else MNGMT_CALLBACK (pTarget, TCD_MNGMT_SUSPEND); }/***************************************************************************** processDmaEot - Handles a DMA end-of-transfer** RETURNS: N/A*/LOCAL VOID processDmaEot ( pTARGET pTarget ) { /* The D12 reports that a DMA operation has completed. */ if (pTarget->dmaInUse) { pTarget->dmaEot = TRUE; processErpQueue (pTarget, pTarget->dmaEndpointId); } }/***************************************************************************** processD12Int - evaluate and process an interrupt from the PDIUSBD12** RETURNS: N/A*/LOCAL VOID processD12Int ( pTARGET pTarget ) { UINT16 intStatus; /* Read interrupt status. * * NOTE: Reading the interrupt status clears interrupt conditions * which are not associated with a specific pipe. */ intStatus = d12ReadIntReg (pTarget); /* Examine interrupt conditions. * * NOTE: Examine control endpoint last...at the end of a transaction, * it is possible for a new setup packet to come in before we've * handled the interrupt associated with the just-ended transaction. */ if ((intStatus & D12_CMD_RIR_ENDPOINT_2_IN) != 0) processErpQueueInt (pTarget, D12_ENDPOINT_2_IN); if ((intStatus & D12_CMD_RIR_ENDPOINT_2_OUT) != 0) processErpQueueInt (pTarget, D12_ENDPOINT_2_OUT); if ((intStatus & D12_CMD_RIR_ENDPOINT_1_IN) != 0) processErpQueueInt (pTarget, D12_ENDPOINT_1_IN); if ((intStatus & D12_CMD_RIR_ENDPOINT_1_OUT) != 0) processErpQueueInt (pTarget, D12_ENDPOINT_1_OUT); if ((intStatus & D12_CMD_RIR_CONTROL_IN) != 0) processErpQueueInt (pTarget, D12_ENDPOINT_CONTROL_IN); if ((intStatus & D12_CMD_RIR_CONTROL_OUT) != 0) processErpQueueInt (pTarget, D12_ENDPOINT_CONTROL_OUT); if ((intStatus & D12_CMD_RIR_BUS_RESET) != 0) processBusReset (pTarget); if ((intStatus & D12_CMD_RIR_SUSPEND) != 0) processSuspendChange (pTarget); if ((intStatus & D12_CMD_RIR_DMA_EOT) != 0) processDmaEot (pTarget); }/***************************************************************************** usbTcdPdiusbd12IntThread - Handles PDIUSBD12 interrupts** This thread normally waits on the TARGET.intPending semaphore. When* the semaphore is signalled, this thread interrogates the target controller* to determine the cause of the interrupt and serives it.** By convention, the <param> to this thread is a pointer to the TARGET* structure for this target controller.** When this thread exits, it signals the TARGET.intThreadExit semaphore* so the foreground thread can no that the thread has terminated successully.** RETURNS: N/A*/LOCAL VOID usbTcdPdiusbd12IntThread ( pVOID param ) { pTARGET pTarget = (pTARGET) param; UINT16 i; do { /* Wait for an interrupt to be signalled. */ if (OSS_SEM_TAKE (pTarget->intPending, OSS_BLOCK) == OK) { if (!pTarget->intThreadExitRequest) { OSS_MUTEX_TAKE (pTarget->tcdMutex, OSS_BLOCK); /* Light LED to indicate we're processing an interrupt */ pTarget->goutByte |= INT_THREAD_LED; OUT_EVAL_GOUT (pTarget->goutByte); /* Process the interrupt */ processD12Int (pTarget); /* See if any queued ERPs need processing. */ for (i = 0; i < D12_NUM_ENDPOINTS; i++) { if (pTarget->endpointNeedsService [i]) { pTarget->endpointNeedsService [i] = FALSE; processErpQueue (pTarget, i); } } /* Re-enable interrupts. */ pTarget->goutByte &= ~INT_THREAD_LED; pTarget->goutByte |= D12EVAL_GOUT_INTENB; OUT_EVAL_GOUT (pTarget->goutByte); OSS_MUTEX_RELEASE (pTarget->tcdMutex); } } } while (!pTarget->intThreadExitRequest); OSS_SEM_GIVE (pTarget->intThreadExit); }/***************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -