// // dwhcixferstagedata.c // // USPi - An USB driver for Raspberry Pi written in C // Copyright (C) 2014 R. Stange // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include #include #include #include #include #include void DWHCITransferStageData (TDWHCITransferStageData *pThis, unsigned nChannel, TUSBRequest *pURB, boolean bIn, boolean bStatusStage) { assert (pThis != 0); pThis->m_nChannel = nChannel; pThis->m_pURB = pURB; pThis->m_bIn = bIn; pThis->m_bStatusStage = bStatusStage; pThis->m_bSplitComplete = FALSE; pThis->m_nTotalBytesTransfered = 0; pThis->m_nState = 0; pThis->m_nSubState = 0; pThis->m_nTransactionStatus = 0; pThis->m_pTempBuffer = 0; pThis->m_pFrameScheduler = 0; assert (pThis->m_pURB != 0); pThis->m_pEndpoint = USBRequestGetEndpoint (pURB); assert (pThis->m_pEndpoint != 0); pThis->m_pDevice = USBEndpointGetDevice (pThis->m_pEndpoint); assert (pThis->m_pDevice != 0); pThis->m_Speed = USBDeviceGetSpeed (pThis->m_pDevice); pThis->m_nMaxPacketSize = USBEndpointGetMaxPacketSize (pThis->m_pEndpoint); pThis->m_bSplitTransaction = USBDeviceGetHubAddress (pThis->m_pDevice) != 0 && pThis->m_Speed != USBSpeedHigh; if (!bStatusStage) { if (USBEndpointGetNextPID (pThis->m_pEndpoint, bStatusStage) == USBPIDSetup) { pThis->m_pBufferPointer = USBRequestGetSetupData (pURB); pThis->m_nTransferSize = sizeof (TSetupData); } else { pThis->m_pBufferPointer = USBRequestGetBuffer (pURB); pThis->m_nTransferSize = USBRequestGetBufLen (pURB); } pThis->m_nPackets = (pThis->m_nTransferSize + pThis->m_nMaxPacketSize - 1) / pThis->m_nMaxPacketSize; if (pThis->m_bSplitTransaction) { if (pThis->m_nTransferSize > pThis->m_nMaxPacketSize) { pThis->m_nBytesPerTransaction = pThis->m_nMaxPacketSize; } else { pThis->m_nBytesPerTransaction = pThis->m_nTransferSize; } pThis->m_nPacketsPerTransaction = 1; } else { pThis->m_nBytesPerTransaction = pThis->m_nTransferSize; pThis->m_nPacketsPerTransaction = pThis->m_nPackets; } } else { assert (pThis->m_pTempBuffer == 0); pThis->m_pTempBuffer = (u32 *) malloc (sizeof (u32)); assert (pThis->m_pTempBuffer != 0); pThis->m_pBufferPointer = pThis->m_pTempBuffer; pThis->m_nTransferSize = 0; pThis->m_nBytesPerTransaction = 0; pThis->m_nPackets = 1; pThis->m_nPacketsPerTransaction = 1; } assert (pThis->m_pBufferPointer != 0); assert (((u32) pThis->m_pBufferPointer & 3) == 0); if (pThis->m_bSplitTransaction) { if (DWHCITransferStageDataIsPeriodic (pThis)) { pThis->m_pFrameScheduler = (TDWHCIFrameScheduler *) malloc (sizeof (TDWHCIFrameSchedulerPeriodic)); DWHCIFrameSchedulerPeriodic ((TDWHCIFrameSchedulerPeriodic *) pThis->m_pFrameScheduler); } else { pThis->m_pFrameScheduler = (TDWHCIFrameScheduler *) malloc (sizeof (TDWHCIFrameSchedulerNonPeriodic)); DWHCIFrameSchedulerNonPeriodic ((TDWHCIFrameSchedulerNonPeriodic *) pThis->m_pFrameScheduler); } assert (pThis->m_pFrameScheduler != 0); } else { if ( USBDeviceGetHubAddress (pThis->m_pDevice) == 0 && pThis->m_Speed != USBSpeedHigh) { pThis->m_pFrameScheduler = (TDWHCIFrameScheduler *) malloc (sizeof (TDWHCIFrameSchedulerNoSplit)); DWHCIFrameSchedulerNoSplit ((TDWHCIFrameSchedulerNoSplit *) pThis->m_pFrameScheduler, DWHCITransferStageDataIsPeriodic (pThis)); assert (pThis->m_pFrameScheduler != 0); } } } void _DWHCITransferStageData (TDWHCITransferStageData *pThis) { assert (pThis != 0); if (pThis->m_pFrameScheduler != 0) { pThis->m_pFrameScheduler->_DWHCIFrameScheduler (pThis->m_pFrameScheduler); free (pThis->m_pFrameScheduler); pThis->m_pFrameScheduler = 0; } pThis->m_pBufferPointer = 0; if (pThis->m_pTempBuffer != 0) { free (pThis->m_pTempBuffer); pThis->m_pTempBuffer = 0; } pThis->m_pEndpoint = 0; pThis->m_pDevice = 0; pThis->m_pURB = 0; } void DWHCITransferStageDataTransactionComplete (TDWHCITransferStageData *pThis, u32 nStatus, u32 nPacketsLeft, u32 nBytesLeft) { assert (pThis != 0); #if 0 if (pThis->m_bSplitTransaction) { Logger->Write ("udata", LOG_DEBUG, "Transaction complete (status 0x%X, packets 0x%X, bytes 0x%X)", nStatus, nPacketsLeft, nBytesLeft); } #endif pThis->m_nTransactionStatus = nStatus; if ( nStatus & ( DWHCI_HOST_CHAN_INT_ERROR_MASK | DWHCI_HOST_CHAN_INT_NAK | DWHCI_HOST_CHAN_INT_NYET)) { return; } u32 nPacketsTransfered = pThis->m_nPacketsPerTransaction - nPacketsLeft; u32 nBytesTransfered = pThis->m_nBytesPerTransaction - nBytesLeft; if ( pThis->m_bSplitTransaction && pThis->m_bSplitComplete && nBytesTransfered == 0 && pThis->m_nBytesPerTransaction > 0) { nBytesTransfered = pThis->m_nMaxPacketSize * nPacketsTransfered; } pThis->m_nTotalBytesTransfered += nBytesTransfered; pThis->m_pBufferPointer = (u8 *) pThis->m_pBufferPointer + nBytesTransfered; if ( !pThis->m_bSplitTransaction || pThis->m_bSplitComplete) { USBEndpointSkipPID (pThis->m_pEndpoint, nPacketsTransfered, pThis->m_bStatusStage); } assert (nPacketsTransfered <= pThis->m_nPackets); pThis->m_nPackets -= nPacketsTransfered; // if (pThis->m_nTotalBytesTransfered > pThis->m_nTransferSize) this will be false: if (pThis->m_nTransferSize - pThis->m_nTotalBytesTransfered < pThis->m_nBytesPerTransaction) { assert (pThis->m_nTotalBytesTransfered <= pThis->m_nTransferSize); pThis->m_nBytesPerTransaction = pThis->m_nTransferSize - pThis->m_nTotalBytesTransfered; } } void DWHCITransferStageDataSetSplitComplete (TDWHCITransferStageData *pThis, boolean bComplete) { assert (pThis != 0); assert (pThis->m_bSplitTransaction); pThis->m_bSplitComplete = bComplete; } void DWHCITransferStageDataSetState (TDWHCITransferStageData *pThis, unsigned nState) { assert (pThis != 0); pThis->m_nState = nState; } unsigned DWHCITransferStageDataGetState (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_nState; } void DWHCITransferStageDataSetSubState (TDWHCITransferStageData *pThis, unsigned nSubState) { assert (pThis != 0); pThis->m_nSubState = nSubState; } unsigned DWHCITransferStageDataGetSubState (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_nSubState; } boolean DWHCITransferStageDataBeginSplitCycle (TDWHCITransferStageData *pThis) { return TRUE; } unsigned DWHCITransferStageDataGetChannelNumber (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_nChannel; } boolean DWHCITransferStageDataIsPeriodic (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_pEndpoint != 0); TEndpointType Type = USBEndpointGetType (pThis->m_pEndpoint); return Type == EndpointTypeInterrupt || Type == EndpointTypeIsochronous; } u8 DWHCITransferStageDataGetDeviceAddress (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_pDevice != 0); return USBDeviceGetAddress (pThis->m_pDevice); } u8 DWHCITransferStageDataGetEndpointType (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_pEndpoint != 0); unsigned nEndpointType = 0; switch (USBEndpointGetType (pThis->m_pEndpoint)) { case EndpointTypeControl: nEndpointType = DWHCI_HOST_CHAN_CHARACTER_EP_TYPE_CONTROL; break; case EndpointTypeBulk: nEndpointType = DWHCI_HOST_CHAN_CHARACTER_EP_TYPE_BULK; break; case EndpointTypeInterrupt: nEndpointType = DWHCI_HOST_CHAN_CHARACTER_EP_TYPE_INTERRUPT; break; default: assert (0); break; } return nEndpointType; } u8 DWHCITransferStageDataGetEndpointNumber (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_pEndpoint != 0); return USBEndpointGetNumber (pThis->m_pEndpoint); } u32 DWHCITransferStageDataGetMaxPacketSize (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_nMaxPacketSize; } TUSBSpeed DWHCITransferStageDataGetSpeed (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_Speed; } u8 DWHCITransferStageDataGetPID (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_pEndpoint != 0); u8 ucPID = 0; switch (USBEndpointGetNextPID (pThis->m_pEndpoint, pThis->m_bStatusStage)) { case USBPIDSetup: ucPID = DWHCI_HOST_CHAN_XFER_SIZ_PID_SETUP; break; case USBPIDData0: ucPID = DWHCI_HOST_CHAN_XFER_SIZ_PID_DATA0; break; case USBPIDData1: ucPID = DWHCI_HOST_CHAN_XFER_SIZ_PID_DATA1; break; default: assert (0); break; } return ucPID; } boolean DWHCITransferStageDataIsDirectionIn (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_bIn; } boolean DWHCITransferStageDataIsStatusStage (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_bStatusStage; } u32 DWHCITransferStageDataGetDMAAddress (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_pBufferPointer != 0); return (u32) pThis->m_pBufferPointer; } u32 DWHCITransferStageDataGetBytesToTransfer (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_nBytesPerTransaction; } u32 DWHCITransferStageDataGetPacketsToTransfer (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_nPacketsPerTransaction; } boolean DWHCITransferStageDataIsSplit (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_bSplitTransaction; } boolean DWHCITransferStageDataIsSplitComplete (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_bSplitTransaction); return pThis->m_bSplitComplete; } u8 DWHCITransferStageDataGetHubAddress (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_bSplitTransaction); assert (pThis->m_pDevice != 0); return USBDeviceGetHubAddress (pThis->m_pDevice); } u8 DWHCITransferStageDataGetHubPortAddress (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_bSplitTransaction); assert (pThis->m_pDevice != 0); return USBDeviceGetHubPortNumber (pThis->m_pDevice); } u8 DWHCITransferStageDataGetSplitPosition (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_nTransferSize <= 188); // TODO return DWHCI_HOST_CHAN_SPLIT_CTRL_ALL; } u32 DWHCITransferStageDataGetStatusMask (TDWHCITransferStageData *pThis) { assert (pThis != 0); u32 nMask = DWHCI_HOST_CHAN_INT_XFER_COMPLETE | DWHCI_HOST_CHAN_INT_HALTED | DWHCI_HOST_CHAN_INT_ERROR_MASK; if ( pThis->m_bSplitTransaction || DWHCITransferStageDataIsPeriodic (pThis)) { nMask |= DWHCI_HOST_CHAN_INT_ACK | DWHCI_HOST_CHAN_INT_NAK | DWHCI_HOST_CHAN_INT_NYET; } return nMask; } u32 DWHCITransferStageDataGetTransactionStatus (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_nTransactionStatus != 0); return pThis->m_nTransactionStatus; } boolean DWHCITransferStageDataIsStageComplete (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_nPackets == 0; } u32 DWHCITransferStageDataGetResultLen (TDWHCITransferStageData *pThis) { assert (pThis != 0); if (pThis->m_nTotalBytesTransfered > pThis->m_nTransferSize) { return pThis->m_nTransferSize; } return pThis->m_nTotalBytesTransfered; } TUSBRequest *DWHCITransferStageDataGetURB (TDWHCITransferStageData *pThis) { assert (pThis != 0); assert (pThis->m_pURB != 0); return pThis->m_pURB; } TDWHCIFrameScheduler *DWHCITransferStageDataGetFrameScheduler (TDWHCITransferStageData *pThis) { assert (pThis != 0); return pThis->m_pFrameScheduler; }