--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usbdrv/peripheral/ldd/perilddsc/src/d_usbcsc.cpp Tue Aug 31 17:01:47 2010 +0300
@@ -0,0 +1,3663 @@
+// 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\usbcsc\d_usbcsc.cpp
+// LDD for USB Device driver stack, using shared chunks:
+// The channel object.
+//
+//
+
+/**
+ @file d_usbcsc.cpp
+ @internalTechnology
+*/
+
+// #include <drivers/usbcsc.h>
+#include <usb/usbcsc.h>
+#include "platform.h"
+
+/*****************************************************************************\
+* DUsbcScLogDevice *
+* *
+* Inherits from DLogicalDevice, the USB Shared Chunk LDD factory class *
+* *
+\*****************************************************************************/
+
+_LIT(KUsbScLddName, "Usbcsc");
+
+static const TInt KUsbRequestCallbackPriority = 2;
+
+/** Real entry point from the Kernel: return a new driver.
+ */
+DECLARE_STANDARD_LDD()
+ {
+ return new DUsbcScLogDevice;
+ }
+
+/** Create a channel on the device.
+
+ @internalComponent
+*/
+TInt DUsbcScLogDevice::Create(DLogicalChannelBase*& aChannel)
+ {
+ aChannel = new DLddUsbcScChannel;
+ return aChannel ? KErrNone : KErrNoMemory;
+ }
+
+
+DUsbcScLogDevice::DUsbcScLogDevice()
+ {
+ iParseMask = KDeviceAllowUnit;
+ iUnitsMask = 0xffffffff; // Leave units decision to the Controller
+ iVersion = TVersion(KUsbcScMajorVersion, KUsbcScMinorVersion, KUsbcScBuildVersion);
+ }
+
+
+TInt DUsbcScLogDevice::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(&KUsbScLddName);
+ }
+
+
+//
+// Return the USB controller capabilities.
+//
+void DUsbcScLogDevice::GetCaps(TDes8& aDes) const
+ {
+ TPckgBuf<TCapsDevUsbc> b;
+ b().version = iVersion;
+ Kern::InfoCopy(aDes, b);
+ }
+
+// End DUsbcScLogDevice
+
+/*****************************************************************************\
+* TUsbcScChunkInfo *
+* *
+* Where Chunk information is stored for the channel, and preseved for the *
+* life of the chunk. *
+* *
+\*****************************************************************************/
+
+void DfcChunkCleanup(TAny*);
+
+TUsbcScChunkInfo::TUsbcScChunkInfo(DLogicalDevice* aLdd)
+ : iChunk(NULL),
+ iCleanup((TDfcFn)&DfcChunkCleanup,this,Kern::SvMsgQue(),0),
+ iChunkMem(NULL),
+ iLdd(aLdd)
+ {
+ iPageNtz = (TInt8)__e32_find_ls1_32(Kern::RoundToPageSize(1));
+ }
+
+TInt TUsbcScChunkInfo::CreateChunk(TInt aTotalSize)
+ {
+ // First, reserve an TUint of memory for each of pages needed to hold aTotalSize of memory.
+ // This will form the chunk map, so that we can look up the memory geometry.
+ iAllocatedSize = (aTotalSize>>iPageNtz)*sizeof(TUint);
+ iPhysicalMap = (TUint*) Kern::AllocZ(iAllocatedSize);
+ TInt r;
+ if (iPhysicalMap==NULL)
+ r = KErrNoMemory;
+ else
+ {
+ TChunkCreateInfo chunkInfo;
+ chunkInfo.iType = TChunkCreateInfo::ESharedKernelMultiple;
+ chunkInfo.iMaxSize = aTotalSize;
+ chunkInfo.iMapAttr = EMapAttrCachedMax;
+ chunkInfo.iOwnsMemory = EFalse;
+ chunkInfo.iDestroyedDfc = &iCleanup;
+
+ TLinAddr chunkMem;
+ r = Kern::ChunkCreate(chunkInfo, iChunk, chunkMem, iChunkMapAttr);
+ iChunkMem = (TInt8*) chunkMem;
+ if (r==KErrNone)
+ iLdd->Open();
+ }
+
+ return r;
+}
+
+
+// This method requests closing the chunk.
+// Note that nothing may happen immediately, as something else may have the chunk open.
+void TUsbcScChunkInfo::Close()
+{
+ Kern::ChunkClose(iChunk);
+}
+
+
+TInt TUsbcScChunkInfo::ChunkAlloc(TInt aOffset, TInt aSize)
+ {
+ TUint pageMask = (~0)<<iPageNtz;
+ TUint rleMask = ~pageMask;
+ TUint pageSize = rleMask+1;
+ TInt r;
+ TLinAddr physAddr;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("::chunkalloc AllocPhysicalRam aSize %d", aSize));
+
+ r = Epoc::AllocPhysicalRam(aSize, physAddr);
+ __KTRACE_OPT(KUSB, if (r!=KErrNone) Kern::Printf("::chunkalloc AllocPhysicalRam r=%d (Error!)", r));
+ if (r==KErrNone)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("::chunkalloc ChunkCommitPhysical iChunk 0x%x size(%d), aOffset 0x%x, aSize 0x%x phsAddr 0x%x",
+ iChunk, sizeof(DChunk), aOffset, aSize,physAddr ));
+
+ r = Kern::ChunkCommitPhysical(iChunk, aOffset, aSize, physAddr);
+ __KTRACE_OPT(KUSB, if (r!=KErrNone) Kern::Printf("::chunkalloc ChunkCommitPhysical r=%d (Error!)", r));
+
+ if (r!=KErrNone)
+ Epoc::FreePhysicalRam(physAddr, aSize);
+ else
+ { // record physical address and length in physical map
+ TInt rle;
+ TInt i=0;
+ for (rle=(aSize>>iPageNtz); rle>0; rle--, i++,physAddr+=pageSize)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("::phys offset 0x%x = 0x%x",
+ (aOffset>>iPageNtz)+i, (physAddr & pageMask) | ((rle>(TInt)rleMask)?(TInt)rleMask:rle)));
+ iPhysicalMap[(aOffset>>iPageNtz)+i] = (physAddr & pageMask) | ((rle>(TInt)rleMask)?(TInt)rleMask:rle);
+ }
+ }
+ }
+ else if (r==KErrNoMemory)
+ r = -KErrNoMemory; // Semi-expected error.
+ return r;
+ }
+
+/**
+This method retrieves the physical address of a given offset into the Chunk, and returns
+the length of contiguous physical memory from this point.
+
+@param aOffset the offset from the start of the chunk, to be queried.
+@param aPhysical a pointer to a TPhysAddr, to be filled with the physical
+ address of the memory at the given offset.
+
+@returns the length of contiguous physical memory from the given offset.
+*/
+
+TInt TUsbcScChunkInfo::GetPhysical(TInt aOffset, TPhysAddr* aPhysical)
+ {
+ // Use masks, to retrieve the two components from the physical map, we created of the memory.
+ TUint pageMask = (~0)<<iPageNtz;
+ TUint val = iPhysicalMap[aOffset>>iPageNtz];
+ *aPhysical=(val & pageMask)+(aOffset & ~pageMask);
+ return ((val & ~pageMask)<<iPageNtz) - (aOffset & ~pageMask);
+ }
+
+
+// DFC calls this fuction, which invokes the cleanup method.
+
+void DfcChunkCleanup(TAny* aChunkInfo)
+ {
+ ((TUsbcScChunkInfo*) aChunkInfo)->ChunkCleanup();
+ }
+
+
+void TUsbcScChunkInfo::ChunkCleanup()
+{
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::ChunkCleanup()"));
+ TUint physAddr;
+ TInt length;
+ TInt offset = 0;
+
+ // The part of the field used for the physical page address.
+ TUint pageMask = (~0)<<iPageNtz;
+
+ // The part of the field used for the run length encoding, of the contiguous pages.
+ TUint rleMask = ~pageMask;
+ TInt records=(iAllocatedSize>>2);
+
+ while (offset < records)
+ {
+ physAddr = iPhysicalMap[offset] & pageMask;
+ length = iPhysicalMap[offset] & rleMask;
+
+ if (physAddr>0)
+ Epoc::FreePhysicalRam(physAddr, length);
+
+ offset += (length>0)?length:1;
+ }
+ Kern::Free(iPhysicalMap);
+
+ DLogicalDevice* ldd = iLdd;
+ delete this;
+ ldd->Close(NULL);
+}
+
+TInt TUsbcScChunkInfo::New(TUsbcScChunkInfo*& aChunk, TInt aSize, DLogicalDevice* aLdd)
+{
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::New totalSize %d", aSize));
+
+ aChunk = new TUsbcScChunkInfo(aLdd);
+ if (aChunk==NULL)
+ {
+ return KErrNoMemory;
+ }
+
+ TInt r = aChunk->CreateChunk(aSize);
+ if (r!=KErrNone)
+ {
+ delete aChunk;
+ aChunk=NULL;
+ return r;
+ }
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::New Created at 0x%x", aChunk->iChunkMem ));
+ return KErrNone;
+}
+
+// End TUsbcScChunkInfo
+
+/*****************************************************************************\
+* TUsbcScBuffer *
+* *
+* Represents a buffer, within a chunk. Each buffers can be used by *
+* differt endpoint on differnt alt settings *
+* *
+\*****************************************************************************/
+
+
+TInt TUsbcScBuffer::Construct(TInt aDirection, DLddUsbcScChannel* aLdd, TInt aBufferOffset, TInt aBufferEndOffset, TInt aMinReadSize, TInt aMaxPacketSize, TInt aMaxReadSize)
+ {
+ TInt r;
+#ifdef _DEBUG
+ iSequence = aBufferOffset; // Initialized at this, so that each buffer starts with a diffrent sequence number
+#endif
+ iMinReadSize = aMinReadSize;
+ TInt size = (aBufferEndOffset - aBufferOffset);
+ TInt pageSize = Kern::RoundToPageSize(1);
+ if (aMaxReadSize > 0)
+ iMaxReadSize = aMaxReadSize;
+ else
+ iMaxReadSize = pageSize + ((size/3) & ~(pageSize -1));
+ iLdd = aLdd;
+ iDirection = aDirection;
+ iMode=0;
+ iChunkInfo = aLdd->iChunkInfo;
+ iChunkAddr = (TLinAddr) (aLdd->iChunkInfo->iChunkMem); //aChunkAddr;
+
+ TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data.
+
+
+ TUint maxAlignment; // Note: This is a mask for max Alignment,
+
+ if (aMaxPacketSize)
+ { // EP0 packets are not DMAed, and so dont need ialignment.
+ iAlignMask = ~3;
+ maxAlignment = 3;
+ }
+ else
+ maxAlignment = 1023; // We don't know what the alignment requirement will be until enumeration, so assume worse case.
+
+ iFirstPacket = aBufferOffset + sizeof(SUsbcScBufferHeader) + headerSize;
+ iFirstPacket = (iFirstPacket + maxAlignment) & ~maxAlignment;
+
+ iBufferStart = (SUsbcScBufferHeader *) (iChunkAddr+aBufferOffset);
+ iBufferEnd = aBufferEndOffset;
+
+ if ((iDirection&1)==KUsbcScOut)
+ iHead = iFirstPacket-headerSize;//aBufferOffset + sizeof(SUsbcScBufferHeader);
+ else
+ iSent = 0;
+
+ iStalled=0;
+ iMaxPacketSize=0;
+
+ r = iStatusList.Construct((aDirection==KUsbcScIn)?KUsbcScInRequests:KUsbcScOutRequests, iLdd->iClient);
+ if (!r)
+ {
+ iMaxPacketSize = aMaxPacketSize; // Indicates configured if ep0, otherwise not.
+ }
+ return r;
+ }
+
+
+void TUsbcScBuffer::CreateChunkBufferHeader()
+{
+ if ((iDirection&1)==KUsbcScOut)
+ {
+ iBufferStart->iHead= iHead;
+ iBufferStart->iTail= iHead; // Initially no data!
+ iBufferStart->iBilTail=iHead;
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: iHead 0x%x bufferHeader 0x%x", iHead,iBufferStart ));
+
+ // Dont need to round here, as we will round it up on endpoint change. (configuration)
+ }
+}
+
+/*
+TUsbcScBuffer::StartEndpoint
+
+This method sets the nessesary paramenters to the buffer, for use for a particular endpoint.
+
+*/
+void TUsbcScBuffer::StartEndpoint(TUsbcRequestCallback* aRequestInfo, TUint aFlags)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartEndpoint (0x%x) : ep %d(%d)",this,aRequestInfo->iEndpointNum, aRequestInfo->iRealEpNum));
+
+ iCallback=aRequestInfo;
+ iMaxPacketSize = iLdd->iController->EndpointPacketSize(iLdd, aRequestInfo->iRealEpNum);
+ iAlignMask = ~(((iMaxPacketSize+1) & 0xFFFFFFF8)-1);
+ iMode = aFlags;
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartEndpoint : max Packets %d, mask 0x%x flags 0x%x", iMaxPacketSize, iAlignMask, iMode));
+ if ((iDirection&1)==KUsbcScOut)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UsbcScOut\n"));
+ // Add dummy packet (doesnt have to be aligned, which avoids what if it changes issue)
+ // And Start next read.
+ iNeedsPacket=KEpIsStarting;
+ }
+ }
+
+
+
+void TUsbcScBuffer::Destroy()
+{
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::Destroy()"));
+ Cancel(KErrCancel);
+ if (iLdd->iController && ((iDirection&1)==KUsbcScOut))
+ { // Me must cancel reads to LDD to, an there will be no list for the callbacks to look into.
+ iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum);
+ }
+ iStatusList.Destroy();
+}
+
+
+
+TInt TUsbcScBuffer::StartDataRead()
+{
+ if (!iMaxPacketSize)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Not Configured"));
+ return KErrNone;
+ }
+ if (iStatusList.iState!=ENotRunning)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Already Stated! (%d)",iStatusList.iState));
+ return KErrNone;
+ }
+
+ TInt maxLength;
+ TInt freeSpace;
+ TPhysAddr physAddr;
+
+ // get next request
+ TUsbcScStatusElement* nextJob = iStatusList.Next();
+ if (nextJob == NULL)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("No more jobs"));
+ if (iMode && KUsbScCoupledRead)
+ return KErrEof;
+ iStatusList.iState=EReadingAhead;
+ }
+ else
+ iStatusList.iState=EInProgress;
+
+ TInt tail = iBufferStart->iTail;
+ TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data.
+ maxLength = iChunkInfo->GetPhysical(iHead + headerSize, &physAddr); //returns all the bytes available after iHead + headerSize)
+
+ __ASSERT_DEBUG(maxLength>0,Kern::Fault("TUsbcScBuffer::StartDataRead(", __LINE__));
+
+
+ if (tail>iHead) // # # # H _ _ _ T # # # #
+ {
+ __KTRACE_OPT(KUSB,Kern::Printf("TUsbcScBuffer::StartDataRead() - tail 0x%x>head 0x%x, maxlength 0x%x", tail, iHead, maxLength));
+
+ freeSpace = (tail & iAlignMask) - (iHead +headerSize + (~iAlignMask+1) ); // Cant read right up to last buffer, or head/tail will cross.
+
+ if (freeSpace<iMinReadSize)
+ {
+ iStatusList.iState=ENotRunning;
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Stall!!"));
+ return KErrOverflow; // Read STALL !! !! !!
+ }
+
+ if (freeSpace<maxLength)
+ maxLength = freeSpace;
+ }
+ if (maxLength> iMaxReadSize)
+ maxLength = iMaxReadSize;
+ // else tail<iHead (or empty) _ _ _ T # # # H _ _ _ _
+ // We would not have set iHead here if too small. So must be ok.
+
+ __ASSERT_DEBUG(maxLength>=iMinReadSize,Kern::Fault("TUsbcScBuffer::StartDataRead(", __LINE__));
+
+ TUint8* data = ((TUsbcScTransferHeader *) (iHead + iChunkAddr))->iData.b;
+ // set up callback stucture
+
+ iCallback->SetRxBufferInfo(data, physAddr, iIndexArray, iSizeArray,maxLength);
+ TInt r;
+ // Go!!
+ r = iLdd->iController->SetupReadBuffer(*iCallback);
+ if (r!=KErrNone)
+ {
+ __KTRACE_OPT(KUSB,Kern::Printf("SetupReadBuffer Error: %d, RT %d",r, iStatusList.iState));
+ iStatusList.Complete(r);
+ }
+ // After this, TUsbcScEndpoint::RequestCallback is called in a DFC.
+ // This in turn calls either TUsbcScBuffer::CompleteRead.
+ return KErrNone;
+}
+
+
+void TUsbcScBuffer::CompleteRead(TBool aStartNextRead)
+{
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::CompleteRead buff=%x",this));
+
+ // The first packet always contains the total #of bytes
+ const TInt byteCount = iCallback->iPacketSize[0];
+ const TInt packetCount = iCallback->iRxPackets;
+ iCallback->iRxPackets=0;
+ TUint flags = 0;
+
+ if (iCallback->iPacketSize[packetCount - 1] < (TUint) iMaxPacketSize)
+ flags = KUsbcScShortPacket;
+
+ UpdateBufferList(byteCount, flags, aStartNextRead);
+}
+
+
+// This method "submits" the current transfer, and starts off the next read.
+
+void TUsbcScBuffer::UpdateBufferList(TInt aByteCount,TUint aFlags, TBool aStartNextRead)
+ {
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst aByteCount %d, flags 0x%x iHead 0x%x", aByteCount, aFlags, iHead));
+
+ TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data.
+ TLinAddr dummy;
+ __KTRACE_OPT(KUSB, Kern::Printf("iHead 0x%x headerSize 0x%x",iHead, headerSize));
+
+ // Find iNext
+
+ TInt next = iHead + headerSize + aByteCount; // next unused byte in buffer.
+ TInt maxLength;
+
+ // This may take a few loops before we settle on a value.
+ do
+ {
+ // round up.
+ next = (next + headerSize + ~iAlignMask) & iAlignMask;
+ maxLength = iChunkInfo->GetPhysical(next, &dummy);
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst next %x buffer end %x min-read: %x maxRun %x", next, iBufferEnd, iMinReadSize, maxLength));
+ // At the end of the buffer - wrap it if needbe.
+ if ((TUint)(next + iMinReadSize) > iBufferEnd)
+ {
+ next = iFirstPacket;
+ continue;
+ }
+ // Not enough space, move onto next block.
+ if (maxLength<iMinReadSize)
+ {
+ next+=maxLength;
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst Skip exhausted block. next %x max %d", next, maxLength));
+ continue;
+ }
+ }
+ while (EFalse);
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst next (pre deduct): %x, Fill in header at head: 0x%x, BuffStart: 0x%x.", next, iHead, iBufferStart));
+
+ next -= headerSize; // Move next back from the data start position, to the header start.
+
+ TUsbcScTransferHeader* header = (TUsbcScTransferHeader*) (iHead + iChunkAddr);
+
+// Create Header
+#ifdef _DEBUG
+ header->iHashId=59*(iLdd->iAlternateSetting+1)+iCallback->iRealEpNum; // Alt setting realated....
+ header->iSequence=iSequence;
+ iSequence++;
+#endif
+ header->iBytes=aByteCount;
+ header->iNext=next;
+ header->iAltSettingSeq=iLdd->iAsSeq;
+ header->iAltSetting=iLdd->iAlternateSetting;
+ header->iFlags=aFlags;
+ __KTRACE_OPT(KUSB, Kern::Printf("We set next to 0x%x", next));
+
+ iStatusList.iState=ENotRunning;
+ if (next==iBufferStart->iTail) //or (othwise is as good as full)
+ {
+ iStalled=next;
+ }
+ else
+ {
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst StartRead?? "));
+ TInt oldHead=iHead;
+ iHead = next;
+
+ if ((aStartNextRead) && (StartDataRead() == KErrOverflow))
+ { // Oh crumbs, set state as slalled.
+ if (oldHead != iBufferStart->iBilTail)
+ // If user has not read everything in the buffer
+ // then set up a stall, so that ldd get to be woken early
+ {
+ iStalled=next;
+ iHead=oldHead;
+ }
+ else // otherwise if everything is read
+ // no choice but to return what we have
+ {
+ iBufferStart->iHead = iHead;
+ }
+ }
+ else
+ {
+ iBufferStart->iHead = next;
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst Compleating\n"));
+ }
+ // Complete userside
+ iStatusList.Complete();
+ }
+ }
+
+void TUsbcScBuffer::PopStall()
+ {
+ if (iStalled==iBufferStart->iTail)
+ return; // Still stalled.
+
+ if (iStalled!=-1) // If not Alt packet only stall
+ {
+ // pop off packet
+ iHead = iStalled;
+ }
+ iStalled=0;
+ // If Alt setting of the popped packet is different to now
+ // Add alt setting change packet.
+
+
+ if (StartDataRead() == KErrOverflow)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::PopStall Warning: Transfer was freed, but still no space!\n"));
+ }
+
+ iBufferStart->iHead = iHead;
+ }
+
+
+
+void TUsbcScBuffer::StartDataWrite()
+ {
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite()"));
+ TUsbcScStatusElement* nextJob = iStatusList.Next();
+ TBool zlpReqd;
+ TInt length;
+ TUint start;
+ TUint8* startAddr;
+ TInt maxLength;
+ TPhysAddr physAddr;
+ TInt r;
+ if (!iMaxPacketSize)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() - Not Configured"));
+ return;
+ }
+
+ if (nextJob == NULL)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() - No more jobs d=%d", iDirection));
+ if (iDirection==KUsbcScBiIn) // assume this is EP0, if this is true.
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() Queue Read on EP0."));
+ // Start other read again.
+ iLdd->iBuffers[iLdd->iEP0OutBuff].StartDataRead();
+ }
+ }
+ else
+ {
+ if (iStatusList.iState==ENotRunning)
+ iSent=0;
+ iStatusList.iState=EInProgress;
+
+ start = nextJob->iStart;
+ startAddr = (TUint8*) (start + ((TUint) (iChunkInfo->iChunkMem)));
+
+ length = nextJob->iLength;
+ zlpReqd = (nextJob->iFlags & KUsbcScWriteFlagsZlp) !=0;
+ // get max read length
+ maxLength = iChunkInfo->GetPhysical( start, &physAddr);
+
+ if (maxLength < length)
+ {
+ // modify request.
+ nextJob->iStart += maxLength;
+ nextJob->iLength -= maxLength;
+ // start this request.
+ iStatusList.iState=EFramgementInProgress;
+ zlpReqd=EFalse;
+ length = maxLength;
+ }
+
+ if (iDirection==KUsbcScBiIn) // this is for EP0
+ {
+ iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum);
+ iLdd->iBuffers[iLdd->iEP0OutBuff].iStatusList.iState=ENotRunning;
+ }
+
+ iCallback->SetTxBufferInfo(startAddr, physAddr, length);
+ iCallback->iZlpReqd = zlpReqd;
+ r = iLdd->iController->SetupWriteBuffer(*iCallback);
+ if (r!=KErrNone)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("SetupWriteBUffer Error: %d",r));
+ iStatusList.Complete(r);
+ }
+ }
+
+ }
+
+void TUsbcScBuffer::CompleteWrite()
+ {
+ TInt error = iCallback->iError;
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::CompleteWrite buff=%x, err=%d",this, error));
+ iSent+= iCallback->iTxBytes;
+
+ // More to send?
+ if (error || iStatusList.iState!=EFramgementInProgress)
+ {
+ // complete request with error (if one).
+ // Some data could have been transmitted, even with an error.
+ iStatusList.Complete(error);
+ }
+
+ // Start next request, or next part of this one.
+ StartDataWrite();
+
+ }
+
+// Cancels the current request's callback.
+// This is not to say it will cancel the actual operation,
+// However it will cancel any further sections of the user perceived operation
+// that are not yet started.
+void TUsbcScBuffer::Cancel(TInt aErrorCode)
+ {
+ iStatusList.CancelQueued();
+ if (iLdd->iController && ((iDirection&1)==KUsbcScIn))
+ {
+ iLdd->iController->CancelWriteBuffer(iLdd, iCallback->iRealEpNum);
+ }
+
+ iStatusList.Complete(aErrorCode);
+ }
+
+void TUsbcScBuffer::Ep0CancelLddRead()
+ {
+ // Stopping a read isn't as easy as one might think.
+ // We cancel the callback, but then check if any data was received (but not returned to us).
+ // If so, we must de-queue the request, and call the completion code.
+
+ iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum);
+ if (iCallback->iRxPackets) // received data?
+ {
+ // remove DFC (if infact sent)
+ iCallback->iDfc.Cancel();
+
+ // process the callback now, but dont start another
+ CompleteRead(EFalse);
+ }
+ }
+
+void TUsbcScBuffer::SendEp0StatusPacket(TInt aState)
+{
+ __KTRACE_OPT(KUSB, Kern::Printf(" TUsbcScBuffer::SendEp0StatusPacket(%d)", aState));
+
+ // We need to add a packet to the buffer, so we must stop the pending read, and start
+ // another after we have added out packet.
+ Ep0CancelLddRead();
+
+ TUint* state = ((TUsbcScTransferHeader *) (iHead + iChunkAddr))->iData.i;
+ *state = aState;
+ UpdateBufferList(4,KUsbcScStateChange);
+}
+
+// End TUsbcScBuffer
+
+/*****************************************************************************\
+* TUsbcScStatusList *
+* *
+* This is a list of read or write requests, containing user status *
+* requests, that should later be completed. *
+* *
+\*****************************************************************************/
+
+/**
+Constructor for TUsbcScStatusList.
+
+@param aSize is the number of requests to allow at any one time. This value
+ must be a power of two, for correct operation.
+
+@returns KErrNoMemory if memory allocation failure, otherwise KErrNone.
+*/
+
+TInt TUsbcScStatusList::Construct(TInt aSize, DThread* aClient)
+ {
+ iSize=aSize;
+ iHead = 0;
+ iLength = 0;
+ iClient = aClient;
+ iElements=(TUsbcScStatusElement *) Kern::AllocZ(sizeof(TUsbcScStatusElement)*aSize);
+ return (iElements==NULL)?KErrNoMemory:KErrNone;
+ };
+
+
+// StatusList must be inactive before destroying.
+void TUsbcScStatusList::Destroy()
+ {
+ if (iState!=ENotRunning)
+ Kern::Fault("TUsbcScStatusList::Destroy", __LINE__);
+ if (iElements)
+ {
+ Kern::Free(iElements);
+ iElements=NULL;
+ }
+ iClient=NULL;
+}
+
+void TUsbcScStatusList::Pop()
+ {
+ if (iLength>0)
+ {
+ iLength--;
+ iHead = ((iHead+1) & (iSize-1));
+ }
+ }
+
+TUsbcScStatusElement* TUsbcScStatusList::Next()
+ {
+ return (iLength==0)?NULL:&(iElements[iHead]);
+ }
+
+TInt TUsbcScStatusList ::Add(TRequestStatus* aStatus, TInt aLength, TUint aStart, TUint aFlags)
+ {
+ __KTRACE_OPT(KUSB,Kern::Printf("Adding request. iLength %d iSize %d", iLength, iSize));
+ if (iLength<iSize)
+ {
+ TUsbcScStatusElement& e = iElements[((iHead+iLength) & (iSize-1))];
+ e.iStatus = aStatus;
+ e.iLength = aLength;
+ e.iStart = aStart;
+ e.iFlags = aFlags;
+ iLength++;
+ __KTRACE_OPT(KUSB,Kern::Printf("Adding request. new iLength %d", iLength));
+
+ return KErrNone;
+ }
+ else
+ return KErrInUse;
+ }
+
+
+
+// This method cancels any requests that have yet to be started.
+
+void TUsbcScStatusList::CancelQueued(TInt aError)
+{
+ if ((iLength==0) || ((iState!=ENotRunning) && (iLength==1))) // Nothing to do.
+ return;
+ TInt elements2Complete = iLength - (iState?1:0);
+ TInt head = iHead;
+ iLength = 0;
+ if (iState) // If (iState != ENotRunning), complete all elements excepting the one at head
+ {
+ head = ((head+1) & (iSize-1)); // To iterate through the queue
+ iLength = 1;
+ }
+ // complete them all.
+ for (; elements2Complete>0; elements2Complete--)
+ {
+ Kern::RequestComplete(iClient, iElements[head].iStatus, aError);
+ head = ((head+1) & (iSize-1));
+ }
+
+}
+
+
+/* This method Completes the head status request, and pops it from its list.
+This version of Complete is to be used in cases where the next request is not
+chained - usually because of an error.
+
+@Param aError - the code to complete with.
+
+returns KErrNotFound if there was no request to complete
+*/
+
+
+TInt TUsbcScStatusList::Complete(TInt aError)
+ {
+ if (iState==ENotRunning)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScStatusList::Complete() - iState == ENotRunning!"));
+ }
+ else
+ {
+ iState=ENotRunning;
+ if (iLength==0)
+ return KErrNotFound;
+
+ Kern::RequestComplete(iClient, iElements[iHead].iStatus, aError);
+
+ iLength--;
+ iHead = ((iHead+1) & (iSize-1));
+ }
+ return KErrNone;
+ }
+
+
+/* This method Completes the head status request, and pops it from its list. (If found.)
+This version of Complete is to be used in cases where the request is successful, and
+ next request after this has (if present) been chained.
+*/
+
+void TUsbcScStatusList::Complete()
+ {
+ if (iLength==0)
+ return;
+ __KTRACE_OPT(KUSB, Kern::Printf("Completing request. iLength %d", iLength));
+
+ Kern::RequestComplete(iClient, iElements[iHead].iStatus, KErrNone);
+
+ iLength--;
+ iHead = ((iHead+1) & (iSize-1));
+ }
+
+// End TUsbcScStatusList
+
+/*****************************************************************************\
+* TRealizeInfo *
+* *
+* Used by DLddUsbcScChannel::RealizeInterface to set up the chunk *
+* *
+\*****************************************************************************/
+
+// Init
+//
+// This method works out the number potential maximum number of endpoints
+// and the number of alt settings. With this information it allocs
+// the necessary space for the given stucture to store information about
+// the endpoints.
+// This is intended to be called by RealizeInterface. This stucture is
+// intended to be only temporary, and the space will be freed with Free()
+// before RealizeInteface has finished.
+
+void TRealizeInfo::Init(TUsbcScAlternateSettingList* aAlternateSettingList)
+{
+ iAlternateSettingList = aAlternateSettingList;
+ iMaxEndpoints=0;
+ iTotalSize =0;
+ iTotalBuffers=0;
+ iAltSettings =0;
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: work out max endpoint"));
+ // Work out max endpoints and number of alternate settings.
+
+ if (iAlternateSettingList)
+ {
+ TUsbcScAlternateSetting* alt = iAlternateSettingList->iHead;
+ while (alt != NULL)
+ {
+ iAltSettings++;
+ if (alt->iNumberOfEndpoints>iMaxEndpoints)
+ iMaxEndpoints = alt->iNumberOfEndpoints;
+ // could work out in/out specifics, but unnecessary.
+ alt = alt->iNext;
+ };
+ }
+
+ // Alloc some temporary working space for temp endpoint metadata
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Alloc temp. Maxendpoints %d", iMaxEndpoints));
+ TInt inout;
+ for (inout=KUsbcScIn; inout<KUsbcScDirections; inout++)
+ {
+ iBufs[inout].iEp = (TUsbcScEndpoint **) Kern::AllocZ(iAltSettings*iMaxEndpoints*sizeof(TUsbcScEndpoint *));
+ iBufs[inout].iSizes = (TInt *) Kern::AllocZ(iMaxEndpoints*sizeof(TInt));
+ }
+}
+
+// CopyAndSortEndpoints
+//
+// This method copies pointers to the endpoint records into TRealizeInfo
+// such that they are sorted in order of size per alt setting.
+// In and Out endpoints are separated, and kept separate.
+// The provided data structure is assumed to have been initialised with
+// Realize_InitRealizeInfo.
+//
+// Return KErrArgument if the direction field is neither In or Out.
+//
+
+TInt TRealizeInfo::CopyAndSortEndpoints()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: copy And sort"));
+
+ TInt altSetting = 0;
+ TInt endpointOffs;
+ TInt endpoint;
+ TInt altEp;
+ TInt inout;
+ TBool placed;
+ TUsbcScAlternateSetting* alt;
+ TEndpointSortBufs* bufsd;
+
+ if (iAlternateSettingList)
+ {
+ for (alt = iAlternateSettingList->iHead;alt!=NULL;alt = alt->iNext )
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: AlternateSetting %x", alt));
+
+ iBufs[KUsbcScIn].iEps =0;
+ iBufs[KUsbcScOut].iEps =0;
+
+ // For alt setting, iterate eps
+ for (altEp=1; altEp <= alt->iNumberOfEndpoints; altEp++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Endpoint to add: %d",altEp));
+
+ TUsbcScEndpoint* nextEp = alt->iEndpoint[altEp];
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: ep Buffer Size: %d",nextEp->EndpointInfo()->iBufferSize));
+
+ inout = (nextEp->EndpointInfo()->iDir==UsbShai::KUsbEpDirIn)?KUsbcScIn:
+ (nextEp->EndpointInfo()->iDir==UsbShai::KUsbEpDirOut)?KUsbcScOut:KUsbcScUnknown;
+ if (inout==KUsbcScUnknown)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: KUsbcScUnknown %x",nextEp->EndpointInfo()->iDir));
+ return KErrArgument;
+ }
+
+ bufsd = &(iBufs[inout]);
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: ep direction: %x # endpoints %d", inout, bufsd->iEps));
+
+
+ // find and position ep, and insert.
+
+ if (bufsd->iEps==0) // First entry.
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Add first endpoint"));
+ endpointOffs = altSetting*iMaxEndpoints;
+ bufsd->iEp[endpointOffs] = nextEp;
+ }
+ else
+ {
+ placed = EFalse;
+ // Move down the list, until we find the right place.
+ for (endpoint=bufsd->iEps-1; endpoint>-1; endpoint--)
+ {
+ endpointOffs = altSetting*iMaxEndpoints + endpoint;
+ if (bufsd->iEp[endpointOffs]->EndpointInfo()->iBufferSize < nextEp->EndpointInfo()->iBufferSize)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Shift Endpoint %d", endpoint));
+
+ bufsd->iEp[endpointOffs+1] = bufsd->iEp[endpointOffs];
+ }
+ else
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Insert After Endpoint %d", endpoint));
+
+ bufsd->iEp[endpointOffs+1] = nextEp;
+ placed = ETrue;
+ break;
+ }
+ } // end for endpoint
+ if (!placed) // if we didn't place it, it must be the biggest so far, so goes at the top.
+ bufsd->iEp[0] = nextEp;
+ } // endif
+ bufsd->iEps++;
+ } // for altEp
+ altSetting++;
+ } // for alt
+ }// if iAltsettingList
+ return KErrNone;
+ }
+
+// CalcBuffSizes
+//
+// This works out the sizes of all the buffers, and stores the result in aBufInfo
+// based on the buffer information provided in the same structure.
+// Realize_CopyAndSortEndpoints is used to fill the structure with the informaition
+// required.
+
+void TRealizeInfo::CalcBuffSizes()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Calculate Buffers"));
+
+ TInt endpoint;
+ TInt inout;
+ TInt altSetting;
+ TUsbcScEndpoint* nextEp;
+ TInt bufferSize;
+ TEndpointSortBufs* bufsd;
+
+ for (inout=KUsbcScIn; inout<KUsbcScDirections; inout++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Direction: %d", inout));
+
+
+ bufsd = &(iBufs[inout]);
+ // for each row, ie, buffer, find largest buffer need.
+ for (endpoint=0; endpoint<iMaxEndpoints; endpoint++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpoint %d", endpoint));
+ TInt bufMaxSize=0;
+ for (altSetting=0; altSetting< iAltSettings; altSetting++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: altSetting %d", altSetting));
+ nextEp= bufsd->iEp[altSetting* iMaxEndpoints + endpoint];
+ if (nextEp!=NULL)
+ {
+ bufferSize = nextEp->EndpointInfo()->iBufferSize;
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: comparing size %d", bufferSize));
+ if (bufferSize> bufMaxSize)
+ bufMaxSize = bufferSize;
+ }
+ } // for altsetting
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: bufMaxSize %d", bufMaxSize));
+ bufsd->iSizes[endpoint] = bufMaxSize;
+ if (bufMaxSize>0)
+ {
+ iTotalSize += bufsd->iSizes[endpoint];
+ iTotalBuffers++;
+ }
+ } // for endpoint
+ } // for in/out
+}
+
+// Free
+//
+// Cleans up after Init()
+
+void TRealizeInfo::Free()
+ {
+ TInt inout;
+ for (inout=KUsbcScIn; inout<KUsbcScDirections; inout++)
+ {
+ Kern::Free(iBufs[inout].iEp);
+ Kern::Free(iBufs[inout].iSizes);
+ }
+ }
+
+// End TRealizeInfo
+
+
+// LayoutChunkHeader
+//
+// Sets up some geometry for the chunk;
+
+void TRealizeInfo::LayoutChunkHeader(TUsbcScChunkInfo* aChunkInfo)
+{
+ // First set up the indexes to the header structures.
+ TUsbcScChunkHdrOffs* chkHdr = (TUsbcScChunkHdrOffs*) aChunkInfo->iChunkMem;
+
+ chkHdr->iBuffers = sizeof(TUsbcScChunkHdrOffs); // First struct just after this one.
+ iChunkStuct = (TUsbcScChunkBuffersHeader*) ( (TInt) aChunkInfo->iChunkMem + chkHdr->iBuffers);
+
+ // Store number of buffers in chunk
+ iChunkStuct->iRecordSize = sizeof(TUsbcScBufferRecord);
+ iChunkStuct->iNumOfBufs=iTotalBuffers;
+
+ iAltSettingsTbl = (TUsbcScChunkAltSettingHeader*) &(iChunkStuct->iBufferOffset[(iTotalBuffers+2)*sizeof(TUsbcScBufferRecord)]); // 2 extra for EP0 in and out.
+
+ chkHdr->iAltSettings = (TUint) iAltSettingsTbl - (TUint) aChunkInfo->iChunkMem;
+
+ iAltSettingsTbl->iEpRecordSize = sizeof(TUint);
+ iAltSettingsTbl->iNumOfAltSettings = iAltSettings;
+
+
+ TInt tableOffset = (TUint) iAltSettingsTbl->iAltTableOffset - (TUint) aChunkInfo->iChunkMem + iAltSettings*sizeof(TInt);
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: table offset: 0x%x, altTble %x iChnkMem %x altSettings %x",tableOffset, iAltSettingsTbl, aChunkInfo->iChunkMem, iAltSettings ));
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: populate chunk - create alt settings table"));
+
+ // Create alt settings table. Set each element of altsettings table, to each induivatual alt setting table.
+ // then fill in the number of endpoints for that alt setting, in the table.
+
+ TInt* noEpForAlt;
+ TInt altSetting;
+ TUsbcScAlternateSetting* alt;
+ if (iAlternateSettingList)
+ {
+ alt = iAlternateSettingList->iHead;
+ for (altSetting=0; altSetting<iAltSettings; altSetting++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: altSetting %d, tableOffset %d", altSetting, tableOffset));
+
+ iAltSettingsTbl->iAltTableOffset[altSetting] = tableOffset;
+ noEpForAlt = (TInt*) &aChunkInfo->iChunkMem[tableOffset];
+
+ *noEpForAlt = alt->iNumberOfEndpoints; // Set NumberofEndpoints field in Altsetting table
+ tableOffset+= sizeof(TInt)+ alt->iNumberOfEndpoints*sizeof(TUsbcScHdrEndpointRecord);
+ alt = alt->iNext;
+ }
+ }
+
+} // end LayoutChunkHeader
+
+
+
+/*****************************************************************************\
+* DLddUsbcScChannel *
+* *
+* Inherits from DLogicalDevice, the USB Shared Chunk LDD factory class *
+* *
+\*****************************************************************************/
+
+//
+// Constructor
+//
+DLddUsbcScChannel::DLddUsbcScChannel()
+ : iValidInterface(EFalse),
+ iAlternateSettingList(NULL),
+ iEndpoint(NULL),
+ iCompleteAllCallbackInfo(this, DLddUsbcScChannel::EmergencyCompleteDfc, KUsbRequestCallbackPriority),
+ iStatusChangePtr(NULL),
+ iStatusCallbackInfo(this, DLddUsbcScChannel::StatusChangeCallback, KUsbRequestCallbackPriority),
+ iEndpointStatusChangePtr(NULL),
+ iEndpointStatusCallbackInfo(this, DLddUsbcScChannel::EndpointStatusChangeCallback,
+ KUsbRequestCallbackPriority),
+ iOtgFeatureChangePtr(NULL),
+ iOtgFeatureCallbackInfo(this, DLddUsbcScChannel::OtgFeatureChangeCallback, KUsbRequestCallbackPriority),
+ iNumberOfEndpoints(0),
+ iDeviceState(UsbShai::EUsbPeripheralStateUndefined),
+ iOwnsDeviceControl(EFalse),
+ iAlternateSetting(0),
+ iAsSeq(0),
+ iStatusFifo(NULL),
+ iUserKnowsAltSetting(ETrue),
+ iDeviceStatusNeeded(EFalse),
+ iChannelClosing(EFalse),
+ iRealizeCalled(EFalse),
+ iChunkInfo(NULL),
+ iNumBuffers(-1),
+ iBuffers(NULL),
+ iEp0Endpoint(NULL)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DLddUsbcScChannel()"));
+ iClient = &Kern::CurrentThread();
+ iClient->Open();
+ for (TInt i = 1; i < KUsbcMaxRequests; i++)
+ {
+ iRequestStatus[i] = NULL;
+ }
+ }
+
+
+//
+// Destructor
+//
+
+DLddUsbcScChannel::~DLddUsbcScChannel()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::~DLddUsbcScChannel()"));
+ if (iController)
+ {
+ iController->DeRegisterClient(this);
+ iStatusCallbackInfo.Cancel();
+ iEndpointStatusCallbackInfo.Cancel();
+ iOtgFeatureCallbackInfo.Cancel();
+ iCompleteAllCallbackInfo.Cancel();
+ DestroyAllInterfaces();
+ if (iOwnsDeviceControl)
+ {
+ iController->ReleaseDeviceControl(this);
+ iOwnsDeviceControl = EFalse;
+ }
+ iController=NULL;
+ DestroyEp0();
+ if (iStatusFifo!=NULL)
+ {
+ delete iStatusFifo;
+ }
+ }
+ __KTRACE_OPT(KUSB, Kern::Printf("Closing buffers"));
+ if (iBuffers)
+ {
+ TInt i;
+ for (i=0; i<(iNumBuffers+2); i++)
+ {
+ iBuffers[i].Destroy();
+ }
+ Kern::Free(iBuffers);
+ }
+
+ if (iRealizeCalled)
+ {
+ // Close Chunk
+ iChunkInfo->Close();
+ // ChunkInfo will delete itself with DFC, but the pointer here is no longer needed.
+ iChunkInfo=NULL;
+ }
+ __KTRACE_OPT(KUSB, Kern::Printf("about to SafeClose"));
+ Kern::SafeClose((DObject*&)iClient, NULL);
+ }
+
+
+//
+// DoCreate - Create channel
+//
+
+TInt DLddUsbcScChannel::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 USBCSC.LDD (USB Driver)")))
+ {
+ return KErrPermissionDenied;
+ }
+
+ iController = DUsbClientController::UsbcControllerPointer();
+
+ if (!iController)
+ {
+ return KErrGeneral;
+ }
+
+ iStatusFifo = new TUsbcDeviceStatusQueue;
+ if (iStatusFifo == NULL)
+ {
+ return KErrNoMemory;
+ }
+
+ if (!Kern::QueryVersionSupported(TVersion(KUsbcScMajorVersion, KUsbcScMinorVersion, KUsbcScBuildVersion), aVer))
+ {
+ return KErrNotSupported;
+ }
+
+ // set up the correct DFC queue
+ SetDfcQ(iController->DfcQ(0)); // sets the channel's dfc queue
+ 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;
+
+ return r;
+ }
+// end DoCreate.
+
+
+//
+// HandleMsg
+//
+// Events from userside arrive here, and delegated to either DoRequest, DoControl or DoCancel.
+//
+
+void DLddUsbcScChannel::HandleMsg(TMessageBase* aMsg)
+ {
+ TThreadMessage& m = *(TThreadMessage*)aMsg;
+ TInt id = m.iValue;
+ __KTRACE_OPT(KUSB, Kern::Printf("HandleMsg 0x%x", id));
+
+ if (id == (TInt) ECloseMsg)
+ {
+ iChannelClosing = ETrue;
+ m.Complete(KErrNone, EFalse);
+ return;
+ }
+
+ TInt r;
+ if (id < 0)
+ {
+ // DoRequest
+ TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
+ r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
+ m.Complete(r, ETrue);
+ }
+ else if (id & RDevUsbcScClient::ERequestCancel)
+ {
+ // DoCancel
+ r = DoCancel(id, (TUint) m.Ptr0(), (TUint) m.Ptr1());
+ m.Complete(r, ETrue);
+ }
+ else
+ {
+ // DoControl
+ r = DoControl(id, m.Ptr0(), m.Ptr1());
+ m.Complete(r, ETrue);
+ }
+ }
+// end HandleMsg.
+
+
+#define BREAK_IF_NULL_ARG(a,r) if (a==NULL) { r = KErrArgument; __KTRACE_OPT(KUSB,Kern::Printf("NULL Argument")); break; }
+
+//
+// DoRequest - Asynchronous requests
+//
+// Overrides pure virtual, called by HandleMsg. (Above)
+//
+TInt DLddUsbcScChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+ {
+ TInt reqNo = aReqNo & RDevUsbcScClient::KFieldIdMask;
+ TInt r = KErrNone; // return via request notify
+ TBool needsCompletion =EFalse;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("DoRequest 0x%08x", aReqNo));
+
+ if ((reqNo>RDevUsbcScClient::ERequestReadDataNotify) &&
+ (reqNo<RDevUsbcScClient::ERequestMaxRequests))
+ {
+ if (iRequestStatus[reqNo])
+ {
+ PanicClientThread(ERequestAlreadyPending);
+ return 0;
+ }
+ iRequestStatus[reqNo] = aStatus;
+ }
+
+ switch (reqNo)
+ {
+ case RDevUsbcScClient::ERequestWriteData:
+ {
+ TInt buffer = (aReqNo>>RDevUsbcScClient::KFieldBuffPos)&RDevUsbcScClient::KFieldBuffMask;
+ __KTRACE_OPT(KUSB, Kern::Printf("ERequestWriteData"));
+ BREAK_IF_NULL_ARG(a2,r);
+
+ r = DoWriteData( aStatus, buffer, (TInt) a1 /*Start*/, (TInt) a2 /* Length */,
+ aReqNo>>RDevUsbcScClient::KFieldFlagsPos ); // Flags
+ break;
+ }
+ case RDevUsbcScClient::ERequestReadDataNotify:
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("ERequestReadDataNotify"));
+ return DoReadDataNotify(aStatus, (TInt) a1, (TInt) a2); // a1 = aBufferNumber, a2 - aLength;
+ }
+
+ case RDevUsbcScClient::ERequestAlternateDeviceStatusNotify:
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("ERequestAlternateDeviceStatusNotify"));
+ BREAK_IF_NULL_ARG(a1,r);
+ iDeviceStatusNeeded = ETrue;
+ iStatusChangePtr = a1;
+ needsCompletion = AlternateDeviceStateTestComplete();
+ break;
+ }
+ case RDevUsbcScClient::ERequestReEnumerate:
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("ERequestReEnumerate"));
+ // If successful, this will complete via the status notification.
+ r = iController->ReEnumerate();
+ break;
+ }
+ case RDevUsbcScClient::ERequestEndpointStatusNotify:
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("ERequestEndpointStatusNotify"));
+ BREAK_IF_NULL_ARG(a1,r);
+
+ iEndpointStatusChangePtr = a1;
+ break;
+ }
+ case RDevUsbcScClient::ERequestOtgFeaturesNotify:
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("ERequestOtgFeaturesNotify"));
+ BREAK_IF_NULL_ARG(a1,r);
+
+ iOtgFeatureChangePtr = a1;
+ break;
+ }
+ default:
+ r = KErrNotSupported;
+ }
+
+ if ((needsCompletion) || (r != KErrNone))
+ {
+ iRequestStatus[reqNo] = aStatus;
+ Kern::RequestComplete(iClient, iRequestStatus[reqNo], r);
+ }
+ return KErrNone;
+ }
+// end DoRequest.
+
+
+//
+// DoReadDataNotify
+//
+// This method sets up the request to facilitate the userside being notifed when new data has been read.
+//
+TInt DLddUsbcScChannel::DoReadDataNotify(TRequestStatus* aStatus, TInt aBufferNum, TInt aLength)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify(x, %d, 0x%x)", aBufferNum, aLength));
+ TInt r = KErrNone;
+ // check range
+ if ((aBufferNum<0) || (aBufferNum>=iNumBuffers)) // Indirectly checks that we are set up.
+ {
+ if (aBufferNum!=KUsbcScEndpointZero)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify : Bad Buffer Number!"));
+ return KErrArgument;
+ }
+ else
+ {
+ aBufferNum = iEP0OutBuff;
+ }
+ }
+ else
+ {
+ // check direction
+ if (iBuffers[aBufferNum].iDirection!=KUsbcScOut)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify : Bad Buffer Direction!"));
+ return KErrNotSupported;
+ }
+ if (!Configured())
+ return KErrUsbInterfaceNotReady;
+ }
+ SUsbcScBufferHeader* scBuffer = (SUsbcScBufferHeader*) iBuffers[aBufferNum].iBufferStart;
+
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify head %x tail %x", iBuffers[aBufferNum].iHead , scBuffer->iTail ));
+
+ if (iBuffers[aBufferNum].iHead != scBuffer->iBilTail)
+ r = KErrCompletion;
+ else
+ if (iBuffers[aBufferNum].iStalled)
+ {
+ iBuffers[aBufferNum].PopStall();
+ return KErrCompletion;
+ }
+ else
+ r = iBuffers[aBufferNum].iStatusList.Add(aStatus, aLength, 0,0);
+
+ if (iBuffers[aBufferNum].iStatusList.iState==ENotRunning)
+ {
+ iBuffers[aBufferNum].StartDataRead();
+ }
+ else
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Job in Progress!"));
+ }
+ return r;
+ }
+// end DoReadDataNotify.
+
+
+
+//
+// DoWriteData
+//
+// This method sets up the request to write data to USB from userside.
+//
+TInt DLddUsbcScChannel::DoWriteData(TRequestStatus* aStatus,TInt aBufferNum, TUint aStart, TUint aLength, TUint aFlags)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData(%d, 0x%x, 0x%x, 0x%x)", aBufferNum, aStart, aLength, aFlags));
+ if (!iUserKnowsAltSetting)
+ return KErrEof;
+ // Check Buffer Number
+ if ((aBufferNum<0) || (aBufferNum>=iNumBuffers))
+ {
+ if ((TUint)aBufferNum!=RDevUsbcScClient::KFieldBuffMask) // KUsbcScEndpointZero & KFieldBuffMas = KFieldBuffMas;
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData : Bad Buffer Number!"));
+ return KErrArgument;
+ }
+ else
+ {
+ aBufferNum = iEP0InBuff;
+ }
+ }
+ else
+ {
+ // check direction
+ if (iBuffers[aBufferNum].iDirection!=KUsbcScIn)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData Bad endpoint Direction"));
+ return KErrArgument;
+ }
+ }
+
+ TUsbcScBuffer& buf=iBuffers[aBufferNum];
+
+ if ((aStart< (((TLinAddr) buf.iBufferStart)-buf.iChunkAddr)) || ((aStart+aLength)>iBuffers[aBufferNum].iBufferEnd))
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData Bad Range aStart or aLength 0x%x > 0x%x + 0x%x < 0x%x", (((TLinAddr) buf.iBufferStart)-buf.iChunkAddr),aStart, aLength, iBuffers[aBufferNum].iBufferEnd ));
+ return KErrArgument;
+ }
+
+ if ( (aBufferNum != iEP0InBuff) && !Configured())
+ return KErrUsbInterfaceNotReady;
+
+ if (aStart & ~buf.iAlignMask)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::DoDataWrite: address 0x%x unaligned.",aStart));
+ return KErrArgument;
+ }
+
+ TInt r = iBuffers[aBufferNum].iStatusList.Add(aStatus, aLength, aStart, aFlags); //update
+
+ if (iBuffers[aBufferNum].iStatusList.iState==ENotRunning)
+ {
+ iBuffers[aBufferNum].StartDataWrite();
+ }
+ else
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Job in Progress!"));
+ }
+
+
+ return r;
+ }
+// end DoWriteData.
+
+
+//
+// Cancel an outstanding request // Cancel need reworking.
+//
+TInt DLddUsbcScChannel::DoCancel(TInt aReqNo, TUint aBuff, TUint aSpair)
+ {
+ TInt r = KErrNone;
+ TInt direction=KUsbcScOut;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: 0x%x aBuff 0x%x", aReqNo, aBuff));
+ switch (aReqNo)
+ {
+ case RDevUsbcScClient::ERequestCancel:
+ TInt buffer;
+ TInt mask;
+
+ for (buffer=1, mask=1; buffer<iNumBuffers; buffer++,mask<<=1)
+ if (aBuff&mask)
+ iBuffers[buffer].Cancel(KErrCancel);
+
+ return KErrNone;
+
+ // coverity[missing_break]
+ case RDevUsbcScClient::ERequestWriteDataCancel:
+ direction = KUsbcScIn;
+ case RDevUsbcScClient::ERequestReadDataNotifyCancel:
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Direction %d endpoints: 0x%x",direction, aReqNo));
+
+ if (((TInt)aBuff)==KUsbcScEndpointZero) // EP0 is bi-directional, so pick correct buffer for call type
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Cancel Endpoint 0/%d",direction));
+ iEp0Endpoint->AbortTransfer();
+ if (direction==KUsbcScIn)
+ aBuff=iEP0InBuff;
+ else
+ aBuff=iEP0OutBuff;
+ }
+ else if ((TInt)aBuff >= iNumBuffers) // check buff no range.
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Error: Bad buffer number"));
+ return KErrArgument;
+ }
+
+ if ((iBuffers[aBuff].iDirection&1)!=direction) // Does direction match call type?
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Error: Bad buffer direction"));
+ return KErrArgument;
+ }
+ iBuffers[aBuff].iStatusList.CancelQueued();
+ iBuffers[aBuff].Cancel(KErrCancel);
+
+ return KErrNone;
+
+ case RDevUsbcScClient::ERequestAlternateDeviceStatusNotifyCancel:
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: ERequestAlternateDeviceStatusNotify 0x%x", aReqNo));
+ iDeviceStatusNeeded = EFalse;
+ iStatusFifo->FlushQueue();
+ if (iStatusChangePtr)
+ {
+ TInt deviceState = iController->GetDeviceStatus();
+ r = Kern::ThreadRawWrite(iClient, iStatusChangePtr, &deviceState, sizeof(deviceState), iClient);
+ if (r != KErrNone)
+ PanicClientThread(r);
+ iStatusChangePtr = NULL;
+ }
+ break;
+
+ case RDevUsbcScClient::ERequestReEnumerateCancel:
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestReEnumerate: 0x%x", aReqNo));
+ break;
+
+ case RDevUsbcScClient::ERequestEndpointStatusNotifyCancel:
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestEndpointStatusNotify: 0x%x", aReqNo));
+ CancelNotifyEndpointStatus();
+ break;
+
+ case RDevUsbcScClient::ERequestOtgFeaturesNotifyCancel:
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestOtgFeaturesNotify: 0x%x", aReqNo));
+ CancelNotifyOtgFeatures();
+ break;
+
+ default:
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Unknown! 0x%x", aReqNo));
+ return KErrArgument;
+ }
+
+ Kern::RequestComplete(iClient,iRequestStatus[aReqNo & ~RDevUsbcScClient::ERequestCancel], KErrCancel);
+ return r;
+ }
+
+
+void DLddUsbcScChannel::CancelNotifyEndpointStatus()
+ {
+ if (iEndpointStatusChangePtr)
+ {
+ TUint epBitmap = 0;
+ for (TInt i = 1; i <= iNumberOfEndpoints; i++)
+ {
+ TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber());
+ TUint b;
+ (v == EEndpointStateStalled) ? b = 1 : b = 0;
+ epBitmap |= b << i;
+ }
+ TInt r=Kern::ThreadRawWrite(iClient, iEndpointStatusChangePtr, (TUint8*) &epBitmap, sizeof(epBitmap), iClient);
+ if (r != KErrNone)
+ PanicClientThread(r);
+ iEndpointStatusChangePtr = NULL;
+ }
+ }
+
+void DLddUsbcScChannel::CancelNotifyOtgFeatures()
+ {
+ if (iOtgFeatureChangePtr)
+ {
+ TUint8 features;
+ iController->GetCurrentOtgFeatures(features);
+ TInt r=Kern::ThreadRawWrite(iClient, iOtgFeatureChangePtr, (TUint8*)&features, sizeof(features), iClient);
+ if (r != KErrNone)
+ PanicClientThread(r);
+ iOtgFeatureChangePtr = NULL;
+ }
+ }
+
+
+
+//
+// DoControl - Synchronous requests
+//
+// Called from HandleMsg.
+
+TInt DLddUsbcScChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DoControl: %d", aFunction));
+
+ TInt r = KErrNone;
+ TInt ep, param;
+ TUsbcScEndpoint* pEndpoint;
+ TPtrC8 pZeroDesc(NULL, 0);
+ TEndpointDescriptorInfo epInfo;
+ TUsbcScIfcInfo ifcInfo;
+ TCSDescriptorInfo desInfo;
+ TUsbcEndpointResource epRes;
+
+ switch (aFunction)
+ {
+ case RDevUsbcScClient::EControlEndpointZeroRequestError:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroRequestError"));
+ r = KErrNone;
+ if (iOwnsDeviceControl || (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured))
+ {
+ iController->Ep0Stall(this);
+ }
+ else
+ {
+ if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
+ r = KErrUsbDeviceNotConfigured;
+ else
+ r = KErrUsbInterfaceNotReady;
+ }
+ break;
+
+ case RDevUsbcScClient::EControlGetAlternateSetting:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetAlternateSetting"));
+ if (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured)
+ {
+ r = iController->GetInterfaceNumber(this, param);
+ if (r == KErrNone)
+ {
+ r = Kern::ThreadRawWrite(iClient, a1, ¶m, sizeof(param), iClient);
+ if (r != KErrNone)
+ PanicClientThread(r);
+ }
+ }
+ else
+ {
+ if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
+ r = KErrUsbDeviceNotConfigured;
+ else
+ r = KErrUsbInterfaceNotReady;
+ }
+ break;
+
+ case RDevUsbcScClient::EControlDeviceStatus:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceStatus"));
+ param = iController->GetDeviceStatus();
+ r = Kern::ThreadRawWrite(iClient, a1, ¶m, sizeof(param), iClient);
+ if (r != KErrNone)
+ PanicClientThread(r);
+ break;
+
+ case RDevUsbcScClient::EControlEndpointStatus:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointStatus"));
+ if (iValidInterface && ValidEndpoint((TInt) a1))
+ {
+ pEndpoint = iEndpoint[(TInt)a1];
+ if (pEndpoint == NULL)
+ r = KErrNotSupported;
+ else
+ {
+ param = iController->GetEndpointStatus(this, iEndpoint[(TInt)a1]->RealEpNumber());
+ r = Kern::ThreadRawWrite(iClient, a2, ¶m, sizeof(param), iClient);
+ if (r != KErrNone)
+ PanicClientThread(r);
+ }
+ }
+ else
+ {
+ if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
+ r = KErrUsbDeviceNotConfigured;
+ else
+ r = KErrUsbInterfaceNotReady;
+ }
+ break;
+
+ case RDevUsbcScClient::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 RDevUsbcScClient::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 RDevUsbcScClient::EControlSendEp0StatusPacket:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSendEp0StatusPacket"));
+ iController->SendEp0StatusPacket(this);
+ break;
+
+ case RDevUsbcScClient::EControlHaltEndpoint:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlHaltEndpoint"));
+ if (iValidInterface && ValidEndpoint((TInt) a1))
+ {
+ r = iController->HaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber());
+ }
+ else
+ {
+ if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
+ r = KErrUsbDeviceNotConfigured;
+ else
+ r = KErrUsbInterfaceNotReady;
+ }
+ break;
+
+ case RDevUsbcScClient::EControlClearHaltEndpoint:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlClearHaltEndpoint"));
+ if (iValidInterface && ValidEndpoint((TInt) a1))
+ {
+ r = iController->ClearHaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber());
+ }
+ else
+ {
+ if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
+ r = KErrUsbDeviceNotConfigured;
+ else
+ r = KErrUsbInterfaceNotReady;
+ }
+ break;
+
+ case RDevUsbcScClient::EControlDumpRegisters:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlDumpRegisters"));
+ iController->DumpRegisters();
+ break;
+
+ case RDevUsbcScClient::EControlReleaseDeviceControl:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseDeviceControl"));
+ iController->ReleaseDeviceControl(this);
+ iOwnsDeviceControl = EFalse;
+ break;
+
+ case RDevUsbcScClient::EControlEndpointZeroMaxPacketSizes:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroMaxPacketSizes"));
+ r = iController->EndpointZeroMaxPacketSizes();
+ break;
+
+ case RDevUsbcScClient::EControlSetEndpointZeroMaxPacketSize:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointZeroMaxPacketSize"));
+ r = iController->SetEndpointZeroMaxPacketSize(reinterpret_cast<TInt>(a1));
+ break;
+
+ case RDevUsbcScClient::EControlGetEndpointZeroMaxPacketSize:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointZeroMaxPacketSize"));
+ r = iController->Ep0PacketSize();
+ break;
+
+ case RDevUsbcScClient::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 RDevUsbcScClient::EControlSetDeviceDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceDescriptor"));
+ BREAK_IF_NULL_ARG(a1,r);
+ r = iController->SetDeviceDescriptor(iClient, *((TDes8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlGetDeviceDescriptorSize:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptorSize"));
+ BREAK_IF_NULL_ARG(a1,r);
+ r = iController->GetDeviceDescriptorSize(iClient, *((TDes8*) a1));
+ break;
+
+ case RDevUsbcScClient::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 RDevUsbcScClient::EControlGetConfigurationDescriptorSize:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptorSize"));
+ if (a1 != NULL)
+ {
+ r = iController->GetConfigurationDescriptorSize(iClient, *((TDes8*) a1));
+ }
+ else
+ r = KErrArgument;
+ break;
+
+ case RDevUsbcScClient::EControlSetConfigurationDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationDescriptor"));
+ r = iController->SetConfigurationDescriptor(iClient, *((TDes8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlGetInterfaceDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptor"));
+ r = iController->GetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2));
+ break;
+
+ case RDevUsbcScClient::EControlGetInterfaceDescriptorSize:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptorSize"));
+ r = iController->GetInterfaceDescriptorSize(iClient, this, (TInt) a1, *(TDes8*) a2);
+ break;
+
+ case RDevUsbcScClient::EControlSetInterfaceDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterfaceDescriptor"));
+ r = iController->SetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2));
+ break;
+
+ case RDevUsbcScClient::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 = (ep<0)?ep:iController->GetEndpointDescriptor(iClient, this, epInfo.iSetting,
+ ep, *(TDes8*) epInfo.iArg);
+ break;
+
+ case RDevUsbcScClient::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 RDevUsbcScClient::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 RDevUsbcScClient::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 RDevUsbcScClient::EControlSetDeviceQualifierDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceQualifierDescriptor"));
+ BREAK_IF_NULL_ARG(a1,r);
+ r = iController->SetDeviceQualifierDescriptor(iClient, *((TDes8*) a1));
+ break;
+
+ case RDevUsbcScClient::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 RDevUsbcScClient::EControlSetOtherSpeedConfigurationDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtherSpeedConfigurationDescriptor"));
+ r = iController->SetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1));
+ break;
+
+
+ case RDevUsbcScClient::EControlGetCSInterfaceDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptor"));
+ r = iController->GetCSInterfaceDescriptorBlock(iClient, this, (TInt) a1, *((TDes8*) a2));
+ break;
+
+ case RDevUsbcScClient::EControlGetCSInterfaceDescriptorSize:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptorSize"));
+ r = iController->GetCSInterfaceDescriptorBlockSize(iClient, this, (TInt) a1, *(TDes8*) a2);
+ break;
+
+ case RDevUsbcScClient::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 RDevUsbcScClient::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 RDevUsbcScClient::EControlSignalRemoteWakeup:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSignalRemoteWakeup"));
+ r = iController->SignalRemoteWakeup();
+ break;
+
+ case RDevUsbcScClient::EControlDeviceDisconnectFromHost:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceDisconnectFromHost"));
+ r = iController->UsbDisconnect();
+ break;
+
+ case RDevUsbcScClient::EControlDeviceConnectToHost:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceConnectToHost"));
+ r = iController->UsbConnect();
+ break;
+
+ case RDevUsbcScClient::EControlDevicePowerUpUdc:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlDevicePowerUpUdc"));
+ r = iController->PowerUpUdc();
+ break;
+
+ case RDevUsbcScClient::EControlSetDeviceControl:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl"));
+ r = iController->SetDeviceControl(this);
+ if (r == KErrNone)
+ {
+ iOwnsDeviceControl = ETrue;
+ if (iEp0Endpoint == NULL)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl"));
+ r = SetupEp0();
+ if (r != KErrNone)
+ {
+ __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupEp0() failed"));
+ iController->ReleaseDeviceControl(this);
+ iOwnsDeviceControl=EFalse;
+ DestroyEp0();
+ }
+ }
+ }
+ else
+ r = KErrInUse;
+ break;
+
+ case RDevUsbcScClient::EControlCurrentlyUsingHighSpeed:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlCurrentlyUsingHighSpeed"));
+ r = iController->CurrentlyUsingHighSpeed();
+ break;
+
+ case RDevUsbcScClient::EControlSetInterface:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterface"));
+ r = Kern::ThreadRawRead(iClient, a2, &ifcInfo, sizeof(ifcInfo));
+ if (r != KErrNone)
+ PanicClientThread(r);
+ r = SetInterface((TInt) a1, &ifcInfo);
+ break;
+
+ case RDevUsbcScClient::EControlReleaseInterface:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseInterface"));
+ if (!iRealizeCalled)
+ {
+ 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."));
+ }
+ }
+ else
+ r = KErrUsbAlreadyRealized;
+ break;
+
+ case RDevUsbcScClient::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 RDevUsbcScClient::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 RDevUsbcScClient::EControlGetStringDescriptorLangId:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptorLangId"));
+ r = iController->GetStringDescriptorLangId(iClient, *((TDes8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlSetStringDescriptorLangId:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptorLangId"));
+ r = iController->SetStringDescriptorLangId(reinterpret_cast<TUint>(a1));
+ break;
+
+ case RDevUsbcScClient::EControlGetManufacturerStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetManufacturerStringDescriptor"));
+ r = iController->GetManufacturerStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlSetManufacturerStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetManufacturerStringDescriptor"));
+ r = iController->SetManufacturerStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlRemoveManufacturerStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveManufacturerStringDescriptor"));
+ r = iController->RemoveManufacturerStringDescriptor();
+ break;
+
+ case RDevUsbcScClient::EControlGetProductStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetProductStringDescriptor"));
+ r = iController->GetProductStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlSetProductStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetProductStringDescriptor"));
+ r = iController->SetProductStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlRemoveProductStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveProductStringDescriptor"));
+ r = iController->RemoveProductStringDescriptor();
+ break;
+
+ case RDevUsbcScClient::EControlGetSerialNumberStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetSerialNumberStringDescriptor"));
+ r = iController->GetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlSetSerialNumberStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetSerialNumberStringDescriptor"));
+ r = iController->SetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlRemoveSerialNumberStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveSerialNumberStringDescriptor"));
+ r = iController->RemoveSerialNumberStringDescriptor();
+ break;
+
+ case RDevUsbcScClient::EControlGetConfigurationStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationStringDescriptor"));
+ r = iController->GetConfigurationStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlSetConfigurationStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationStringDescriptor"));
+ r = iController->SetConfigurationStringDescriptor(iClient, *((TPtr8*) a1));
+ break;
+
+ case RDevUsbcScClient::EControlRemoveConfigurationStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveConfigurationStringDescriptor"));
+ r = iController->RemoveConfigurationStringDescriptor();
+ break;
+
+ case RDevUsbcScClient::EControlGetStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptor"));
+ r = iController->GetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2));
+ break;
+
+ case RDevUsbcScClient::EControlSetStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptor"));
+ r = iController->SetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2));
+ break;
+
+ case RDevUsbcScClient::EControlRemoveStringDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveStringDescriptor"));
+ r = iController->RemoveStringDescriptor((TUint8) (TInt) a1);
+ break;
+
+ case RDevUsbcScClient::EControlQueryEndpointResourceUse:
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlQueryEndpointResourceUse"));
+ epRes = (TUsbcEndpointResource)((TInt) a2);
+ TInt realEp=-1;
+ r = GetRealEpForEpResource((TInt)a1, realEp);
+ if (r==KErrNone)
+ r = iController->QueryEndpointResource(this, realEp, epRes);
+ break;
+ }
+ case RDevUsbcScClient::EControlSetOtgDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtgDescriptor"));
+ r = iController->SetOtgDescriptor(iClient, *((const TDesC8*)a1));
+ break;
+
+ case RDevUsbcScClient::EControlGetOtgDescriptor:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtgDescriptor"));
+ r = iController->GetOtgDescriptor(iClient, *((TDes8*)a1));
+ break;
+
+ case RDevUsbcScClient::EControlGetOtgFeatures:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtgFeatures"));
+ r = iController->GetOtgFeatures(iClient, *((TDes8*)a1));
+ break;
+
+ case RDevUsbcScClient::EControlRealizeInterface:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlRealizeInterface"));
+ r = RealizeInterface();
+ break;
+ case RDevUsbcScClient::EControlStartNextInAlternateSetting:
+ __KTRACE_OPT(KUSB, Kern::Printf("EControlStartNextInAlternateSetting"));
+ r = StartNextInAlternateSetting();
+ break;
+
+ default:
+ __KTRACE_OPT(KUSB, Kern::Printf("Function code not supported"));
+ r = KErrNotSupported;
+ }
+
+ return r;
+ }
+// end DoControl.
+
+
+
+//
+// Overriding DObject virtual
+//
+TInt DLddUsbcScChannel::RequestUserHandle(DThread* aThread, TOwnerType /*aType*/)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::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;
+ }
+ }
+
+inline TInt DLddUsbcScChannel::GetRealEpForEpResource(TInt aEndpoint, TInt& aRealEp)
+ {
+ if (iEndpoint) // if we've enumerated at least once, proceed as normal.
+ {
+ if (aEndpoint <= iNumberOfEndpoints && aEndpoint >= 0)
+ {
+ aRealEp=iEndpoint[aEndpoint]->RealEpNumber();
+ return KErrNone;
+ }
+ }
+ else // Assume alternate setting 0.
+ {
+ if (iAlternateSettingList) // Check it has been set up.
+ {
+ TUsbcScAlternateSetting* alt = iAlternateSettingList->iHead;
+ if (alt && (aEndpoint <= alt->iNumberOfEndpoints && aEndpoint >= 0))
+ {
+ aRealEp= alt->iEndpoint[aEndpoint]->RealEpNumber();
+ return KErrNone;
+ }
+ }
+ }
+ return KErrUsbDeviceNotConfigured;
+ }
+
+
+TUsbcEndpointInfoArray::TUsbcEndpointInfoArray(const TUsbcScEndpointInfo* aData, TInt aDataSize)
+ {
+ iType = EUsbcScEndpointInfo;
+ iData = (TUint8*) aData;
+ if (aDataSize>0)
+ iDataSize = aDataSize;
+ else
+ iDataSize = sizeof(TUsbcScEndpointInfo);
+ }
+
+
+//
+// SetInterface
+//
+// Called from DoControl. Sets the configuration of a given Interface. // Needs changing
+// All interfaces must be configured before one can be used.
+//
+
+TInt DLddUsbcScChannel::SetInterface(TInt aInterfaceNumber, TUsbcScIfcInfo* aInfoBuf)
+ {
+ // Copy interface description.
+
+ if (iRealizeCalled)
+ return KErrUsbAlreadyRealized;
+
+ if (!iAlternateSettingList)
+ {
+ iAlternateSettingList = new TUsbcScAlternateSettingList;
+ if (iAlternateSettingList==NULL)
+ {
+ return KErrNoMemory;
+ }
+ }
+
+ // Read descriptor in
+ TUsbcScInterfaceInfoBuf ifc_info_buf;
+ TUsbcScInterfaceInfoBuf* const ifc_info_buf_ptr = aInfoBuf->iInterfaceData;
+ const TInt srcLen = Kern::ThreadGetDesLength(iClient, ifc_info_buf_ptr);
+
+ __KTRACE_OPT(KUSB, Kern::Printf("SetInterface srcLen = %d len = %d", srcLen, ifc_info_buf.Length() ));
+
+ 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);
+ }
+
+ // The list of endpoints is within the interface info.
+ TUsbcScEndpointInfo* pEndpointData = ifc_info_buf().iEndpointData;
+
+ const TInt num_endpoints = ifc_info_buf().iTotalEndpointsUsed;
+ __KTRACE_OPT(KUSB, Kern::Printf("SetInterface num_endpoints=%d", num_endpoints));
+ if (num_endpoints>KMaxEndpointsPerClient)
+ return KErrOverflow;
+
+
+ // Initialize real ep numbers list.
+ TInt i;
+ TInt real_ep_numbers[KMaxEndpointsPerClient+1]; // range 1->KMaxEndpointsPerClient (0 not used)
+ for (i=0; i<=KMaxEndpointsPerClient; i++)
+ real_ep_numbers[i] = -1;
+
+
+ // See if PIL will accept this interface
+ __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Calling controller"));
+ TUsbcEndpointInfoArray endpointData = TUsbcEndpointInfoArray(ifc_info_buf().iEndpointData);
+
+ r = iController->SetInterface(this,
+ iClient,
+ aInterfaceNumber,
+ ifc_info_buf().iClass,
+ aInfoBuf->iString,
+ (TInt) ifc_info_buf().iTotalEndpointsUsed,
+ endpointData,
+ &real_ep_numbers[0],
+ 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;
+ }
+
+ // create alternate setting record
+ TUsbcScAlternateSetting* alternateSettingListRec = new TUsbcScAlternateSetting;
+ if (!alternateSettingListRec)
+ {
+ r = KErrNoMemory;
+ goto ReleaseInterface;
+ }
+
+ // other endpoints
+ for (TInt i = 1; i <= num_endpoints; i++, pEndpointData++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d", i));
+
+ if ((pEndpointData->iType==UsbShai::KUsbEpTypeControl)
+ || (pEndpointData->iDir != UsbShai::KUsbEpDirIn && pEndpointData->iDir != UsbShai::KUsbEpDirOut)
+ || (pEndpointData->iSize > 1024) || (pEndpointData->iSize<=0))
+ {
+ r = KErrUsbBadEndpoint;
+ goto CleanUp;
+ }
+ // Check data
+
+ TUint* bufferSize = &(pEndpointData->iBufferSize);
+ if (*bufferSize==0)
+ *bufferSize= KUsbcScDefaultBufferSize;
+
+ TInt pageSize = Kern::RoundToPageSize(1);
+ // Round buffersize up to nearest pagesize.
+ *bufferSize = (*bufferSize+pageSize-1) & ~(pageSize-1);
+
+ TUsbcScEndpoint* ep = new TUsbcScEndpoint(this, iController, pEndpointData, i);
+ alternateSettingListRec->iEndpoint[i] = ep;
+ if (!ep)
+ {
+ r = KErrNoMemory;
+ goto CleanUp;
+ }
+ if (ep->Construct() != KErrNone)
+ {
+ r = KErrNoMemory;
+ goto CleanUp;
+ }
+
+
+ __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d rec=0x%08x ep==0x%08x",
+ i, alternateSettingListRec, ep));
+ }
+
+ if (iAlternateSettingList->iHead)
+ {
+ iAlternateSettingList->iTail->iNext = alternateSettingListRec;
+ alternateSettingListRec->iPrevious = iAlternateSettingList->iTail;
+ iAlternateSettingList->iTail = alternateSettingListRec;
+ }
+ else
+ {
+ iAlternateSettingList->iHead = alternateSettingListRec;
+ iAlternateSettingList->iTail = alternateSettingListRec;
+ }
+
+ alternateSettingListRec->iNext = NULL;
+ 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]);
+ }
+
+ return KErrNone;
+
+ CleanUp:
+ delete alternateSettingListRec;
+ //Fall Through
+
+ ReleaseInterface:
+#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;
+ }
+// end SetInterface
+
+
+
+#ifdef _DEBUG
+void RealizeInterface_Dump(TUint* aMem)
+ {
+ TUint *mem= NULL;
+ __KTRACE_OPT(KUSB, mem = aMem);
+ if (mem!=NULL)
+ {
+ TInt j;
+ Kern::Printf("Final chunk header State:");
+ for (j=0; j<30; j+=8)
+ Kern::Printf("%2x: %8x %8x %8x %8x %8x %8x %8x %8x", j, mem[j], mem[j+1], mem[j+2], mem[j+3], mem[j+4], mem[j+5], mem[j+6], mem[j+7] );
+ };
+ };
+#endif
+
+
+/*
+Chunk Created, filled with structure, and passed back to userside.
+*/
+TInt DLddUsbcScChannel::RealizeInterface(void)
+{
+ if (iRealizeCalled)
+ return KErrUsbAlreadyRealized;
+
+ TRealizeInfo bufInfo;
+
+ TInt errorOrChunk = KErrNone;
+ TBool openedCS = EFalse;
+ TInt offset =0;
+
+ // Start by creating a temporary scratchpad for endpoint calculations.
+ bufInfo.Init(iAlternateSettingList);
+
+ // Fill in our scratchpad with all the required endpoints, sorting them
+ // in order of size required.
+ errorOrChunk = bufInfo.CopyAndSortEndpoints();
+ if (errorOrChunk!=KErrNone)
+ {
+ goto realize_end;
+ }
+
+ // We now have endpoints sorted in order of size for each altsetting.
+ // The very largest for each endpoint will share the first buffer, and all of
+ // the second largest ends points will share the second buffer, and so on.
+ // Find the highest buffer size for each row, to determine the buffer size,
+ // and keep a total of total space needed.
+ bufInfo.CalcBuffSizes();
+
+ // We now have the max sizes wanted for each endpoint buffer.
+ // we also have to total size for all endpoints.
+ // and finally we have the total number of buffers.
+
+ // Add on size for header, then add on size for guard pages.
+ bufInfo.iTotalSize+= KHeaderSize + bufInfo.iTotalBuffers * KGuardSize;
+
+ // Create shared Chunk . . . . . . . . . .
+ if (iChunkInfo==NULL)
+ {
+ NKern::ThreadEnterCS();
+ openedCS = ETrue;
+ errorOrChunk = TUsbcScChunkInfo::New(iChunkInfo, bufInfo.iTotalSize, (DLogicalDevice*) iDevice);
+ if (errorOrChunk!=KErrNone)
+ {
+ goto realize_end;
+ }
+ }
+ else
+ {
+ // As of writing, the was no way for iChunk to be anything other then NULL.
+ // You cannot 'unrealise' and iChunk cannot be set any other way.
+ Kern::Fault("DLddUsbcScChannel::RealizeInterface", __LINE__);
+ }
+
+ // Populate the shared chunk . . . . . . .
+
+
+ // First create chunk header.
+ errorOrChunk = iChunkInfo->ChunkAlloc(offset, KHeaderSize);
+ if (errorOrChunk!=KErrNone)
+ {
+ if (errorOrChunk==-KErrNoMemory)
+ errorOrChunk=KErrNoMemory;
+ goto realize_end;
+ }
+
+
+ offset+=KHeaderSize + KGuardSize; // Also any more for EP0?
+
+ // Next, lay out the geometry of the chunk header.
+
+ bufInfo.LayoutChunkHeader(iChunkInfo);
+
+
+ { // Scope ep0Size
+ TInt ep0Size=0;
+
+ // Create K-side buffer table
+ if (!iBuffers)
+ iBuffers = (TUsbcScBuffer *) Kern::AllocZ(sizeof(TUsbcScBuffer) * (bufInfo.iTotalBuffers+2)); // +2 is for ep0.
+ if (!iBuffers)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Error: Alloc iBufers failed!"));
+ errorOrChunk = KErrNoMemory;
+ goto realize_end;
+ }
+
+
+ errorOrChunk = SetupEp0();
+ if (errorOrChunk)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: SetupEp0 . ERROR %d",errorOrChunk));
+ goto realize_end;
+ }
+
+ ep0Size = iEp0Endpoint->EndpointInfo()->iSize;
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0. max packet size %d", ep0Size));
+
+ // Create EP0 buffers
+ iEP0OutBuff=bufInfo.iTotalBuffers;
+ errorOrChunk = iBuffers[iEP0OutBuff].Construct(KUsbcScBiOut, this, KUsbScEP0OutBufPos, KUsbScEP0OutBufEnd, ep0Size, ep0Size, ep0Size);
+ if (errorOrChunk)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0 Out. ERROR %d",errorOrChunk));
+ goto realize_end;
+ }
+
+ iBuffers[iEP0OutBuff].CreateChunkBufferHeader();
+ iBuffers[iEP0OutBuff].iCallback = iEp0Endpoint->iRequestCallbackInfo;
+ ((TUsbcScBufferRecord*) &(
+ bufInfo.iChunkStuct->iBufferOffset[KUsbcScEp0OutBuff*sizeof(TUsbcScBufferRecord)]
+ )) ->Set(KUsbScEP0OutBufPos, KUsbScEP0OutBufEnd);
+
+
+ iEP0InBuff=bufInfo.iTotalBuffers+1;
+ errorOrChunk = iBuffers[iEP0InBuff].Construct( KUsbcScBiIn , this, KUsbScEP0InBufPos , KUsbScEP0InBufEnd , ep0Size, ep0Size, ep0Size);
+ if (errorOrChunk)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0 In. ERROR %d",errorOrChunk));
+ goto realize_end;
+ }
+
+ iBuffers[iEP0InBuff].iCallback = iEp0Endpoint->iRequestCallbackInfo;
+
+ ((TUsbcScBufferRecord*) &(
+ bufInfo.iChunkStuct->iBufferOffset[KUsbcScEp0InBuff*sizeof(TUsbcScBufferRecord)]
+ ))->Set(KUsbScEP0InBufPos, KUsbScEP0InBufEnd);
+
+
+ } // end ep0Size scope
+
+ // Create resources and tables. . . . . .
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Create resources tables"));
+
+ { // scope of bufNum
+ // For each EP buffer
+ TInt buffNum=0;
+ TInt buffMinSize;
+ TInt endpointNumber;
+ TUsbcScEndpoint* endpointRecord;
+ TInt endpoint;
+ TInt inout;
+ TEndpointSortBufs* bufsd;
+ TUsbcScHdrEndpointRecord* epRecord;
+ for (endpoint=0; endpoint<bufInfo.iMaxEndpoints; endpoint++) // endpoint = buf row.
+ {
+ for (inout=KUsbcScIn; inout<KUsbcScDirections; inout++)
+ {
+ buffMinSize = KUsbSc_BigBuff_MinimumRamRun;
+
+ TInt needed = bufInfo.iBufs[inout].iSizes[endpoint];
+ if (needed)
+ {
+ TInt bufStart = offset;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: buf row:%d inout %d, iBufferOffset[%d+2]=%x",endpoint, inout, buffNum, bufStart));
+
+ bufsd = &(bufInfo.iBufs[inout]);
+ // and then point all endpoints that use it, towards it.
+ TInt altSetting;
+ TUint maxReadSize = ~0;
+ for (altSetting=0; altSetting < bufInfo.iAltSettings; altSetting++)
+ {
+ endpointRecord =bufsd->iEp[altSetting*bufInfo.iMaxEndpoints + endpoint];
+ if (endpointRecord)
+ {
+ endpointNumber = endpointRecord->EpNumber();
+ endpointRecord->SetBuffer(&iBuffers[buffNum]);
+
+ epRecord = (TUsbcScHdrEndpointRecord*) &iChunkInfo->iChunkMem[
+ (bufInfo.iAltSettingsTbl->iAltTableOffset[altSetting]) // i.e. Just after altSettingsTbl
+ +sizeof(TInt) // after number of endpoints field
+ +(endpointNumber-1)*sizeof(TUsbcScHdrEndpointRecord)
+ ];
+ epRecord->iBufferNo = (TUint8) buffNum;
+
+ TInt epType=(endpointRecord->EndpointInfo()->iType);
+ epType= (epType& UsbShai::KUsbEpTypeControl)?KUsbScHdrEpTypeControl:
+ (epType& UsbShai::KUsbEpTypeIsochronous)?KUsbScHdrEpTypeIsochronous:
+ (epType& UsbShai::KUsbEpTypeBulk)?KUsbScHdrEpTypeBulk:
+ (epType& UsbShai::KUsbEpTypeInterrupt)?KUsbScHdrEpTypeInterrupt:KUsbScHdrEpTypeUnknown;
+
+ epRecord->iType = (inout+1) | (epType<<2);
+
+ if (endpointRecord->EndpointInfo()->iReadSize)
+ maxReadSize = (maxReadSize <= endpointRecord->EndpointInfo()->iReadSize) ? maxReadSize : endpointRecord->EndpointInfo()->iReadSize;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpointNum %d in altSetting %d, alt table @ %d",
+ endpointNumber, altSetting,bufInfo.iAltSettingsTbl->iAltTableOffset[altSetting]));
+ }
+ else
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpointNum NA in altSetting %d", altSetting));
+ }
+
+ } // end for
+
+
+ // Alloc memory for buffer.
+ TInt grabSize = needed;
+ // Generally, a buffer fragmented into smaller memory regions will reduce the efficiency
+ // of reading or writing data, and so avoiding the allocation of very small sections
+ // is advantageous.
+ // However, if only a small amount is being allocated to start with, it is likely
+ // smaller amounts of data are to be sent (reducing this advantage), and 1 memory page
+ // is a much bigger proportion of the buffer, and so more worth allocating individually.
+
+ TInt minimumGrab;
+ if (needed<KUsbScBigBuffIs)
+ {
+ minimumGrab=Kern::RoundToPageSize(1);
+ buffMinSize = KUsbSc_SmallBuff_MinimumRamRun; // 1k
+ }
+ else
+ {
+ minimumGrab = buffMinSize+Kern::RoundToPageSize(1);
+ }
+
+ // Grab required memory, in bits as big as possible, down to the minimum size.
+ while (needed >= minimumGrab)
+ {
+ TInt r;
+ r = iChunkInfo->ChunkAlloc(offset, grabSize);
+ if (r==KErrNone)
+ {
+ offset+=grabSize;
+ needed-=grabSize;
+ }
+ else
+ {
+ if (r==-KErrNoMemory)
+ {
+ grabSize>>=1;
+ }
+ if ((grabSize<minimumGrab) || (r!=-KErrNoMemory))
+ {
+ errorOrChunk = r;
+ goto realize_end;
+ }
+ }
+ } // end while needed
+
+ // Initialize buffer
+ iBuffers[buffNum].Construct(inout, this, bufStart, offset, buffMinSize, 0, maxReadSize);
+ iBuffers[buffNum].CreateChunkBufferHeader();
+ ((TUsbcScBufferRecord*) &(
+ bufInfo.iChunkStuct->iBufferOffset[(buffNum+2)*sizeof(TUsbcScBufferRecord)]
+ ))->Set(bufStart, offset);
+
+
+ // inc pointers for next buffer
+ buffNum++;
+ offset+=KGuardSize;
+ } // end if needed
+
+ } // end for inout
+ } // end for each buffer
+ } // scope of bufNum
+
+#ifdef _DEBUG
+ RealizeInterface_Dump((TUint*) iChunkInfo->iChunkMem); // Debug only tracing
+#endif
+
+realize_end:
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: cleanup. Err=%d", errorOrChunk));
+ // Here we clean up after either success, or after bailing out early.
+
+ bufInfo.Free();
+
+ if (iChunkInfo)
+ {
+ if (errorOrChunk==KErrNone)
+ {
+ // Everything is looking good - create RChunk for Userside.
+ errorOrChunk = Kern::MakeHandleAndOpen(iClient, iChunkInfo->iChunk);
+ iRealizeCalled = (errorOrChunk>=0);
+ } // endif errorOrChunk
+
+ if (errorOrChunk<0) // If error, destroy the chunk.
+ {
+ iChunkInfo->Close();
+ // ChunkInfo will delete itself with DFC, but the pointer here is no longer needed.
+ iChunkInfo=NULL;
+
+ // Destroy iBuffers
+ if (iBuffers)
+ {
+ TInt i;
+ for (i=0; i<(iNumBuffers+2); i++)
+ {
+ iBuffers[i].iStatusList.Destroy();
+ }
+ Kern::Free(iBuffers);
+ iBuffers=NULL;
+ }
+
+ }
+ else
+ {
+ iNumBuffers = bufInfo.iTotalBuffers;
+ iValidInterface = ETrue; // Let the games commence!
+ }
+
+ } // endif iChunkInfo
+ if (openedCS)
+ NKern::ThreadLeaveCS();
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: returning %x (%d)", errorOrChunk, errorOrChunk));
+ return errorOrChunk;
+} // End RealizeInterface
+
+
+//
+// DestroyAllInterfaces
+//
+
+void DLddUsbcScChannel::DestroyAllInterfaces()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyAllInterfaces"));
+ // Removes all interfaces
+ if (iAlternateSettingList)
+ {
+ if (iAlternateSettingList->iHead != NULL)
+ {
+ TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iTail;
+ while (alternateSettingListRec)
+ {
+ iAlternateSettingList->iTail = alternateSettingListRec->iPrevious;
+ // If this contains NULL now that is only possible if the record to be deleted was at the head
+ __KTRACE_OPT(KUSB, Kern::Printf("Release interface %d \n", alternateSettingListRec->iSetting));
+ iController->ReleaseInterface(this, alternateSettingListRec->iSetting);
+ delete alternateSettingListRec;
+ if (iAlternateSettingList->iTail == NULL) //No more interfaces left
+ break;
+ else
+ {
+ iAlternateSettingList->iTail->iNext = NULL;
+ alternateSettingListRec = iAlternateSettingList->iTail;
+ }
+ }
+ }
+ delete iAlternateSettingList;
+ }
+
+ iNumberOfEndpoints = 0;
+ iAlternateSettingList = NULL;
+ iValidInterface = EFalse;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyAllInterfaces done"));
+ }
+
+
+
+
+
+//
+// DestroyInterface
+//
+
+void DLddUsbcScChannel::DestroyInterface(TUint aInterfaceNumber)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyInterface \n"));
+
+ if (iAlternateSetting == aInterfaceNumber)
+ {
+ ResetInterface(KErrUsbInterfaceNotReady);
+ iValidInterface = EFalse;
+ iNumberOfEndpoints = 0;
+ }
+ if (iAlternateSettingList)
+ {
+ TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iTail;
+ TUsbcScAlternateSetting* alternateSettingListRecFound = NULL;
+ while (alternateSettingListRec)
+ {
+ if (alternateSettingListRec->iSetting == aInterfaceNumber)
+ {
+ alternateSettingListRecFound = alternateSettingListRec;
+ if (alternateSettingListRec->iPrevious == NULL) //Interface is at HEAD OF List, Should only be if Interface is also at Tail of list
+ {
+ iAlternateSettingList->iHead = alternateSettingListRec->iNext; // Should be NULL
+ if (alternateSettingListRec->iNext)
+ iAlternateSettingList->iHead->iPrevious = NULL;
+ }
+ else if (alternateSettingListRec->iNext == NULL) //Interface is at TAIL OF List
+ {
+ iAlternateSettingList->iTail = alternateSettingListRecFound->iPrevious;
+ iAlternateSettingList->iTail->iNext = NULL;
+ }
+ else //Somewhere in the middle (would not expect this in normal operation, but here for completeness)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyInterface Middle interface!\n"));
+ alternateSettingListRec->iPrevious->iNext = alternateSettingListRec->iNext;
+ alternateSettingListRec->iNext->iPrevious = alternateSettingListRec->iPrevious;
+ }
+
+ delete alternateSettingListRecFound;
+ break;
+ }
+ alternateSettingListRec = alternateSettingListRec->iPrevious;
+ }
+ }
+ }
+
+//
+// SetupEp0
+//
+
+TInt DLddUsbcScChannel::SetupEp0()
+ {
+ __ASSERT_ALWAYS(iEp0Endpoint==NULL, Kern::Fault("DLddUsbcScChannel::SetupEp0", __LINE__));
+
+ TUsbcScEndpointInfo ep0Info = TUsbcScEndpointInfo(UsbShai::KUsbEpTypeControl, UsbShai::KUsbEpDirBidirect);
+ ep0Info.iSize = iController->Ep0PacketSize();
+
+ TUsbcScEndpoint* ep0 = new TUsbcScEndpoint(this, iController, &ep0Info, 0);
+ if (ep0 == NULL)
+ {
+ return KErrNoMemory;
+ }
+
+ TInt r = ep0->Construct();
+ if (r != KErrNone)
+ {
+ delete ep0;
+ return KErrNoMemory;
+ }
+
+ ep0->SetRealEpNumber(0);
+ ep0->SetBuffer(NULL); // Cannot find it this way.
+
+ iEp0Endpoint = ep0;
+ return KErrNone;
+ }
+
+//
+// DestroyEp0
+//
+
+void DLddUsbcScChannel::DestroyEp0()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DestroyEp0"));
+ delete iEp0Endpoint;
+ iEp0Endpoint = NULL;
+ }
+
+
+void DLddUsbcScChannel::RequestCallbackEp0(TAny* aDLddUsbcScChannel)
+ {
+ DLddUsbcScChannel* channel = (DLddUsbcScChannel*) aDLddUsbcScChannel;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::RequestCallbackEp0"));
+
+ if (channel->ChannelClosing())
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Channel Closing: Completion not accepted!"));
+ return;
+ }
+
+ switch (channel->iEp0Endpoint->iRequestCallbackInfo->iTransferDir)
+ {
+ case UsbShai::EControllerWrite:
+ channel->iBuffers[channel->iEP0InBuff].CompleteWrite();
+ return;
+ case UsbShai::EControllerRead:
+ channel->iBuffers[channel->iEP0OutBuff].CompleteRead();
+ return;
+ default:
+ Kern::Printf("DLddUsbcScChannel::RequestCallbackEp0 - Unexpected completion direction %d",channel->iEp0Endpoint->iRequestCallbackInfo->iTransferDir);
+ Kern::Fault("DLddUsbcScChannel::RequestCallbackEp0", __LINE__);
+ }
+ }
+
+
+
+
+
+
+//
+// EndpointStatusChangeCallback
+//
+
+void DLddUsbcScChannel::EndpointStatusChangeCallback(TAny* aDLddUsbcScChannel)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback"));
+ DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel;
+ if (dUsbc->iChannelClosing)
+ return;
+ TUint endpointState = dUsbc->iEndpointStatusCallbackInfo.State();
+ const TInt reqNo = (TInt) RDevUsbcScClient::ERequestEndpointStatusNotify;
+ if (dUsbc->iRequestStatus[reqNo])
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback Notify status"));
+ DThread* client = dUsbc->iClient;
+ // set client descriptor length to zero
+ TInt r = Kern::ThreadRawWrite(client, dUsbc->iEndpointStatusChangePtr, &endpointState,
+ sizeof(TUint), client);
+ if (r != KErrNone)
+ dUsbc->PanicClientThread(r);
+ Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], r);
+ dUsbc->iEndpointStatusChangePtr = NULL;
+ }
+ }
+
+
+//
+// StatusChangeCallback
+//
+
+void DLddUsbcScChannel::StatusChangeCallback(TAny* aDLddUsbcScChannel)
+ {
+ DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel;
+ if (dUsbc->iChannelClosing)
+ return;
+
+ TUsbcDeviceState deviceState;
+ TInt i;
+ for (i = 0;
+ (i < KUsbcDeviceStateRequests) && ((deviceState = dUsbc->iStatusCallbackInfo.State(i)) != UsbShai::EUsbPeripheralNoState);
+ ++i)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallBack status=%d", deviceState));
+ if (deviceState & KUsbAlternateSetting)
+ {
+ dUsbc->ProcessAlternateSetting(deviceState);
+ }
+ else
+ {
+ dUsbc->ProcessDeviceState(deviceState);
+ // Send Status to EP0 buffer.
+ // Before the client calls RDevUsbcScClient::FinalizeInterface(),
+ // this function might be called.
+ // So we add a guard for dUsbc->iBuffers
+ if( dUsbc->iBuffers )
+ {
+ dUsbc->iBuffers[dUsbc->iEP0OutBuff].SendEp0StatusPacket(deviceState);
+ }
+ }
+
+ // Only queue if userside is interested
+ if (dUsbc->iDeviceStatusNeeded)
+ {
+ dUsbc->iStatusFifo->AddStatusToQueue(deviceState);
+ const TInt reqNo = (TInt) RDevUsbcScClient::ERequestAlternateDeviceStatusNotify;
+ if (dUsbc->AlternateDeviceStateTestComplete())
+ Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], 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 DLddUsbcScChannel::OtgFeatureChangeCallback(TAny* aDLddUsbcScChannel)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback"));
+ DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel;
+ if (dUsbc->iChannelClosing)
+ return;
+
+ TUint8 features;
+ // No return value check. Assume OTG always supported here
+ dUsbc->iController->GetCurrentOtgFeatures(features);
+
+ const TInt reqNo = (TInt) RDevUsbcScClient::ERequestOtgFeaturesNotify;
+ if (dUsbc->iRequestStatus[reqNo])
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback Notify status"));
+ TInt r = Kern::ThreadRawWrite(dUsbc->iClient, dUsbc->iOtgFeatureChangePtr,
+ &features, sizeof(TUint8), dUsbc->iClient);
+ if (r != KErrNone)
+ dUsbc->PanicClientThread(r);
+ Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], r);
+ dUsbc->iOtgFeatureChangePtr = NULL;
+ }
+ }
+
+
+//
+// SelectAlternateSetting
+//
+
+TInt DLddUsbcScChannel::SelectAlternateSetting(TUint aAlternateSetting)
+ {
+ TUsbcScEndpoint* ep;
+
+ // First, find the alt setting record, which corresponds to the alt setting number.
+ TUsbcScAlternateSetting* alternateSettingListRec;
+ if(iAlternateSettingList)
+ {
+ for (alternateSettingListRec = iAlternateSettingList->iHead; alternateSettingListRec; alternateSettingListRec = alternateSettingListRec->iNext)
+ if (alternateSettingListRec->iSetting == aAlternateSetting)
+ {
+ // Record has been located.
+
+ // Update current ep setting vars
+ iEndpoint = alternateSettingListRec->iEndpoint;
+ iNumberOfEndpoints = alternateSettingListRec->iNumberOfEndpoints;
+
+
+
+ // Reset buffers for new ep set
+ for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
+ {
+ ep = alternateSettingListRec->iEndpoint[i];
+ if (ep!=NULL)
+ ep->StartBuffer(); // Buffer::StartEndpoint(...) sets the necessary parameters to the buffer, for use for a perticular endpoint.
+ }
+
+ return KErrNone;
+ }
+ }
+ return KErrGeneral;
+ }
+
+/* The user calls this to move into the next alternate setting. After this call, it is assumed the user wants to
+Transmit using endpoints belonging to this alternate Setting. Writes to the IN endpoints will be allowed until
+the host changed the alternate setting again
+Returns a 32 int with the top 16 bits represents the sequance, and the botten, the alternatre setting no.
+*/
+TInt32 DLddUsbcScChannel::StartNextInAlternateSetting()
+ {
+ iUserKnowsAltSetting = ETrue;
+ return iAsSeq<<16 | iAlternateSetting;
+ }
+
+
+//
+// EpFromAlternateSetting
+//
+
+TInt DLddUsbcScChannel::EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint)
+ {
+ TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iHead;
+ 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 KErrNotFound;
+ }
+ }
+ alternateSettingListRec = alternateSettingListRec->iNext;
+ }
+ __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no aAlternateSetting %d found", aAlternateSetting));
+ return KErrNotFound;
+ }
+
+//
+// ProcessAlternateSetting
+//
+
+TInt DLddUsbcScChannel::ProcessAlternateSetting(TUint aAlternateSetting)
+ {
+
+ TUint newSetting = aAlternateSetting&(~KUsbAlternateSetting);
+ __KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting 0x%08x selecting alternate setting 0x%08x", aAlternateSetting, newSetting));
+ iUserKnowsAltSetting=EFalse;
+ iAlternateSetting = newSetting;
+ iAsSeq++;
+
+ ResetInterface(KErrUsbInterfaceChange); // kill any outstanding IN transfers
+
+ TInt r = SelectAlternateSetting(newSetting);
+ if (r != KErrNone)
+ return r;
+
+
+ StartEpReads();
+ return KErrNone;
+ }
+
+
+//
+// ProcessDeviceState
+//
+// Called from StatusChangeCallback.
+
+TInt DLddUsbcScChannel::ProcessDeviceState(TUsbcDeviceState aDeviceState)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::ProcessDeviceState(%d -> %d)", iDeviceState, aDeviceState));
+ if (iDeviceState == aDeviceState)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" No state change => nothing to be done."));
+ return KErrNone;
+ }
+ if (iDeviceState == UsbShai::EUsbPeripheralStateSuspended)
+ {
+ __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 == UsbShai::EUsbPeripheralStateConfigured);
+ TBool deconfigured = EFalse;
+ TInt cancellationCode = KErrNone;
+ if (aDeviceState == UsbShai::EUsbPeripheralStateSuspended)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf(" Suspending..."));
+ iOldDeviceState = iDeviceState;
+ // Put PSL into low power mode here
+ }
+ else
+ {
+ deconfigured = (iDeviceState == UsbShai::EUsbPeripheralStateConfigured &&
+ aDeviceState != UsbShai::EUsbPeripheralStateConfigured);
+ if (iDeviceState == UsbShai::EUsbPeripheralStateConfigured)
+ {
+ if (aDeviceState == UsbShai::EUsbPeripheralStateUndefined)
+ cancellationCode = KErrUsbCableDetached;
+ else if (aDeviceState == UsbShai::EUsbPeripheralStateAddress)
+ cancellationCode = KErrUsbDeviceNotConfigured;
+ else if (aDeviceState == UsbShai::EUsbPeripheralStateDefault)
+ cancellationCode = KErrUsbDeviceBusReset;
+ else
+ cancellationCode = KErrUsbDeviceNotConfigured;
+ }
+ }
+ 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)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChannel:: Reumerated!"));
+ // Select main interface & latch in new endpoint set
+ SelectAlternateSetting(0);
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChannel:: StartReads!"));
+ StartEpReads();
+ }
+ }
+
+ const TInt reqNo = (TInt) RDevUsbcScClient::ERequestReEnumerate;
+ if (renumerateState && iRequestStatus[reqNo])
+ {
+ // This lot must be done if we are reenumerated
+ Kern::RequestComplete(iClient, iRequestStatus[reqNo], KErrNone);
+ }
+
+ return KErrNone;
+ }
+
+
+TBool DLddUsbcScChannel::AlternateDeviceStateTestComplete()
+ {
+ TBool completeNow = EFalse;
+ const TInt reqNo = (TInt) RDevUsbcScClient::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"));
+ // set client descriptor length to zero
+ TInt r = Kern::ThreadRawWrite(iClient, iStatusChangePtr, &deviceState,
+ sizeof(TUint32), iClient);
+ if (r != KErrNone)
+ PanicClientThread(r);
+ iStatusChangePtr = NULL;
+ }
+ }
+ return completeNow;
+ }
+
+
+void DLddUsbcScChannel::DeConfigure(TInt aErrorCode)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DeConfigure()"));
+ // Called after deconfiguration. Cancels transfers on all endpoints.
+ ResetInterface(aErrorCode);
+ // Cancel the endpoint status notify request if it is outstanding.
+ const TInt KEpNotReq = RDevUsbcScClient::ERequestEndpointStatusNotify;
+ if (iRequestStatus[KEpNotReq])
+ {
+ CancelNotifyEndpointStatus();
+ Kern::RequestComplete(iClient, iRequestStatus[KEpNotReq], aErrorCode);
+ }
+ // We have to reset the alternate setting number when the config goes away.
+ SelectAlternateSetting(0);
+ iAlternateSetting = 0;
+ }
+
+
+void DLddUsbcScChannel::StartEpReads()
+ {
+ // Queued after enumeration. Starts reads on all endpoints.
+ // The endpoint itself decides if it can do a read
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 1"));
+
+ TInt i;
+ TInt8 needsPacket;
+
+ for (i=0; i<iNumBuffers; i++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 2 %d",i));
+
+ needsPacket = iBuffers[i].iNeedsPacket;
+ if (needsPacket)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 3"));
+ iBuffers[i].UpdateBufferList(0,0,(needsPacket==TUsbcScBuffer::KEpIsStarting));
+ }
+ }
+
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 4"));
+
+ // now update ep0
+ iBuffers[iEP0OutBuff].Ep0CancelLddRead();
+ iBuffers[iEP0OutBuff].UpdateBufferList(0,0);
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 5"));
+
+ }
+
+
+void DLddUsbcScChannel::ResetInterface(TInt aErrorCode)
+ {
+ if (!iValidInterface && !iOwnsDeviceControl)
+ return;
+
+ TInt i;
+ for (i=0; i<iNumBuffers; i++)
+ {
+ iBuffers[i].iNeedsPacket=TUsbcScBuffer::KNoEpAssigned;
+ }
+
+ TUsbcScBuffer* buffer;
+
+ for (i = 1; i <= iNumberOfEndpoints; i++)
+ {
+ // Firstly, cancel ('garbge collect') any stale reads/writes into PIL.
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i));
+ iEndpoint[i]->AbortTransfer();
+
+ // All OUT endpoints need a packet sent, to indicate the termination of the current ep 'pipe'.
+ // This will complete any current read, or will be read later.
+ // All IN endpoints must be simply cancelled, including anything queued.
+ // Ep0 operates outside alt settings, and so we don't cancel anything.
+
+ buffer=iEndpoint[i]->GetBuffer();
+ if (buffer->iDirection==KUsbcScIn)
+ {
+ buffer->iStatusList.Complete(KErrCancel); //aErrorCode
+ buffer->iStatusList.CancelQueued(); //aErrorCode
+ }
+ else
+ buffer->iNeedsPacket=TUsbcScBuffer::KEpIsEnding; // We will send a packet on re-start, which doubles as a 'cancel'
+ // for the old alt setting.
+ }
+ }
+
+
+
+void DLddUsbcScChannel::EmergencyCompleteDfc(TAny* aDLddUsbcScChannel)
+ {
+ ((DLddUsbcScChannel*) aDLddUsbcScChannel)->DoEmergencyComplete();
+ }
+
+TInt DLddUsbcScChannel::DoEmergencyComplete()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DoEmergencyComplete"));
+ // cancel any pending DFCs
+ // complete all client requests
+
+ TUsbcScBuffer* buffer;
+ TInt i;
+ // Complete EP0 request
+
+ TInt direction=iEp0Endpoint->iRequestCallbackInfo->iTransferDir;
+ if (direction==UsbShai::EControllerWrite)
+ {
+ iBuffers[iEP0InBuff].iStatusList.CancelQueued();
+ iBuffers[iEP0InBuff].iStatusList.Complete(KErrDisconnected);
+ }
+ else if (direction==UsbShai::EControllerRead)
+ {
+ iBuffers[iEP0OutBuff].iStatusList.CancelQueued();
+ iBuffers[iEP0OutBuff].iStatusList.Complete(KErrDisconnected);
+ }
+
+ // Complete other Eps request
+ for (i = 1; i <= iNumberOfEndpoints; i++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i));
+ buffer=iEndpoint[i]->GetBuffer();
+ buffer->iStatusList.CancelQueued();
+ buffer->iStatusList.Complete(KErrDisconnected);
+ }
+
+ // Complete remaining requests
+
+ for (TInt i = 0; i < KUsbcMaxRequests; i++)
+ {
+ if (iRequestStatus[i])
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Complete request 0x%x", iRequestStatus[i]));
+ Kern::RequestComplete(iClient, iRequestStatus[i], KErrDisconnected);
+ }
+ }
+ iStatusCallbackInfo.Cancel();
+ iEndpointStatusCallbackInfo.Cancel();
+ iOtgFeatureCallbackInfo.Cancel();
+
+ return KErrNone;
+ }
+
+
+void DLddUsbcScChannel::PanicClientThread(TInt aReason)
+ {
+ Kern::ThreadKill(iClient, EExitPanic, aReason, KUsbLDDKillCat);
+ }
+
+// End DLddUsbcScChannel
+
+/*****************************************************************************\
+* TUsbcScEndpoint *
+* *
+* *
+* *
+\*****************************************************************************/
+
+
+// Constructor
+TUsbcScEndpoint::TUsbcScEndpoint(DLddUsbcScChannel* aLDD, DUsbClientController* aController,
+ const TUsbcScEndpointInfo* aEndpointInfo, TInt aEndpointNum
+ )
+ : iRequestCallbackInfo(NULL),
+ iController(aController),
+ iEndpointInfo(*aEndpointInfo),
+ iClientReadPending(EFalse),
+ iClientWritePending(EFalse),
+ iEndpointNumber(aEndpointNum),
+ iRealEpNumber(-1),
+ iLdd(aLDD),
+ iError(KErrNone),
+ iBytesTransferred(0),
+ iBuffer(NULL)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::TUsbcScEndpoint"));
+ }
+
+
+TInt TUsbcScEndpoint::Construct()
+ {
+ __KTRACE_OPT(KUSB,Kern::Printf("TUsbcScEndpoint::TUsbcScEndpoint iEndpointNumber %d\n",iEndpointNumber));
+
+ iRequestCallbackInfo = new TUsbcRequestCallback(iLdd,
+ iEndpointNumber,
+ (iEndpointNumber==0)?DLddUsbcScChannel::RequestCallbackEp0:TUsbcScEndpoint::RequestCallback,
+ (iEndpointNumber==0)? (TAny*) iLdd: (TAny*) this,
+ iLdd->iDfcQ,
+ KUsbRequestCallbackPriority);
+
+ return (iRequestCallbackInfo == NULL)?KErrNoMemory:KErrNone;
+ }
+
+
+TUsbcScEndpoint::~TUsbcScEndpoint()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::~TUsbcScEndpoint(%d)", iEndpointNumber));
+ AbortTransfer();
+ delete iRequestCallbackInfo;
+ }
+
+// This is called by the PIL, on return from a read or write.
+// Inturn it calls either the read or write function for that buffer.
+
+void TUsbcScEndpoint::RequestCallback(TAny* aTUsbcScEndpoint)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::RequestCallback"));
+
+ if (((TUsbcScEndpoint*)aTUsbcScEndpoint)->iLdd->ChannelClosing())
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Channel Closing: Completion not accepted!"));
+ return;
+ }
+
+ switch (((TUsbcScEndpoint*) aTUsbcScEndpoint)->iRequestCallbackInfo->iTransferDir)
+ {
+ case UsbShai::EControllerWrite:
+ ((TUsbcScEndpoint*) aTUsbcScEndpoint)->iBuffer->CompleteWrite();
+ return;
+ case UsbShai::EControllerRead:
+ ((TUsbcScEndpoint*) aTUsbcScEndpoint)->iBuffer->CompleteRead();
+ return;
+ default:
+ Kern::Printf("TUsbcScEndpoint::RequestCallback - Unexpected compleation direction %d",((TUsbcScEndpoint*) aTUsbcScEndpoint)->iRequestCallbackInfo->iTransferDir);
+ Kern::Fault("TUsbcScEndpoint::RequestCallback", __LINE__);
+ }
+ }
+
+
+/*
+
+This is used to tidy up cancel calls into the PIL, regardless of them being reads or writes
+
+*/
+
+void TUsbcScEndpoint::AbortTransfer()
+ {
+ if (!iLdd->iRealizeCalled)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::AbortTransfer Ep# %d Real Ep # %d - N.R.",iEndpointNumber, iRealEpNumber));
+ return;
+ }
+ else
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::AbortTransfer Ep# %d Real Ep # %d",iEndpointNumber, iRealEpNumber));
+ }
+
+
+ if (iBuffer && (iBuffer->iStatusList.iState) || (!iRealEpNumber))
+ {
+ if (iRequestCallbackInfo->iTransferDir==UsbShai::EControllerWrite)
+ iController->CancelWriteBuffer(iLdd, iRealEpNumber);
+ else if (iRequestCallbackInfo->iTransferDir==UsbShai::EControllerRead)
+ iController->CancelReadBuffer(iLdd, iRealEpNumber);
+ else
+ {
+ if (iEndpointNumber!=0) // endpoint zero starts off not sent in any direction, then keeps changing.
+ {
+ __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: Invalid Direction %d on (%d,%d)!\n",iRequestCallbackInfo->iTransferDir,iEndpointNumber, iRealEpNumber));
+ }
+ else
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("\nTUsbcScEndpoint::AbortTransfer Can't stop direction %d on (%d,%d)!\n",iRequestCallbackInfo->iTransferDir,iEndpointNumber, iRealEpNumber));
+ }
+ }
+ }
+ else if (!iBuffer)
+ {
+ __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: iBuffer is NULL on (%d,%d)\n",iEndpointNumber, iRealEpNumber));
+ return;
+ }
+
+ if (iRequestCallbackInfo)
+ iRequestCallbackInfo->iDfc.Cancel();
+ else
+ {
+ __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: iRequestCallbackInfo is NULL\n"));
+ }
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint Done."));
+ }
+
+// End TUsbcScEndpoint
+
+
+/*****************************************************************************\
+* TUsbcScAlternateSettingList *
+* *
+* *
+* *
+\*****************************************************************************/
+
+
+TUsbcScAlternateSetting::TUsbcScAlternateSetting()
+ : iNext(NULL),
+ iPrevious(NULL),
+ iNumberOfEndpoints(0),
+ iSetting(0)
+ {
+ for (TInt i = 0; i <= KMaxEndpointsPerClient; i++)
+ {
+ iEndpoint[i] = NULL;
+ }
+ }
+
+
+TUsbcScAlternateSetting::~TUsbcScAlternateSetting()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScAlternateSetting::~TUsbcScAlternateSetting()"));
+ for (TInt i = 0; i <= KMaxEndpointsPerClient; i++)
+ {
+ delete iEndpoint[i];
+ }
+ }
+
+// End TUsbcScAlternateSettingList
+
+
+
+TUsbcScAlternateSettingList::TUsbcScAlternateSettingList()
+ : iHead(NULL),
+ iTail(NULL)
+ {
+ }
+
+TUsbcScAlternateSettingList::~TUsbcScAlternateSettingList()
+ {
+ }
+
+
+
+/*****************************************************************************\
+* TUsbcDeviceStatusQueue *
+* *
+* *
+* *
+\*****************************************************************************/
+
+
+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;
+ }
+
+// End TUsbcDeviceStatusQueue
+
+//---
+