474 lines
12 KiB
C
474 lines
12 KiB
C
|
//
|
||
|
// dwhcixferstagedata.c
|
||
|
//
|
||
|
// USPi - An USB driver for Raspberry Pi written in C
|
||
|
// Copyright (C) 2014 R. Stange <rsta2@o2online.de>
|
||
|
//
|
||
|
// 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 <http://www.gnu.org/licenses/>.
|
||
|
//
|
||
|
#include <uspi/dwhcixferstagedata.h>
|
||
|
#include <uspi/dwhciframeschedper.h>
|
||
|
#include <uspi/dwhciframeschednper.h>
|
||
|
#include <uspi/dwhciframeschednsplit.h>
|
||
|
#include <uspi/dwhci.h>
|
||
|
#include <uspios.h>
|
||
|
#include <uspi/assert.h>
|
||
|
|
||
|
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;
|
||
|
}
|