// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32/drivers/usbc/d_usbc.cpp
// LDD for USB Device driver stack:
// The channel object.
//
//
/**
@file d_usbc.cpp
@internalTechnology
*/
#include <drivers/usbc.h>
_LIT(KUsbLddName, "Usbc");
static const TInt KUsbRequestCallbackPriority = 2;
// Quick sanity check on endpoint properties
static TBool ValidateEndpoint(const TUsbcEndpointInfo* aEndpointInfo)
{
const TUint dir = aEndpointInfo->iDir;
const TInt size = aEndpointInfo->iSize;
if (size <= 0)
return EFalse;
switch (aEndpointInfo->iType)
{
case KUsbEpTypeControl:
if (dir != KUsbEpDirBidirect || size > 64)
return EFalse;
break;
case KUsbEpTypeIsochronous:
if ((dir != KUsbEpDirIn && dir != KUsbEpDirOut) || size > 1024)
return EFalse;
break;
case KUsbEpTypeBulk:
if ((dir != KUsbEpDirIn && dir != KUsbEpDirOut) || size > 512)
return EFalse;
break;
case KUsbEpTypeInterrupt:
if ((dir != KUsbEpDirIn && dir != KUsbEpDirOut) || size > 1024)
return EFalse;
break;
default:
return EFalse;
}
return ETrue;
}
/** Real entry point from the Kernel: return a new driver.
*/
DECLARE_STANDARD_LDD()
{
return new DUsbcLogDevice;
}
/** Create a channel on the device.
@internalComponent
*/
TInt DUsbcLogDevice::Create(DLogicalChannelBase*& aChannel)
{
aChannel = new DLddUsbcChannel;
return aChannel ? KErrNone : KErrNoMemory;
}
DUsbcLogDevice::DUsbcLogDevice()
{
iParseMask = KDeviceAllowUnit;
iUnitsMask = 0xffffffff; // Leave units decision to the Controller
iVersion = TVersion(KUsbcMajorVersion, KUsbcMinorVersion, KUsbcBuildVersion);
}
TInt DUsbcLogDevice::Install()
{
// Only proceed if we have the Controller underneath us
if (!DUsbClientController::UsbcControllerPointer())
{
__KTRACE_OPT(KPANIC, Kern::Printf("LDD Install: USB Controller Not Present"));
return KErrGeneral;
}
return SetName(&KUsbLddName);
}
//
// Return the USB controller capabilities.
//
void DUsbcLogDevice::GetCaps(TDes8& aDes) const
{
TPckgBuf<TCapsDevUsbc> b;
b().version = iVersion;
Kern::InfoCopy(aDes, b);
}
//
// Constructor
//
DLddUsbcChannel::DLddUsbcChannel()
: iValidInterface(EFalse),
iAlternateSettingList(NULL),
iCompleteAllCallbackInfo(this, DLddUsbcChannel::EmergencyCompleteDfc, KUsbRequestCallbackPriority),
iStatusChangePtr(NULL),
iStatusCallbackInfo(this, DLddUsbcChannel::StatusChangeCallback, KUsbRequestCallbackPriority),
iEndpointStatusChangePtr(NULL),
iEndpointStatusCallbackInfo(this, DLddUsbcChannel::EndpointStatusChangeCallback,
KUsbRequestCallbackPriority),
iOtgFeatureChangePtr(NULL),
iOtgFeatureCallbackInfo(this, DLddUsbcChannel::OtgFeatureChangeCallback, KUsbRequestCallbackPriority),
iNumberOfEndpoints(0),
iDeviceState(EUsbcDeviceStateUndefined),
iOwnsDeviceControl(EFalse),
iAlternateSetting(0),
iDeviceStatusNeeded(EFalse),
iChannelClosing(EFalse)
{
__KTRACE_OPT(KUSB, Kern::Printf("*** DLddUsbcChannel::DLddUsbcChannel CTOR"));
iClient = &Kern::CurrentThread();
iClient->Open();
for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
{
iEndpoint[i] = NULL;
}
for (TInt i = 1; i < KUsbcMaxRequests; i++)
{
iRequestStatus[i] = NULL;
}
}
DLddUsbcChannel::~DLddUsbcChannel()
{
__KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::~DLddUsbcChannel()"));
if (iController)
{
iStatusCallbackInfo.Cancel();
iEndpointStatusCallbackInfo.Cancel();
iOtgFeatureCallbackInfo.Cancel();
iCompleteAllCallbackInfo.Cancel();
AbortInterface();
DestroyAllInterfaces();
if (iOwnsDeviceControl)
{
iController->ReleaseDeviceControl(this);
iOwnsDeviceControl = EFalse;
}
iController->DeRegisterClient(this);
DestroyEp0();
delete iStatusFifo;
Kern::DestroyClientRequest(iStatusChangeReq);
Kern::DestroyClientRequest(iEndpointStatusChangeReq);
Kern::DestroyClientRequest(iOtgFeatureChangeReq);
Kern::DestroyVirtualPinObject(iPinObj1);
Kern::DestroyVirtualPinObject(iPinObj2);
Kern::DestroyVirtualPinObject(iPinObj3);
for (TInt i = 0; i < KUsbcMaxRequests; i++)
{
Kern::DestroyClientBufferRequest(iClientAsynchNotify[i]->iBufferRequest);
delete iClientAsynchNotify[i];
}
}
Kern::SafeClose((DObject*&)iClient, NULL);
}
inline TBool DLddUsbcChannel::ValidEndpoint(TInt aEndpoint)
{
return (aEndpoint <= iNumberOfEndpoints && aEndpoint >= 0);
}
//
// Create channel
//
TInt DLddUsbcChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
{
__KTRACE_OPT(KUSB, Kern::Printf("LDD DoCreateL 1 Ver = %02d %02d %02d",
aVer.iMajor, aVer.iMinor, aVer.iBuild));
if (!Kern::CurrentThreadHasCapability(ECapabilityCommDD,
__PLATSEC_DIAGNOSTIC_STRING("Checked by USBC.LDD (USB Driver)")))
{
return KErrPermissionDenied;
}
iController = DUsbClientController::UsbcControllerPointer();
if (!iController)
{
return KErrGeneral;
}
iStatusFifo = new TUsbcDeviceStatusQueue;
if (iStatusFifo == NULL)
{
return KErrNoMemory;
}
if (!Kern::QueryVersionSupported(TVersion(KUsbcMajorVersion, KUsbcMinorVersion, KUsbcBuildVersion), aVer))
{
return KErrNotSupported;
}
// set up the correct DFC queue
SetDfcQ(iController->DfcQ(0)); // sets the channel's dfc queue
#ifdef DFC_REALTIME_STATE
iDfcQ.SetRealtimeState(ERealtimeStateOn);
#endif
iCompleteAllCallbackInfo.SetDfcQ(iDfcQ);
iStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc
iEndpointStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc
iOtgFeatureCallbackInfo.SetDfcQ(iDfcQ);
iMsgQ.Receive(); //start up the message q
TInt r = iController->RegisterClientCallback(iCompleteAllCallbackInfo);
if (r != KErrNone)
return r;
r = iController->RegisterForStatusChange(iStatusCallbackInfo);
if (r != KErrNone)
return r;
r = iController->RegisterForEndpointStatusChange(iEndpointStatusCallbackInfo);
if (r != KErrNone)
return r;
r = iController->RegisterForOtgFeatureChange(iOtgFeatureCallbackInfo);
if (r != KErrNone)
return r;
r = Kern::CreateClientDataRequest(iStatusChangeReq);
if (r != KErrNone)
return r;
r = Kern::CreateClientDataRequest(iEndpointStatusChangeReq);
if (r != KErrNone)
return r;
r = Kern::CreateClientDataRequest(iOtgFeatureChangeReq);
if (r != KErrNone)
return r;
Kern::CreateVirtualPinObject(iPinObj1);
Kern::CreateVirtualPinObject(iPinObj2);
Kern::CreateVirtualPinObject(iPinObj3);
for (TInt i = 0; i < KUsbcMaxRequests; i++)
{
iClientAsynchNotify[i] = new TClientAsynchNotify;
if(iClientAsynchNotify[i] == NULL)
return KErrNoMemory;
r = Kern::CreateClientBufferRequest(iClientAsynchNotify[i]->iBufferRequest,1,TClientBufferRequest::EPinVirtual);
if (r != KErrNone)
{
delete iClientAsynchNotify[i];
iClientAsynchNotify[i]=NULL;
return r;
}
}
return r;
}
void DLddUsbcChannel::CompleteBufferRequest(DThread* aThread, TInt aReqNo, TInt aReason)
{
iRequestStatus[aReqNo]=NULL;
Kern::QueueBufferRequestComplete(aThread, iClientAsynchNotify[aReqNo]->iBufferRequest, aReason);
}
TClientBuffer * DLddUsbcChannel::GetClientBuffer(TInt aEndpoint)
{
return iClientAsynchNotify[aEndpoint]->iClientBuffer;
}
//Runs in client thread
TInt DLddUsbcChannel::SendMsg(TMessageBase * aMsg)
{
TThreadMessage& m=* (TThreadMessage*)aMsg;
TInt id = m.iValue;
TInt r = KErrNone;
//Cancel Request
if (id == KMaxTInt)
{
r = DLogicalChannel::SendMsg(aMsg);
return r;
}
if (id < 0)
{
// DoRequest
TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
r = PreSendRequest(aMsg,~id, pS, m.Ptr1(), m.Ptr2());
if (r == KErrNone)
{
r = DLogicalChannel::SendMsg(aMsg);
}
}
else
{
//SendControl
r = SendControl(aMsg);
}
return r;
}
TInt DLddUsbcChannel::PreSendRequest(TMessageBase * aMsg,TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
{
TInt r = KErrNone;
if (aReqNo >= KUsbcMaxRequests)
{
Kern::RequestComplete(aStatus, KErrNotSupported);
return KErrNotSupported;
}
if (aReqNo > KUsbcMaxEpNumber)//DoOtherAsyncReq
{
switch (aReqNo)
{
case RDevUsbcClient::ERequestEndpointStatusNotify:
iEndpointStatusChangeReq->Reset();
iEndpointStatusChangeReq->SetStatus(aStatus);
iEndpointStatusChangeReq->SetDestPtr(a1);
break;
case RDevUsbcClient::ERequestOtgFeaturesNotify:
iOtgFeatureChangeReq->Reset();
iOtgFeatureChangeReq->SetStatus(aStatus);
iOtgFeatureChangeReq->SetDestPtr(a1);
break;
case RDevUsbcClient::ERequestAlternateDeviceStatusNotify:
iStatusChangeReq->Reset();
iStatusChangeReq->SetStatus(aStatus);
iStatusChangeReq->SetDestPtr(a1);
break;
case RDevUsbcClient::ERequestReEnumerate://WE use bufferrequest to complete even tho we dont add any buffers
iClientAsynchNotify[aReqNo]->Reset();
r=iClientAsynchNotify[aReqNo]->iBufferRequest->StartSetup(aStatus);
if (r != KErrNone)
return r;
iClientAsynchNotify[aReqNo]->iBufferRequest->EndSetup();
break;
}
}
else //DoTransferAsyncReq
{
if(a1 == NULL)
return KErrArgument;
iClientAsynchNotify[aReqNo]->Reset();
r=iClientAsynchNotify[aReqNo]->iBufferRequest->StartSetup(aStatus);
if (r != KErrNone)
return r;
kumemget(&iTfrInfo,a1,sizeof(TEndpointTransferInfo));
r=iClientAsynchNotify[aReqNo]->iBufferRequest->AddBuffer(iClientAsynchNotify[aReqNo]->iClientBuffer, iTfrInfo.iDes);
if (r != KErrNone)
return r;
iClientAsynchNotify[aReqNo]->iBufferRequest->EndSetup();
TThreadMessage& m=*(TThreadMessage*)aMsg;
m.iArg[1] = (TAny*)&iTfrInfo; //Use Channel owned TransfereInfo structure
}
return KErrNone;
}
void DLddUsbcChannel::HandleMsg(TMessageBase* aMsg)
{
TThreadMessage& m = *(TThreadMessage*)aMsg;
TInt id = m.iValue;
if (id == (TInt) ECloseMsg)
{
iChannelClosing = ETrue;
m.Complete(KErrNone, EFalse);
return;
}
else if (id == KMaxTInt)
{
// Cancel request
TInt mask = m.Int0();
TInt b = 1;
for(TInt reqNo = 0; reqNo < KUsbcMaxRequests; reqNo++)
{
TRequestStatus* pS = iRequestStatus[reqNo];
if ((mask & b) && (pS != NULL))
{
DoCancel(reqNo);
}
b <<= 1;
}
m.Complete(KErrNone, ETrue);
return;
}
if (id < 0)
{
// DoRequest
TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
m.Complete(KErrNone, ETrue);
}
else
{
// DoControl
TInt r = DoControl(id, m.Ptr0(), m.Ptr1());
m.Complete(r, ETrue);
}
}
//
// Overriding DObject virtual
//
TInt DLddUsbcChannel::RequestUserHandle(DThread* aThread, TOwnerType /*aType*/)
{
__KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::RequestUserHandle"));
// The USB client LDD is not designed for a channel to be shared between
// threads. It saves a pointer to the current thread when it is opened, and
// uses this to complete any asynchronous requests.
// It is therefore not acceptable for the handle to be duplicated and used
// by another thread:
if (aThread == iClient)
{
return KErrNone;
}
else
{
return KErrAccessDenied;
}
}
//
// Asynchronous requests - overriding pure virtual
//
void DLddUsbcChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
{
// Check on request status
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest 0x%08x", aReqNo));
TInt r = KErrNone;
if (iRequestStatus[aReqNo] != NULL)
{
DestroyAllInterfaces();
PanicClientThread(ERequestAlreadyPending);
}
else
{
TBool needsCompletion;
iRequestStatus[aReqNo] = aStatus;
if (aReqNo > KUsbcMaxEpNumber)
{
r = DoOtherAsyncReq(aReqNo, a1, a2, needsCompletion);
if (needsCompletion)
{
switch (aReqNo)
{
case RDevUsbcClient::ERequestEndpointStatusNotify:
iRequestStatus[aReqNo]=NULL;
Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,r);
break;
case RDevUsbcClient::ERequestOtgFeaturesNotify:
iRequestStatus[aReqNo]=NULL;
Kern::QueueRequestComplete(iClient,iOtgFeatureChangeReq,r);
break;
case RDevUsbcClient::ERequestAlternateDeviceStatusNotify:
iRequestStatus[aReqNo]=NULL;
Kern::QueueRequestComplete(iClient,iStatusChangeReq,r);
break;
case RDevUsbcClient::ERequestReEnumerate:
iRequestStatus[aReqNo]=NULL;
Kern::QueueBufferRequestComplete(iClient, iClientAsynchNotify[aReqNo]->iBufferRequest, r);
break;
}
}
}
else
{
r = DoTransferAsyncReq(aReqNo, a1, a2, needsCompletion);
if (needsCompletion)
{
//Kern::RequestComplete(iClient, iRequestStatus[aReqNo], r);
CompleteBufferRequest(iClient, aReqNo, r);
}
}
}
}
TInt DLddUsbcChannel::DoOtherAsyncReq(TInt aReqNo, TAny* a1, TAny* a2, TBool& aNeedsCompletion)
{
// The general assumption is that none of these will complete now.
// However, those that make this function return something other than
// KErrNone will get completed by the calling function.
// So, 1) If you are returning KErrNone but really need to complete because
// completion criteria can be met (for example, sufficient data is
// available in the buffer) and then set aNeedsCompletion = ETrue.
// 2) Do NOT complete here AT ALL.
//
aNeedsCompletion = EFalse;
TInt r = KErrNone;
switch (aReqNo)
{
case RDevUsbcClient::ERequestAlternateDeviceStatusNotify:
{
__KTRACE_OPT(KUSB, Kern::Printf("EControlReqDeviceStatusNotify"));
if (a1 != NULL)
{
iDeviceStatusNeeded = ETrue;
iStatusChangePtr = a1;
aNeedsCompletion = AlternateDeviceStateTestComplete();
}
else
r = KErrArgument;
break;
}
case RDevUsbcClient::ERequestReEnumerate:
{
__KTRACE_OPT(KUSB, Kern::Printf("ERequestReEnumerate"));
// If successful, this will complete via the status notification.
r = iController->ReEnumerate();
break;
}
case RDevUsbcClient::ERequestEndpointStatusNotify:
{
__KTRACE_OPT(KUSB, Kern::Printf("ERequestEndpointStatusNotify"));
if (a1 != NULL)
{
iEndpointStatusChangePtr = a1;
}
else
r = KErrArgument;
break;
}
case RDevUsbcClient::ERequestOtgFeaturesNotify:
{
__KTRACE_OPT(KUSB, Kern::Printf("ERequestOtgFeaturesNotify"));
if (a1 != NULL)
{
iOtgFeatureChangePtr = a1;
}
else
r = KErrArgument;
break;
}
default:
r = KErrNotSupported;
}
aNeedsCompletion = aNeedsCompletion || (r != KErrNone);
return r;
}
TInt DLddUsbcChannel::DoTransferAsyncReq(TInt aEndpointNum, TAny* a1, TAny* a2, TBool& aNeedsCompletion)
{
// The general assumption is that none of these will complete now.
// however, those that are returning something other than KErrNone will get completed
// by the calling function.
// So, 1) if you are returning KErrNone but really need to complete because completion criteria can be met
// (for example, sufficient data is available in the buffer) and then set aNeedsCompletion=ETrue..
// 2) Do NOT complete here AT ALL.
//
aNeedsCompletion = EFalse;
TInt r = KErrNone;
TUsbcEndpoint* pEndpoint = NULL;
TUsbcEndpointInfo* pEndpointInfo = NULL;
TEndpointTransferInfo* pTfr = NULL;
if (aEndpointNum == 0)
{
// ep0 requests
if (!(iValidInterface || iOwnsDeviceControl))
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest rejected: not configured (Ep0)"));
r = KErrUsbInterfaceNotReady;
goto exit;
}
}
else
{
// other eps
if (!(iValidInterface && (iDeviceState == EUsbcDeviceStateConfigured ||
iDeviceState == EUsbcDeviceStateSuspended))
)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest rejected not configured (Ep %d)", aEndpointNum));
r = KErrUsbInterfaceNotReady;
goto exit;
}
}
if (!ValidEndpoint(aEndpointNum))
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Read: in error complete"));
r = KErrUsbEpNotInInterface;
goto exit;
}
if (a1 == NULL)
{
r = KErrArgument;
goto exit;
}
pTfr = (TEndpointTransferInfo *)a1;
if (pTfr->iTransferSize < 0)
{
r = KErrArgument;
goto exit;
}
pEndpoint = iEndpoint[aEndpointNum];
if (!pEndpoint)
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Read: in error complete"));
r = KErrUsbEpNotInInterface;
goto exit;
}
pEndpointInfo = pEndpoint->EndpointInfo();
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest %d", aEndpointNum));
switch (pTfr->iTransferType)
{
case ETransferTypeReadData:
case ETransferTypeReadPacket:
case ETransferTypeReadUntilShort:
case ETransferTypeReadOneOrMore:
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read"));
if (pEndpoint->iDmaBuffers->RxIsActive())
{
__KTRACE_OPT(KUSB, Kern::Printf("**** ReadReq ep%d RxActive", aEndpointNum));
}
else
{
__KTRACE_OPT(KUSB, Kern::Printf("**** ReadReq ep%d RxInActive", aEndpointNum));
}
if (pEndpointInfo->iDir != KUsbEpDirOut &&
pEndpointInfo->iDir != KUsbEpDirBidirect)
{
// Trying to do the wrong thing
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Read: in error complete"));
r = KErrUsbEpBadDirection;
break;
}
// Set the length of data to zero now to catch all cases
TPtrC8 pZeroDesc(NULL, 0);
r=Kern::ThreadBufWrite(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer, pZeroDesc, 0, 0,iClient);
if (r != KErrNone)
PanicClientThread(r);
pEndpoint->SetTransferInfo(pTfr);
if (pEndpoint->iDmaBuffers->IsReaderEmpty())
{
pEndpoint->SetClientReadPending(ETrue);
}
else
{
if (pTfr->iTransferType == ETransferTypeReadPacket)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read packet: data available complete"));
r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
aNeedsCompletion = ETrue;
break;
}
else if (pTfr->iTransferType == ETransferTypeReadData)
{
if (pTfr->iTransferSize <= pEndpoint->RxBytesAvailable())
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete"));
r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
aNeedsCompletion = ETrue;
break;
}
else
{
pEndpoint->SetClientReadPending(ETrue);
}
}
else if (pTfr->iTransferType == ETransferTypeReadOneOrMore)
{
if (pEndpoint->RxBytesAvailable() > 0)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete"));
r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
aNeedsCompletion = ETrue;
break;
}
else
{
pEndpoint->SetClientReadPending(ETrue);
}
}
else if (pTfr->iTransferType == ETransferTypeReadUntilShort)
{
TInt nRx = pEndpoint->RxBytesAvailable();
TInt maxPacketSize = pEndpoint->EndpointInfo()->iSize;
if( (pTfr->iTransferSize <= nRx) ||
(nRx < maxPacketSize) ||
pEndpoint->iDmaBuffers->ShortPacketExists())
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete"));
r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
aNeedsCompletion = ETrue;
}
else
{
pEndpoint->SetClientReadPending(ETrue);
}
}
}
r = pEndpoint->TryToStartRead(EFalse);
if (r != KErrNone)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read: couldn't start read"));
r = KErrNone; // Reader full isn't a userside error;
}
break;
}
case ETransferTypeWrite:
{
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 1"));
if (pEndpointInfo->iDir != KUsbEpDirIn &&
pEndpointInfo->iDir != KUsbEpDirBidirect)
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Write: wrong direction complete"));
r = KErrUsbEpBadDirection;
break;
}
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 2"));
TInt desLength=iClientAsynchNotify[aEndpointNum]->iClientBuffer->Length();
if (desLength < pTfr->iTransferSize)
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Write: user buffer too short"));
r = KErrUsbTransferSize;
break;
}
__KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 3 length=%d maxlength=%d",
pTfr->iTransferSize, desLength));
// Zero length writes are acceptable
pEndpoint->SetClientWritePending(ETrue);
r = pEndpoint->TryToStartWrite(pTfr);
if (r != KErrNone)
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Write: couldn't start write"));
pEndpoint->SetClientWritePending(EFalse);
}
break;
}
default:
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoTransferAsyncReq: pTfr->iTransferType = %d not supported",
pTfr->iTransferType));
r = KErrNotSupported;
break;
}
exit:
aNeedsCompletion = aNeedsCompletion || (r != KErrNone);
return r;
}
//
// Cancel an outstanding request - overriding pure virtual
//
TInt DLddUsbcChannel::DoCancel(TInt aReqNo)
{
TInt r = KErrNone;
__KTRACE_OPT(KUSB, Kern::Printf("DoCancel: 0x%x", aReqNo));
if (aReqNo <= iNumberOfEndpoints)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoCancel endpoint: 0x%x", aReqNo));
iEndpoint[aReqNo]->CancelTransfer(iClient,iClientAsynchNotify[aReqNo]->iClientBuffer);
}
else if (aReqNo == RDevUsbcClient::ERequestAlternateDeviceStatusNotify)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoCancel: ERequestAlternateDeviceStatusNotify 0x%x", aReqNo));
iDeviceStatusNeeded = EFalse;
iStatusFifo->FlushQueue();
if (iStatusChangePtr)
{
iStatusChangeReq->Data()=iController->GetDeviceStatus();
iStatusChangePtr = NULL;
if (iStatusChangeReq->IsReady())
{
iRequestStatus[aReqNo] = NULL;
Kern::QueueRequestComplete(iClient, iStatusChangeReq, KErrCancel);
}
return KErrNone;
}
}
else if (aReqNo == RDevUsbcClient::ERequestReEnumerate)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestReEnumerate: 0x%x", aReqNo));
}
else if (aReqNo == RDevUsbcClient::ERequestEndpointStatusNotify)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestEndpointStatusNotify: 0x%x", aReqNo));
CancelNotifyEndpointStatus();
if (iEndpointStatusChangeReq->IsReady())
{
iRequestStatus[aReqNo] = NULL;
Kern::QueueRequestComplete(iClient, iEndpointStatusChangeReq, KErrCancel);
}
return KErrNone;
}
else if (aReqNo == RDevUsbcClient::ERequestOtgFeaturesNotify)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestOtgFeaturesNotify: 0x%x", aReqNo));
CancelNotifyOtgFeatures();
if (iOtgFeatureChangeReq->IsReady())
{
iRequestStatus[aReqNo] = NULL;
Kern::QueueRequestComplete(iClient, iOtgFeatureChangeReq, KErrCancel);
}
}
else
{
__KTRACE_OPT(KUSB, Kern::Printf("DoCancel Unknown! 0x%x", aReqNo));
}
if (r == KErrNone)
r = KErrCancel;
CompleteBufferRequest(iClient, aReqNo, r);
return r;
}
void DLddUsbcChannel::CancelNotifyEndpointStatus()
{
if (iEndpointStatusChangePtr)
{
TUint epBitmap = 0;
for (TInt i = 0; i <= iNumberOfEndpoints; i++)
{
TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber());
TUint b;
(v == EEndpointStateStalled) ? b = 1 : b = 0;
epBitmap |= b << i;
}
iEndpointStatusChangeReq->Data()=epBitmap;
iEndpointStatusChangePtr = NULL;
}
}
void DLddUsbcChannel::CancelNotifyOtgFeatures()
{
if (iOtgFeatureChangePtr)
{
TUint8 features;
iController->GetCurrentOtgFeatures(features);
iOtgFeatureChangeReq->Data()=features;
iOtgFeatureChangePtr = NULL;
}
}
TInt DLddUsbcChannel::PinMemory(TDesC8 *aDes, TVirtualPinObject *aPinObj)
{
TInt r = KErrNone;
TInt len,mlen;
const TUint8*p = Kern::KUDesInfo(*aDes, len,mlen);
r=Kern::PinVirtualMemory(aPinObj, (TLinAddr) p, len);
return r;
}
//Called in Client thread context
TInt DLddUsbcChannel::SendControl(TMessageBase* aMsg)
{
TThreadMessage& m=*(TThreadMessage*)aMsg;
const TInt fn=m.iValue;
TAny *const a1=m.Ptr0();
TAny *const a2=m.Ptr1();
TInt kern_param;
TEndpointDescriptorInfo epi;
TUsbcIfcInfo ifc;
TCSDescriptorInfo desInfo;
TInt r = KErrNone;
switch (fn)
{
case RDevUsbcClient::EControlDeviceStatus:
case RDevUsbcClient::EControlGetAlternateSetting:
m.iArg[0] = &kern_param; // update message to point to kernel-side buffer
break;
case RDevUsbcClient::EControlQueryReceiveBuffer:
case RDevUsbcClient::EControlEndpointStatus:
m.iArg[1] = &kern_param; // update message to point to kernel-side buffer
break;
case RDevUsbcClient::EControlEndpointCaps:
case RDevUsbcClient::EControlDeviceCaps:
case RDevUsbcClient::EControlGetDeviceDescriptor:
case RDevUsbcClient::EControlSetDeviceDescriptor:
case RDevUsbcClient::EControlGetDeviceDescriptorSize:
case RDevUsbcClient::EControlGetConfigurationDescriptor:
case RDevUsbcClient::EControlGetConfigurationDescriptorSize:
case RDevUsbcClient::EControlGetDeviceQualifierDescriptor:
case RDevUsbcClient::EControlSetDeviceQualifierDescriptor:
case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor:
case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor:
case RDevUsbcClient::EControlGetStringDescriptorLangId:
case RDevUsbcClient::EControlGetManufacturerStringDescriptor:
case RDevUsbcClient::EControlSetManufacturerStringDescriptor:
case RDevUsbcClient::EControlGetProductStringDescriptor:
case RDevUsbcClient::EControlSetProductStringDescriptor:
case RDevUsbcClient::EControlGetSerialNumberStringDescriptor:
case RDevUsbcClient::EControlSetSerialNumberStringDescriptor:
case RDevUsbcClient::EControlGetConfigurationStringDescriptor:
case RDevUsbcClient::EControlSetConfigurationStringDescriptor:
case RDevUsbcClient::EControlSetOtgDescriptor:
case RDevUsbcClient::EControlGetOtgDescriptor:
case RDevUsbcClient::EControlGetOtgFeatures:
r=PinMemory((TDesC8 *) a1, iPinObj1);
if(r!=KErrNone)
{
PanicClientThread(r);
return r;
}
break;
case RDevUsbcClient::EControlGetInterfaceDescriptor:
case RDevUsbcClient::EControlGetInterfaceDescriptorSize:
case RDevUsbcClient::EControlSetInterfaceDescriptor:
case RDevUsbcClient::EControlGetCSInterfaceDescriptor:
case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize:
case RDevUsbcClient::EControlGetStringDescriptor:
case RDevUsbcClient::EControlSetStringDescriptor:
r=PinMemory((TDesC8 *) a2, iPinObj1);
if(r!=KErrNone)
{
PanicClientThread(r);
return r;
}
break;
case RDevUsbcClient::EControlGetEndpointDescriptor:
case RDevUsbcClient::EControlGetEndpointDescriptorSize:
case RDevUsbcClient::EControlSetEndpointDescriptor:
case RDevUsbcClient::EControlGetCSEndpointDescriptor:
case RDevUsbcClient::EControlGetCSEndpointDescriptorSize:
if(a1!=NULL)
{
r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a1, sizeof(epi));
if(r!=KErrNone)
{
PanicClientThread(r);
return r;
}
kumemget(&epi, a1, sizeof(epi));
r=PinMemory((TDesC8 *) epi.iArg, iPinObj2);
if(r!=KErrNone)
{
Kern::UnpinVirtualMemory(iPinObj1);
PanicClientThread(r);
return r;
}
}
break;
case RDevUsbcClient::EControlSetInterface:
if(a2!=NULL)
{
r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a2, sizeof(ifc));
if(r!=KErrNone)
{
PanicClientThread(r);
return r;
}
kumemget(&ifc, a2, sizeof(ifc));
r=PinMemory((TDesC8 *) ifc.iInterfaceData, iPinObj2);
if(r!=KErrNone)
{
Kern::UnpinVirtualMemory(iPinObj1);
PanicClientThread(r);
return r;
}
}
break;
case RDevUsbcClient::EControlSetCSInterfaceDescriptor:
case RDevUsbcClient::EControlSetCSEndpointDescriptor:
if(a1!=NULL)
{
r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a1, sizeof(desInfo));
if(r!=KErrNone)
{
PanicClientThread(r);
return r;
}
kumemget(&desInfo, a1, sizeof(desInfo));
r=PinMemory((TDesC8 *) desInfo.iArg, iPinObj2);
if(r!=KErrNone)
{
Kern::UnpinVirtualMemory(iPinObj1);
PanicClientThread(r);
return r;
}
}
break;
}
//Send Message and wait for synchronous complete
r = DLogicalChannel::SendMsg(aMsg);
switch (fn)
{
case RDevUsbcClient::EControlDeviceStatus:
case RDevUsbcClient::EControlGetAlternateSetting:
umemput32(a1, &kern_param, sizeof(kern_param));
break;
case RDevUsbcClient::EControlQueryReceiveBuffer:
case RDevUsbcClient::EControlEndpointStatus:
umemput32(a2, &kern_param, sizeof(kern_param));
break;
case RDevUsbcClient::EControlDeviceCaps:
case RDevUsbcClient::EControlEndpointCaps:
case RDevUsbcClient::EControlGetDeviceDescriptor:
case RDevUsbcClient::EControlSetDeviceDescriptor:
case RDevUsbcClient::EControlGetDeviceDescriptorSize:
case RDevUsbcClient::EControlGetConfigurationDescriptor:
case RDevUsbcClient::EControlGetConfigurationDescriptorSize:
case RDevUsbcClient::EControlGetDeviceQualifierDescriptor:
case RDevUsbcClient::EControlSetDeviceQualifierDescriptor:
case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor:
case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor:
case RDevUsbcClient::EControlGetStringDescriptorLangId:
case RDevUsbcClient::EControlGetManufacturerStringDescriptor:
case RDevUsbcClient::EControlSetManufacturerStringDescriptor:
case RDevUsbcClient::EControlGetProductStringDescriptor:
case RDevUsbcClient::EControlSetProductStringDescriptor:
case RDevUsbcClient::EControlGetSerialNumberStringDescriptor:
case RDevUsbcClient::EControlSetSerialNumberStringDescriptor:
case RDevUsbcClient::EControlGetConfigurationStringDescriptor:
case RDevUsbcClient::EControlSetConfigurationStringDescriptor:
case RDevUsbcClient::EControlSetOtgDescriptor:
case RDevUsbcClient::EControlGetOtgDescriptor:
case RDevUsbcClient::EControlGetOtgFeatures:
if(a1!=NULL)
{
Kern::UnpinVirtualMemory(iPinObj1);
}
break;
case RDevUsbcClient::EControlGetInterfaceDescriptor:
case RDevUsbcClient::EControlGetInterfaceDescriptorSize:
case RDevUsbcClient::EControlSetInterfaceDescriptor:
case RDevUsbcClient::EControlGetCSInterfaceDescriptor:
case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize:
case RDevUsbcClient::EControlGetStringDescriptor:
case RDevUsbcClient::EControlSetStringDescriptor:
if(a2!=NULL)
{
Kern::UnpinVirtualMemory(iPinObj1);
}
break;
case RDevUsbcClient::EControlGetEndpointDescriptor:
case RDevUsbcClient::EControlGetEndpointDescriptorSize:
case RDevUsbcClient::EControlSetEndpointDescriptor:
case RDevUsbcClient::EControlGetCSEndpointDescriptor:
case RDevUsbcClient::EControlGetCSEndpointDescriptorSize:
case RDevUsbcClient::EControlSetCSInterfaceDescriptor:
case RDevUsbcClient::EControlSetCSEndpointDescriptor:
if(a1!=NULL)
{
Kern::UnpinVirtualMemory(iPinObj1);
Kern::UnpinVirtualMemory(iPinObj2);
}
break;
case RDevUsbcClient::EControlSetInterface:
if(a2!=NULL)
{
Kern::UnpinVirtualMemory(iPinObj1);
Kern::UnpinVirtualMemory(iPinObj2);
}
break;
}
return r;
}
TInt DLddUsbcChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
{
__KTRACE_OPT(KUSB, Kern::Printf("DoControl: %d", aFunction));
TInt r = KErrNone;
TInt ep;
TUsbcEndpoint* pEndpoint;
TPtrC8 pZeroDesc(NULL, 0);
TEndpointDescriptorInfo epInfo;
TUsbcIfcInfo ifcInfo;
TCSDescriptorInfo desInfo;
TUsbcEndpointResource epRes;
TInt bandwidthPriority;
switch (aFunction)
{
case RDevUsbcClient::EControlEndpointZeroRequestError:
__KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroRequestError"));
r = KErrNone;
if (iOwnsDeviceControl || (iValidInterface && iDeviceState == EUsbcDeviceStateConfigured))
{
iController->Ep0Stall(this);
}
else
{
if (iDeviceState != EUsbcDeviceStateConfigured)
r = KErrUsbDeviceNotConfigured;
else
r = KErrUsbInterfaceNotReady;
}
break;
case RDevUsbcClient::EControlGetAlternateSetting:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetAlternateSetting"));
if (iValidInterface && iDeviceState == EUsbcDeviceStateConfigured)
{
r = iController->GetInterfaceNumber(this, *(TInt*)a1);
}
else
{
if (iDeviceState != EUsbcDeviceStateConfigured)
r = KErrUsbDeviceNotConfigured;
else
r = KErrUsbInterfaceNotReady;
}
break;
case RDevUsbcClient::EControlDeviceStatus:
__KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceStatus"));
*(TInt*)a1 = iController->GetDeviceStatus();
break;
case RDevUsbcClient::EControlEndpointStatus:
__KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointStatus"));
if (iValidInterface && ValidEndpoint((TInt) a1))
{
pEndpoint = iEndpoint[(TInt)a1];
if (pEndpoint == NULL)
r = KErrNotSupported;
else
{
*(TInt*)a2 = iController->GetEndpointStatus(this, iEndpoint[(TInt)a1]->RealEpNumber());
}
}
else
{
if (iDeviceState != EUsbcDeviceStateConfigured)
r = KErrUsbDeviceNotConfigured;
else
r = KErrUsbInterfaceNotReady;
}
break;
case RDevUsbcClient::EControlQueryReceiveBuffer:
__KTRACE_OPT(KUSB, Kern::Printf("EControlQueryReceiveBuffer"));
if (iValidInterface && ValidEndpoint((TInt) a1))
{
pEndpoint=iEndpoint[(TInt) a1];
if (pEndpoint == NULL)
r = KErrNotSupported;
else if (pEndpoint->EndpointInfo()->iDir != KUsbEpDirIn)
{
__KTRACE_OPT(KUSB, Kern::Printf(" bytes = %d", pEndpoint->RxBytesAvailable()));
*(TInt*)a2 = pEndpoint->RxBytesAvailable();
}
}
else
{
if (iDeviceState != EUsbcDeviceStateConfigured)
r = KErrUsbDeviceNotConfigured;
else
r = KErrUsbInterfaceNotReady;
}
break;
case RDevUsbcClient::EControlEndpointCaps:
__KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointCaps"));
r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
if (r != KErrNone)
PanicClientThread(r);
iController->EndpointCaps(this, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlDeviceCaps:
__KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceCaps"));
r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
if (r != KErrNone)
PanicClientThread(r);
iController->DeviceCaps(this, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlSendEp0StatusPacket:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSendEp0StatusPacket"));
iController->SendEp0StatusPacket(this);
break;
case RDevUsbcClient::EControlHaltEndpoint:
__KTRACE_OPT(KUSB, Kern::Printf("EControlHaltEndpoint"));
if (iValidInterface && ValidEndpoint((TInt) a1))
{
r = iController->HaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber());
}
else
{
if (iDeviceState != EUsbcDeviceStateConfigured)
r = KErrUsbDeviceNotConfigured;
else
r = KErrUsbInterfaceNotReady;
}
break;
case RDevUsbcClient::EControlClearHaltEndpoint:
__KTRACE_OPT(KUSB, Kern::Printf("EControlClearHaltEndpoint"));
if (iValidInterface && ValidEndpoint((TInt) a1))
{
r = iController->ClearHaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber());
}
else
{
if (iDeviceState != EUsbcDeviceStateConfigured)
r = KErrUsbDeviceNotConfigured;
else
r = KErrUsbInterfaceNotReady;
}
break;
case RDevUsbcClient::EControlDumpRegisters:
__KTRACE_OPT(KUSB, Kern::Printf("EControlDumpRegisters"));
iController->DumpRegisters();
break;
case RDevUsbcClient::EControlReleaseDeviceControl:
__KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseDeviceControl"));
iController->ReleaseDeviceControl(this);
iOwnsDeviceControl = EFalse;
break;
case RDevUsbcClient::EControlEndpointZeroMaxPacketSizes:
__KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroMaxPacketSizes"));
r = iController->EndpointZeroMaxPacketSizes();
break;
case RDevUsbcClient::EControlSetEndpointZeroMaxPacketSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointZeroMaxPacketSize"));
r = iController->SetEndpointZeroMaxPacketSize(reinterpret_cast<TInt>(a1));
break;
case RDevUsbcClient::EControlGetEndpointZeroMaxPacketSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointZeroMaxPacketSize"));
r = iController->Ep0PacketSize();
break;
case RDevUsbcClient::EControlGetDeviceDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptor"));
r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
if (r != KErrNone)
PanicClientThread(r);
r = iController->GetDeviceDescriptor(iClient, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlSetDeviceDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceDescriptor"));
if (a1 != NULL)
r = iController->SetDeviceDescriptor(iClient, *((TDes8*) a1));
else
r = KErrArgument;
break;
case RDevUsbcClient::EControlGetDeviceDescriptorSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptorSize"));
if (a1 != NULL)
r = iController->GetDeviceDescriptorSize(iClient, *((TDes8*) a1));
else
r = KErrArgument;
break;
case RDevUsbcClient::EControlGetConfigurationDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptor"));
r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient);
if (r != KErrNone)
PanicClientThread(r);
r = iController->GetConfigurationDescriptor(iClient, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlGetConfigurationDescriptorSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptorSize"));
if (a1 != NULL)
{
r = iController->GetConfigurationDescriptorSize(iClient, *((TDes8*) a1));
}
else
r = KErrArgument;
break;
case RDevUsbcClient::EControlSetConfigurationDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationDescriptor"));
r = iController->SetConfigurationDescriptor(iClient, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlGetInterfaceDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptor"));
r = iController->GetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2));
break;
case RDevUsbcClient::EControlGetInterfaceDescriptorSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptorSize"));
r = iController->GetInterfaceDescriptorSize(iClient, this, (TInt) a1, *(TDes8*) a2);
break;
case RDevUsbcClient::EControlSetInterfaceDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterfaceDescriptor"));
r = iController->SetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2));
break;
case RDevUsbcClient::EControlGetEndpointDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptor"));
r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
if (r != KErrNone)
PanicClientThread(r);
ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
r = iController->GetEndpointDescriptor(iClient, this, epInfo.iSetting,
ep, *(TDes8*) epInfo.iArg);
break;
case RDevUsbcClient::EControlGetEndpointDescriptorSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptorSize"));
r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
if (r != KErrNone)
PanicClientThread(r);
ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
r = iController->GetEndpointDescriptorSize(iClient, this, epInfo.iSetting,
ep, *(TDes8*) epInfo.iArg);
break;
case RDevUsbcClient::EControlSetEndpointDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointDescriptor"));
r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
if (r != KErrNone)
PanicClientThread(r);
ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
r = iController->SetEndpointDescriptor(iClient, this, epInfo.iSetting,
ep, *(TDes8*)epInfo.iArg);
break;
case RDevUsbcClient::EControlGetDeviceQualifierDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceQualifierDescriptor"));
r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
if (r != KErrNone)
PanicClientThread(r);
r = iController->GetDeviceQualifierDescriptor(iClient, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlSetDeviceQualifierDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceQualifierDescriptor"));
if (a1 != NULL)
r = iController->SetDeviceQualifierDescriptor(iClient, *((TDes8*) a1));
else
r = KErrArgument;
break;
case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtherSpeedConfigurationDescriptor"));
r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient);
if (r != KErrNone)
PanicClientThread(r);
r = iController->GetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtherSpeedConfigurationDescriptor"));
r = iController->SetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlGetCSInterfaceDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptor"));
r = iController->GetCSInterfaceDescriptorBlock(iClient, this, (TInt) a1, *((TDes8*) a2));
break;
case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptorSize"));
r = iController->GetCSInterfaceDescriptorBlockSize(iClient, this, (TInt) a1, *(TDes8*) a2);
break;
case RDevUsbcClient::EControlGetCSEndpointDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptor"));
r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
if (r != KErrNone)
PanicClientThread(r);
ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
r = iController->GetCSEndpointDescriptorBlock(iClient, this, epInfo.iSetting,
ep, *(TDes8*) epInfo.iArg);
break;
case RDevUsbcClient::EControlGetCSEndpointDescriptorSize:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptorSize"));
r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
if (r != KErrNone)
PanicClientThread(r);
ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
r = iController->GetCSEndpointDescriptorBlockSize(iClient, this, epInfo.iSetting,
ep, *(TDes8*) epInfo.iArg);
break;
case RDevUsbcClient::EControlSignalRemoteWakeup:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSignalRemoteWakeup"));
r = iController->SignalRemoteWakeup();
break;
case RDevUsbcClient::EControlDeviceDisconnectFromHost:
__KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceDisconnectFromHost"));
r = iController->UsbDisconnect();
break;
case RDevUsbcClient::EControlDeviceConnectToHost:
__KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceConnectToHost"));
r = iController->UsbConnect();
break;
case RDevUsbcClient::EControlDevicePowerUpUdc:
__KTRACE_OPT(KUSB, Kern::Printf("EControlDevicePowerUpUdc"));
r = iController->PowerUpUdc();
break;
case RDevUsbcClient::EControlSetDeviceControl:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl"));
r = iController->SetDeviceControl(this);
if (r == KErrNone)
{
iOwnsDeviceControl = ETrue;
if (iEndpoint[0] == NULL)
{
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl 11"));
r = SetupEp0();
if (r != KErrNone)
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupEp0() failed"));
iController->ReleaseDeviceControl(this);
DestroyEp0();
iOwnsDeviceControl = EFalse;
}
iEndpoint[0]->TryToStartRead(EFalse);
}
}
else
r = KErrInUse;
break;
case RDevUsbcClient::EControlCurrentlyUsingHighSpeed:
__KTRACE_OPT(KUSB, Kern::Printf("EControlCurrentlyUsingHighSpeed"));
r = iController->CurrentlyUsingHighSpeed();
break;
case RDevUsbcClient::EControlSetInterface:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterface"));
r = Kern::ThreadRawRead(iClient, a2, &ifcInfo, sizeof(ifcInfo));
if (r != KErrNone)
PanicClientThread(r);
if (iValidInterface && (iDeviceState == EUsbcDeviceStateConfigured))
{
r = KErrGeneral;
}
else
{
bandwidthPriority = ifcInfo.iBandwidthPriority;
if ((bandwidthPriority & 0xffffff00) ||
((bandwidthPriority & 0x0f) >= KUsbcDmaBufMaxPriorities) ||
(((bandwidthPriority >> 4) & 0x0f) >= KUsbcDmaBufMaxPriorities))
{
r = KErrArgument;
}
else
{
r = SetInterface((TInt) a1, &ifcInfo);
}
}
break;
case RDevUsbcClient::EControlReleaseInterface:
__KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseInterface"));
r = iController->ReleaseInterface(this, (TInt) a1);
if (r == KErrNone)
{
DestroyInterface((TUint) a1);
}
else
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error in PIL: LDD interface won't be released."));
}
break;
case RDevUsbcClient::EControlSetCSInterfaceDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSInterfaceDescriptor"));
r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo));
if (r != KErrNone)
PanicClientThread(r);
r = iController->SetCSInterfaceDescriptorBlock(iClient, this, desInfo.iSetting,
*reinterpret_cast<const TDes8*>(desInfo.iArg),
desInfo.iSize);
break;
case RDevUsbcClient::EControlSetCSEndpointDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSEndpointDescriptor"));
r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo));
if (r != KErrNone)
PanicClientThread(r);
ep = EpFromAlternateSetting(desInfo.iSetting, desInfo.iEndpoint);
r = iController->SetCSEndpointDescriptorBlock(iClient, this, desInfo.iSetting, ep,
*reinterpret_cast<const TDes8*>(desInfo.iArg),
desInfo.iSize);
break;
case RDevUsbcClient::EControlGetStringDescriptorLangId:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptorLangId"));
r = iController->GetStringDescriptorLangId(iClient, *((TDes8*) a1));
break;
case RDevUsbcClient::EControlSetStringDescriptorLangId:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptorLangId"));
r = iController->SetStringDescriptorLangId(reinterpret_cast<TUint>(a1));
break;
case RDevUsbcClient::EControlGetManufacturerStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetManufacturerStringDescriptor"));
r = iController->GetManufacturerStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlSetManufacturerStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetManufacturerStringDescriptor"));
r = iController->SetManufacturerStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlRemoveManufacturerStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveManufacturerStringDescriptor"));
r = iController->RemoveManufacturerStringDescriptor();
break;
case RDevUsbcClient::EControlGetProductStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetProductStringDescriptor"));
r = iController->GetProductStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlSetProductStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetProductStringDescriptor"));
r = iController->SetProductStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlRemoveProductStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveProductStringDescriptor"));
r = iController->RemoveProductStringDescriptor();
break;
case RDevUsbcClient::EControlGetSerialNumberStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetSerialNumberStringDescriptor"));
r = iController->GetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlSetSerialNumberStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetSerialNumberStringDescriptor"));
r = iController->SetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlRemoveSerialNumberStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveSerialNumberStringDescriptor"));
r = iController->RemoveSerialNumberStringDescriptor();
break;
case RDevUsbcClient::EControlGetConfigurationStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationStringDescriptor"));
r = iController->GetConfigurationStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlSetConfigurationStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationStringDescriptor"));
r = iController->SetConfigurationStringDescriptor(iClient, *((TPtr8*) a1));
break;
case RDevUsbcClient::EControlRemoveConfigurationStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveConfigurationStringDescriptor"));
r = iController->RemoveConfigurationStringDescriptor();
break;
case RDevUsbcClient::EControlGetStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptor"));
r = iController->GetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2));
break;
case RDevUsbcClient::EControlSetStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptor"));
r = iController->SetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2));
break;
case RDevUsbcClient::EControlRemoveStringDescriptor:
__KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveStringDescriptor"));
r = iController->RemoveStringDescriptor((TUint8) (TInt) a1);
break;
case RDevUsbcClient::EControlAllocateEndpointResource:
epRes = (TUsbcEndpointResource)((TInt) a2);
if (!ValidEndpoint((TInt)a1))
{
r = KErrUsbEpNotInInterface;
}
else
{
r = iController->AllocateEndpointResource(this, iEndpoint[(TInt)a1]->RealEpNumber(), epRes);
}
break;
case RDevUsbcClient::EControlDeAllocateEndpointResource:
epRes = (TUsbcEndpointResource)((TInt) a2);
if (!ValidEndpoint((TInt)a1))
{
r = KErrUsbEpNotInInterface;
}
else
{
r = iController->DeAllocateEndpointResource(this, iEndpoint[(TInt)a1]->RealEpNumber(), epRes);
}
break;
case RDevUsbcClient::EControlQueryEndpointResourceUse:
epRes = (TUsbcEndpointResource)((TInt) a2);
if (!ValidEndpoint((TInt)a1))
{
r = KErrUsbEpNotInInterface;
}
else
{
r = iController->QueryEndpointResource(this, iEndpoint[(TInt)a1]->RealEpNumber(), epRes);
}
break;
case RDevUsbcClient::EControlSetOtgDescriptor:
{
r = iController->SetOtgDescriptor(iClient, *((const TDesC8*)a1));
}
break;
case RDevUsbcClient::EControlGetOtgDescriptor:
{
r = iController->GetOtgDescriptor(iClient, *((TDes8*)a1));
}
break;
case RDevUsbcClient::EControlGetOtgFeatures:
{
r = iController->GetOtgFeatures(iClient, *((TDes8*)a1));
}
break;
default:
__KTRACE_OPT(KUSB, Kern::Printf("Function code not supported"));
r = KErrNotSupported;
}
return r;
}
TInt DLddUsbcChannel::SetInterface(TInt aInterfaceNumber, TUsbcIfcInfo* aInfoBuf)
{
TUsbcInterfaceInfoBuf ifc_info_buf;
TUsbcInterfaceInfoBuf* const ifc_info_buf_ptr = aInfoBuf->iInterfaceData;
const TInt srcLen = Kern::ThreadGetDesLength(iClient, ifc_info_buf_ptr);
if (srcLen < ifc_info_buf.Length())
{
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface can't copy"));
PanicClientThread(EDesOverflow);
}
TInt r = Kern::ThreadDesRead(iClient, ifc_info_buf_ptr, ifc_info_buf, 0, KChunkShiftBy0);
if (r != KErrNone)
{
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface Copy failed reason=%d", r));
PanicClientThread(r);
}
TUsbcEndpointInfo* pEndpointData = ifc_info_buf().iEndpointData;
// If an alternate interface is being asked for then do nothing,
// just pass it down to the Controller.
const TInt num_endpoints = ifc_info_buf().iTotalEndpointsUsed;
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface num_endpoints=%d", num_endpoints));
// [The next 4 variables have to be initialized here because of the goto's that follow.]
// Both IN and OUT buffers will be fully cached:
const TUint32 cacheAttribs = EMapAttrSupRw | EMapAttrCachedMax;
const TUint32 bandwidthPriority = aInfoBuf->iBandwidthPriority;
// Supports ep0+5 endpoints
TInt real_ep_numbers[6] = {-1, -1, -1, -1, -1, -1};
// See if PIL will accept this interface
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface Calling controller"));
r = iController->SetInterface(this,
iClient,
aInterfaceNumber,
ifc_info_buf().iClass,
aInfoBuf->iString,
ifc_info_buf().iTotalEndpointsUsed,
ifc_info_buf().iEndpointData,
&real_ep_numbers,
ifc_info_buf().iFeatureWord);
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface controller returned %d", r));
if (r != KErrNone)
{
__KTRACE_OPT(KPANIC, Kern::Printf("SetInterface failed reason=%d", r));
return r;
}
// [The next variable has to be initialized here because of the goto's that follow.]
TUsbcAlternateSettingList* alternateSettingListRec;
// ep0
if (iEndpoint[0] == NULL)
{
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface 11"));
r = SetupEp0();
if (r != KErrNone)
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupEp0() failed"));
DestroyEp0();
goto F1;
}
}
alternateSettingListRec = new TUsbcAlternateSettingList;
if (!alternateSettingListRec)
{
r = KErrNoMemory;
goto F1;
}
__KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::SetInterface num_endpoints=%d", num_endpoints));
// other endpoints
// calculate the total buffer size
for (TInt i = 1; i <= num_endpoints; i++, pEndpointData++)
{
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d", i));
if (!ValidateEndpoint(pEndpointData))
{
r = KErrUsbBadEndpoint;
goto F2;
}
TUsbcEndpoint* ep = new TUsbcEndpoint(this, iController, pEndpointData, i, bandwidthPriority);
alternateSettingListRec->iEndpoint[i] = ep;
if (!ep)
{
r = KErrNoMemory;
goto F2;
}
if (ep->Construct() != KErrNone)
{
r = KErrNoMemory;
goto F2;
}
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d rec=0x%08x ep==0x%08x",
i, alternateSettingListRec, ep));
}
// buf size of each endpoint
TInt bufSizes[KMaxEndpointsPerClient + 1];
TInt epNum[KMaxEndpointsPerClient + 1];
// init
for( TInt i=0;i<KMaxEndpointsPerClient+1;i++ )
{
bufSizes[i] = -1;
epNum[i] = i;
}
// Record the actual buf size of each endpoint
for( TInt i=1;i<=num_endpoints;i++ )
{
bufSizes[i] = alternateSettingListRec->iEndpoint[i]->BufferSize();
}
__KTRACE_OPT(KUSB, Kern::Printf("Sort the endpoints:"));
// sort the endpoint number by the bufsize decreasely
for( TInt i=1;i<num_endpoints;i++ )
{
TInt epMaxBuf = i;
for(TInt k=i+1;k<=num_endpoints;k++ )
{
if( bufSizes[epMaxBuf]<bufSizes[k])
{
epMaxBuf = k;
}
}
TInt temp = bufSizes[i];
bufSizes[i] = bufSizes[epMaxBuf];
bufSizes[epMaxBuf] = temp;
temp = epNum[i];
epNum[i] = epNum[epMaxBuf];
epNum[epMaxBuf] = temp;
alternateSettingListRec->iEpNumDeOrderedByBufSize[i] = epNum[i];
__KTRACE_OPT(KUSB, Kern::Printf(" %d:%d", epNum[i], bufSizes[i]));
}
alternateSettingListRec->iEpNumDeOrderedByBufSize[num_endpoints] = epNum[num_endpoints];
__KTRACE_OPT(KUSB, Kern::Printf(" %d:%d", epNum[num_endpoints], bufSizes[num_endpoints]));
__KTRACE_OPT(KUSB, Kern::Printf("\n"));
// chain in this alternate setting
alternateSettingListRec->iNext = iAlternateSettingList;
iAlternateSettingList = alternateSettingListRec;
alternateSettingListRec->iSetting = aInterfaceNumber;
alternateSettingListRec->iNumberOfEndpoints = num_endpoints;
// Record the 'real' endpoint number used by the PDD in both the Ep and
// the Req callback:
for (TInt i = 1; i <= num_endpoints; i++)
{
alternateSettingListRec->iEndpoint[i]->SetRealEpNumber(real_ep_numbers[i]);
}
r = SetupInterfaceMemory(iHwChunks, cacheAttribs );
if( r==KErrNone )
{
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface ready to exit"));
if (aInterfaceNumber == 0)
{
// make sure we're ready to go with the main interface
iValidInterface = ETrue;
__KTRACE_OPT(KUSB, Kern::Printf("SetInterface SelectAlternateSetting"));
SelectAlternateSetting(0);
}
return KErrNone;
}
else
{
__KTRACE_OPT(KUSB, Kern::Printf("Destroying all interfaces"));
DestroyAllInterfaces();
DestroyEp0();
return r;
}
F2:
delete alternateSettingListRec;
//Fall through
F1:
#if _DEBUG
TInt r1 = iController->ReleaseInterface(this, aInterfaceNumber);
__KTRACE_OPT(KUSB, Kern::Printf("Release Interface controller returned %d", r1));
#else
(void) iController->ReleaseInterface(this, aInterfaceNumber);
#endif
return r;
}
// realloc the memory, and set the previous interfaces
TInt DLddUsbcChannel::SetupInterfaceMemory(RArray<DPlatChunkHw*> &aHwChunks,
TUint32 aCacheAttribs )
{
TUsbcAlternateSettingList* asRec = iAlternateSettingList;
// if buffers has been changed
TBool chunkChanged = EFalse;
TInt numOfEp = asRec->iNumberOfEndpoints;
// 1, collect all bufs' sizes for the current interface
// to realloc all the chunks
__KTRACE_OPT(KUSB, Kern::Printf("Collect all buffer sizes:"));
RArray<TInt> bufSizes;
for(TInt i=1;i<=numOfEp;i++)
{
TInt nextEp = asRec->iEpNumDeOrderedByBufSize[i];
TInt epBufCount = asRec->iEndpoint[nextEp]->BufferNumber();
__KTRACE_OPT(KUSB, Kern::Printf(" ep %d, buf count %d", nextEp, epBufCount ));
for(TInt k=0;k<epBufCount;k++)
{
TInt epBufSize = asRec->iEndpoint[nextEp]->BufferSize();
TInt r = bufSizes.Append(epBufSize);
if(r!=KErrNone)
{
iController->DeRegisterClient(this);
bufSizes.Close();
return r;
}
__KTRACE_OPT(KUSB,Kern::Printf(" %d", epBufSize ));
}
__KTRACE_OPT(KUSB, Kern::Printf("\n"));
}
// 2, alloc the buffer decreasely, biggest-->smallest
// 2.1 check the existing chunks
TInt bufCount = bufSizes.Count();
__KTRACE_OPT(KUSB, Kern::Printf(" ep buf number needed %d", bufCount ));
__KTRACE_OPT(KUSB, Kern::Printf(" chunks available %d", aHwChunks.Count() ));
TInt chunkInd = 0;
while( (chunkInd<aHwChunks.Count())&& (chunkInd<bufCount))
{
TUint8* oldAddr = NULL;
oldAddr = reinterpret_cast<TUint8*>(aHwChunks[chunkInd]->LinearAddress());
DPlatChunkHw* chunk = ReAllocate(bufSizes[chunkInd], aHwChunks[chunkInd], aCacheAttribs);
if (chunk == NULL)
{
__KTRACE_OPT(KUSB, Kern::Printf("Failed to alloc chunks size %d!", bufSizes[chunkInd]));
// lost all interfaces:
// Tell Controller to release Interface and h/w resources associated with this
iController->DeRegisterClient(this);
bufSizes.Close();
return KErrNoMemory;
}
else
{
// Parcel out the memory between endpoints
TUint8* newAddr = reinterpret_cast<TUint8*>(chunk->LinearAddress());
__KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory alloc new chunk=0x%x, size=%d", newAddr,bufSizes[chunkInd]));
chunkChanged = (newAddr != oldAddr);
aHwChunks[chunkInd] = chunk;
}
chunkInd++;
}
// 2.2 in case available chunks are not enough
while( chunkInd<bufCount)
{
DPlatChunkHw* chunk = NULL;
chunk = Allocate( bufSizes[chunkInd], aCacheAttribs);
if (chunk == NULL)
{
__KTRACE_OPT(KUSB, Kern::Printf("Failed to alloc chunk, size %d!", bufSizes[chunkInd]));
// lost all interfaces:
// Tell Controller to release Interface and h/w resources associated with this
iController->DeRegisterClient(this);
bufSizes.Close();
return KErrNoMemory;
}
else
{
// Parcel out the memory between endpoints
__KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory alloc new chunk=0x%x, size=%d",
reinterpret_cast<TUint8*>(chunk->LinearAddress()), bufSizes[chunkInd]));
TInt r = aHwChunks.Append(chunk);
if(r!=KErrNone)
{
ClosePhysicalChunk(chunk);
iController->DeRegisterClient(this);
bufSizes.Close();
return r;
}
}
chunkInd++;
}
// 3, Set the the bufs of the interfaces
ReSetInterfaceMemory(asRec, aHwChunks);
if(chunkChanged)
{
__KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory readdressing."));
asRec = asRec->iNext;
while (asRec)
{
// Interfaces are not concurrent so they can all start at the same logical address
__KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory readdressing setting=%d", asRec->iSetting));
ReSetInterfaceMemory(asRec, aHwChunks);
asRec = asRec->iNext;
}
}
return KErrNone;
}
TInt DLddUsbcChannel::SetupEp0()
{
__KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 entry %x", this));
TInt ep0Size = iController->Ep0PacketSize();
TUsbcEndpointInfo ep0Info = TUsbcEndpointInfo(KUsbEpTypeControl, KUsbEpDirBidirect, ep0Size);
TUsbcEndpoint* ep0 = new TUsbcEndpoint(this, iController, &ep0Info, 0, 0);
if (ep0 == NULL)
{
return KErrNoMemory;
}
// In case we have to return early:
iEndpoint[0] = ep0;
TInt r = ep0->Construct();
if (r != KErrNone)
{
return KErrNoMemory;
}
TInt bufferNum = ep0->BufferNumber();
TInt bufferSize = ep0->BufferSize();
TUint32 cacheAttribs = EMapAttrSupRw | EMapAttrCachedMax;
for(TInt i=0;i<bufferNum;i++)
{
DPlatChunkHw* chunk = Allocate(bufferSize, cacheAttribs );
if(chunk==NULL)
{
return KErrNoMemory;
}
TInt r = iHwChunksEp0.Append(chunk);
if(r!=KErrNone)
{
ClosePhysicalChunk(chunk);
return r;
}
TUint8 * buf;
buf = (TUint8*) chunk->LinearAddress();
ep0->SetBufferAddr( i, buf);
__KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 60 buffer number %d", i));
__KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 60 buffer size %d", bufferSize));
}
ep0->SetRealEpNumber(0);
return KErrNone;
}
// Set buffer address of the interface
// Precondition: Enough chunks available.
void DLddUsbcChannel::ReSetInterfaceMemory(TUsbcAlternateSettingList* aAlternateSettingListRec,
RArray<DPlatChunkHw*> &aHwChunks)
{
TUsbcAlternateSettingList* asRec = aAlternateSettingListRec;
// set all the interfaces
TInt chunkInd = 0;
TInt numOfEp = asRec->iNumberOfEndpoints;
for (TInt i = 1; i <= numOfEp; i++)
{
TInt nextEp = asRec->iEpNumDeOrderedByBufSize[i];
TInt epBufCount = asRec->iEndpoint[nextEp]->BufferNumber();
for(TInt k=0;k<epBufCount;k++)
{
TUsbcEndpoint* ep = asRec->iEndpoint[nextEp];
if (ep != NULL )
{
TUint8* pBuf = NULL;
pBuf = reinterpret_cast<TUint8*>(aHwChunks[chunkInd]->LinearAddress());
ep->SetBufferAddr( k, pBuf);
__KTRACE_OPT(KUSB, Kern::Printf(" ep %d, buf %d, addr 0x%x", nextEp, k, pBuf ));
chunkInd++;
__ASSERT_DEBUG(chunkInd<=aHwChunks.Count(),
Kern::Printf(" Error: available chunks %d, run out at epInd%d, bufInd%d",
aHwChunks.Count(), i, k));
__ASSERT_DEBUG(chunkInd<=aHwChunks.Count(),
Kern::Fault("usbc.ldd", __LINE__));
}
}
}
}
void DLddUsbcChannel::DestroyAllInterfaces()
{
// Removes all interfaces
TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
while (alternateSettingListRec)
{
iController->ReleaseInterface(this, alternateSettingListRec->iSetting);
TUsbcAlternateSettingList* alternateSettingListRecNext = alternateSettingListRec->iNext;
delete alternateSettingListRec;
alternateSettingListRec = alternateSettingListRecNext;
}
iNumberOfEndpoints = 0;
iAlternateSettingList = NULL;
for(TInt i=0;i<iHwChunks.Count();i++)
{
ClosePhysicalChunk( iHwChunks[i]);
}
iHwChunks.Close();
iValidInterface = EFalse;
}
void DLddUsbcChannel::DestroyInterface(TUint aInterfaceNumber)
{
if (iAlternateSetting == aInterfaceNumber)
{
ResetInterface(KErrUsbInterfaceNotReady);
iValidInterface = EFalse;
iNumberOfEndpoints = 0;
for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
{
iEndpoint[i] = NULL;
}
}
TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
TUsbcAlternateSettingList* alternateSettingListRecOld = NULL;
while (alternateSettingListRec)
{
TUsbcAlternateSettingList* alternateSettingListRecNext = alternateSettingListRec->iNext;
if (alternateSettingListRec->iSetting == aInterfaceNumber)
{
// This record is to be deleted
if (alternateSettingListRecOld == NULL)
{
// The record to be deleted is at the list head
iAlternateSettingList = alternateSettingListRecNext;
}
else
{
// The record to be deleted is NOT at the list head
alternateSettingListRecOld->iNext = alternateSettingListRecNext;
}
delete alternateSettingListRec;
break;
}
alternateSettingListRecOld = alternateSettingListRec;
alternateSettingListRec = alternateSettingListRecNext;
}
if (iAlternateSettingList == NULL)
{
// if no interfaces left destroy non-ep0 buffering
for(TInt i=0;i<iHwChunks.Count();i++)
{
ClosePhysicalChunk( iHwChunks[i]);
}
iHwChunks.Close();
}
}
void DLddUsbcChannel::DestroyEp0()
{
delete iEndpoint[0];
iEndpoint[0] = NULL;
for(TInt i=0;i<iHwChunksEp0.Count();i++)
{
ClosePhysicalChunk( iHwChunksEp0[i] );
}
iHwChunksEp0.Close();
}
void DLddUsbcChannel::EndpointStatusChangeCallback(TAny* aDLddUsbcChannel)
{
__KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback"));
DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
if (dUsbc->iChannelClosing)
return;
TUint endpointState = dUsbc->iEndpointStatusCallbackInfo.State();
const TInt reqNo = (TInt) RDevUsbcClient::ERequestEndpointStatusNotify;
if (dUsbc->iRequestStatus[reqNo])
{
__KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback Notify status"));
DThread* client = dUsbc->iClient;
dUsbc->iEndpointStatusChangeReq->Data() = endpointState;
dUsbc->iRequestStatus[reqNo] = NULL;
Kern::QueueRequestComplete(client,dUsbc->iEndpointStatusChangeReq,KErrNone);
dUsbc->iEndpointStatusChangePtr = NULL;
}
}
void DLddUsbcChannel::StatusChangeCallback(TAny* aDLddUsbcChannel)
{
DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
if (dUsbc->iChannelClosing)
return;
TUsbcDeviceState deviceState;
TInt i;
for (i = 0;
(i < KUsbcDeviceStateRequests) && ((deviceState = dUsbc->iStatusCallbackInfo.State(i)) != EUsbcNoState);
++i)
{
__KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallBack status=%d", deviceState));
if (deviceState & KUsbAlternateSetting)
{
dUsbc->ProcessAlternateSetting(deviceState);
}
else
{
dUsbc->ProcessDeviceState(deviceState);
}
// Only queue if userside is interested
if (dUsbc->iDeviceStatusNeeded)
{
dUsbc->iStatusFifo->AddStatusToQueue(deviceState);
const TInt reqNo = (TInt) RDevUsbcClient::ERequestAlternateDeviceStatusNotify;
if (dUsbc->AlternateDeviceStateTestComplete())
{
dUsbc->iRequestStatus[reqNo]=NULL;
Kern::QueueRequestComplete(dUsbc->iClient,dUsbc->iStatusChangeReq,KErrNone);
}
}
}
// We don't want to be interrupted in the middle of this:
const TInt irqs = NKern::DisableInterrupts(2);
dUsbc->iStatusCallbackInfo.ResetState();
NKern::RestoreInterrupts(irqs);
}
void DLddUsbcChannel::OtgFeatureChangeCallback(TAny* aDLddUsbcChannel)
{
__KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback"));
DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
if (dUsbc->iChannelClosing)
return;
TUint8 features;
// No return value check. Assume OTG always supported here
dUsbc->iController->GetCurrentOtgFeatures(features);
const TInt reqNo = (TInt) RDevUsbcClient::ERequestOtgFeaturesNotify;
if (dUsbc->iRequestStatus[reqNo])
{
__KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback Notify status"));
dUsbc->iOtgFeatureChangeReq->Data()=features;
dUsbc->iRequestStatus[reqNo] = NULL;
Kern::QueueRequestComplete(dUsbc->iClient,dUsbc->iOtgFeatureChangeReq,KErrNone);
dUsbc->iOtgFeatureChangePtr = NULL;
}
}
TInt DLddUsbcChannel::SelectAlternateSetting(TUint aAlternateSetting)
{
TInt r = KErrGeneral; // error code doesn't go userside
TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
while (alternateSettingListRec)
{
if (alternateSettingListRec->iSetting == aAlternateSetting)
{
// found the correct interface, now latch in new endpoint set
for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
{
iEndpoint[i] = NULL;
}
iNumberOfEndpoints = alternateSettingListRec->iNumberOfEndpoints;
r = KErrNone;
for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
{
iEndpoint[i] = alternateSettingListRec->iEndpoint[i];
}
// Only after correct alternate setting has been chosen.
UpdateEndpointSizes();
}
alternateSettingListRec = alternateSettingListRec->iNext;
}
return r;
}
TInt DLddUsbcChannel::EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint)
{
TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
while (alternateSettingListRec)
{
if (alternateSettingListRec->iSetting == aAlternateSetting)
{
if ((aEndpoint <= alternateSettingListRec->iNumberOfEndpoints) &&
(aEndpoint >= 0))
{
return alternateSettingListRec->iEndpoint[aEndpoint]->RealEpNumber();
}
else
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: aEndpoint %d wrong for aAlternateSetting %d",
aEndpoint, aAlternateSetting));
return -1;
}
}
alternateSettingListRec = alternateSettingListRec->iNext;
}
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: no aAlternateSetting %d found", aAlternateSetting));
return -1;
}
TInt DLddUsbcChannel::ProcessAlternateSetting(TUint aAlternateSetting)
{
ResetInterface(KErrUsbInterfaceChange); // kill any outstanding transfers
__KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting 0x%08x", aAlternateSetting));
TUint newSetting = aAlternateSetting&(~KUsbAlternateSetting);
__KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting selecting alternate setting 0x%08x", newSetting));
TInt r = SelectAlternateSetting(newSetting);
if (r != KErrNone)
return r;
StartEpReads();
iAlternateSetting = newSetting;
return KErrNone;
}
TInt DLddUsbcChannel::ProcessDeviceState(TUsbcDeviceState aDeviceState)
{
__KTRACE_OPT(KUSB, Kern::Printf("ProcessDeviceState(%d -> %d)", iDeviceState, aDeviceState));
if (iDeviceState == aDeviceState)
{
__KTRACE_OPT(KUSB, Kern::Printf(" No state change => nothing to be done."));
return KErrNone;
}
if (iDeviceState == EUsbcDeviceStateSuspended)
{
__KTRACE_OPT(KUSB, Kern::Printf(" Coming out of Suspend: old state = %d", iOldDeviceState));
iDeviceState = iOldDeviceState;
if (iDeviceState == aDeviceState)
{
__KTRACE_OPT(KUSB, Kern::Printf(" New state same as before Suspend => nothing to be done."));
return KErrNone;
}
}
TBool renumerateState = (aDeviceState == EUsbcDeviceStateConfigured);
TBool deconfigured = EFalse;
TInt cancellationCode = KErrNone;
if (aDeviceState == EUsbcDeviceStateSuspended)
{
__KTRACE_OPT(KUSB, Kern::Printf(" Suspending..."));
iOldDeviceState = iDeviceState;
// Put PSL into low power mode here
}
else
{
deconfigured = (iDeviceState == EUsbcDeviceStateConfigured &&
aDeviceState != EUsbcDeviceStateConfigured);
if (iDeviceState == EUsbcDeviceStateConfigured)
{
if (aDeviceState == EUsbcDeviceStateUndefined)
cancellationCode = KErrUsbCableDetached;
else if (aDeviceState == EUsbcDeviceStateAddress)
cancellationCode = KErrUsbDeviceNotConfigured;
else if (aDeviceState == EUsbcDeviceStateDefault)
cancellationCode = KErrUsbDeviceBusReset;
else
cancellationCode = KErrUsbDeviceNotConfigured;
}
}
__KTRACE_OPT(KUSB, Kern::Printf(" %d --> %d", iDeviceState, aDeviceState));
iDeviceState = aDeviceState;
if (iValidInterface || iOwnsDeviceControl)
{
// This LDD may not own an interface. It could be some manager reenumerating
// after its subordinate LDDs have setup their interfaces.
if (deconfigured)
{
DeConfigure(cancellationCode);
}
else if (renumerateState)
{
// Update size of Ep0.
iEndpoint[0]->SetMaxPacketSize(iController->Ep0PacketSize());
// First cancel transfers on all endpoints
ResetInterface(KErrUsbInterfaceChange);
// Select main interface & latch in new endpoint set
SelectAlternateSetting(0);
// Here we go
StartEpReads();
}
}
const TInt reqNo = (TInt) RDevUsbcClient::ERequestReEnumerate;
if (renumerateState && iRequestStatus[reqNo])
{
// This lot must be done if we are reenumerated
CompleteBufferRequest(iClient, reqNo, KErrNone);
}
return KErrNone;
}
void DLddUsbcChannel::UpdateEndpointSizes()
{
// The regular ones.
TInt i = 0;
while ((++i <= KMaxEndpointsPerClient) && iEndpoint[i])
{
const TInt size = iController->EndpointPacketSize(this, iEndpoint[i]->RealEpNumber());
if (size < 0)
{
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: Packet size < 0 for ep %d", i));
continue;
}
iEndpoint[i]->SetMaxPacketSize(size);
}
__ASSERT_DEBUG(i == iNumberOfEndpoints + 1,
Kern::Printf(" Error: iNumberOfEndpoints wrong (%d)", iNumberOfEndpoints));
}
DPlatChunkHw* DLddUsbcChannel::ReAllocate(TInt aBuffersize, DPlatChunkHw* aHwChunk, TUint32 aCacheAttribs)
{
DPlatChunkHw* chunk = aHwChunk;
if ((!chunk) || (chunk->iSize < aBuffersize))
{
if (chunk)
{
ClosePhysicalChunk(chunk);
}
__KTRACE_OPT(KUSB, Kern::Printf("ReAllocate need to get new chunk"));
chunk = Allocate(aBuffersize, aCacheAttribs);
}
return chunk;
}
DPlatChunkHw* DLddUsbcChannel::Allocate(TInt aBuffersize, TUint32 aCacheAttribs)
{
TUint32 physAddr = 0;
TUint32 size = Kern::RoundToPageSize(aBuffersize);
if (Epoc::AllocPhysicalRam(size, physAddr) != KErrNone)
return NULL;
DPlatChunkHw* HwChunk;
if (DPlatChunkHw::New(HwChunk, physAddr, aBuffersize, aCacheAttribs) != KErrNone)
{
Epoc::FreePhysicalRam(physAddr, size);
return NULL;
}
return HwChunk;
}
TInt DLddUsbcChannel::DoRxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TBool aReEntrant)
{
TBool completeNow;
TInt err = aTUsbcEndpoint->CopyToClient(iClient, completeNow,iClientAsynchNotify[aEndpoint]->iClientBuffer);
if (completeNow)
{
aTUsbcEndpoint->SetClientReadPending(EFalse);
CompleteBufferRequest(iClient, aEndpoint, err);
}
aTUsbcEndpoint->TryToStartRead(aReEntrant);
return err;
}
void DLddUsbcChannel::DoRxCompleteNow(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint)
{
aTUsbcEndpoint->SetClientReadPending(EFalse);
CompleteBufferRequest(iClient, aEndpoint, KErrCancel);
}
void DLddUsbcChannel::DoTxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TInt aError)
{
aTUsbcEndpoint->SetClientWritePending(EFalse);
CompleteBufferRequest(iClient, aEndpoint, aError);
}
TBool DLddUsbcChannel::AlternateDeviceStateTestComplete()
{
TBool completeNow = EFalse;
const TInt reqNo = (TInt) RDevUsbcClient::ERequestAlternateDeviceStatusNotify;
if (iRequestStatus[reqNo])
{
// User req is outstanding
TUint32 deviceState;
if (iStatusFifo->GetDeviceQueuedStatus(deviceState) == KErrNone)
{
// Device state waiting to be sent userside
completeNow = ETrue;
__KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallback Notify status"));
iStatusChangeReq->Data()=deviceState;
iStatusChangePtr = NULL;
}
}
return completeNow;
}
void DLddUsbcChannel::EmergencyCompleteDfc(TAny* aDLddUsbcChannel)
{
((DLddUsbcChannel*) aDLddUsbcChannel)->DoEmergencyComplete();
}
void DLddUsbcChannel::DeConfigure(TInt aErrorCode)
{
__KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::DeConfigure()"));
// Called after deconfiguration. Cancels transfers on all endpoints.
ResetInterface(aErrorCode);
// Cancel the endpoint status notify request if it is outstanding.
const TInt KEpNotReq = RDevUsbcClient::ERequestEndpointStatusNotify;
if (iRequestStatus[KEpNotReq])
{
CancelNotifyEndpointStatus();
iRequestStatus[KEpNotReq]=NULL;
Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,aErrorCode);
}
// We have to reset the alternate setting number when the config goes away.
SelectAlternateSetting(0);
iAlternateSetting = 0;
}
void DLddUsbcChannel::StartEpReads()
{
// Queued after enumeration. Starts reads on all endpoints.
// The endpoint itself decides if it can do a read
TInt i;
for (i = 0; i <= iNumberOfEndpoints; i++)
{
// The endpoint itself will decide if it can read
iEndpoint[i]->TryToStartRead(EFalse);
}
}
void DLddUsbcChannel::ResetInterface(TInt aErrorCode)
{
// Called after change in alternate setting. Cancels transfers on all endpoints
if (iValidInterface || iOwnsDeviceControl)
{
// Reset each endpoint except ep0
for (TInt i = 1; i <= iNumberOfEndpoints; i++)
{
__KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i));
iEndpoint[i]->CancelTransfer(iClient,iClientAsynchNotify[i]->iClientBuffer); // Copies data userside
iEndpoint[i]->AbortTransfer(); // kills any ldd->pil outstanding transfers
iEndpoint[i]->iDmaBuffers->Flush();
if (iRequestStatus[i] != NULL)
CompleteBufferRequest(iClient, i, aErrorCode);
iEndpoint[i]->SetClientWritePending(EFalse);
iEndpoint[i]->SetClientReadPending(EFalse);
}
}
}
void DLddUsbcChannel::AbortInterface()
{
// Called after when channel is closing
if (iValidInterface || iOwnsDeviceControl)
{
for (TInt i = 0; i <= iNumberOfEndpoints; i++)
{
if (iEndpoint[i])
{
// kills any LDD->PDD outstanding transfers
iEndpoint[i]->AbortTransfer();
}
}
}
}
void DLddUsbcChannel::ClosePhysicalChunk(DPlatChunkHw*& aHwChunk)
{
if (aHwChunk)
{
const TPhysAddr addr = aHwChunk->PhysicalAddress();
const TInt size = aHwChunk->iSize;
aHwChunk->Close(NULL);
Epoc::FreePhysicalRam(addr, size);
}
aHwChunk = NULL;
}
TInt DLddUsbcChannel::DoEmergencyComplete()
{
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::DoEmergencyComplete"));
// cancel any pending DFCs
// complete all client requests
for (TInt i = 0; i < KUsbcMaxRequests; i++)
{
if (iRequestStatus[i])
{
__KTRACE_OPT(KUSB, Kern::Printf("Complete request 0x%x", iRequestStatus[i]));
if (i == RDevUsbcClient::ERequestAlternateDeviceStatusNotify)
{
iDeviceStatusNeeded = EFalse;
iStatusFifo->FlushQueue();
if (iStatusChangePtr)
{
iStatusChangeReq->Data() = iController->GetDeviceStatus();
iStatusChangePtr = NULL;
if (iStatusChangeReq->IsReady())
{
iRequestStatus[i] = NULL;
Kern::QueueRequestComplete(iClient, iStatusChangeReq,
KErrDisconnected);
}
}
}
else if (i == RDevUsbcClient::ERequestEndpointStatusNotify)
{
if (iEndpointStatusChangePtr)
{
TUint epBitmap = 0;
for (TInt i = 0; i <= iNumberOfEndpoints; i++)
{
TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber());
TUint b;
(v == EEndpointStateStalled) ? b = 1 : b = 0;
epBitmap |= b << i;
}
iEndpointStatusChangeReq->Data() = epBitmap;
iEndpointStatusChangePtr = NULL;
}
if (iEndpointStatusChangeReq->IsReady())
{
iRequestStatus[i] = NULL;
Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,KErrDisconnected);
}
}
else if (i == RDevUsbcClient::ERequestOtgFeaturesNotify)
{
if (iOtgFeatureChangePtr)
{
TUint8 features;
iController->GetCurrentOtgFeatures(features);
iOtgFeatureChangeReq->Data()=features;
iOtgFeatureChangePtr = NULL;
}
if (iOtgFeatureChangeReq->IsReady())
{
iRequestStatus[i] = NULL;
Kern::QueueRequestComplete(iClient, iOtgFeatureChangeReq,
KErrDisconnected);
}
}
else
{
CompleteBufferRequest(iClient, i, KErrDisconnected);
}
}
}
iStatusCallbackInfo.Cancel();
iEndpointStatusCallbackInfo.Cancel();
iOtgFeatureCallbackInfo.Cancel();
return KErrNone;
}
void DLddUsbcChannel::PanicClientThread(TInt aReason)
{
Kern::ThreadKill(iClient, EExitPanic, aReason, KUsbLDDKillCat);
}
// ===============Endpoint====================
// Constructor
TUsbcEndpoint::TUsbcEndpoint(DLddUsbcChannel* aLDD, DUsbClientController* aController,
const TUsbcEndpointInfo* aEndpointInfo, TInt aEndpointNum,
TInt aBandwidthPriority)
: iController(aController),
iEndpointInfo(aEndpointInfo->iType, aEndpointInfo->iDir, aEndpointInfo->iSize),
iClientReadPending(EFalse),
iClientWritePending(EFalse),
iEndpointNumber(aEndpointNum),
iRealEpNumber(-1),
iLdd(aLDD),
iError(KErrNone),
iRequestCallbackInfo(NULL),
iBytesTransferred(0),
iBandwidthPriority(aBandwidthPriority)
{
ResetTransferInfo();
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::TUsbcEndpoint 2"));
}
TInt TUsbcEndpoint::Construct()
{
iDmaBuffers = new TDmaBuf(&iEndpointInfo, iBandwidthPriority);
if (iDmaBuffers == NULL)
{
return KErrNoMemory;
}
const TInt r = iDmaBuffers->Construct(&iEndpointInfo);
if (r != KErrNone)
{
return r;
}
iRequestCallbackInfo = new TUsbcRequestCallback(iLdd,
iEndpointNumber,
TUsbcEndpoint::RequestCallback,
this,
iLdd->iDfcQ,
KUsbRequestCallbackPriority);
if (iRequestCallbackInfo == NULL)
{
return KErrNoMemory;
}
return KErrNone;
}
TUsbcEndpoint::~TUsbcEndpoint()
{
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::~TUsbcEndpoint(%d)", iEndpointNumber));
AbortTransfer();
delete iRequestCallbackInfo;
delete iDmaBuffers;
}
void TUsbcEndpoint::RequestCallback(TAny* aTUsbcEndpoint)
{
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::RequestCallback"));
((TUsbcEndpoint*) aTUsbcEndpoint)->EndpointComplete();
}
void TUsbcEndpoint::SetMaxPacketSize(TInt aSize)
{
iEndpointInfo.iSize = aSize;
iDmaBuffers->SetMaxPacketSize(aSize);
}
TInt TUsbcEndpoint::EndpointComplete()
{
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete ep=%d %d",
iEndpointNumber, iRequestCallbackInfo->iEndpointNum));
if (iLdd->ChannelClosing())
{
__KTRACE_OPT(KUSB, Kern::Printf("We're going home -> completions no longer accepted"));
return KErrNone;
}
TTransferDirection transferDir = iRequestCallbackInfo->iTransferDir;
TInt error = iRequestCallbackInfo->iError;
switch (transferDir)
{
case EControllerWrite:
{
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete Write 2"));
if (!iDmaBuffers->TxIsActive())
{
__KTRACE_OPT(KUSB, Kern::Printf(" TX completion but !iDmaBuffers->TxIsActive()"));
break;
}
iDmaBuffers->TxSetInActive();
TBool completeNow = EFalse;
iBytesTransferred += iRequestCallbackInfo->iTxBytes;
if (iClientWritePending)
{
//Complete Outstanding Write if necessary
iError = error;
if (iError != KErrNone)
{
completeNow = ETrue;
if (iError == KErrPrematureEnd) // Previous write could not be completed
iError = KErrNone;
}
else
{
if (iBytesTransferred == (TUint32) iTransferInfo.iTransferSize)
{
completeNow = ETrue;
}
else
{
iError = ContinueWrite();
if (iError != KErrNone)
completeNow = ETrue;
}
}
if (completeNow)
{
TxComplete();
ResetTransferInfo();
if (iEndpointNumber == 0)
{
iDmaBuffers->Flush();
TryToStartRead(EFalse);
}
}
}
break;
}
case EControllerRead:
{
// The first packet always contains the total #of bytes
const TInt byteCount = iRequestCallbackInfo->iPacketSize[0];
const TInt packetCount = iRequestCallbackInfo->iRxPackets;
iDmaBuffers->ReadXferComplete(byteCount, packetCount, error);
// We queue the dfc if we can complete the read, i.e. if we are reading a packet,
// or if we have enough data to satisfy a read data request.
if (iClientReadPending)
{
//Complete outstanding read
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete Read 3 (bytes "
"available=%d)", iDmaBuffers->RxBytesAvailable()));
TInt bytesReqd = iTransferInfo.iTransferSize - iBytesTransferred;
TBool completeNow = EFalse;
if (iTransferInfo.iTransferType == ETransferTypeReadPacket ||
iTransferInfo.iTransferType == ETransferTypeReadOneOrMore)
{
// Always complete on a packet read
completeNow = ETrue;
}
else if (iTransferInfo.iTransferType == ETransferTypeReadData)
{
// Complete only if enough data is present
if (iDmaBuffers->RxBytesAvailable() >= bytesReqd)
completeNow = ETrue;
}
else if (iTransferInfo.iTransferType == ETransferTypeReadUntilShort)
{
// Complete if enough data is present or if a short packet has been delivered
const TInt maxPacketSize = iEndpointInfo.iSize;
const TInt lastPacketSize = iRequestCallbackInfo->iPacketSize[packetCount - 1];
if (lastPacketSize < maxPacketSize)
completeNow = ETrue;
else if (iDmaBuffers->RxBytesAvailable() >= bytesReqd)
completeNow = ETrue;
else
{
const TUint type = iEndpointInfo.iType;
if ((type == KUsbEpTypeBulk) && (lastPacketSize & (maxPacketSize - 1)))
{
completeNow = ETrue;
}
else if ((type != KUsbEpTypeBulk) &&
(lastPacketSize > maxPacketSize) &&
(lastPacketSize % maxPacketSize))
{
completeNow = ETrue;
}
}
}
if (completeNow)
{
iError = error;
RxComplete(EFalse);
iClientReadPending = EFalse;
}
}
iDmaBuffers->RxSetInActive();
if (error != KErrNone)
{
return error;
}
if (TryToStartRead(EFalse) != KErrNone)
{
// if (iEndpointNumber != 0)
// Kern::Printf("EndpointComplete couldn't start read on ep=%d", iEndpointNumber);
}
break;
}
default:
// shouldn't get here
break;
}
return KErrNone;
}
void TUsbcEndpoint::TxComplete()
{
iLdd->DoTxComplete(this, iEndpointNumber, iError);
}
TInt TUsbcEndpoint::RxComplete(TBool aReEntrant)
{
return iLdd->DoRxComplete(this, iEndpointNumber, aReEntrant);
}
void TUsbcEndpoint::RxCompleteNow()
{
iLdd->DoRxCompleteNow(this, iEndpointNumber);
}
TInt TUsbcEndpoint::CopyToClient(DThread* aClient, TClientBuffer *aTcb)
{
TBool completeNow;
return CopyToClient(aClient, completeNow,aTcb);
}
TInt TUsbcEndpoint::CopyToClient(DThread* aClient, TBool& aCompleteNow, TClientBuffer *aTcb)
{
TInt err;
const TInt length = iTransferInfo.iTransferSize;
const TBool KReadData = EFalse;
const TBool KReadUntilShort = ETrue;
__KTRACE_OPT(KUSB, Kern::Printf("CopyToClient: length = %d", length));
if (iTransferInfo.iTransferType == ETransferTypeReadPacket)
{
err = iDmaBuffers->RxCopyPacketToClient(aClient, aTcb, length);
aCompleteNow = ETrue;
}
else if (iTransferInfo.iTransferType == ETransferTypeReadOneOrMore)
{
err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred,
KReadData, aCompleteNow);
aCompleteNow = ETrue;
}
else if (iTransferInfo.iTransferType == ETransferTypeReadUntilShort)
{
err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred,
KReadUntilShort, aCompleteNow);
}
else
{
err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred,
KReadData, aCompleteNow);
}
if (aCompleteNow)
{
ResetTransferInfo();
SetClientReadPending(EFalse);
}
return err;
}
TInt TUsbcEndpoint::TryToStartRead(TBool aReEntrant)
{
__KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead 1 ep=%d", iEndpointNumber));
TInt r = KErrNone;
if (iEndpointInfo.iDir != KUsbEpDirOut &&
iEndpointInfo.iDir != KUsbEpDirBidirect)
{
// Verify ep direction
__KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead wrong direction ep=%d", iEndpointNumber));
return KErrUsbEpBadDirection;
}
if (iEndpointNumber == 0)
{
// Can't issue an Ep0 read if reader or writer is active
if (iDmaBuffers->TxIsActive())
{
__KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead ep0 Tx already active FATAL"));
return KErrUsbEpNotReady;
}
if (iDmaBuffers->RxIsActive())
{
__KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead ep0 Rx already active non-FATAL"));
}
}
if (!(iDmaBuffers->RxIsActive()))
{
TUint8* bufferAddr;
TPhysAddr physAddr;
TUsbcPacketArray* indexArray;
TUsbcPacketArray* sizeArray;
TInt length;
r = iDmaBuffers->RxGetNextXfer(bufferAddr, indexArray, sizeArray, length, physAddr);
if (r == KErrNone)
{
iDmaBuffers->RxSetActive();
iRequestCallbackInfo->SetRxBufferInfo(bufferAddr, physAddr, indexArray, sizeArray, length);
__KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead 2 bufferAddr=0x%08x", bufferAddr));
r = iController->SetupReadBuffer(*iRequestCallbackInfo);
if (r != KErrNone)
{
iDmaBuffers->RxSetInActive();
__KTRACE_OPT(KPANIC, Kern::Printf(" Error: TryToStartRead controller rejects read"));
}
}
else
{
if (iClientReadPending)
{
// Deadlock, try to resolve it by draining buffer into descriptor
if (!aReEntrant)
{
RxComplete(ETrue);
}
else
{
// we are stuck, better complete userside otherwise the userside request will hang
RxCompleteNow();
}
}
}
}
return r;
}
TInt TUsbcEndpoint::TryToStartWrite(TEndpointTransferInfo* pTfr)
{
__KTRACE_OPT(KUSB, Kern::Printf("TryToStartWrite 1 ep=%d", iEndpointNumber));
if (iEndpointInfo.iDir != KUsbEpDirIn &&
iEndpointInfo.iDir != KUsbEpDirBidirect)
{
// Verify ep direction
return KErrUsbEpBadDirection;
}
if (iEndpointNumber == 0)
{
// Can't issue an Ep0 write if unread data is available or writer is active
if (iDmaBuffers->TxIsActive() || !iDmaBuffers->IsReaderEmpty())
{
return KErrUsbEpNotReady;
}
if (iDmaBuffers->RxIsActive())
{
// if a reader is active then cancel the read
iDmaBuffers->RxSetInActive();
iController->CancelReadBuffer(iLdd, iRealEpNumber);
}
}
SetTransferInfo(pTfr);
ContinueWrite();
return KErrNone;
}
TInt TUsbcEndpoint::ContinueWrite()
{
__KTRACE_OPT(KUSB, Kern::Printf("ContinueWrite 2"));
TUint8* bufferAddr;
TPhysAddr physAddr;
TInt bufferLength;
TInt r = iDmaBuffers->TxGetNextXfer(bufferAddr, bufferLength, physAddr);
if (r != KErrNone) // probably already active
return r;
__KTRACE_OPT(KUSB, Kern::Printf("ContinueWrite 3"));
iDmaBuffers->TxSetActive();
TBool zlpReqd = EFalse;
TUint32 transferSize = iTransferInfo.iTransferSize;
TInt length = Min(transferSize - iBytesTransferred, (TUint32) bufferLength);
if (iBytesTransferred+length>=transferSize)
{
// only send a zlp if this is the last buffer of the transfer
zlpReqd = iTransferInfo.iZlpReqd;
}
r = iDmaBuffers->TxStoreData(iLdd->Client(), iLdd->GetClientBuffer(iEndpointNumber), length, iBytesTransferred);
if (r != KErrNone)
return r;
iDmaBuffers->TxSetActive();
iRequestCallbackInfo->SetTxBufferInfo(bufferAddr, physAddr, length);
iRequestCallbackInfo->iZlpReqd = zlpReqd;
#if 0
for (TInt i = 0; i < iRequestCallbackInfo->iLength; i++)
{
__KTRACE_OPT(KUSB, Kern::Printf("Buffer[%d] = 0x%02x", i, iRequestCallbackInfo->iBufferStart[i]));
}
#endif
r = iController->SetupWriteBuffer(*iRequestCallbackInfo);
return r;
}
void TUsbcEndpoint::CancelTransfer(DThread* aThread, TClientBuffer *aTcb)
{
__KTRACE_OPT(KUSB, Kern::Printf("CancelTransfer"));
if (iDmaBuffers != NULL)
{
if (iClientWritePending)
{
__KTRACE_OPT(KUSB, Kern::Printf(" (iClientWritePending)"));
iClientWritePending = EFalse;
iController->CancelWriteBuffer(iLdd, iRealEpNumber);
iDmaBuffers->TxSetInActive();
}
if (iClientReadPending)
{
__KTRACE_OPT(KUSB, Kern::Printf(" (iClientReadPending)"));
iClientReadPending = EFalse;
CopyToClient(aThread,aTcb);
}
}
}
void TUsbcEndpoint::AbortTransfer()
{
__KTRACE_OPT(KUSB, Kern::Printf("Abort Transfer"));
if (iDmaBuffers != NULL)
{
if (iDmaBuffers->TxIsActive())
{
__KTRACE_OPT(KUSB, Kern::Printf(" (iClientWritePending)"));
iController->CancelWriteBuffer(iLdd, iRealEpNumber);
iDmaBuffers->TxSetInActive();
}
if (iDmaBuffers->RxIsActive())
{
__KTRACE_OPT(KUSB, Kern::Printf(" (iClientReadPending)"));
iController->CancelReadBuffer(iLdd, iRealEpNumber);
iDmaBuffers->RxSetInActive();
}
iRequestCallbackInfo->iDfc.Cancel();
}
}
TUsbcAlternateSettingList::TUsbcAlternateSettingList()
: iNext(NULL),
iNumberOfEndpoints(0),
iSetting(0)
{
for (TInt i = 0; i <= KMaxEndpointsPerClient; i++)
{
iEpNumDeOrderedByBufSize[i] = -1;
iEndpoint[i] = NULL;
}
}
TUsbcAlternateSettingList::~TUsbcAlternateSettingList()
{
__KTRACE_OPT(KUSB, Kern::Printf("TUsbcAlternateSettingList::~TUsbcAlternateSettingList()"));
for (TInt i = 0; i <= KMaxEndpointsPerClient; i++)
{
delete iEndpoint[i];
}
}
TUsbcDeviceStatusQueue::TUsbcDeviceStatusQueue()
{
FlushQueue();
}
void TUsbcDeviceStatusQueue::FlushQueue()
{
for (TInt i = 0; i < KUsbDeviceStatusQueueDepth; i++)
{
iDeviceStatusQueue[i] = KUsbDeviceStatusNull;
}
iStatusQueueHead = 0;
}
void TUsbcDeviceStatusQueue::AddStatusToQueue(TUint32 aDeviceStatus)
{
// Only add a new status if it is not a duplicate of the one at the head of the queue
if (!(iStatusQueueHead != 0 &&
iDeviceStatusQueue[iStatusQueueHead - 1] == aDeviceStatus))
{
if (iStatusQueueHead == KUsbDeviceStatusQueueDepth)
{
// Discard item at tail of queue
TUint32 status;
GetDeviceQueuedStatus(status);
}
iDeviceStatusQueue[iStatusQueueHead] = aDeviceStatus;
iStatusQueueHead++;
}
}
TInt TUsbcDeviceStatusQueue::GetDeviceQueuedStatus(TUint32& aDeviceStatus)
{
TInt r = KErrNone;
if (iStatusQueueHead <= 0)
{
r = KErrGeneral;
aDeviceStatus = KUsbDeviceStatusNull;
}
else
{
aDeviceStatus = iDeviceStatusQueue[0];
for(TInt i = 1; i < KUsbDeviceStatusQueueDepth; i++)
{
TUint32 s = iDeviceStatusQueue[i];
iDeviceStatusQueue[i - 1] = s;
}
iStatusQueueHead--;
iDeviceStatusQueue[KUsbDeviceStatusQueueDepth - 1] = KUsbDeviceStatusNull;
}
return r;
}
void TClientAsynchNotify::Reset()
{
iBufferRequest->Reset();
iClientBuffer=NULL;
}
//---