diff -r 000000000000 -r 96e5fb8b040d kernel/eka/drivers/usbc/d_usbc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbc/d_usbc.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,3058 @@ +// 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 + + +_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 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), + iBufferBaseEp0(NULL), + iBufferSizeEp0(0), + iNumberOfEndpoints(0), + iHwChunkIN(NULL), + iHwChunkOUT(NULL), + iHwChunkEp0(NULL), + 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(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(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(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(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; + TInt totalINBufferSize = 0; + TInt totalOUTBufferSize = 0; + + 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; + } + + // other endpoints + 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; + } + if (pEndpointData->iDir == KUsbEpDirIn) + { + totalINBufferSize += ep->BufferTotalSize(); + __KTRACE_OPT(KUSB, Kern::Printf("IN buffering now %d", totalINBufferSize)); + } + else if (pEndpointData->iDir == KUsbEpDirOut) + { + totalOUTBufferSize += ep->BufferTotalSize(); + __KTRACE_OPT(KUSB, Kern::Printf("OUT buffering now %d", totalOUTBufferSize)); + } + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d rec=0x%08x ep==0x%08x", + i, alternateSettingListRec, ep)); + } + + // 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]); + } + + if (totalOUTBufferSize != 0) + { + // maximally cached always + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface setting up OUT buffering size=%d", totalOUTBufferSize)); + iHwChunkOUT = SetupInterfaceMemory(totalOUTBufferSize, iHwChunkOUT, KUsbEpDirOut, cacheAttribs); + if (iHwChunkOUT == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf("SetInterface can't get chunk for OUT buffering size=%d reason=%d", + totalOUTBufferSize, r)); + r = KErrNoMemory; + goto KillAll; + } + } + if (totalINBufferSize != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface setting up IN buffering size=%d", totalINBufferSize)); + iHwChunkIN = SetupInterfaceMemory(totalINBufferSize, iHwChunkIN, KUsbEpDirIn, cacheAttribs); + if (iHwChunkIN == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf("SetInterface can't get chunk for IN buffering size=%d reason=%d", + totalOUTBufferSize, r)); + r = KErrNoMemory; + goto KillAll; + } + } + __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; + + KillAll: + __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; + } + + +DPlatChunkHw* DLddUsbcChannel::SetupInterfaceMemory(TInt aBufferSize, DPlatChunkHw* aHwChunk, + TUint aDirection, TUint32 aCacheAttribs) + { + TUint8* oldBase = NULL; + if (aHwChunk != NULL) + oldBase = reinterpret_cast(aHwChunk->LinearAddress()); + + DPlatChunkHw* chunk = ReAllocate(aBufferSize, aHwChunk, aCacheAttribs); + if (chunk == NULL) + { + // lost all interfaces: + // Tell Controller to release Interface and h/w resources associated with this + iController->DeRegisterClient(this); + } + else + { + // Parcel out the memory between endpoints + TUint8* newBase = reinterpret_cast(chunk->LinearAddress()); + TBool needsRebase = (newBase != oldBase); + TUint8* pBuf = newBase; + TUint8* pBufIf = pBuf; // this is where an interface's ep buffering starts + TUsbcAlternateSettingList* asRec = iAlternateSettingList; + // the current interface + __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory rebasing setting=%d", asRec->iSetting)); + RebaseInterfaceMemory(asRec, pBuf, aDirection); + // now the others if a rebase has occured + if (needsRebase) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory rebasing ")); + 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 rebasing setting=%d", asRec->iSetting)); + pBuf = pBufIf; + RebaseInterfaceMemory(asRec, pBuf, aDirection); + asRec = asRec->iNext; + } + } + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface numberOfEndpoints")); + } + return chunk; + } + + +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 bufferSize = ep0->BufferTotalSize(); + TUint32 cacheAttribs = EMapAttrSupRw | EMapAttrCachedMax; + iHwChunkEp0 = Allocate(bufferSize, cacheAttribs); + if (iHwChunkEp0 == NULL) + { + return KErrNoMemory; + } + iBufferSizeEp0 = bufferSize; + iBufferBaseEp0 = (TUint8*) iHwChunkEp0->LinearAddress(); + ep0->SetBufferBase(iBufferBaseEp0); + ep0->SetRealEpNumber(0); + __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 60 buffersize=%d", iBufferSizeEp0)); + __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 exit bufferbase=0x%08x", iBufferBaseEp0)); + return KErrNone; + } + + +void DLddUsbcChannel::RebaseInterfaceMemory(TUsbcAlternateSettingList* aAlternateSettingListRec, + TUint8* aBase, TUint aDirection) + { + TUint8* pBuf = aBase; + __KTRACE_OPT(KUSB, Kern::Printf("RebaseInterfaceMemory buffer base rec= 0x%08x", aAlternateSettingListRec)); + for (TInt i = 1; i <= aAlternateSettingListRec->iNumberOfEndpoints; i++) + { + TUsbcEndpoint* ep = aAlternateSettingListRec->iEndpoint[i]; + if (ep != NULL && (ep->EndpointInfo()->iDir == aDirection)) + { + __KTRACE_OPT(KUSB, Kern::Printf("RebaseInterfaceMemory buffer base for ep%d 0x%08x 0x%08x", + i, pBuf, ep)); + pBuf = ep->SetBufferBase(pBuf); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("RebaseInterfaceMemory ep%d wrong direction", i)); + } + } + } + + +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; + + ClosePhysicalChunk(iHwChunkIN); + ClosePhysicalChunk(iHwChunkOUT); + + 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 + ClosePhysicalChunk(iHwChunkIN); + ClosePhysicalChunk(iHwChunkOUT); + } + } + + +void DLddUsbcChannel::DestroyEp0() + { + delete iEndpoint[0]; + iEndpoint[0] = NULL; + ClosePhysicalChunk(iHwChunkEp0); + } + + +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])); + 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++) + { + 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; +} + +//---