pi1541/uspi/lib/dwhcixferstagedata.c
2018-05-20 14:53:34 +10:00

473 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;
}