--- a/kernel/eka/debug/crashMonitor/inc/scmdatasave.h Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/debug/crashMonitor/inc/scmdatasave.h Wed Apr 14 17:22:59 2010 +0300
@@ -43,6 +43,7 @@
_LIT8(KKernelHeapChunkName, "ekern.exe::SvHeap");
+_LIT8(KKernelProcessName, "ekern.exe");
/**
--- a/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -978,11 +978,11 @@
{
LOG_CONTEXT
- //Get Chunk object container
- DObjectCon* objectContainer = Kern::Containers()[EChunk];
+ //Get process object container
+ DObjectCon* objectContainer = Kern::Containers()[EProcess];
if(objectContainer == NULL)
{
- CLTRACE("\tFailed to get object container for the chunks");
+ CLTRACE("\tFailed to get object container for the processes");
return KErrNotFound;
}
@@ -995,7 +995,39 @@
TInt numObjects = objectContainer->Count();
- for(TInt cnt = 0; cnt< numObjects; cnt ++)
+ DProcess* kernelProcess = NULL;
+ for(TInt cnt = 0; cnt < numObjects; cnt ++)
+ {
+ DProcess* candidateProcess = (DProcess*)(*objectContainer)[cnt];
+
+ //Get the objects name
+ TBuf8<KMaxKernelName> name;
+ candidateProcess->TraceAppendFullName(name,EFalse);
+ if(name == KKernelProcessName)
+ {
+ kernelProcess = candidateProcess;
+ }
+ }
+ if (!kernelProcess)
+ return KErrNotFound;
+
+ //Get chunk object container
+ objectContainer = Kern::Containers()[EChunk];
+ if(objectContainer == NULL)
+ {
+ CLTRACE("\tFailed to get object container for the chunks");
+ return KErrNotFound;
+ }
+
+ //Must check the mutex on this is ok otherwise the data will be in an inconsistent state
+ if(objectContainer->Lock()->iHoldCount)
+ {
+ CLTRACE("\tChunk Container is in an inconsistant state");
+ return KErrCorrupt;
+ }
+
+ numObjects = objectContainer->Count();
+ for(TInt cnt = 0; cnt < numObjects; cnt ++)
{
DChunk* candidateHeapChunk = (DChunk*)(*objectContainer)[cnt];
@@ -1005,14 +1037,8 @@
if(name == KKernelHeapChunkName)
{
- #ifndef __MEMMODEL_FLEXIBLE__
- aHeapLocation = (TInt32)candidateHeapChunk->iBase;
- #else
- aHeapLocation = (TInt32)candidateHeapChunk->iFixedBase;
- #endif
-
- aHeapSize = candidateHeapChunk->iSize;
-
+ aHeapLocation = (TInt32)candidateHeapChunk->Base(kernelProcess);
+ aHeapSize = candidateHeapChunk->iSize;
return KErrNone;
}
}
--- a/kernel/eka/drivers/dma/dmapil.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/drivers/dma/dmapil.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -491,20 +491,20 @@
*iChannel.iNullPtr = iFirstHdr;
iChannel.iNullPtr = &(iLastHdr->iNext);
iChannel.DoQueue(*this);
+ __DMA_INVARIANT();
iChannel.Signal();
}
else
{
// Someone is cancelling all requests...
req_count = --iChannel.iQueuedRequests;
+ __DMA_INVARIANT();
iChannel.Signal();
if (req_count == 0)
{
iChannel.QueuedRequestCountChanged();
}
}
-
- __DMA_INVARIANT();
}
EXPORT_C TInt DDmaRequest::ExpandDesList(TInt aCount)
@@ -574,7 +574,15 @@
void DDmaRequest::Invariant()
{
- iChannel.Wait();
+ // This invariant may be called either with,
+ // or without the channel lock already held
+ TBool channelLockAquired=EFalse;
+ if(!iChannel.iLock.HeldByCurrentThread())
+ {
+ iChannel.Wait();
+ channelLockAquired = ETrue;
+ }
+
__DMA_ASSERTD(iChannel.IsOpened());
__DMA_ASSERTD(0 <= iMaxTransferSize);
__DMA_ASSERTD(0 <= iDesCount && iDesCount <= iChannel.iMaxDesCount);
@@ -588,7 +596,11 @@
__DMA_ASSERTD(iChannel.iController->IsValidHdr(iFirstHdr));
__DMA_ASSERTD(iChannel.iController->IsValidHdr(iLastHdr));
}
- iChannel.Signal();
+
+ if(channelLockAquired)
+ {
+ iChannel.Signal();
+ }
}
#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,12 @@
+# component name "USB Descriptors"
+
+component base_drivers_usbdescriptors
+
+source \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdescriptors
+
+binary \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdescriptors all
+
+notes_source \component_defs\release.src
+
+ipr E
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/bld.inf Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 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/usbho/usbdescriptors/bld.inf
+//
+//
+
+/**
+ @file
+*/
+
+
+PRJ_PLATFORMS
+
+ARMV5 ARMV5SMP
+
+
+PRJ_MMPFILES
+
+#ifndef GCCXML
+#if defined(GENERIC_MARM) || !defined(WINS) || defined(GENERIC_X86)
+#if !defined(MARM_THUMB) && !defined(MARM_ARMI)
+
+#if !defined(WINS)
+#if !defined(X86)
+#if defined(SYMBIAN_ENABLE_USB_OTG_HOST)
+
+usbdescriptors
+
+#endif
+#endif
+#endif
+
+#endif
+#endif
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,370 @@
+// Copyright (c) 2007-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.
+//
+// Description:
+// Symbian USBDI Descriptor Parsing Framework.
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <d32usbdescriptors.h>
+#include "usbdescutils.h"
+
+
+// ---------------------
+// UsbDescriptorParser
+// ---------------------
+
+/**
+The main parsing function of the USB descriptor parsing framework.
+
+This will perform a best effort parse of a USB descriptor tree. It is best effort in the
+fact that upon encountering a form of syntatic corruption in the source data it will error
+the parse attempt, but also return the incomplete descriptor tree up to the parsing error.
+
+@param aUsbDes The source data that will be parsed.
+@param aDesc The pointer that will be updated to the top-level descriptor.
+
+@return KErrNone if successful, a system-wide error code otherwise.
+
+@publishedPartner
+@prototype
+*/
+EXPORT_C /*static*/ TInt UsbDescriptorParser::Parse(const TDesC8& aUsbDes, TUsbGenericDescriptor*& aDesc)
+ {
+ TInt ret = KErrNone;
+ aDesc = NULL;
+ TPtrC8 des(aUsbDes);
+
+ // First we must find the top level descriptor (the one we will return to the caller).
+ TRAP(ret, aDesc = FindParserAndParseAndCheckL(des, NULL));
+ if(ret == KErrNone && !aDesc)
+ {
+ ret = KErrNotFound;
+ }
+
+ if(ret == KErrNone)
+ {
+ // Now we have a top level descriptor - we now try to build up the descriptor
+ // tree if there are more descriptors available.
+ TRAP(ret, ParseDescriptorTreeL(des, *aDesc));
+ }
+
+ // Ensure that all the data has been parsed if successful.
+ if(ret == KErrNone && des.Length() > 0)
+ {
+ // If no parser was found for some data then we should have been errored with KErrNotFound.
+ __ASSERT_DEBUG(EFalse, UsbDescFault(UsbdiFaults::EUsbDescSuccessButDataLeftUnparsed));
+ ret = KErrUnknown;
+ }
+
+ return ret;
+ }
+
+/**
+The function to register a custom parsing routine in the USB descriptor parser framework.
+
+The routine is registered locally to the current thread, and so if an application wishes
+to perform the same custom parsing in multiple threads, it must call this function with
+the appropriate routine in each thread context.
+
+If the custom routine becomes unapplicable after being registered, the application may
+unregister it using the UsbDescriptorParser::UnregisterCustomParser function.
+@see UsbDescriptorParser::UnregisterCustomParser
+
+@param aParserFunc The routine which will be added to the USB descriptor parsing framework.
+
+@publishedPartner
+@prototype
+*/
+EXPORT_C /*static*/ void UsbDescriptorParser::RegisterCustomParserL(TUsbDescriptorParserL aParserFunc)
+ {
+ TBool newlyCreatedList = EFalse;
+ CUsbCustomDescriptorParserList* parserList = static_cast<CUsbCustomDescriptorParserList*>(Dll::Tls());
+ if(!parserList)
+ {
+ parserList = CUsbCustomDescriptorParserList::NewL();
+ newlyCreatedList = ETrue;
+ CleanupStack::PushL(parserList);
+ }
+
+ parserList->RegisterParserL(aParserFunc);
+
+ if(newlyCreatedList)
+ {
+ Dll::SetTls(parserList);
+ CleanupStack::Pop(parserList);
+ }
+ }
+
+/**
+The function to unregister a custom parsing routine in the USB descriptor parser framework.
+
+This routine will only unregister the routine from the current thread context. If the routine
+is registered in multiple threads and it is no longer wanted in any thread, an application
+must call this function in each thread context that the routine is registered.
+
+It is safe to call this function even if RegisterCustomParserL has never been called successfully.
+
+@see UsbDescriptorParser::RegisterCustomParserL
+
+@param aParserFunc The routine which will be removed from the USB descriptor parsing framework.
+
+@publishedPartner
+@prototype
+*/
+EXPORT_C /*static*/ void UsbDescriptorParser::UnregisterCustomParser(TUsbDescriptorParserL aParserFunc)
+ {
+ CUsbCustomDescriptorParserList* parserList = static_cast<CUsbCustomDescriptorParserList*>(Dll::Tls());
+ if(parserList)
+ {
+ parserList->UnregisterParser(aParserFunc);
+ if(parserList->NumOfRegisteredParsers() <= 0)
+ {
+ Dll::FreeTls();
+ delete parserList;
+ }
+ }
+ }
+
+/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseAndCheckL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc)
+ {
+ TUsbGenericDescriptor* ret = FindParserAndParseL(aUsbDes, aPreviousDesc);
+ // We need to ensure that the parsers have correctly initialised the USB descriptor objects.
+ // It is important that we check as it is possible that a custom parser did the parsing.
+ __ASSERT_ALWAYS(!ret || (!ret->iParent && !ret->iFirstChild && !ret->iNextPeer),
+ UsbDescPanic(UsbdiPanics::EUsbDescNonNullPointersAfterParsing));
+ return ret;
+ }
+
+// Utility macro to tidy up the parsing routine.
+#define RETURN_IF_PARSEDL(aRet, aParserL, aUsbDes, aPreviousDesc)\
+ {\
+ aRet = aParserL(aUsbDes, aPreviousDesc);\
+ if(aRet)\
+ {\
+ return aRet;\
+ }\
+ }
+
+/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc)
+ {
+ // Special termination case.
+ if(aUsbDes.Length() == 0)
+ {
+ return NULL;
+ }
+
+ TUsbGenericDescriptor* des;
+
+ // Try the default parsing routines.
+ RETURN_IF_PARSEDL(des, TUsbDeviceDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbDeviceQualifierDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbConfigurationDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbOtherSpeedDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbInterfaceAssociationDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbInterfaceDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbEndpointDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbOTGDescriptor::ParseL, aUsbDes, aPreviousDesc);
+ RETURN_IF_PARSEDL(des, TUsbStringDescriptor::ParseL, aUsbDes, aPreviousDesc);
+
+ // Then we try the custom parsers that have been registered.
+ const CUsbCustomDescriptorParserList* parserList = static_cast<const CUsbCustomDescriptorParserList*>(Dll::Tls());
+ if(parserList)
+ {
+ TInt numOfParsers = parserList->NumOfRegisteredParsers()-1;
+ for(TInt index=0; index<numOfParsers; ++index)
+ {
+ TUsbDescriptorParserL parserL = parserList->RegisteredParser(index);
+ RETURN_IF_PARSEDL(des, parserL, aUsbDes, aPreviousDesc);
+ }
+ }
+
+ // Then we try the unknown descriptor parser.
+ RETURN_IF_PARSEDL(des, UnknownUsbDescriptorParserL, aUsbDes, aPreviousDesc);
+
+ // Otherwise we haven't found anybody to parse the binary data.
+ User::Leave(KErrNotFound); // inform caller that there is no parser for the data.
+ return NULL;
+ }
+
+/*static*/ void UsbDescriptorParser::ParseDescriptorTreeL(TPtrC8& aUsbDes, TUsbGenericDescriptor& aPreviousDesc)
+ {
+ TUsbGenericDescriptor* desc = &aPreviousDesc;
+ while(desc)
+ {
+ TUsbGenericDescriptor* preDesc = desc;
+ desc = FindParserAndParseAndCheckL(aUsbDes, desc);
+ if(desc)
+ {
+ CleanupStack::PushL(desc);
+ BuildTreeL(*desc, *preDesc);
+ CleanupStack::Pop(desc);
+ }
+ }
+ }
+
+/*static*/ void UsbDescriptorParser::BuildTreeL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aPreviousDesc)
+ {
+ // We assume that the new descriptor has been properly initialised with NULL pointers.
+ __ASSERT_DEBUG(!aNewDesc.iFirstChild && !aNewDesc.iNextPeer && !aNewDesc.iParent,
+ UsbDescFault(UsbdiFaults::EUsbDescTreePointersAlreadySet));
+
+ // Find first "top" parent claiming this new descriptor as a child.
+ TUsbGenericDescriptor* parent = &aPreviousDesc;
+ TUsbGenericDescriptor* topLevel = &aPreviousDesc;
+ while(parent)
+ {
+ if(aNewDesc.IsParent(*parent) || parent->IsChild(aNewDesc))
+ {
+ break; // we have found a parent.
+ }
+ topLevel = parent; // Save the current one for use if we cannot find a parent
+ parent = parent->iParent; // Scroll back up the tree.
+ }
+ __ASSERT_DEBUG(topLevel, UsbDescFault(UsbdiFaults::EUsbDescNoTopLevelDescriptorFound));
+
+ if(parent)
+ {
+ // We should be able to place the descriptor directly as a child of this descriptor,
+ // however it is not that simple because of IADs (Interface Association Descriptors).
+ // The ECN states "All of the interface numbers in the set of associated interfaces must be
+ // contiguous" meaning that if an IAD has two interfaces starting at 1 then the configuration
+ // bundle may have interface descriptors in '1 then 3 then 2' order. As such we need to be able
+ // to go backwards to find the most suitable binding. The general way for doing this is to
+ // find the right-most, lowest descriptor that descriptor considers a parent.
+ // Where the tree is arranged with peers horizontally linked left to
+ // right, with children linked vertically top to bottom.
+ TUsbGenericDescriptor& suitableParent = FindSuitableParentL(aNewDesc, *parent);
+
+ TUsbGenericDescriptor* peer = suitableParent.iFirstChild;
+ if(peer)
+ {
+ TUsbGenericDescriptor* lastPeer;
+ do
+ {
+ lastPeer = peer;
+ peer = peer->iNextPeer;
+ }
+ while(peer);
+ lastPeer->iNextPeer = &aNewDesc;
+ }
+ else
+ {
+ // we are the first child so just update.
+ suitableParent.iFirstChild = &aNewDesc;
+ }
+ aNewDesc.iParent = &suitableParent;
+ }
+ else if(aNewDesc.IsPeer(*topLevel) || topLevel->IsPeer(aNewDesc))
+ {
+ // There is no explicit parent in the tree so, we may just have a group of top-level peers
+ // in the bundle. If the previous descriptor is a peer then we shall just tag on its tier.
+ TUsbGenericDescriptor* lastPeer;
+ TUsbGenericDescriptor* peer = topLevel;
+ do
+ {
+ lastPeer = peer;
+ peer = peer->iNextPeer;
+ }
+ while(peer);
+ lastPeer->iNextPeer = &aNewDesc;
+ }
+ else
+ {
+ // The descriptor could not be bound into the tree, indicating that the bundle of descriptors
+ // is unvalid.
+ User::Leave(KErrUsbBadDescriptorTopology);
+ }
+ }
+
+/*static*/ TUsbGenericDescriptor& UsbDescriptorParser::FindSuitableParentL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aTopParent)
+ {
+ // This implements the algorithm to search down from the top parent found in the tree to the right most, lowest descriptor
+ // that will accept the new descriptor as a child.
+
+ TUsbGenericDescriptor* bestMatch = &aTopParent;
+
+ TUsbGenericDescriptor* desc = aTopParent.iFirstChild;
+ if(desc)
+ {
+ // Do a depth first search.
+ FOREVER
+ {
+ // First see if the descriptor is suitable.
+ __ASSERT_DEBUG(desc, UsbDescFault(UsbdiFaults::EUsbDescRunOffTree));
+ if(aNewDesc.IsParent(*desc) || desc->IsChild(aNewDesc))
+ {
+ bestMatch = desc;
+ }
+ // Now walk to the next point in the tree.
+ if(desc->iFirstChild)
+ {
+ desc = desc->iFirstChild;
+ }
+ else if(desc->iNextPeer)
+ {
+ desc = desc->iNextPeer;
+ }
+ else
+ {
+ // We've run to the end of a bottom tier, so go back up.
+ do
+ {
+ __ASSERT_DEBUG(desc->iParent, UsbDescFault(UsbdiFaults::EUsbDescTreeMemberHasNoParent));
+ desc = desc->iParent;
+ }
+ while(!desc->iNextPeer && desc != &aTopParent);
+ if(desc == &aTopParent)
+ {
+ // This means that we must have got back to the original
+ // parent. So we don't do any more.
+ break;
+ }
+ desc = desc->iNextPeer;
+ }
+ }
+ }
+ return *bestMatch;
+ }
+
+/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::UnknownUsbDescriptorParserL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbGenericDescriptor* unknownDes = NULL;
+
+ const TInt KMinUnknownDesLength = 2; // Length and type fields
+ if( aUsbDes.Length() >= KMinUnknownDesLength)
+ {
+ // We require unknown descriptors to have at least the length and type fields.
+ // Any more exotic descriptors should have a custom parser for the framework to use.
+ TUint8 unknownDesLen = aUsbDes[TUsbGenericDescriptor::KbLengthOffset];
+
+ // Robustness check - check the length field is valid.
+ if(aUsbDes.Length() < unknownDesLen || unknownDesLen < KMinUnknownDesLength)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ unknownDes = new(ELeave) TUsbGenericDescriptor;
+ // Set the standard fields
+ unknownDes->ibLength = unknownDesLen;
+ unknownDes->ibDescriptorType = aUsbDes[TUsbGenericDescriptor::KbDescriptorTypeOffset] ;
+ // Set the blob appropriately
+ unknownDes->iBlob.Set(aUsbDes.Left(unknownDesLen));
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(unknownDesLen));
+ }
+
+ return unknownDes;
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,1356 @@
+// Copyright (c) 2007-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.
+//
+// Description:
+// Symbian USBDI Descriptors Parsing Routines.
+//
+//
+
+/**
+ @file
+ @publishedPartner
+*/
+
+#include <d32usbdescriptors.h>
+#include "usbdescutils.h"
+
+
+// ----------------
+// TUsbGenericDescriptor
+// ----------------
+
+EXPORT_C TUsbGenericDescriptor::TUsbGenericDescriptor()
+ : iRecognisedAndParsed(EUnrecognised)
+ , iNextPeer(NULL)
+ , iFirstChild(NULL)
+ , iParent(NULL)
+ {
+ }
+
+/**
+Deletes all child and peer descriptors. Does not delete this descriptor, the caller is responsible for
+doing this separately.
+*/
+EXPORT_C void TUsbGenericDescriptor::DestroyTree()
+ {
+ // Store the tree pointers
+ TUsbGenericDescriptor* child = this->iFirstChild;
+ TUsbGenericDescriptor* peer = this->iNextPeer;
+
+ // Now we chop off the tree from the root node, by doing this
+ // we don't need to NULL pointers as we go down (which makes
+ // the iterative algorithm more efficient).
+ this->iFirstChild = NULL;
+ this->iNextPeer = NULL;
+
+ // Now we walk and destroy the tree from the two pointers
+ // we have
+ WalkAndDelete(child);
+ WalkAndDelete(peer);
+ }
+
+void TUsbGenericDescriptor::WalkAndDelete(TUsbGenericDescriptor* aDesc)
+ {
+ if(!aDesc)
+ {
+ return;
+ }
+
+ TUsbGenericDescriptor* topLevel = aDesc->iParent;
+ do
+ {
+ if(aDesc->iFirstChild)
+ {
+ // walk down the tree depth first.
+ aDesc = aDesc->iFirstChild;
+ }
+ else if(aDesc->iNextPeer)
+ {
+ // Walk along each peer at the "bottom"
+ TUsbGenericDescriptor* peer = aDesc->iNextPeer;
+ delete aDesc;
+ aDesc = peer;
+ }
+ else
+ {
+ // End of bottom tier, so we go back up to the parent
+ // and null the first child pointer so we don't go back
+ // down again.
+ TUsbGenericDescriptor* parent = aDesc->iParent;
+ delete aDesc;
+ aDesc = parent;
+ if(aDesc)
+ {
+ aDesc->iFirstChild = NULL;
+ }
+
+ // if we have gone up to the top level for destruction then we don't
+ // do anymore.
+ if(aDesc == topLevel)
+ {
+ break;
+ }
+ }
+ }
+ while(aDesc);
+ }
+
+/**
+Utility method to retrieve a TUint8 value from a given offset in the descriptor.
+@param aOffset The offset in the binary blob at which to retrieve the value.
+@return The value from the descriptor.
+*/
+EXPORT_C TUint8 TUsbGenericDescriptor::TUint8At(TInt aOffset) const
+ {
+ return ParseTUint8(iBlob, aOffset);
+ }
+
+/**
+Utility method to retrieve a TUint16 value from a given offset in the descriptor.
+@param aOffset The offset in the binary blob at which to retrieve the value.
+@return The value from the descriptor.
+*/
+EXPORT_C TUint16 TUsbGenericDescriptor::TUint16At(TInt aOffset) const
+ {
+ return ParseTUint16(iBlob, aOffset);
+ }
+
+/**
+Utility method to retrieve a TUint32 value from a given offset in the descriptor.
+@param aOffset The offset in the binary blob at which to retrieve the value.
+@return The value from the descriptor.
+*/
+EXPORT_C TUint32 TUsbGenericDescriptor::TUint32At(TInt aOffset) const
+ {
+ return ParseTUint32(iBlob, aOffset);
+ }
+
+/**
+Assignment operator to fill in the TUsbGenericDescriptor fields from a TUsbGenericDescriptor.
+Note that if a TUsbGenericDescriptor derived class has additional member fields then
+they should define a specialised assignment overload for that type.
+*/
+EXPORT_C TUsbGenericDescriptor& TUsbGenericDescriptor::operator=(const TUsbGenericDescriptor& aDescriptor)
+ {
+ ibLength = aDescriptor.ibLength;
+ ibDescriptorType = aDescriptor.ibDescriptorType;
+ iRecognisedAndParsed = aDescriptor.iRecognisedAndParsed;
+ iNextPeer = aDescriptor.iNextPeer;
+ iFirstChild = aDescriptor.iFirstChild;
+ iParent = aDescriptor.iParent;
+ iBlob.Set(aDescriptor.iBlob);
+ return *this;
+ }
+
+/**
+This function determines whether the given USB descriptor is a parent
+of the descriptor the method is called on. The implementation may be
+specialised for each type of descriptor to ensure the tree is correctly
+built up.
+@param aPotentialRelative The USB descriptor that is being queried to see if it is a parent or peer.
+@return TBool Efalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor
+*/
+/*virtual*/ TBool TUsbGenericDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
+ {
+ // As generic descriptors we consider all other "unknown" descriptors as peers, and
+ // all "known" descriptors as parents of the descriptor.
+ switch(aPotentialParent.ibDescriptorType)
+ {
+ case EDevice:
+ case EConfiguration:
+ case EString:
+ case EInterface:
+ case EEndpoint:
+ case EDeviceQualifier:
+ case EOtherSpeedConfiguration:
+ case EInterfacePower:
+ case EOTG:
+ case EDebug:
+ case EInterfaceAssociation:
+ return ETrue;
+ default:
+ return EFalse;
+ }
+ }
+
+/**
+This function determines whether the given USB descriptor is a peer
+of the descriptor the method is called on. The implementation may be
+specialised for each type of descriptor to ensure the tree is correctly
+built up.
+@param aPotentialPeer The USB descriptor that is being queried to see if it is a peer.
+@return TBool EFalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor
+*/
+/*virtual*/ TBool TUsbGenericDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
+ {
+ // As generic descriptors we are very permissive in binding peers.
+ return ETrue;
+ }
+
+/**
+This function determines whether the given USB descriptor is a child
+of the descriptor the method is called on. The implementation may be
+specialised for each type of descriptor to ensure the tree is correctly
+built up.
+@param aPotentialChild The USB descriptor that is being queried to see if it is a child.
+@return TBool ETrue if the given USB descriptor is a child of this USB descriptor, ETrue if a peer of this descriptor
+*/
+/*virtual*/ TBool TUsbGenericDescriptor::IsChild(TUsbGenericDescriptor& /*aPotentialChild*/)
+ {
+ // We just use the logic in the IsParent.
+ return EFalse;
+ }
+
+/**
+Ensures no memory is leaked if an owned TUsbGenericDescriptor is no longer needed.
+@param aPtr The TUsbGenericDescriptor that is to be cleaned up.
+@internalComponent
+*/
+EXPORT_C /*static*/ void TUsbGenericDescriptor::Cleanup(TAny* aPtr)
+ {
+ TUsbGenericDescriptor* ptr = static_cast<TUsbGenericDescriptor*>(aPtr);
+ ptr->DestroyTree(); // belt and braces really.
+ delete ptr;
+ }
+
+
+// ----------------------
+// TUsbDeviceDescriptor
+// See section 9.6.1 of the USB 2.0 specification.
+// ----------------------
+
+EXPORT_C TUsbDeviceDescriptor::TUsbDeviceDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbDeviceDescriptor* ret = NULL;
+ // Only cast if correctly indentified as device descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EDevice &&
+ aOriginal->ibLength == TUsbDeviceDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbDeviceDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint16 TUsbDeviceDescriptor::USBBcd() const
+ {
+ return ParseTUint16(iBlob, EbcdUSB);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceClass() const
+ {
+ return ParseTUint8(iBlob, EbDeviceClass);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceSubClass() const
+ {
+ return ParseTUint8(iBlob, EbDeviceSubClass);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceProtocol() const
+ {
+ return ParseTUint8(iBlob, EbDeviceProtocol);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::MaxPacketSize0() const
+ {
+ return ParseTUint8(iBlob, EbMaxPacketSize0);
+ }
+
+EXPORT_C TUint16 TUsbDeviceDescriptor::VendorId() const
+ {
+ return ParseTUint16(iBlob, EidVendor);
+ }
+
+EXPORT_C TUint16 TUsbDeviceDescriptor::ProductId() const
+ {
+ return ParseTUint16(iBlob, EidProduct);
+ }
+
+EXPORT_C TUint16 TUsbDeviceDescriptor::DeviceBcd() const
+ {
+ return ParseTUint16(iBlob, EbcdDevice);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::ManufacturerIndex() const
+ {
+ return ParseTUint8(iBlob, EiManufacturer);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::ProductIndex() const
+ {
+ return ParseTUint8(iBlob, EiProduct);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::SerialNumberIndex() const
+ {
+ return ParseTUint8(iBlob, EiSerialNumber);
+ }
+
+EXPORT_C TUint8 TUsbDeviceDescriptor::NumConfigurations() const
+ {
+ return ParseTUint8(iBlob, EbNumConfigurations);
+ }
+
+/**
+The parsing routine for device descriptors.
+Here the previous descriptor parameter is ignored - because logically a device descriptor can be neither a peer
+nor a child.
+
+@internalComponent
+*/
+/*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc)
+ {
+ TUsbDeviceDescriptor* devDes = NULL;
+
+ const TInt KMinDeviceDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinDeviceDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EDevice &&
+ aUsbDes[KbLengthOffset] == TUsbDeviceDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbDeviceDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Robustness check - check that the device descriptor is the first to be parsed.
+ if(aPreviousDesc)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be a device descriptor.
+ devDes = new(ELeave) TUsbDeviceDescriptor;
+ // Set the standard fields
+ devDes->ibLength = TUsbDeviceDescriptor::KSizeInOctets;
+ devDes->ibDescriptorType = EDevice;
+ // Set the blob appropriately
+ devDes->iBlob.Set(aUsbDes.Left(TUsbDeviceDescriptor::KSizeInOctets));
+
+ devDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbDeviceDescriptor::KSizeInOctets));
+ }
+
+ return devDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbDeviceDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
+ {
+ // The device descriptor should only come by itself in a bundle, so must be top-level.
+ return EFalse;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbDeviceDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
+ {
+ // The device descriptor should only come by itself in a bundle, so no other peers.
+ return EFalse;
+ }
+
+
+// ------------------------------
+// TUsbDeviceQualifierDescriptor
+// See section 9.6.2 of the USB 2.0 specification.
+// ------------------------------
+
+EXPORT_C TUsbDeviceQualifierDescriptor::TUsbDeviceQualifierDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbDeviceQualifierDescriptor* ret = NULL;
+ // Only cast if correctly indentified as device qualifier descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EDeviceQualifier &&
+ aOriginal->ibLength == TUsbDeviceQualifierDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbDeviceQualifierDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint16 TUsbDeviceQualifierDescriptor::USBBcd() const
+ {
+ return ParseTUint16(iBlob, EbcdUSB);
+ }
+
+EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceClass() const
+ {
+ return ParseTUint8(iBlob, EbDeviceClass);
+ }
+
+EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceSubClass() const
+ {
+ return ParseTUint8(iBlob, EbDeviceSubClass);
+ }
+
+EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceProtocol() const
+ {
+ return ParseTUint8(iBlob, EbDeviceProtocol);
+ }
+
+EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::MaxPacketSize0() const
+ {
+ return ParseTUint8(iBlob, EbMaxPacketSize0);
+ }
+
+EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::NumConfigurations() const
+ {
+ return ParseTUint8(iBlob, EbNumConfigurations);
+ }
+
+EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::Reserved() const
+ {
+ return ParseTUint8(iBlob, EbReserved);
+ }
+
+/**
+The parsing routine for device qualifier descriptors.
+
+@internalComponent
+*/
+/*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbDeviceQualifierDescriptor* devQualDes = NULL;
+
+ const TInt KMinDevQualDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinDevQualDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EDeviceQualifier &&
+ aUsbDes[KbLengthOffset] == TUsbDeviceQualifierDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbDeviceQualifierDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be a device quialifier descriptor.
+ devQualDes = new(ELeave) TUsbDeviceQualifierDescriptor;
+ // Set the standard fields
+ devQualDes->ibLength = TUsbDeviceQualifierDescriptor::KSizeInOctets;
+ devQualDes->ibDescriptorType = EDeviceQualifier;
+ // Set the blob appropriately
+ devQualDes->iBlob.Set(aUsbDes.Left(TUsbDeviceQualifierDescriptor::KSizeInOctets));
+
+ devQualDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbDeviceQualifierDescriptor::KSizeInOctets));
+ }
+
+ return devQualDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
+ {
+ // Like a device descriptor, they should be top-level.
+ return EFalse;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
+ {
+ // Like a device descriptor, they should come by themselves.
+ return EFalse;
+ }
+
+
+// ----------------------------
+// TUsbConfigurationDescriptor
+// See section 9.6.3 of the USB 2.0 specification.
+// ----------------------------
+
+EXPORT_C TUsbConfigurationDescriptor::TUsbConfigurationDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbConfigurationDescriptor* ret = NULL;
+ // Only cast if correctly indentified as configuration descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EConfiguration &&
+ aOriginal->ibLength == TUsbConfigurationDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbConfigurationDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint16 TUsbConfigurationDescriptor::TotalLength() const
+ {
+ return ParseTUint16(iBlob, EwTotalLength);
+ }
+
+EXPORT_C TUint8 TUsbConfigurationDescriptor::NumInterfaces() const
+ {
+ return ParseTUint8(iBlob, EbNumInterfaces);
+ }
+
+EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationValue() const
+ {
+ return ParseTUint8(iBlob, EbConfigurationValue);
+ }
+
+EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationIndex() const
+ {
+ return ParseTUint8(iBlob, EiConfiguration);
+ }
+
+EXPORT_C TUint8 TUsbConfigurationDescriptor::Attributes() const
+ {
+ return ParseTUint8(iBlob, EbmAttributes);
+ }
+
+EXPORT_C TUint8 TUsbConfigurationDescriptor::MaxPower() const
+ {
+ return ParseTUint8(iBlob, EbMaxPower);
+ }
+
+/**
+The parsing routine for configuration descriptors.
+
+@internalComponent
+*/
+/*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbConfigurationDescriptor* configDes = NULL;
+
+ const TInt KMinConfigDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinConfigDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EConfiguration &&
+ aUsbDes[KbLengthOffset] == TUsbConfigurationDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbConfigurationDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Robustness check - check that there is sufficient data for whole bundle (wTotalLength)
+ const TInt KwTotalLengthOffset = 2;
+ if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset))
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be a configuration descriptor.
+ configDes = new(ELeave) TUsbConfigurationDescriptor;
+ // Set the standard fields
+ configDes->ibLength = TUsbConfigurationDescriptor::KSizeInOctets;
+ configDes->ibDescriptorType = EConfiguration;
+ // Set the blob appropriately
+ configDes->iBlob.Set(aUsbDes.Left(TUsbConfigurationDescriptor::KSizeInOctets));
+
+ configDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbConfigurationDescriptor::KSizeInOctets));
+ }
+
+ return configDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbConfigurationDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
+ {
+ // A configuration descriptor should always be the top-level descriptor in a configuration
+ // bundle.
+ return EFalse;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbConfigurationDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
+ {
+ // There should only ever be one configuration descriptor in a bundle.
+ return EFalse;
+ }
+
+
+// --------------------------
+// TUsbOtherSpeedDescriptor
+// See section 9.6.4 of the USB 2.0 specification.
+// --------------------------
+
+EXPORT_C TUsbOtherSpeedDescriptor::TUsbOtherSpeedDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbOtherSpeedDescriptor* ret = NULL;
+ // Only cast if correctly indentified as other speed descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EOtherSpeedConfiguration &&
+ aOriginal->ibLength == TUsbOtherSpeedDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbOtherSpeedDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint16 TUsbOtherSpeedDescriptor::TotalLength() const
+ {
+ return ParseTUint16(iBlob, EwTotalLength);
+ }
+
+EXPORT_C TUint8 TUsbOtherSpeedDescriptor::NumInterfaces() const
+ {
+ return ParseTUint8(iBlob, EbNumInterfaces);
+ }
+
+EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationValue() const
+ {
+ return ParseTUint8(iBlob, EbConfigurationValue);
+ }
+
+EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationIndex() const
+ {
+ return ParseTUint8(iBlob, EiConfiguration);
+ }
+
+EXPORT_C TUint8 TUsbOtherSpeedDescriptor::Attributes() const
+ {
+ return ParseTUint8(iBlob, EbmAttributes);
+ }
+
+EXPORT_C TUint8 TUsbOtherSpeedDescriptor::MaxPower() const
+ {
+ return ParseTUint8(iBlob, EbMaxPower);
+ }
+
+/**
+The parsing routine for other speed descriptors.
+
+@internalComponent
+*/
+/*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbOtherSpeedDescriptor* oSpeedDes = NULL;
+
+ const TInt KMinOtherSpeedDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinOtherSpeedDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EOtherSpeedConfiguration &&
+ aUsbDes[KbLengthOffset] == TUsbOtherSpeedDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbOtherSpeedDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Robustness check - check that there is sufficient data for whole bundle (wTotalLength)
+ const TInt KwTotalLengthOffset = 2;
+ if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset))
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be an other speed descriptor.
+ oSpeedDes = new(ELeave) TUsbOtherSpeedDescriptor;
+ // Set the standard fields
+ oSpeedDes->ibLength = TUsbOtherSpeedDescriptor::KSizeInOctets;
+ oSpeedDes->ibDescriptorType = EOtherSpeedConfiguration;
+ // Set the blob appropriately
+ oSpeedDes->iBlob.Set(aUsbDes.Left(TUsbOtherSpeedDescriptor::KSizeInOctets));
+
+ oSpeedDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbOtherSpeedDescriptor::KSizeInOctets));
+ }
+
+ return oSpeedDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
+ {
+ // Other speed descriptor is like a configuration descriptor, in that it should
+ // not have any parents in a bundle.
+ return EFalse;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
+ {
+ // There should only ever be one other speed descriptor in a bundle.
+ return EFalse;
+ }
+
+
+// ------------------------------------
+// TUsbInterfaceAssociationDescriptor
+// See the USB IAD ECN.
+// ------------------------------------
+
+EXPORT_C TUsbInterfaceAssociationDescriptor::TUsbInterfaceAssociationDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbInterfaceAssociationDescriptor* ret = NULL;
+ // Only cast if correctly indentified as interface association descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EInterfaceAssociation &&
+ aOriginal->ibLength == TUsbInterfaceAssociationDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbInterfaceAssociationDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FirstInterface() const
+ {
+ return ParseTUint8(iBlob, EbFirstInterface);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::InterfaceCount() const
+ {
+ return ParseTUint8(iBlob, EbInterfaceCount);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionClass() const
+ {
+ return ParseTUint8(iBlob, EbFunctionClass);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionSubClass() const
+ {
+ return ParseTUint8(iBlob, EbFunctionSubClass);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionProtocol() const
+ {
+ return ParseTUint8(iBlob, EbFunctionProtocol);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionIndex() const
+ {
+ return ParseTUint8(iBlob, EiFunction);
+ }
+
+/*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbInterfaceAssociationDescriptor* intAssocDes = NULL;
+
+ const TInt KMinIntAssocDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinIntAssocDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EInterfaceAssociation &&
+ aUsbDes[KbLengthOffset] == TUsbInterfaceAssociationDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbInterfaceAssociationDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be a interface association descriptor.
+ intAssocDes = new(ELeave) TUsbInterfaceAssociationDescriptor;
+ // Set the standard fields
+ intAssocDes->ibLength = TUsbInterfaceAssociationDescriptor::KSizeInOctets;
+ intAssocDes->ibDescriptorType = EInterfaceAssociation;
+ // Set the blob appropriately
+ intAssocDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceAssociationDescriptor::KSizeInOctets));
+
+ intAssocDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceAssociationDescriptor::KSizeInOctets));
+ }
+
+ return intAssocDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
+ {
+ switch(aPotentialParent.ibDescriptorType)
+ {
+ case EConfiguration:
+ return ETrue;
+ case EOtherSpeedConfiguration:
+ return ETrue; // I think this should be EFalse by my reading of the USB spec - however
+ // it is not explicitly clear, so play it safe.
+ default:
+ return EFalse;
+ }
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
+ {
+ switch(aPotentialPeer.ibDescriptorType)
+ {
+ case EInterfaceAssociation:
+ return ETrue;
+ case EInterface:
+ // Only interfaces are peers of IADs.
+ {
+ TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialPeer);
+ if(intDesc)
+ {
+ TInt intNum = intDesc->InterfaceNumber();
+ intNum -= FirstInterface();
+ if(intNum < 0 || intNum >= InterfaceCount())
+ {
+ // The interface number is outside the IAD region.
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+ default:
+ return EFalse;
+ }
+ }
+
+/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsChild(TUsbGenericDescriptor& aPotentialChild)
+ {
+ switch(aPotentialChild.ibDescriptorType)
+ {
+ case EInterface:
+ // Only interfaces are children of IADs. And only if they are special.
+ {
+ TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialChild);
+ if(intDesc)
+ {
+ TInt intNum = intDesc->InterfaceNumber();
+ intNum -= FirstInterface();
+ if(intNum >= 0 && intNum < InterfaceCount())
+ {
+ // The interface number is within the IAD region required.
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+ default:
+ return EFalse;
+ }
+ }
+
+
+// -------------------------
+// TUsbInterfaceDescriptor
+// See section 9.6.5 of the USB 2.0 specification.
+// -------------------------
+
+EXPORT_C TUsbInterfaceDescriptor::TUsbInterfaceDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbInterfaceDescriptor* ret = NULL;
+ // Only cast if correctly indentified as interface descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EInterface &&
+ aOriginal->ibLength == TUsbInterfaceDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbInterfaceDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceNumber() const
+ {
+ return ParseTUint8(iBlob, EbInterfaceNumber);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceDescriptor::AlternateSetting() const
+ {
+ return ParseTUint8(iBlob, EbAlternateSetting);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceDescriptor::NumEndpoints() const
+ {
+ return ParseTUint8(iBlob, EbNumEndpoints);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceClass() const
+ {
+ return ParseTUint8(iBlob, EbInterfaceClass);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceSubClass() const
+ {
+ return ParseTUint8(iBlob, EbInterfaceSubClass);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceProtocol() const
+ {
+ return ParseTUint8(iBlob, EbInterfaceProtocol);
+ }
+
+EXPORT_C TUint8 TUsbInterfaceDescriptor::Interface() const
+ {
+ return ParseTUint8(iBlob, EiInterface);
+ }
+
+/**
+The parsing routine for interface descriptors.
+
+@internalComponent
+*/
+/*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbInterfaceDescriptor* intDes = NULL;
+
+ const TInt KMinInterfaceDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinInterfaceDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EInterface &&
+ aUsbDes[KbLengthOffset] == TUsbInterfaceDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbInterfaceDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be an interface descriptor.
+ intDes = new(ELeave) TUsbInterfaceDescriptor;
+ // Set the standard fields
+ intDes->ibLength = TUsbInterfaceDescriptor::KSizeInOctets;
+ intDes->ibDescriptorType = EInterface;
+ // Set the blob appropriately
+ intDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceDescriptor::KSizeInOctets));
+
+ intDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceDescriptor::KSizeInOctets));
+ }
+
+ return intDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbInterfaceDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
+ {
+ switch(aPotentialParent.ibDescriptorType)
+ {
+ case EConfiguration:
+ return ETrue;
+ case EOtherSpeedConfiguration:
+ return ETrue; // I think this should be EFalse by my reading of the USB spec - however
+ // it is not explicitly clear, so play it safe.
+ // case EInterfaceAssociation:
+ // We let the IAD descriptor handle the logic of how we bind to it.
+ default:
+ return EFalse;
+ }
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbInterfaceDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
+ {
+ switch(aPotentialPeer.ibDescriptorType)
+ {
+ //case EInterfaceAssociation:
+ // We let the IAD descriptor handle the logic of how we bind to it.
+ case EInterface:
+ // If another interface descriptor then it is a peer not child.
+ return ETrue;
+ default:
+ // Any other descriptors are ignored.
+ return EFalse;
+ }
+ }
+
+
+// ------------------------
+// TUsbEndpointDescriptor
+// See section 9.6.6 of the USB 2.0 specification.
+// ------------------------
+
+EXPORT_C TUsbEndpointDescriptor::TUsbEndpointDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbEndpointDescriptor* ret = NULL;
+ // Only cast if correctly indentified as endpoint descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EEndpoint &&
+ aOriginal->ibLength == TUsbEndpointDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbEndpointDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint8 TUsbEndpointDescriptor::EndpointAddress() const
+ {
+ return ParseTUint8(iBlob, EbEndpointAddress);
+ }
+
+EXPORT_C TUint8 TUsbEndpointDescriptor::Attributes() const
+ {
+ return ParseTUint8(iBlob, EbmAttributes);
+ }
+
+EXPORT_C TUint16 TUsbEndpointDescriptor::MaxPacketSize() const
+ {
+ return ParseTUint16(iBlob, EwMaxPacketSize);
+ }
+
+EXPORT_C TUint8 TUsbEndpointDescriptor::Interval() const
+ {
+ return ParseTUint8(iBlob, EbInterval);
+ }
+
+/**
+The parsing routine for endpoint descriptors.
+
+@internalComponent
+*/
+/*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbEndpointDescriptor* endDes = NULL;
+
+ const TInt KMinEndpointDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinEndpointDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EEndpoint &&
+ aUsbDes[KbLengthOffset] == TUsbEndpointDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbEndpointDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be an endpoint descriptor.
+ endDes = new(ELeave) TUsbEndpointDescriptor;
+ // Set the standard fields
+ endDes->ibLength = TUsbEndpointDescriptor::KSizeInOctets;
+ endDes->ibDescriptorType = EEndpoint;
+ // Set the blob appropriately
+ endDes->iBlob.Set(aUsbDes.Left(TUsbEndpointDescriptor::KSizeInOctets));
+
+ endDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbEndpointDescriptor::KSizeInOctets));
+ }
+
+ return endDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbEndpointDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
+ {
+ switch(aPotentialParent.ibDescriptorType)
+ {
+ case EInterface:
+ return ETrue;
+ default:
+ return EFalse;
+ }
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbEndpointDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
+ {
+ switch(aPotentialPeer.ibDescriptorType)
+ {
+ case EEndpoint:
+ return ETrue;
+ default:
+ return EFalse;
+ }
+ }
+
+// ------------------------
+// TUsbOTGDescriptor
+// See section 6.4 of the USB 2.0 On-The-Go Supplement Revision 1.3
+// ------------------------
+
+EXPORT_C TUsbOTGDescriptor::TUsbOTGDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbOTGDescriptor* ret = NULL;
+ // Only cast if correctly indentified as otg descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EOTG &&
+ aOriginal->ibLength == TUsbOTGDescriptor::KSizeInOctets &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbOTGDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+EXPORT_C TUint8 TUsbOTGDescriptor::Attributes() const
+ {
+ return ParseTUint8(iBlob, EbmAttributes);
+ }
+
+EXPORT_C TBool TUsbOTGDescriptor::HNPSupported() const
+ {
+ return (ParseTUint8(iBlob, EbmAttributes) & 0x02) == 0x02;
+ }
+
+EXPORT_C TBool TUsbOTGDescriptor::SRPSupported() const
+ {
+ // Note: an illegal device (see 6.4.2 of the OTG specification) could
+ // incorrectly return False for SRP and True for HNP
+ // However this function just extracts the bit rather than attempting to
+ // fix up a broken device. Devices broken in this way wouldn't be expected on
+ // the TPL.
+ return (ParseTUint8(iBlob, EbmAttributes) & 0x01) == 0x01;
+ }
+
+/**
+The parsing routine for OTG descriptors.
+
+@internalComponent
+*/
+/*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbOTGDescriptor* endDes = NULL;
+
+ const TInt KMinOTGDesDecisionLength = 2;
+ if( aUsbDes.Length() >= KMinOTGDesDecisionLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EOTG &&
+ aUsbDes[KbLengthOffset] == TUsbOTGDescriptor::KSizeInOctets)
+ {
+ // Robustness check - check the length field is valid, and that we have enough data.
+ if(aUsbDes.Length() < TUsbOTGDescriptor::KSizeInOctets)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be an OTG descriptor.
+ endDes = new(ELeave) TUsbOTGDescriptor;
+ // Set the standard fields
+ endDes->ibLength = TUsbOTGDescriptor::KSizeInOctets;
+ endDes->ibDescriptorType = EOTG;
+ // Set the blob appropriately
+ endDes->iBlob.Set(aUsbDes.Left(TUsbOTGDescriptor::KSizeInOctets));
+
+ // Null the pointers
+ endDes->iFirstChild = NULL;
+ endDes->iNextPeer = NULL;
+ endDes->iParent = NULL;
+
+ endDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(TUsbOTGDescriptor::KSizeInOctets));
+ }
+
+ return endDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbOTGDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
+ {
+ switch(aPotentialParent.ibDescriptorType)
+ {
+ case EConfiguration: // we are part of a configuration descriptor, or standalone
+ return ETrue;
+ default:
+ return EFalse;
+ }
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbOTGDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
+ {
+ switch(aPotentialPeer.ibDescriptorType)
+ {
+ //case EInterfaceAssociation:
+ // We let the IAD descriptor handle the logic of how we bind to it.
+ case EInterface:
+ // If another interface descriptor then it is a peer not child.
+ return ETrue;
+ default:
+ // Any other descriptors are ignored.
+ return EFalse;
+ }
+ }
+
+
+// ----------------------
+// TUsbStringDescriptor
+// See section 9.6.7 of the USB 2.0 specification.
+// ----------------------
+
+// The length of the header in a string descriptor (i.e. the same as every other standard USB descriptor).
+static const TInt KStringDescriptorHeaderFieldLength = 2;
+
+EXPORT_C TUsbStringDescriptor::TUsbStringDescriptor()
+ {
+ }
+
+EXPORT_C /*static*/ TUsbStringDescriptor* TUsbStringDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
+ {
+ TUsbStringDescriptor* ret = NULL;
+ // Only cast if correctly indentified as string descriptor
+ if( aOriginal &&
+ aOriginal->ibDescriptorType == EString &&
+ aOriginal->ibLength >= KStringDescriptorHeaderFieldLength &&
+ aOriginal->iRecognisedAndParsed == ERecognised)
+ {
+ ret = static_cast<TUsbStringDescriptor*>(aOriginal);
+ }
+ return ret;
+ }
+
+/**
+For string descriptor zero, this function allows a means to iterate through the list of supported languages
+for strings on this device.
+
+@param aIndex Index into language ID table.
+@return The language ID at the requested index, or KErrNotFound if the end of the list has been reached.
+Note that the language IDs are unsigned 16-bit numbers, while the return from this function is signed 32-bit.
+*/
+EXPORT_C TInt TUsbStringDescriptor::GetLangId(TInt aIndex) const
+ {
+ __ASSERT_ALWAYS(aIndex >= 0, UsbDescPanic(UsbdiPanics::EUsbDescNegativeIndexToLangId));
+ const TUint8 KSizeOfLangIdField = 2;
+
+ TInt offset = KStringDescriptorHeaderFieldLength + KSizeOfLangIdField * aIndex;
+ if(offset >= ibLength)
+ {
+ return KErrNotFound;
+ }
+ return ParseTUint16(iBlob, offset);
+ }
+
+/**
+Writes the string data into a Symbian descriptor of sufficient size.
+
+@param aString The Symbian descriptor that will have the string data written into it.
+*/
+EXPORT_C void TUsbStringDescriptor::StringData(TDes16& aString) const
+ {
+ const TUint8 KUnicodeCharacterWidth = 2;
+ aString.Zero();
+
+ TInt index = KStringDescriptorHeaderFieldLength;
+ while(index+KUnicodeCharacterWidth <= ibLength)
+ {
+ aString.Append(ParseTUint16(iBlob, index));
+ index += KUnicodeCharacterWidth;
+ }
+ }
+
+
+/*static*/ TUsbStringDescriptor* TUsbStringDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
+ {
+ TUsbStringDescriptor* stringDes = NULL;
+
+ if( aUsbDes.Length() >= KStringDescriptorHeaderFieldLength &&
+ aUsbDes[KbDescriptorTypeOffset] == EString)
+ {
+ TUint8 stringDesLen = aUsbDes[KbLengthOffset];
+
+ // Robustness check - check the length field is valid
+ if(aUsbDes.Length() < stringDesLen || stringDesLen < KStringDescriptorHeaderFieldLength)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ // Robustness check - check the length is a multiple of two.
+ if(stringDesLen % 2 != 0)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Looks ok to be a string descriptor.
+ stringDes = new(ELeave) TUsbStringDescriptor;
+ // Set the standard fields
+ stringDes->ibLength = stringDesLen;
+ stringDes->ibDescriptorType = EString;
+ // Set the blob appropriately
+ stringDes->iBlob.Set(aUsbDes.Left(stringDesLen));
+
+ stringDes->iRecognisedAndParsed = ERecognised;
+
+ // Update the data-left-to-parse Symbian descriptor
+ aUsbDes.Set(aUsbDes.Mid(stringDesLen));
+ }
+
+ return stringDes;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbStringDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
+ {
+ // String descriptors have no parents - they are standalone.
+ return EFalse;
+ }
+
+/**
+@internalComponent
+*/
+/*virtual*/ TBool TUsbStringDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
+ {
+ // String descriptors have no peers - they are standalone.
+ return EFalse;
+ }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.mmp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,31 @@
+// Copyright (c) 2007-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.
+//
+// Description:
+//
+
+TARGET usbdescriptors.dll
+TARGETTYPE dll
+CAPABILITY All -Tcb
+VENDORID 0x70000001
+
+DEFFILE ../../../~/usbdescriptors.def
+
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+USERINCLUDE .
+
+SOURCEPATH .
+SOURCE usbdescriptors.cpp
+SOURCE usbdescparser.cpp
+SOURCE usbdescutils.cpp
+
+LIBRARY euser.lib
+
+SMPSAFE
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,55 @@
+// Copyright (c) 2007-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.
+//
+// Description:
+//
+
+#include "usbdescutils.h"
+
+/**
+@file
+@internalComponent
+*/
+
+/*static*/ CUsbCustomDescriptorParserList* CUsbCustomDescriptorParserList::NewL()
+ {
+ CUsbCustomDescriptorParserList* self = new(ELeave) CUsbCustomDescriptorParserList;
+ return self;
+ }
+
+CUsbCustomDescriptorParserList::~CUsbCustomDescriptorParserList()
+ {
+ iParserList.Close();
+ }
+
+void CUsbCustomDescriptorParserList::RegisterParserL(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc)
+ {
+ iParserList.AppendL(aParserFunc);
+ }
+
+void CUsbCustomDescriptorParserList::UnregisterParser(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc)
+ {
+ TInt res = iParserList.Find(aParserFunc);
+ if(res != KErrNotFound)
+ {
+ iParserList.Remove(res);
+ }
+ }
+
+TInt CUsbCustomDescriptorParserList::NumOfRegisteredParsers() const
+ {
+ return iParserList.Count();
+ }
+
+UsbDescriptorParser::TUsbDescriptorParserL CUsbCustomDescriptorParserList::RegisteredParser(TInt aIndex) const
+ {
+ return iParserList[aIndex];
+ }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.h Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,94 @@
+// Copyright (c) 2007-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.
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#ifndef USBDESCUTILS_H
+#define USBDESCUTILS_H
+
+#include <d32usbdescriptors.h>
+#include <d32usbdi_errors.h>
+
+inline void UsbDescFault(UsbdiFaults::TUsbDescFaults aFault)
+ {
+ User::Panic(UsbdiFaults::KUsbDescFaultCat, aFault);
+ }
+
+inline void UsbDescPanic(UsbdiPanics::TUsbDescPanics aPanic)
+ {
+ User::Panic(UsbdiPanics::KUsbDescPanicCat, aPanic);
+ }
+
+/**
+Utility function for retrieving a TUint8 from a Little Endian USB descriptor.
+@param aDes The descriptor to parse.
+@param aOffset The offset in the descriptor where to parse.
+@return The TUint8 value parsed.
+*/
+inline TUint8 ParseTUint8(TPtrC8 aDes, TInt aOffset)
+ {
+ return aDes[aOffset];
+ }
+
+/**
+Utility function for retrieving a TUint16 from a Little Endian USB descriptor.
+@param aDes The descriptor to parse.
+@param aOffset The offset in the descriptor where to parse.
+@return The TUint16 value parsed.
+*/
+inline TUint16 ParseTUint16(TPtrC8 aDes, TInt aOffset)
+ {
+ return ((TUint16)aDes[aOffset]) | ( ((TUint16)aDes[aOffset+1]) << 8 );
+ }
+
+/**
+Utility function for retrieving a TUint32 from a Little Endian USB descriptor.
+@param aDes The descriptor to parse.
+@param aOffset The offset in the descriptor where to parse.
+@return The TUint32 value parsed.
+*/
+inline TUint32 ParseTUint32(TPtrC8 aDes, TInt aOffset)
+ {
+ // Put enough brackets to ensure that all casting is correct
+ // and the expression looks symmetrical
+ return ( ((TUint32)(aDes[aOffset])) ) |
+ ( ((TUint32)(aDes[aOffset + 1])) << 8 ) |
+ ( ((TUint32)(aDes[aOffset + 2])) << 16 ) |
+ ( ((TUint32)(aDes[aOffset + 3])) << 24 );
+ }
+
+/**
+A utility class to store the custom descriptor parsers.
+The USBDI descriptor parsing framework creates and stores an instance
+of this class in TLS when a custom parse is registered.
+*/
+NONSHARABLE_CLASS(CUsbCustomDescriptorParserList) : public CBase
+ {
+public:
+ static CUsbCustomDescriptorParserList* NewL();
+ ~CUsbCustomDescriptorParserList();
+
+ void RegisterParserL(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc);
+ void UnregisterParser(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc);
+ TInt NumOfRegisteredParsers() const;
+ UsbDescriptorParser::TUsbDescriptorParserL RegisteredParser(TInt aIndex) const;
+
+private:
+ RArray<UsbDescriptorParser::TUsbDescriptorParserL> iParserList;
+ };
+
+
+#endif // USBDESCUTILS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,12 @@
+# component name "USB DI Utils"
+
+component base_drivers_usbdi_utils
+
+source \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdi_utils
+
+binary \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdi_utils all
+
+notes_source \component_defs\release.src
+
+ipr E
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/bld.inf Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 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/usbho/usbdi_utils/bld.inf
+//
+//
+
+/**
+ @file
+*/
+
+
+PRJ_PLATFORMS
+
+ARMV5 ARMV5SMP
+
+
+PRJ_MMPFILES
+
+#ifndef GCCXML
+#if defined(GENERIC_MARM) || !defined(WINS) || defined(GENERIC_X86)
+#if !defined(MARM_THUMB) && !defined(MARM_ARMI)
+
+#if !defined(WINS)
+#if !defined(X86)
+#if defined(SYMBIAN_ENABLE_USB_OTG_HOST)
+
+usbdi_utils
+
+#endif
+#endif
+#endif
+
+#endif
+#endif
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdi_utils.mmp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,37 @@
+// Copyright (c) 2007-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:
+//
+
+target usbdi_utils.dll
+targettype dll
+capability All -Tcb
+vendorid 0x70000001
+
+deffile ../../../~/usbdi_utils.def
+
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+userinclude .
+
+sourcepath .
+source usbtransfers.cpp
+source usbtransferstrategy.cpp
+source usbinterface.cpp
+source usbpipe.cpp
+source usbdiutils.cpp
+source zerocopytransferstrategy.cpp
+
+library euser.lib
+library usbdescriptors.lib
+
+SMPSAFE
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,28 @@
+// Copyright (c) 2007-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:
+//
+
+#include "usbdiutils.h"
+
+
+void UsbdiUtils::Panic(UsbdiPanics::TUsbdiPanics aPanic)
+ {
+ User::Panic(UsbdiPanics::KUsbdiPanicCat, aPanic);
+ }
+
+
+void UsbdiUtils::Fault(UsbdiFaults::TUsbdiFaults aFault)
+ {
+ User::Panic(UsbdiFaults::KUsbdiFaultCat, aFault);
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.h Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,34 @@
+// Copyright (c) 2007-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#ifndef USBDIUTILS_H
+#define USBDIUTILS_H
+
+#include <d32usbdi_errors.h>
+
+
+NONSHARABLE_CLASS(UsbdiUtils)
+ {
+public:
+ static void Panic(UsbdiPanics::TUsbdiPanics aPanic);
+ static void Fault(UsbdiFaults::TUsbdiFaults aFault);
+ };
+
+#endif // USBDIUTILS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbinterface.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,154 @@
+// Copyright (c) 2007-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:
+//
+
+#include <d32usbdi.h>
+
+#include <d32usbtransfers.h>
+#include "usbtransferstrategy.h"
+#include "zerocopytransferstrategy.h"
+
+
+/**
+Opens an interface identified by a token. When the hub driver loads a driver (via function driver
+framework), this token is generated to allow the driver to open the interface.
+
+This also causes the interface's descriptors to be parsed for future reference.
+
+@param[in] aToken The token for the interface to open.
+@return System-wide error code.
+*/
+EXPORT_C TInt RUsbInterface::Open(TUint32 aToken, TOwnerType aType)
+ {
+ TPckgC<TUint32> token(aToken);
+ TInt err = DoCreate(Name(), VersionRequired(), KNullUnit, NULL, &token, aType);
+ if(err == KErrNone)
+ {
+ // Create a transfer strategy
+ iTransferStrategy = new RUsbZeroCopyTransferStrategy;
+ if(!iTransferStrategy)
+ {
+ Close();
+ return KErrNoMemory;
+ }
+
+ // Get descriptor size
+ TInt interfaceDescSize = 0;
+ err = DoControl(EGetInterfaceDescriptorSize, &interfaceDescSize);
+ if(err != KErrNone)
+ {
+ Close();
+ return err;
+ }
+ iInterfaceDescriptorData = HBufC8::New(interfaceDescSize);
+
+ if(!iInterfaceDescriptorData)
+ {
+ Close();
+ return KErrNoMemory;
+ }
+
+ // Get descriptor data
+ TPtr8 interfaceDesc = iInterfaceDescriptorData->Des();
+ err = DoControl(EGetInterfaceDescriptor, &interfaceDesc);
+ if(err != KErrNone)
+ {
+ Close();
+ return err;
+ }
+
+ // Parse descriptor
+ TUsbGenericDescriptor* parsed = NULL;
+ err = UsbDescriptorParser::Parse(*iInterfaceDescriptorData, parsed);
+ if(err != KErrNone)
+ {
+ if(parsed)
+ {
+ parsed->DestroyTree(); //or however much has been completed
+ delete parsed;
+ }
+ Close();
+ return err;
+ }
+
+ iHeadInterfaceDescriptor = TUsbInterfaceDescriptor::Cast(parsed);
+ if(!iHeadInterfaceDescriptor)
+ {
+ if(parsed)
+ {
+ parsed->DestroyTree();
+ delete parsed;
+ }
+ Close();
+ return KErrCorrupt;
+ }
+ }
+
+ return err;
+ }
+
+/**
+Close handle to interface.
+
+Closes any pipe handles still open.
+*/
+EXPORT_C void RUsbInterface::Close()
+ {
+ iAlternateSetting = 0;
+ if(iHeadInterfaceDescriptor)
+ {
+ iHeadInterfaceDescriptor->DestroyTree();
+ delete iHeadInterfaceDescriptor;
+ iHeadInterfaceDescriptor = NULL;
+ }
+ if(iInterfaceDescriptorData)
+ {
+ delete iInterfaceDescriptorData;
+ iInterfaceDescriptorData = NULL;
+ }
+ if(iTransferStrategy)
+ {
+ iTransferStrategy->Close();
+ delete iTransferStrategy;
+ iTransferStrategy = NULL;
+ }
+ RBusLogicalChannel::Close();
+ }
+
+
+EXPORT_C TInt RUsbInterface::RegisterTransferDescriptor(RUsbTransferDescriptor& aTransfer)
+ {
+ TTransferMemoryDetails details;
+ details.iType = aTransfer.iType;
+ details.iSize = aTransfer.iMaxSize;
+ details.iMaxPackets = aTransfer.iMaxNumPackets;
+ TInt err = DoControl(EGetSizeAndAlignment, &details);
+ if(err != KErrNone)
+ {
+ return err;
+ }
+ return iTransferStrategy->RegisterTransferDescriptor(aTransfer, details.iSize, details.iAlignment, details.iMaxPackets);
+ }
+
+EXPORT_C void RUsbInterface::ResetTransferDescriptors()
+ {
+ iTransferStrategy->ResetTransferDescriptors();
+ }
+
+EXPORT_C TInt RUsbInterface::InitialiseTransferDescriptors()
+ {
+ return iTransferStrategy->InitialiseTransferDescriptors(*this);
+ }
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbpipe.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,31 @@
+// Copyright (c) 2007-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:
+//
+
+#include <d32usbdi.h>
+#include <d32usbtransfers.h>
+
+#include "usbtransferstrategy.h"
+
+
+/**
+Queue a transfer.
+@param[in] aTransfer The transfer descriptor to execute.
+@param[out] aRequest Holds completion status of the transfer.
+*/
+EXPORT_C void RUsbPipe::Transfer(RUsbTransferDescriptor& aTransfer, TRequestStatus& aRequest)
+ {
+ IssueTransfer(aTransfer.iHandle, aRequest);
+ }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransfers.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,205 @@
+// Copyright (c) 2007-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:
+//
+
+#include <d32usbtransfers.h>
+
+#include <d32usbdi_errors.h>
+#include "usbtransferstrategy.h"
+#include "usbdiutils.h"
+
+
+// ========================
+// RUsbTransferDescriptor
+// ========================
+
+/**
+Constructor protected to as this class is only intended as a base class.
+*/
+RUsbTransferDescriptor::RUsbTransferDescriptor(TTransferType aType, TInt aMaxSize, TInt aMaxNumPackets)
+ : iHandle(KInvalidHandle)
+ , iType(aType)
+ , iMaxSize(aMaxSize)
+ , iMaxNumPackets(aMaxNumPackets)
+ {
+ }
+
+/**
+Releases resources allocated to this transfer descriptor.
+*/
+void RUsbTransferDescriptor::Close()
+ {
+ // Do nothing - the buffer is owned by the {R,D}UsbInterface.
+ // This is provided in case the descriptor owns resources in future.
+ }
+
+
+// ============================
+// RUsbIsocTransferDescriptor
+// ============================
+
+EXPORT_C RUsbIsocTransferDescriptor::RUsbIsocTransferDescriptor(TInt aMaxSize, TInt aMaxNumPackets)
+ : RUsbTransferDescriptor(EIsochronous, aMaxSize, aMaxNumPackets)
+ , iWriteHandle(KInvalidHandle)
+ {
+ }
+
+EXPORT_C void RUsbIsocTransferDescriptor::Reset()
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ iWriteHandle = iHandle;
+ iTransferStrategy->IsocReset(iHandle);
+ }
+
+EXPORT_C TPacketLengths RUsbIsocTransferDescriptor::Lengths()
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ return iTransferStrategy->IsocLengths(iHandle);
+ }
+
+EXPORT_C TPacketResults RUsbIsocTransferDescriptor::Results()
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ return iTransferStrategy->IsocResults(iHandle);
+ }
+
+EXPORT_C TInt RUsbIsocTransferDescriptor::MaxPacketSize()
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ return iTransferStrategy->IsocMaxPacketSize(iHandle);
+ }
+
+EXPORT_C TPtr8 RUsbIsocTransferDescriptor::WritablePackets(TInt aNumPacketsRequested, TInt& aMaxNumOfPacketsAbleToWrite)
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ if(iWriteHandle == KInvalidHandle)
+ {
+ return TPtr8(NULL, 0);
+ }
+ return iTransferStrategy->IsocWritablePackets(iHandle, iWriteHandle, aNumPacketsRequested, aMaxNumOfPacketsAbleToWrite);
+ }
+
+EXPORT_C void RUsbIsocTransferDescriptor::SaveMultiple(TInt aNumOfPackets)
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ __ASSERT_ALWAYS(iWriteHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorWriteHandle));
+ TInt writeHandle = iTransferStrategy->IsocSaveMultiple(iHandle, iWriteHandle, aNumOfPackets);
+ iWriteHandle = (writeHandle < 0) ? KInvalidHandle : writeHandle;
+ }
+
+EXPORT_C TPtrC8 RUsbIsocTransferDescriptor::Packets(TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumOfPacketsReturned) const
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ return iTransferStrategy->IsocPackets(iHandle, aFirstPacketIndex, aNumPacketsRequested, aNumOfPacketsReturned);
+ }
+
+EXPORT_C void RUsbIsocTransferDescriptor::ReceivePackets(TInt aNumOfPackets)
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle));
+ iTransferStrategy->IsocReceivePackets(iHandle, aNumOfPackets);
+ }
+
+
+// ============================
+// RUsbBulkTransferDescriptor
+// ============================
+
+EXPORT_C RUsbBulkTransferDescriptor::RUsbBulkTransferDescriptor(TInt aMaxSize)
+ : RUsbTransferDescriptor(EBulk, aMaxSize, 0)
+ {
+ }
+
+/**
+@return A modifiable pointer to the entire data buffer.
+*/
+EXPORT_C TPtr8 RUsbBulkTransferDescriptor::WritableBuffer()
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle));
+ return iTransferStrategy->BulkWritableBuffer(iHandle);
+ }
+
+/**
+Update the transfer descriptor given the length of data supplied.
+@param[in] aLength Length of data to write or expect.
+*/
+EXPORT_C void RUsbBulkTransferDescriptor::SaveData(TInt aLength)
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle));
+ iTransferStrategy->BulkSaveData(iHandle, aLength);
+ }
+
+/**
+@return A non-modifiable pointer to the entire data buffer.
+*/
+EXPORT_C TPtrC8 RUsbBulkTransferDescriptor::Buffer() const
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle));
+ return iTransferStrategy->BulkBuffer(iHandle);
+ }
+
+/**
+@param aZlpStatus the ZLP type to use for the transfer
+*/
+EXPORT_C void RUsbBulkTransferDescriptor::SetZlpStatus(TZlpStatus aZlpStatus)
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle));
+ iTransferStrategy->BulkSetZlpStatus(iHandle, aZlpStatus);
+ }
+
+
+// ============================
+// RUsbIntrTransferDescriptor
+// ============================
+
+EXPORT_C RUsbIntrTransferDescriptor::RUsbIntrTransferDescriptor(TInt aMaxSize)
+ : RUsbTransferDescriptor(EInterrupt, aMaxSize, 0)
+ {
+ }
+
+/**
+@return A modifiable pointer to the entire data buffer.
+*/
+EXPORT_C TPtr8 RUsbIntrTransferDescriptor::WritableBuffer()
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle));
+ return iTransferStrategy->IntrWritableBuffer(iHandle);
+ }
+
+/**
+Update the transfer descriptor given the length of data supplied.
+@param[in] aLength Length of data to write or expect.
+*/
+EXPORT_C void RUsbIntrTransferDescriptor::SaveData(TInt aLength)
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle));
+ iTransferStrategy->IntrSaveData(iHandle, aLength);
+ }
+
+/**
+@return A non-modifiable pointer to the entire data buffer.
+*/
+EXPORT_C TPtrC8 RUsbIntrTransferDescriptor::Buffer() const
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle));
+ return iTransferStrategy->IntrBuffer(iHandle);
+ }
+
+/**
+@param aZlpStatus the ZLP type to use for the transfer
+*/
+EXPORT_C void RUsbIntrTransferDescriptor::SetZlpStatus(TZlpStatus aZlpStatus)
+ {
+ __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle));
+ return iTransferStrategy->IntrSetZlpStatus(iHandle, aZlpStatus);
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,114 @@
+// Copyright (c) 2007-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:
+//
+
+#include "usbtransferstrategy.h"
+
+#include <d32usbtransfers.h>
+#include <d32usbdi_errors.h>
+#include "usbdiutils.h"
+
+
+TPacketLengths::TPacketLengths(TUint16* aRecvPtr, TUint16* aReqPtr, TInt& aMaxNumPackets)
+ : iRecvPtr(aRecvPtr)
+ , iReqPtr(aReqPtr)
+ , iMaxNumPackets(aMaxNumPackets)
+ {}
+
+EXPORT_C TPacketLengths::TLength TPacketLengths::At(TInt aIndex)
+ {
+ __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfLengthArray));
+ return TPacketLengths::TLength(*(iRecvPtr + aIndex), *(iReqPtr + aIndex));
+ }
+
+EXPORT_C const TPacketLengths::TLength TPacketLengths::At(TInt aIndex) const
+ {
+ __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfLengthArray));
+ return TPacketLengths::TLength(*(iRecvPtr + aIndex), *(iReqPtr + aIndex));
+ }
+
+EXPORT_C TPacketLengths::TLength TPacketLengths::operator[](TInt aIndex)
+ {
+ return At(aIndex);
+ }
+
+EXPORT_C const TPacketLengths::TLength TPacketLengths::operator[](TInt aIndex) const
+ {
+ return At(aIndex);
+ }
+
+EXPORT_C TInt TPacketLengths::MaxNumPackets()
+ {
+ return iMaxNumPackets;
+ }
+
+EXPORT_C TUint16 TPacketLengths::TLength::operator=(TUint16 aValue)
+ {
+ iRecv = aValue;
+ iReq = aValue;
+ return aValue;
+ }
+
+EXPORT_C TPacketLengths::TLength::operator TUint16() const
+ {
+ return iRecv;
+ }
+
+TPacketLengths::TLength::TLength(TUint16& aRecv, TUint16& aReq)
+ : iRecv(aRecv)
+ , iReq(aReq)
+ {
+ }
+
+
+TPacketResults::TPacketResults(TInt* aResPtr, TInt& aMaxNumPackets)
+ : iResPtr(aResPtr)
+ , iMaxNumPackets(aMaxNumPackets)
+ {
+ }
+
+EXPORT_C TInt TPacketResults::At(TInt aIndex) const
+ {
+ __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfResultArray));
+ return *(iResPtr + aIndex);
+ }
+
+EXPORT_C TInt TPacketResults::operator[](TInt aIndex) const
+ {
+ return At(aIndex);
+ }
+
+EXPORT_C TInt TPacketResults::MaxNumPackets()
+ {
+ return iMaxNumPackets;
+ }
+
+
+
+void RUsbTransferStrategy::Close()
+ {
+ // Doesn't currently own any resources.
+ }
+
+void RUsbTransferStrategy::SetTransferHandle(RUsbTransferDescriptor& aTransfer, TInt aHandle) const
+ {
+ aTransfer.iHandle = aHandle;
+ aTransfer.iTransferStrategy = const_cast<RUsbTransferStrategy*>(this);
+ if(aTransfer.iType == RUsbTransferDescriptor::EIsochronous)
+ {
+ static_cast<RUsbIsocTransferDescriptor&>(aTransfer).iWriteHandle = aHandle;
+ }
+ }
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.h Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,64 @@
+// Copyright (c) 2007-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#ifndef USBTRANSFERSTRATEGY_H
+#define USBTRANSFERSTRATEGY_H
+
+#include <e32std.h>
+#include <d32usbtransfers.h>
+
+
+NONSHARABLE_CLASS(RUsbTransferStrategy)
+ {
+public:
+ virtual void Close();
+
+ virtual TInt RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets) =0;
+ virtual void ResetTransferDescriptors() =0;
+ virtual TInt InitialiseTransferDescriptors(RUsbInterface& aInterface) =0;
+
+public: // Interrupt transfer descriptor methods
+ virtual TPtr8 IntrWritableBuffer(TInt aHandle) =0;
+ virtual void IntrSaveData(TInt aHandle, TInt aLength) =0;
+ virtual void IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) =0;
+ virtual TPtrC8 IntrBuffer(TInt aHandle) const =0;
+
+public: // Bulk transfer descriptor methods
+ virtual TPtr8 BulkWritableBuffer(TInt aHandle) =0;
+ virtual void BulkSaveData(TInt aHandle, TInt aLength) =0;
+ virtual void BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) =0;
+ virtual TPtrC8 BulkBuffer(TInt aHandle) const =0;
+
+public: // Isochronous transfer descriptor methods
+ virtual void IsocReset(TInt aHandle) =0;
+ virtual TPacketLengths IsocLengths(TInt aHandle) =0;
+ virtual TPacketResults IsocResults(TInt aHandle) =0;
+ virtual TInt IsocMaxPacketSize(TInt aHandle) =0;
+ virtual TPtr8 IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite) =0;
+ virtual TInt IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets) =0;
+ virtual TPtrC8 IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const =0;
+ virtual void IsocReceivePackets(TInt aHandle, TInt aNumOfPackets) =0;
+
+protected:
+ void SetTransferHandle(RUsbTransferDescriptor& aTransfer, TInt aHandle) const;
+ };
+
+
+#endif // USBTRANSFERSTRATEGY_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.h Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,152 @@
+// Copyright (c) 2007-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.
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#ifndef ZEROCOPYMETADATA_H
+#define ZEROCOPYMETADATA_H
+
+#include <e32def.h>
+
+// The type used to represent an address various betwen user and kernel
+// mode. To aid us we use a macro to produce only one definition.
+#ifndef __KERNEL_MODE__
+#define TAddrType TUint8*
+#else // __KERNEL_MODE__
+#define TAddrType TLinAddr
+#endif // __KERNEL_MODE__
+
+
+NONSHARABLE_CLASS(UsbZeroCopyChunkHeaderBase)
+ {
+public:
+ static inline RUsbTransferDescriptor::TTransferType& TransferType(TAddrType aBase, TInt aHeaderOffset);
+protected:
+ enum THeaderBaseSizes
+ {
+ ETransferTypeSize = sizeof(RUsbTransferDescriptor::TTransferType)
+ };
+ enum THeaderBaseLayout
+ {
+ ETransferType = 0,
+ // End of fields
+ EHeaderBaseSize = ETransferType + ETransferTypeSize
+ };
+ };
+
+
+NONSHARABLE_CLASS(UsbZeroCopyBulkIntrChunkHeader) : public UsbZeroCopyChunkHeaderBase
+ {
+public:
+ static inline TInt HeaderSize();
+
+ static inline TInt& DataOffset(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& DataLength(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& DataMaxLength(TAddrType aBase, TInt aHeaderOffset);
+ static inline RUsbTransferDescriptor::TZlpStatus& ZlpStatus(TAddrType aBase, TInt aHeaderOffset);
+private:
+ enum THeaderSizes
+ {
+ EDataOffsetSize = sizeof(TInt),
+ EDataLengthSize = sizeof(TInt),
+ EDataMaxLengthSize = sizeof(TInt),
+ EZlpStatusSize = sizeof(RUsbTransferDescriptor::TZlpStatus)
+ };
+ enum THeaderLayout
+ {
+ EDataOffset = EHeaderBaseSize,
+ EDataLength = EDataOffset + EDataOffsetSize,
+ EDataMaxLength = EDataLength + EDataLengthSize,
+ EZlpStatus = EDataMaxLength + EDataMaxLengthSize,
+ // End of fields
+ EHeaderSize = EZlpStatus + EZlpStatusSize
+ };
+ };
+
+
+NONSHARABLE_CLASS(UsbZeroCopyIsocChunkHeader) : public UsbZeroCopyChunkHeaderBase
+ {
+public: // Lengths Array constants
+ static const TInt KLengthsElementSize = sizeof(TUint16);
+ static const TInt KResultsElementSize = sizeof(TInt);
+public:
+ static inline TInt HeaderSize();
+
+ static inline TInt& FirstElementOffset(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& MaxNumPackets(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& MaxPacketSize(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& LengthsOffset(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& ReqLenOffset(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& ResultsOffset(TAddrType aBase, TInt aHeaderOffset);
+private:
+ enum THeaderSizes
+ {
+ EFirstElementOffsetSize = sizeof(TInt),
+ EMaxNumPacketsSize = sizeof(TInt),
+ EMaxPacketSizeSize = sizeof(TInt),
+ ELengthsOffsetSize = sizeof(TInt),
+ EReqLenOffsetSize = sizeof(TInt),
+ EResultsOffsetSize = sizeof(TInt)
+ };
+ enum THeaderLayout
+ {
+ EFirstElementOffset = EHeaderBaseSize,
+ EMaxNumPackets = EFirstElementOffset + EFirstElementOffsetSize,
+ EMaxPacketSize = EMaxNumPackets + EMaxNumPacketsSize,
+ ELengthsOffset = EMaxPacketSize + EMaxPacketSizeSize,
+ EReqLenOffset = ELengthsOffset + ELengthsOffsetSize,
+ EResultsOffset = EReqLenOffset + EReqLenOffsetSize,
+ // End of fields
+ EHeaderSize = EResultsOffset + EResultsOffsetSize
+ };
+ };
+
+
+NONSHARABLE_CLASS(UsbZeroCopyIsocChunkElement)
+ {
+public:
+ // NumOfPackets constants
+ static const TInt KInvalidElement = -1;
+ // NextElementOffset constants
+ static const TInt KEndOfList = -1;
+public:
+ static inline TInt ElementSize();
+
+ static inline TInt& DataOffset(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& NumPackets(TAddrType aBase, TInt aHeaderOffset);
+ static inline TInt& NextElementOffset(TAddrType aBase, TInt aHeaderOffset);
+private:
+ enum THeaderSizes
+ {
+ EDataOffsetSize = sizeof(TInt),
+ ENumPacketsSize = sizeof(TInt),
+ ENextElementOffsetSize = sizeof(TInt),
+ };
+ enum THeaderLayout
+ {
+ EDataOffset = 0,
+ ENumPackets = EDataOffset + EDataOffsetSize,
+ ENextElementOffset = ENumPackets + ENumPacketsSize,
+ // End of fields
+ EElementSize = ENextElementOffset + ENextElementOffsetSize
+ };
+ };
+
+#include "zerocopymetadata.inl"
+
+#undef TAddrType // Prevent the macro from leaking outside this header
+
+#endif // ZEROCOPYMETADATA_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.inl Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,141 @@
+// Copyright (c) 2007-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.
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+
+template<typename XReturnType, TInt XFieldOffset>
+inline XReturnType& Field(TAddrType aBase, TInt aHeaderOffset)
+ {
+ TInt offset = aHeaderOffset + XFieldOffset;
+ return *reinterpret_cast<XReturnType*>(aBase + offset);
+ }
+
+
+//
+// UsbZeroCopyChunkHeaderBase
+//
+
+inline RUsbTransferDescriptor::TTransferType& UsbZeroCopyChunkHeaderBase::TransferType(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<RUsbTransferDescriptor::TTransferType, ETransferType>(aBase, aHeaderOffset);
+ }
+
+
+
+//
+// UsbZeroCopyBulkIntrChunkHeader
+//
+
+inline TInt UsbZeroCopyBulkIntrChunkHeader::HeaderSize()
+ {
+ __ASSERT_COMPILE(EHeaderSize % sizeof(TInt) == 0);
+ return EHeaderSize;
+ }
+
+
+inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataOffset(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EDataOffset>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataLength(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EDataLength>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EDataMaxLength>(aBase, aHeaderOffset);
+ }
+
+inline RUsbTransferDescriptor::TZlpStatus& UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<RUsbTransferDescriptor::TZlpStatus, EZlpStatus>(aBase, aHeaderOffset);
+ }
+
+
+
+//
+// UsbZeroCopyIsocChunkHeader
+//
+
+inline TInt UsbZeroCopyIsocChunkHeader::HeaderSize()
+ {
+ __ASSERT_COMPILE(EHeaderSize % sizeof(TInt) == 0);
+ return EHeaderSize;
+ }
+
+
+inline TInt& UsbZeroCopyIsocChunkHeader::FirstElementOffset(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EFirstElementOffset>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyIsocChunkHeader::MaxNumPackets(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EMaxNumPackets>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyIsocChunkHeader::MaxPacketSize(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EMaxPacketSize>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyIsocChunkHeader::LengthsOffset(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, ELengthsOffset>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyIsocChunkHeader::ReqLenOffset(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EReqLenOffset>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyIsocChunkHeader::ResultsOffset(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EResultsOffset>(aBase, aHeaderOffset);
+ }
+
+
+
+//
+// UsbZeroCopyIsocChunkHeader
+//
+
+inline TInt UsbZeroCopyIsocChunkElement::ElementSize()
+ {
+ __ASSERT_COMPILE(EElementSize % sizeof(TInt) == 0);
+ return EElementSize;
+ }
+
+
+inline TInt& UsbZeroCopyIsocChunkElement::DataOffset(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, EDataOffset>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyIsocChunkElement::NumPackets(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, ENumPackets>(aBase, aHeaderOffset);
+ }
+
+inline TInt& UsbZeroCopyIsocChunkElement::NextElementOffset(TAddrType aBase, TInt aHeaderOffset)
+ {
+ return Field<TInt, ENextElementOffset>(aBase, aHeaderOffset);
+ }
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,982 @@
+// Copyright (c) 2007-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:
+//
+
+#include "zerocopytransferstrategy.h"
+
+#include <d32usbtransfers.h>
+#include <d32usbdi.h>
+#include <d32usbdi_errors.h>
+#include "zerocopymetadata.h"
+#include "usbdiutils.h"
+
+
+RUsbZeroCopyTransferStrategy::TUsbTransferDescriptorDetails::TUsbTransferDescriptorDetails(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aRequiredAlignment, TInt aRequiredMaxPackets)
+ : iTransferDesc(aTransferDesc)
+ , iRequiredSize(aRequiredSize)
+ , iRequiredAlignment(aRequiredAlignment)
+ , iRequiredMaxPackets(aRequiredMaxPackets)
+ {
+ }
+
+RUsbZeroCopyTransferStrategy::RUsbZeroCopyTransferStrategy()
+ : iInterfaceHandle(NULL)
+ {
+ }
+
+
+void RUsbZeroCopyTransferStrategy::Close()
+ {
+ iInterfaceHandle = NULL;
+ iChunk.Close();
+ iRegisteredTransfers.Close();
+ RUsbTransferStrategy::Close();
+ }
+
+
+TInt RUsbZeroCopyTransferStrategy::RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets)
+ {
+ __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered));
+ if (iRegisteredTransfers.Find(aTransferDesc, CompareTransferDescriptor) != KErrNotFound)
+ {
+ return KErrAlreadyExists;
+ }
+ return iRegisteredTransfers.Append(TUsbTransferDescriptorDetails(aTransferDesc, aRequiredSize, aStartAlignment, aRequiredMaxPackets));
+ }
+
+TBool RUsbZeroCopyTransferStrategy::CompareTransferDescriptor(const RUsbTransferDescriptor* aTransferDesc, const TUsbTransferDescriptorDetails& aDetails)
+ {
+ return aTransferDesc == &aDetails.iTransferDesc;
+ }
+
+
+void RUsbZeroCopyTransferStrategy::ResetTransferDescriptors()
+ {
+ __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered));
+ iRegisteredTransfers.Reset();
+ }
+
+
+TInt RUsbZeroCopyTransferStrategy::InitialiseTransferDescriptors(RUsbInterface& aInterface)
+ {
+ __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered));
+
+ // This is the equivilent of a standard R-class Open() method, so initialise the references
+ // we are going to use.
+ iInterfaceHandle = &aInterface;
+
+ // First get the page-size as we will need this for isoc transfer calculations.
+ TInt hcdPageSize = 0;
+ TInt err = aInterface.GetHcdPageSize(hcdPageSize);
+ if (err != KErrNone)
+ {
+ Close(); // roll back
+ return err;
+ }
+ iPageSize = hcdPageSize;
+
+ TInt currentOffset = 0;
+ TInt numStandardTransfers = 0;
+ TInt numIsocTransfers = 0;
+ TInt numIsocElements = 0;
+ err = CalculateDataLayout(currentOffset, numStandardTransfers, numIsocTransfers, numIsocElements);
+ if (err != KErrNone)
+ {
+ Close(); // roll back
+ return err;
+ }
+
+ TInt metaDataStart = 0;
+ CalculateMetaDataLayout(currentOffset, metaDataStart, numStandardTransfers, numIsocTransfers, numIsocElements);
+
+ // currentOffset should now be just past the region required for all the data and meta data.
+ // Therefore it equals the total size of the buffer we need to hold them all.
+ err = iInterfaceHandle->AllocateSharedChunk(iChunk, currentOffset, iBaseOffset);
+ if (err != KErrNone)
+ {
+ Close(); // roll back
+ return err;
+ }
+
+ InitialiseMetaData(metaDataStart, numStandardTransfers, numIsocTransfers, numIsocElements);
+
+ return KErrNone;
+ }
+
+TInt RUsbZeroCopyTransferStrategy::CalculateDataLayout(TInt& aCurrentOffset, TInt& aNumStandardTransfers, TInt& aNumIsocTransfers, TInt& aNumIsocElements)
+ {
+ const TUint32 pageAddrBits = iPageSize-1;
+ const TUint32 pageTableMask = ~pageAddrBits;
+
+ //Get the maximum wMaxPacketSize of the associated interface for Bulk/Interrupt EPs
+ TInt maxMaxBulk = 0;
+ TInt maxMaxInterrupt = 0;
+ TInt err = GetMaximumMaxPacketSize(maxMaxBulk, maxMaxInterrupt);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ // Work out where to place the transfers, and how much space is needed.
+ TInt numTransfers = iRegisteredTransfers.Count();
+ for (TInt i=0; i < numTransfers; ++i)
+ {
+ TUsbTransferDescriptorDetails& details = iRegisteredTransfers[i];
+
+ err = CaculateAdditionalAlignment(aCurrentOffset, maxMaxBulk, maxMaxInterrupt, details);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ // only allow intra-page alignment requests that are powers of 2 (so offset agnostic).
+ __ASSERT_ALWAYS(details.iRequiredAlignment <= iPageSize, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorAlignmentOverPageBoundary));
+ __ASSERT_ALWAYS(IsPowerOfTwo(details.iRequiredAlignment), UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorAlignmentNotPowerOfTwo));
+
+ TInt alignPad = IncNeededToAlign(aCurrentOffset, details.iRequiredAlignment);
+ __ASSERT_DEBUG(alignPad < iPageSize, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadAlignment)); // just re-asserting what should be guarded above
+ aCurrentOffset += alignPad; // Align to the start of transfer buffer
+
+ // There are stark differences between isoc transfers and transfer of other types.
+ if (details.iTransferDesc.iType == RUsbTransferDescriptor::EIsochronous)
+ {
+ // First do some Isoc specific checks
+ __ASSERT_ALWAYS(details.iRequiredMaxPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorNoPacketsRequested));
+
+ // For the allocation we have to consider the worse case - that is that the max
+ // number of packets at the max packet size.
+ // We are constrained by the USB stack to not allow transfers across page boundaries.
+
+ // As such we calculate how many packets we can fit into a page to determine the
+ // number of pages for data we need.
+ const TInt packetsPerPage = iPageSize/details.iRequiredSize;
+
+ // Assign the start to an appropriate point.
+ details.iAssignedOffset = aCurrentOffset;
+ TInt packetsToStore = details.iRequiredMaxPackets;
+ TInt numElements = 0; // for counting up the number of pages we need meta-data for.
+
+ // The size requried to hold a length array for the descriptor
+ const TInt lengthsArrayLength = UsbZeroCopyIsocChunkHeader::KLengthsElementSize * details.iRequiredMaxPackets;
+ // The size required to hold a result array for the descriptor
+ const TInt resultsArrayLength = UsbZeroCopyIsocChunkHeader::KResultsElementSize * details.iRequiredMaxPackets;
+
+ // Determine how much we can fit into the remaining space of the current page.
+ TBool samePage = (pageTableMask & aCurrentOffset) == (pageTableMask & (aCurrentOffset - alignPad));
+ if (samePage)
+ {
+ TInt remainingSpace = iPageSize - (pageAddrBits & aCurrentOffset);
+ TInt packetsThatFit = remainingSpace / details.iRequiredSize;
+ if (packetsThatFit >= packetsToStore)
+ {
+ // We can fit it in this page so we finish here - this is the special case.
+ aCurrentOffset += packetsToStore * details.iRequiredSize;
+ ++aNumIsocElements;
+ ++aNumIsocTransfers;
+ details.iNumElements = 1;
+ // Do the lengths array
+ aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KLengthsElementSize);
+ details.iLengthsOffset = aCurrentOffset;
+ aCurrentOffset += lengthsArrayLength;
+ // The dual lengths array should be implicitly alligned
+ details.iReqLenOffset = aCurrentOffset;
+ aCurrentOffset += lengthsArrayLength;
+ // Now handle the results array
+ aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KResultsElementSize);
+ details.iResultsOffset = aCurrentOffset;
+ aCurrentOffset += resultsArrayLength;
+ continue;
+ }
+ aCurrentOffset = (pageTableMask & aCurrentOffset) + iPageSize; // Advance to next page
+ packetsToStore -= packetsThatFit;
+ ++numElements;
+ }
+ __ASSERT_DEBUG(packetsToStore > 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorNoPacketsLeftToStore));
+
+ // Determine the number of pages extra that are needed (minus one)
+ TInt pagesRequired = packetsToStore / packetsPerPage;
+
+ // Determine how much of the last page is actually needed.
+ TInt trailingPackets = packetsToStore % packetsPerPage;
+ TInt usedSpace = trailingPackets * details.iRequiredSize;
+
+ // Commit the amount for the buffers.
+ aCurrentOffset += usedSpace + pagesRequired*iPageSize;
+ numElements += pagesRequired + /*the final page*/1; // We have already included the first page (if already partially used)
+ aNumIsocElements += numElements;
+ ++aNumIsocTransfers;
+
+ // Used to ensure only allocate an appropriate number per-descriptor.
+ details.iNumElements = numElements;
+
+ // We also need an array of lengths for each packet that we use (need to align to even bytes).
+ aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KLengthsElementSize);
+ details.iLengthsOffset = aCurrentOffset;
+ aCurrentOffset += lengthsArrayLength;
+ // Dual length array should be implicitly aligned
+ details.iReqLenOffset = aCurrentOffset;
+ aCurrentOffset += lengthsArrayLength;
+ // Now handle the results array
+ aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KResultsElementSize);
+ details.iResultsOffset = aCurrentOffset;
+ aCurrentOffset += resultsArrayLength;
+ }
+ else
+ {
+ details.iAssignedOffset = aCurrentOffset;
+ aCurrentOffset += details.iRequiredSize;
+ ++aNumStandardTransfers;
+ }
+ }
+
+ return KErrNone;
+ }
+
+
+void RUsbZeroCopyTransferStrategy::CalculateMetaDataLayout(TInt& aCurrentOffset, TInt& aMetaDataStart, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements)
+ {
+ // Round up to 4 byte alignment for handling the meta-data correctly.
+ aCurrentOffset += IncNeededToAlign(aCurrentOffset, sizeof(TInt));
+
+ aMetaDataStart = aCurrentOffset;
+
+ // Now calculate the size required for the transfer meta-data.
+ aCurrentOffset += aNumStandardTransfers * UsbZeroCopyBulkIntrChunkHeader::HeaderSize();
+ aCurrentOffset += aNumIsocTransfers * UsbZeroCopyIsocChunkHeader::HeaderSize();
+ aCurrentOffset += aNumIsocElements * UsbZeroCopyIsocChunkElement::ElementSize();
+ }
+
+void RUsbZeroCopyTransferStrategy::InitialiseMetaData(TInt aMetaDataOffset, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements)
+ {
+ const TUint32 pageAddrBits = iPageSize-1;
+ const TUint32 pageTableMask = ~pageAddrBits;
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ TInt numTransfers = iRegisteredTransfers.Count();
+ for (TInt i=0; i < numTransfers; ++i)
+ {
+ TUsbTransferDescriptorDetails details = iRegisteredTransfers[i];
+
+ if (details.iTransferDesc.iType == RUsbTransferDescriptor::EIsochronous)
+ {
+ // Initialise Meta-data (minus elements).
+ UsbZeroCopyIsocChunkHeader::TransferType(chunkBase, aMetaDataOffset) = details.iTransferDesc.iType;
+ UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aMetaDataOffset) = details.iRequiredMaxPackets;
+ UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aMetaDataOffset) = details.iRequiredSize;
+ // Double check that the length array is aligned correctly.
+ __ASSERT_DEBUG(details.iLengthsOffset % UsbZeroCopyIsocChunkHeader::KLengthsElementSize == 0,
+ UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorLengthsArrayBadAlignment));
+ UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aMetaDataOffset) = details.iLengthsOffset;
+ UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aMetaDataOffset) = details.iReqLenOffset;
+ // Double check that the result array is aligned correctly.
+ __ASSERT_DEBUG(details.iResultsOffset % UsbZeroCopyIsocChunkHeader::KResultsElementSize == 0,
+ UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorResultsArrayBadAlignment));
+ UsbZeroCopyIsocChunkHeader::ResultsOffset(chunkBase, aMetaDataOffset) = details.iResultsOffset;
+ // Initialise transfer descriptor
+ SetTransferHandle(details.iTransferDesc, aMetaDataOffset);
+ // Move on to next meta-data slot
+ TInt prevMetaOffset = aMetaDataOffset;
+ aMetaDataOffset += UsbZeroCopyIsocChunkHeader::HeaderSize();
+
+ // Initialise elements for transfers
+ UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, prevMetaOffset) = aMetaDataOffset;
+
+ TInt isocElementsUnmapped = details.iNumElements;
+ // First element could be anywhere, the others are at the start of (virtually) contiguous pages
+ TInt offset = details.iAssignedOffset;
+ while (isocElementsUnmapped > 0)
+ {
+ // Update the data references
+ UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, aMetaDataOffset) = offset;
+ UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aMetaDataOffset) = 0; // Default value.
+ // Move on to the next element and bind it to the chain.
+ prevMetaOffset = aMetaDataOffset;
+ aMetaDataOffset += UsbZeroCopyIsocChunkElement::ElementSize();
+ UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, prevMetaOffset) = aMetaDataOffset;
+ // Move to the next page
+ offset = (pageTableMask&offset)+iPageSize;
+ --isocElementsUnmapped;
+ --aNumIsocElements;
+ }
+ // We have reached the end of the list so we should update the next element offset for the
+ // last element to indicate that it is the terminator.
+ UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, prevMetaOffset) = UsbZeroCopyIsocChunkElement::KEndOfList;
+ --aNumIsocTransfers;
+ }
+ else
+ {
+ // Initialise Meta-data.
+ UsbZeroCopyBulkIntrChunkHeader::TransferType(chunkBase, aMetaDataOffset) = details.iTransferDesc.iType;
+ UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aMetaDataOffset) = details.iAssignedOffset;
+ UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aMetaDataOffset) = 0;
+ UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aMetaDataOffset) = details.iRequiredSize;
+ UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(chunkBase, aMetaDataOffset) = RUsbTransferDescriptor::ESendZlpIfRequired;
+ // Initialise transfer descriptor
+ SetTransferHandle(details.iTransferDesc, aMetaDataOffset);
+ // Move on to next meta-data slot
+ aMetaDataOffset += UsbZeroCopyBulkIntrChunkHeader::HeaderSize();
+ --aNumStandardTransfers;
+ }
+ }
+
+ __ASSERT_DEBUG(aNumStandardTransfers == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation));
+ __ASSERT_DEBUG(aNumIsocTransfers == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation));
+ __ASSERT_DEBUG(aNumIsocElements == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation));
+ }
+
+
+TBool RUsbZeroCopyTransferStrategy::IsPowerOfTwo(TUint aNumber)
+ {
+ return aNumber && !(aNumber & (aNumber - 1)); //this returns true if the integer is a power of two
+ }
+
+
+TInt RUsbZeroCopyTransferStrategy::IncNeededToAlign(TInt aOffset, TUint aAlignment)
+ {
+ if (aAlignment == 0)
+ {
+ return 0;
+ }
+ TInt remain = aOffset % aAlignment;
+ return (aAlignment - remain) % aAlignment;
+ }
+
+
+// Standard Methods
+
+TPtr8 RUsbZeroCopyTransferStrategy::WritableBuffer(TInt aHandle)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ TUint8* dataPtr = chunkBase + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aHandle);
+ TInt maxLength = UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aHandle);
+
+ return TPtr8(dataPtr, 0, maxLength);
+ }
+
+void RUsbZeroCopyTransferStrategy::SaveData(TInt aHandle, TInt aLength)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ TInt maxLength = UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aHandle);
+ __ASSERT_ALWAYS(aLength <= maxLength, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavedToMuchData));
+
+ UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aHandle) = aLength;
+ }
+
+void RUsbZeroCopyTransferStrategy::SetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(chunkBase, aHandle) = aZlpStatus;
+ }
+
+TPtrC8 RUsbZeroCopyTransferStrategy::Buffer(TInt aHandle) const
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ TUint8* dataPtr = chunkBase + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aHandle);
+ TInt length = UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aHandle);
+
+ return TPtrC8(dataPtr, length);
+ }
+
+
+
+
+// Isochronous Methods
+
+void RUsbZeroCopyTransferStrategy::Reset(TInt aHandle)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ // Loop through and reset number of packets in each element as 0
+ TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle);
+ while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList)
+ {
+ UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = 0;
+ elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset);
+ }
+ }
+
+TPacketLengths RUsbZeroCopyTransferStrategy::Lengths(TInt aHandle)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle);
+ TUint16* lengthsPtr = reinterpret_cast<TUint16*>(chunkBase + lengthsOffset);
+
+ TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle);
+ TUint16* reqLenPtr = reinterpret_cast<TUint16*>(chunkBase + reqLenOffset);
+
+ TInt& maxNumPackets = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle);
+
+ return TPacketLengths(lengthsPtr, reqLenPtr, maxNumPackets);
+ }
+
+TPacketResults RUsbZeroCopyTransferStrategy::Results(TInt aHandle)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ TInt resultsOffset = UsbZeroCopyIsocChunkHeader::ResultsOffset(chunkBase, aHandle);
+ TInt* resultsPtr = reinterpret_cast<TInt*>(chunkBase + resultsOffset);
+
+ TInt& maxNumPackets = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle);
+
+ return TPacketResults(resultsPtr, maxNumPackets);
+ }
+
+TInt RUsbZeroCopyTransferStrategy::MaxPacketSize(TInt aHandle)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle);
+
+ return maxPacketSize;
+ }
+
+TPtr8 RUsbZeroCopyTransferStrategy::WritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+ __ASSERT_DEBUG(aWriteHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadWriteHandle));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ const TUint32 pageAddrBits = iPageSize-1;
+ const TUint32 pageTableMask = ~pageAddrBits;
+
+ if (aHandle == aWriteHandle)
+ {
+ // The initial write handle will be the same as the standard handle so we need to find the actual
+ // element to work correctly.
+ aWriteHandle = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle);
+ }
+
+ // Now we have two cases - the number of packets requested is contained in one page, or it crosses the page.
+ // 1) If we cross the page then we get the buffer for upto the end of the page, and inform the user of the number
+ // of packets they are able to write into it (normally this will be quite high as we can consider 0 length
+ // packets.)
+ // 2) If we are on one page then we provide a buffer to the end of the page and return the number of packets
+ // the requested as the max they can write. However we also now mark it so that an attempt to get a subsequent
+ // writable buffer will return a 0 max length TPtr8 and 0 max number of packets to write. If they want write
+ // more they need to reset the descriptor and start again.
+
+ if (UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) == UsbZeroCopyIsocChunkElement::KInvalidElement)
+ {
+ // Here we are testing the second case, if we previously marked an element as invalid then we must not
+ // return a valid buffer.
+ aMaxNumPacketsAbleToWrite = 0;
+ return TPtr8(NULL, 0);
+ }
+
+ TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, aWriteHandle);
+
+ TUint8* dataPtr = chunkBase + dataOffset;
+ TInt totalMaxSize = aNumPacketsRequested * UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle);
+ // The USB stack requires isoc transfer to be limited to a page (not allowed to cross the boundary).
+ TUint32 dataAddr = reinterpret_cast<TUint32>(dataPtr);
+ TBool samePage = (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalMaxSize));
+ TInt allowableSize = samePage ? totalMaxSize : iPageSize - (pageAddrBits & dataAddr);
+
+ TInt numPacketsRemaining = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle) - UsedPackets(aHandle);
+
+ if (aNumPacketsRequested < numPacketsRemaining)
+ {
+ // This is the 2nd case as documented in the comment. So we mark the next packet as invalid.
+ aMaxNumPacketsAbleToWrite = aNumPacketsRequested;
+ TInt nextElement = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, aWriteHandle);
+ if (nextElement != UsbZeroCopyIsocChunkElement::KEndOfList)
+ {
+ UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, nextElement) = UsbZeroCopyIsocChunkElement::KInvalidElement; // Mark as invalid.
+ }
+ // else we are at the end of the list anyway
+ }
+ else
+ {
+ aMaxNumPacketsAbleToWrite = numPacketsRemaining;
+ }
+
+ return TPtr8(dataPtr, allowableSize);
+ }
+
+TInt RUsbZeroCopyTransferStrategy::SaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumPackets)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+ __ASSERT_DEBUG(aWriteHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadWriteHandle));
+ __ASSERT_ALWAYS(aNumPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorNoPacketsToSave));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ if (aHandle == aWriteHandle)
+ {
+ aWriteHandle = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle);
+ }
+
+ // if marked invalid then they shouldn't try to save it (they haven't been able to write anything into the data anyway).
+ __ASSERT_ALWAYS(UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) != UsbZeroCopyIsocChunkElement::KInvalidElement,
+ UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorInvalidSaveCall));
+
+ // Ensure they've not tried to write in too many packets
+ TInt usedPackets = UsedPackets(aHandle);
+ __ASSERT_ALWAYS(aNumPackets + usedPackets <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle),
+ UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavedTooManyPackets));
+
+ // Check that the length values have not exceeded the maximum.
+ TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle);
+ TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle);
+ TUint16* lengthsPtr = reinterpret_cast<TUint16*>(chunkBase + lengthsOffset);
+#ifdef _DEBUG
+ // The requested length is only functionally needed for IN transfers, but it provides an
+ // extra check that the length values that were requested by the user are those that are
+ // been requested on the USB stack.
+ TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle);
+ TUint16* reqLenPtr = reinterpret_cast<TUint16*>(chunkBase + reqLenOffset);
+#endif // _DEBUG
+ for (TInt i=0; i < aNumPackets; ++i)
+ {
+ __ASSERT_ALWAYS(lengthsPtr[usedPackets + i] <= maxPacketSize, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavingTooLargeAPacket));
+ __ASSERT_DEBUG(lengthsPtr[usedPackets + i] == reqLenPtr[usedPackets + i], UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces
+ }
+
+ // Commit the packets to the transfer descriptor.
+ UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) = aNumPackets;
+ TInt headerOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, aWriteHandle);
+
+ // Return the handle to the next region for writing.
+ return (headerOffset == UsbZeroCopyIsocChunkElement::KEndOfList) ? KErrEof : headerOffset;
+ }
+
+/**
+Used to walk the elements to total up the number of packets that have been saved in the transfer descriptor.
+*/
+TInt RUsbZeroCopyTransferStrategy::UsedPackets(TInt aHeaderOffset)
+ {
+ __ASSERT_DEBUG(aHeaderOffset >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorInvalidHeaderOffset));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+ TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHeaderOffset);
+ TInt totalNumPackets = 0;
+ while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList)
+ {
+ TInt numPackets = UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset);
+ if (numPackets == 0 || numPackets == UsbZeroCopyIsocChunkElement::KInvalidElement)
+ {
+ break;
+ }
+ totalNumPackets += numPackets;
+ elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset);
+ }
+ return totalNumPackets;
+ }
+
+/**
+Used to read packets out from the transfer descriptor.
+Note that some of the panics are belt'n'braces, and are used to sanity test result that has been
+provided. These should be correct (as the results are set by the kernel), however because the user
+has access to length array (for writing out packets) it is possible for them to 'corrupt' the result.
+We panic explicitly in UDEB builds, in UREL the guards are not present and the user may get returned
+a bad descriptor.
+*/
+TPtrC8 RUsbZeroCopyTransferStrategy::Packets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+ __ASSERT_ALWAYS(aFirstPacketIndex >= 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorPacketNotInBounds));
+ __ASSERT_ALWAYS(aNumPacketsRequested > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooFewPacketsRequested));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ __ASSERT_ALWAYS(aNumPacketsRequested <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle),
+ UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooManyPacketsRequested));
+
+#ifdef _DEBUG
+ const TUint32 pageAddrBits = iPageSize-1;
+ const TUint32 pageTableMask = ~pageAddrBits;
+#endif // _DEBUG
+ const TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle);
+
+ TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle);
+ TInt packetCount = 0;
+ while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList)
+ {
+ TInt numPackets = UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset);
+ if (numPackets == 0 || numPackets == UsbZeroCopyIsocChunkElement::KInvalidElement)
+ {
+ // We've got to the end of the elements and not found the packets we are after.
+ break;
+ }
+ TInt previousPacketCount = packetCount;
+ packetCount += numPackets;
+ if (aFirstPacketIndex < packetCount) // If true then start packet must be in this element
+ {
+ TInt intraElementIndex = aFirstPacketIndex - previousPacketCount;
+ TInt maxPacketsForReturn = packetCount - aFirstPacketIndex;
+
+ TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle);
+ TUint16* lengthsPtr = reinterpret_cast<TUint16*>(chunkBase + lengthsOffset + previousPacketCount * sizeof(TUint16));
+ TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle);
+ TUint16* reqLenPtr = reinterpret_cast<TUint16*>(chunkBase + reqLenOffset + previousPacketCount * sizeof(TUint16));
+
+ aNumPacketsReturned = (aNumPacketsRequested < maxPacketsForReturn) ? aNumPacketsRequested : maxPacketsForReturn;
+
+ TInt distanceToReqPacket = 0;
+ for (TInt i=0; i < intraElementIndex; ++i)
+ {
+ TUint16 reqLen = reqLenPtr[i];
+ __ASSERT_DEBUG(reqLen <= maxPacketSize,
+ UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorReceivedTooLargeAPacket)); // Belt'n'Braces
+ distanceToReqPacket += reqLen;
+ }
+ TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, elementOffset);
+ TUint8* dataPtr = chunkBase + dataOffset + distanceToReqPacket;
+
+ TInt totalLengthPackets = 0;
+ for (TInt i=0; i < aNumPacketsReturned; ++i)
+ {
+ TUint16 len = lengthsPtr[intraElementIndex + i];
+ TUint16 reqLen = reqLenPtr[intraElementIndex + i];
+ __ASSERT_DEBUG(len <= maxPacketSize,
+ UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorReceivedTooLargeAPacket)); // Belt'n'Braces
+
+ totalLengthPackets += len;
+
+ // Here we handle the potential gaps that may appear in the data stream if a short
+ // packet is received.
+ if (len < reqLen)
+ {
+ // if here then we received a short packet, as such we can only return up to here
+ aNumPacketsReturned = i+1;
+ break;
+ }
+ // Otherwise we expect them to be equal (if we got more than requested then something odd has happened.
+ __ASSERT_DEBUG(len == reqLen, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces
+ }
+
+ // The USB stack requires isoc transfer to be limited to a page (not allowed to cross the boundary).
+ // Therefore one of our elements must have data only on one page.
+#ifdef _DEBUG
+ TUint32 dataAddr = reinterpret_cast<TUint32>(dataPtr);
+ TBool samePage = (totalLengthPackets == 0) || (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalLengthPackets - 1));
+ __ASSERT_DEBUG(samePage, UsbdiUtils::Panic(UsbdiPanics::EIsocTransferResultCrossesPageBoundary)); // Belt'n'Braces
+#endif // _DEBUG
+
+ return TPtrC8(dataPtr, totalLengthPackets);
+ }
+
+ // No luck so far, move on to try the next element
+ elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset);
+ }
+
+ // No suitable packet range found.
+ aNumPacketsReturned = 0;
+ return TPtrC8(NULL, 0);
+ }
+
+void RUsbZeroCopyTransferStrategy::ReceivePackets(TInt aHandle, TInt aNumPackets)
+ {
+ __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle));
+ __ASSERT_ALWAYS(aNumPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooFewPacketsRequested));
+
+ TUint8* chunkBase = iChunk.Base() + iBaseOffset;
+
+ __ASSERT_ALWAYS(aNumPackets <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle),
+ UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooManyPacketsRequested));
+
+ const TUint32 pageAddrBits = iPageSize-1;
+ const TUint32 pageTableMask = ~pageAddrBits;
+ const TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle);
+
+#ifdef _DEBUG
+ // Here we make the best check we can that the user has set-up the requested lengths they require.
+ // If there is a difference, they have either a corrupted metadata chunk, or they are reusing a
+ // previous buffer without setting the lengths requested.
+ TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle);
+ TUint16* lengthsPtr = reinterpret_cast<TUint16*>(chunkBase + lengthsOffset);
+ TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle);
+ TUint16* reqLenPtr = reinterpret_cast<TUint16*>(chunkBase + reqLenOffset);
+ for (TInt i=0; i < aNumPackets; ++i)
+ {
+ __ASSERT_DEBUG(lengthsPtr[i] == reqLenPtr[i],
+ UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces
+ }
+#endif // _DEBUG
+
+ TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle);
+ while (aNumPackets)
+ {
+ __ASSERT_DEBUG(elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList,
+ UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorUnexpectedEndOfIsocList));
+
+ TInt totalMaxSize = aNumPackets * maxPacketSize;
+
+ TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, elementOffset);
+ TUint8* dataPtr = chunkBase + dataOffset;
+ TUint32 dataAddr = reinterpret_cast<TUint32>(dataPtr);
+ TBool samePage = (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalMaxSize));
+ TInt allowableSize = samePage ? totalMaxSize : iPageSize - (pageAddrBits & dataAddr);
+ TInt numPackets = allowableSize / maxPacketSize;
+
+ // TODO We could assert here in debug as a double check using UsedPackets()
+
+ __ASSERT_DEBUG(numPackets > 0,
+ UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorUnfillableElement));
+
+ UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = numPackets;
+ aNumPackets -= numPackets;
+
+ elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset);
+ }
+
+ if (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList)
+ {
+ UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = UsbZeroCopyIsocChunkElement::KInvalidElement; // Mark as invalid.
+ }
+ }
+
+
+
+
+
+TPtr8 RUsbZeroCopyTransferStrategy::IntrWritableBuffer(TInt aHandle)
+ {
+ return WritableBuffer(aHandle);
+ }
+
+void RUsbZeroCopyTransferStrategy::IntrSaveData(TInt aHandle, TInt aLength)
+ {
+ SaveData(aHandle, aLength);
+ }
+
+void RUsbZeroCopyTransferStrategy::IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus)
+ {
+ SetZlpStatus(aHandle, aZlpStatus);
+ }
+
+TPtrC8 RUsbZeroCopyTransferStrategy::IntrBuffer(TInt aHandle) const
+ {
+ return Buffer(aHandle);
+ }
+
+TPtr8 RUsbZeroCopyTransferStrategy::BulkWritableBuffer(TInt aHandle)
+ {
+ return WritableBuffer(aHandle);
+ }
+
+void RUsbZeroCopyTransferStrategy::BulkSaveData(TInt aHandle, TInt aLength)
+ {
+ SaveData(aHandle, aLength);
+ }
+
+void RUsbZeroCopyTransferStrategy::BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus)
+ {
+ SetZlpStatus(aHandle, aZlpStatus);
+ }
+
+TPtrC8 RUsbZeroCopyTransferStrategy::BulkBuffer(TInt aHandle) const
+ {
+ return Buffer(aHandle);
+ }
+
+void RUsbZeroCopyTransferStrategy::IsocReset(TInt aHandle)
+ {
+ Reset(aHandle);
+ }
+
+TPacketLengths RUsbZeroCopyTransferStrategy::IsocLengths(TInt aHandle)
+ {
+ return Lengths(aHandle);
+ }
+
+TPacketResults RUsbZeroCopyTransferStrategy::IsocResults(TInt aHandle)
+ {
+ return Results(aHandle);
+ }
+
+TInt RUsbZeroCopyTransferStrategy::IsocMaxPacketSize(TInt aHandle)
+ {
+ return MaxPacketSize(aHandle);
+ }
+
+TPtr8 RUsbZeroCopyTransferStrategy::IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite)
+ {
+ return WritablePackets(aHandle, aWriteHandle, aNumPacketsRequested, aMaxNumPacketsAbleToWrite);
+ }
+
+TInt RUsbZeroCopyTransferStrategy::IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets)
+ {
+ return SaveMultiple(aHandle, aWriteHandle, aNumOfPackets);
+ }
+
+TPtrC8 RUsbZeroCopyTransferStrategy::IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const
+ {
+ return Packets(aHandle, aFirstPacketIndex, aNumPacketsRequested, aNumPacketsReturned);
+ }
+
+void RUsbZeroCopyTransferStrategy::IsocReceivePackets(TInt aHandle, TInt aNumOfPackets)
+ {
+ ReceivePackets(aHandle, aNumOfPackets);
+ }
+
+
+//Calculate-alignment related methods
+
+/**
+ Scan through all the bulk/interrupt endpoints associated with the particular interface
+ (and all its alternate settings) to find the maximum bMaxPacketSize across all of these.
+ For Interrupt, if there is EP of which the maxPacketSize is not power of 2,
+ the maxmaxpaceketsize will be assigned the first maxPacketSize which is not power of 2.
+*/
+TInt RUsbZeroCopyTransferStrategy::GetMaximumMaxPacketSize(TInt& aMaxMaxBulk, TInt& aMaxMaxInterrupt)
+ {
+ TUsbInterfaceDescriptor interfaceDesc;
+ TInt err = iInterfaceHandle->GetInterfaceDescriptor(interfaceDesc);
+ if (KErrNone != err)
+ {
+ return err;
+ }
+
+ const TUint8 KEPTransferTypeBulk = 0x02;
+ const TUint8 KEPTransferTypeInterrupt = 0x03;
+ const TUint8 KEPTransferTypeMask = 0x03;
+
+ TBool ignoreInterruptEP = EFalse;
+ //Traverse all related interface alternate settings
+ TUsbGenericDescriptor* descriptor = &interfaceDesc;
+ while (descriptor)
+ {
+ TUsbInterfaceDescriptor* interface = TUsbInterfaceDescriptor::Cast(descriptor);
+
+ if (interface)
+ {
+ //Traverse all endpoint descriptor in the interface
+ TUsbGenericDescriptor* subDescriptor = interface->iFirstChild;
+
+ while (subDescriptor)
+ {
+ TUsbEndpointDescriptor* endpoint = TUsbEndpointDescriptor::Cast(subDescriptor);
+
+ if (endpoint)
+ {
+ TBool isBulkEP = ((endpoint->Attributes() & KEPTransferTypeMask) == KEPTransferTypeBulk);
+ TBool isInterruptEP = ((endpoint->Attributes() & KEPTransferTypeMask) == KEPTransferTypeInterrupt);
+ TUint maxPacketSize = endpoint->MaxPacketSize();
+
+ //Caculate the maximum maxPacketSize
+ if (isBulkEP)
+ {
+ if (maxPacketSize > aMaxMaxBulk)
+ {
+ aMaxMaxBulk = maxPacketSize;
+ }
+ }
+ else if(isInterruptEP && !ignoreInterruptEP)
+ {
+ if (!IsPowerOfTwo(maxPacketSize))
+ {
+ aMaxMaxInterrupt = maxPacketSize;
+ ignoreInterruptEP = ETrue;
+ }
+
+ if (maxPacketSize > aMaxMaxInterrupt)
+ {
+ aMaxMaxInterrupt = maxPacketSize;
+ }
+ }
+ }
+
+ subDescriptor = subDescriptor->iNextPeer;
+ }
+ }
+
+ descriptor = descriptor->iNextPeer;
+ }
+
+ return KErrNone;
+ }
+
+/**
+Calculate the additional alignment requirement on bulk and interrupt transfer.
+For Bulk transfer,
+ Scan through all the bulk/interrupt endpoints associated with the particular interface
+ to find the maximum wMaxPacketSize across all of these. The new alignment for the transfer
+ is the maximum between the maximum bMaxPacketSize and the original alignment
+For Interrupt transfer,
+ Check if there is endpoints of which the wMaxPacketSize is not power of 2,
+ if no, do the same as bulk;
+ if yes, the size of transfer data is limited to one page size, and the additional alignment
+ calcualted to make the transfer data not to span page boundary
+
+*/
+TInt RUsbZeroCopyTransferStrategy::CaculateAdditionalAlignment(TInt aCurrentOffset, TInt aMaxMaxBulk, TInt aMaxMaxInterrupt, TUsbTransferDescriptorDetails& aTransferDetails)
+ {
+ RUsbTransferDescriptor::TTransferType transferType = aTransferDetails.iTransferDesc.iType;
+ TBool isBulkTransfer = (transferType == RUsbTransferDescriptor::EBulk);
+ TBool isInterruptTransfer = (transferType == RUsbTransferDescriptor::EInterrupt);
+
+ if (isBulkTransfer)
+ {
+ if (aMaxMaxBulk > aTransferDetails.iRequiredAlignment)
+ {
+ aTransferDetails.iRequiredAlignment = aMaxMaxBulk;
+ }
+ }
+ else if (isInterruptTransfer)
+ {
+ if (IsPowerOfTwo(aMaxMaxInterrupt))
+ {
+ if (aMaxMaxInterrupt > aTransferDetails.iRequiredAlignment)
+ {
+ aTransferDetails.iRequiredAlignment = aMaxMaxInterrupt;
+ }
+ }
+ else
+ {
+ if (aTransferDetails.iRequiredSize > iPageSize)
+ {
+ //The transfer data can not span the page boundary
+ //if there is EP of which wMaxPacketSize is not power-of-2,
+ return KErrNotSupported;
+ }
+ else
+ {
+ TInt sizeLeftOfCurrentPage = IncNeededToAlign(aCurrentOffset,iPageSize);
+ TInt alignPad = IncNeededToAlign(aCurrentOffset, aTransferDetails.iRequiredAlignment);
+
+ //The transfer data can't fit into the current page
+ //Align the trasfer data to the next page
+ if ( sizeLeftOfCurrentPage < (alignPad + aTransferDetails.iRequiredSize) )
+ {
+ aTransferDetails.iRequiredAlignment = iPageSize;
+ }
+ }
+ }
+ }
+ return KErrNone;
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.h Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,112 @@
+// Copyright (c) 2007-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#ifndef ZEROCOPYTRANSFERSTRATEGY_H
+#define ZEROCOPYTRANSFERSTRATEGY_H
+
+#include "usbtransferstrategy.h"
+
+
+NONSHARABLE_CLASS(RUsbZeroCopyTransferStrategy) : public RUsbTransferStrategy
+ {
+public:
+ RUsbZeroCopyTransferStrategy();
+ virtual TInt RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets);
+ virtual void ResetTransferDescriptors();
+ virtual TInt InitialiseTransferDescriptors(RUsbInterface& aInterface);
+
+ virtual void Close();
+
+public: // Interrupt transfer descriptor methods
+ virtual TPtr8 IntrWritableBuffer(TInt aHandle);
+ virtual void IntrSaveData(TInt aHandle, TInt aLength);
+ virtual void IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus);
+ virtual TPtrC8 IntrBuffer(TInt aHandle) const;
+public: // Bulk transfer descriptor methods
+ virtual TPtr8 BulkWritableBuffer(TInt aHandle);
+ virtual void BulkSaveData(TInt aHandle, TInt aLength);
+ virtual void BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus);
+ virtual TPtrC8 BulkBuffer(TInt aHandle) const;
+public: // Isochronous transfer descriptor methods
+ virtual void IsocReset(TInt aHandle);
+ virtual TPacketLengths IsocLengths(TInt aHandle);
+ virtual TPacketResults IsocResults(TInt aHandle);
+ virtual TInt IsocMaxPacketSize(TInt aHandle);
+ virtual TPtr8 IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite);
+ virtual TInt IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets);
+ virtual TPtrC8 IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const;
+ virtual void IsocReceivePackets(TInt aHandle, TInt aNumOfPackets);
+
+
+private: // Standard (Bulk, Ctrl and Intr) Buffer methods
+ TPtr8 WritableBuffer(TInt aHandle);
+ void SaveData(TInt aHandle, TInt aLength);
+ void SetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus);
+ TPtrC8 Buffer(TInt aHandle) const;
+
+private: // Isoc Buffer methods
+ void Reset(TInt aHandle);
+ TPacketLengths Lengths(TInt aHandle);
+ TPacketResults Results(TInt aHandle);
+ TInt MaxPacketSize(TInt aHandle);
+ TPtr8 WritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite);
+ TInt SaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets);
+ TPtrC8 Packets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const;
+ void ReceivePackets(TInt aHandle, TInt aNumOfPackets);
+
+private:
+ NONSHARABLE_STRUCT(TUsbTransferDescriptorDetails)
+ {
+ TUsbTransferDescriptorDetails(RUsbTransferDescriptor&, TInt, TUint, TInt);
+ RUsbTransferDescriptor& iTransferDesc;
+ const TInt iRequiredSize;
+ TUint iRequiredAlignment;
+ const TInt iRequiredMaxPackets;
+ // Members to aid internal logic
+ TInt iAssignedOffset;
+ TInt iLengthsOffset; // Only applicable to isoc
+ TInt iReqLenOffset; // Only applicable to isoc
+ TInt iResultsOffset; // Only applicable to isoc
+ TInt iNumElements; // Only applicable to isoc
+ };
+
+private:
+ TInt CalculateDataLayout(TInt& aCurrentOffset, TInt& aNumStandardTransfers, TInt& aNumIsocTransfers, TInt& aNumIsocElements);
+ void CalculateMetaDataLayout(TInt& aCurrentOffset, TInt& aMetaDataStart, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements);
+ void InitialiseMetaData(TInt aMetaDataOffset, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements);
+ TInt UsedPackets(TInt aHeaderOffset);
+ TBool IsPowerOfTwo(TUint aNumber);
+ TInt IncNeededToAlign(TInt aOffset, TUint aAlignment);
+ static TBool CompareTransferDescriptor(const RUsbTransferDescriptor* aTransferDesc, const TUsbTransferDescriptorDetails& aDetails);
+
+private: //Calculate additional alignment related methods
+ TInt GetMaximumMaxPacketSize(TInt& aMaxMaxBulk, TInt& aMaxMaxInterrupt);
+ TInt CaculateAdditionalAlignment(TInt aCurrentOffset, TInt aMaxMaxBulk, TInt aMaxMaxInterrupt, TUsbTransferDescriptorDetails& aTransferDetails);
+private:
+ RArray<TUsbTransferDescriptorDetails> iRegisteredTransfers;
+
+private:
+ RUsbInterface* iInterfaceHandle;
+ RChunk iChunk;
+ TInt iBaseOffset;
+ TInt iPageSize;
+ };
+
+#endif // ZEROCOPYTRANSFERSTRATEGY_H
--- a/kernel/eka/include/d32otgdi_errors.h Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/include/d32otgdi_errors.h Wed Apr 14 17:22:59 2010 +0300
@@ -41,6 +41,8 @@
const TInt KErrUsbOtgBadState = -6675;
+const TInt KErrUsbOtgInOPTTestingMode = -6676;
+
const TInt KErrUsbOtgStackNotStarted = -6680;
const TInt KErrUsbOtgVbusAlreadyRaised = -6681;
const TInt KErrUsbOtgSrpForbidden = -6682;
--- a/kernel/eka/include/drivers/locmedia.h Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/include/drivers/locmedia.h Wed Apr 14 17:22:59 2010 +0300
@@ -23,7 +23,7 @@
#if defined(_DEBUG) && defined(__DEMAND_PAGING__)
#define __CONCURRENT_PAGING_INSTRUMENTATION__
#endif
-#if defined(_DEBUG) && defined(__DEMAND_PAGING__)
+#ifdef __DEMAND_PAGING__
#define __DEMAND_PAGING_BENCHMARKS__
#endif
--- a/kernel/eka/include/e32ver.h Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/include/e32ver.h Wed Apr 14 17:22:59 2010 +0300
@@ -28,7 +28,7 @@
const TInt KE32MajorVersionNumber=2;
const TInt KE32MinorVersionNumber=0;
-const TInt KE32BuildVersionNumber=2102;
+const TInt KE32BuildVersionNumber=2109;
const TInt KMachineConfigurationMajorVersionNumber=1;
const TInt KMachineConfigurationMinorVersionNumber=0;
--- a/kernel/eka/kernel/ekern.mmp Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/kernel/ekern.mmp Wed Apr 14 17:22:59 2010 +0300
@@ -50,6 +50,7 @@
// we have to keep this here, and not in kern_int.mmh, because media drivers
// use the same macro name for different puposes...
macro __DEMAND_PAGING__
+macro __DEMAND_PAGING_BENCHMARKS__
#endif
--- a/kernel/eka/kernel/kern_int.mmh Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/kernel/kern_int.mmh Wed Apr 14 17:22:59 2010 +0300
@@ -61,10 +61,6 @@
macro __SUPPORT_DEMAND_PAGING_EMULATION__
#endif
-#if defined(DEMAND_PAGING) && defined(DEMAND_PAGING_BENCHMARKS)
-macro __DEMAND_PAGING_BENCHMARKS__
-#endif
-
#ifdef SYMBIAN_OLD_EXPORT_LOCATION
systeminclude ../include/kernel
#endif
--- a/kernel/eka/release.txt Wed Mar 31 23:38:45 2010 +0300
+++ b/kernel/eka/release.txt Wed Apr 14 17:22:59 2010 +0300
@@ -1,3 +1,69 @@
+Version 2.00.2109
+=================
+(Made by vfebvre 29/03/2010)
+
+1. mmoate
+ 1. DEF145151 \e32utils\nistsecurerng\* has incorrect distribution.policy.s60 ID
+
+
+Version 2.00.2108
+=================
+(Made by vfebvre 26/03/2010)
+
+1. seolney
+ 1. DEF144784 Fault possible if client deletes DMA request in callback
+
+2. jimmzhou
+ 1. ou1cimx1#320637[kernel92]Phone Crash when USB MobileTV device CU-14A is connected
+
+3. gcochran
+ 1. DEF145128 TRLM-83EGSL Paging HAL stats not visible in TB92
+
+
+Version 2.00.2107
+=================
+(Made by vfebvre 24/03/2010)
+
+1. lanerobe
+ 1. DEF144929 KHS Documentation is not contributed to the Symbian Foundation
+
+
+Version 2.00.2106
+=================
+(Made by vfebvre 23/03/2010)
+
+1. lanerobe
+ 1. DEF144874 Intermittent E32TEST T_MSTIM test failures on the H4 (line 371)
+
+
+Version 2.00.2105
+=================
+(Made by vfebvre 22/03/2010)
+
+1. josezhou
+ 1. ou1cimx1#312934 : RUsbHubDriver interface can only be called by FDF, but multiple clients might have conflict requests to the interfaces
+
+2. ferporta
+ 1. PDEF145131 System Crash Monitor contains memory model dependent #defines
+ 2. DEF144875 E32TEST T_RMDEBUG2_OEM failing on UREL SMP configurations
+
+
+Version 2.00.2104
+=================
+(Made by vfebvre 19/03/2010)
+
+1. lanerobe
+ 1. DEF144712 Symbian Foundation build error due to missing usb components
+
+
+Version 2.00.2103
+=================
+(Made by vfebvre 18/03/2010)
+
+1. genwei
+ 1. ou1cimx1#301151: The device under test exits the high-speed host electrical test mode without operator action
+
+
Version 2.00.2102
=================
(Made by vfebvre 17/03/2010)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp Wed Apr 14 17:22:59 2010 +0300
@@ -0,0 +1,11 @@
+# component name "Kernel and Hardware Services Documentation"
+
+component kernelhwsrv_doc_pub
+
+source \sf\os\kernelhwsrv\kernelhwsrv_info\doc_pub\
+
+notes_source \component_defs\release.src
+
+
+ipr E
+
--- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -400,28 +400,49 @@
test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse));
test(KErrNone == iServSession.SuspendThread(iThreadID));
- //test getting the global list, ETrue as should find the target debug thread
- DoTestGetThreadList(ETrue, EScopeGlobal);
-
- //test getting this thread's thread list, ETrue as should find the target debug thread
- DoTestGetThreadList(ETrue, EScopeThreadSpecific, RThread().Id().Id());
-
- //test getting this process's thread list, ETrue as should find the target debug thread
- DoTestGetThreadList(ETrue, EScopeProcessSpecific, RProcess().Id().Id());
+ TBool found = EFalse;
+
+ /* We need these loops because on some system the kernel run mode debugger does not
+ immediately present the thread in the thread list.
+ */
+
+ for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ )
+ {
+ //test getting this process's thread list, ETrue as should find the target debug thread
+ User::After(50000);
+ found = DoTestGetThreadList(ETrue, EScopeProcessSpecific, RProcess().Id().Id());
+ }
+ test( found );
+ found = EFalse;
+
+ for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ )
+ {
+ //test getting the global list, ETrue as should find the target debug thread
+ User::After(50000);
+ found = DoTestGetThreadList(ETrue, EScopeGlobal);
+ }
+ test( found );
+
+ found = EFalse;
+ for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ )
+ {
+ //test getting this thread's thread list, ETrue as should find the target debug thread
+ User::After(50000);
+ found = DoTestGetThreadList(ETrue, EScopeThreadSpecific, RThread().Id().Id());
+ }
+ test( found );
test(KErrNone == iServSession.ResumeThread(iThreadID));
test(KErrNone == iServSession.DetachExecutable(iFileName));
}
-
-void CRunModeAgent::DoTestGetThreadList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId)
+
+TBool CRunModeAgent::DoTestGetThreadList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId)
{
- test.Next(_L("DoTestGetThreadList\n"));
-
//create data to pass
RBuf8 buffer;
TUint32 size = 0;
- //perform the call to get the Code segs
+ //perform the call to get the thread list
DoGetList(EThreads, aListScope, buffer, size, aTargetId);
//initialise data about the target debug thread to compare the kernel's data against
@@ -438,22 +459,22 @@
{
TThreadListEntry* entry = (TThreadListEntry*)ptr;
TPtr entryName(&(entry->iName[0]), entry->iNameLength, entry->iNameLength);
+
if( (threadId == entry->iThreadId) && (processId == entry->iProcessId) && (0 == name.CompareF(entryName)) )
{
test(entry->iSupervisorStackBaseValid);
test(entry->iSupervisorStackSizeValid);
//if all match then we've found it
found = ETrue;
+ break;
}
ptr += Align4(entry->GetSize());
}
- //check whether the expected result happened
- test(found == aShouldPass);
-
//clean up
buffer.Close();
+ return found;
}
@@ -582,6 +603,12 @@
}
+
+/**
+ * Get a list from the run mode debug system. Most list calls will initially return KErrTooBig,
+ * since the initial size of the buffer is 0. However it is sometimes valid for a list to be empty
+ * given its filtering and scope. These calls should return KErrNone.
+ */
void CRunModeAgent::DoGetList(const TListId aListId, const TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId)
{
//close the buffer in case there's stuff allocated in it
@@ -589,19 +616,20 @@
//initialise it to be one byte big, which will guarantee data won't fit in it
test(KErrNone == aBuffer.Create(1));
aSize = 0;
-
+
+ TInt ret = KErrNone;
//should pass this test (assuming we've passed in sensible arguments above...)
if(EScopeGlobal == aListScope)
{
- test(KErrTooBig == iServSession.GetList(aListId, aBuffer, aSize));
+ ret = iServSession.GetList(aListId, aBuffer, aSize);
}
else if(EScopeThreadSpecific == aListScope)
{
- test(KErrTooBig == iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize));
+ ret = iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize);
}
else if(EScopeProcessSpecific == aListScope)
{
- test(KErrTooBig == iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize));
+ ret = iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize);
}
else
{
@@ -609,6 +637,17 @@
test(0);
}
+ if( KErrNone == ret )
+ {
+ /* In the case that there is no data, just return and let the caller check
+ the buffer. It is valid for a caller to not expect any data to be returned.
+ */
+ return;
+ }
+
+ // The only other allowed return is KErrTooBig
+ test( ret == KErrTooBig );
+
//keep allocating larger buffers, beginning with the aSize returned by the above call,
//and hopefully we'll eventually make a large enough one
test(KErrNone == aBuffer.ReAlloc(aSize));
@@ -2727,9 +2766,9 @@
/* Wait a little while and try again, just in case the process is still being removed.
This can happen on a very busy system or when a popup for the events is still active
*/
- RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads. ProcessExists(id=%d), waiting for it to exit %d",
+ RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads. ProcessExists(id=%d), waiting count exit=%d",
I64LOW(processId), waitCount);
- User::After(500);
+ User::After(50000);
}
test(!ProcessExists(processId));
}
@@ -2738,34 +2777,37 @@
// helper function to check whether a thread with id aThreadId exists in the process with id aProcessId
TBool CRunModeAgent::ThreadExistsForProcess(const TThreadId aThreadId, const TProcessId aProcessId)
{
- TUint32 size;
- RBuf8 buffer;
- test(KErrNone == buffer.Create(1024));
- TInt err = iServSession.GetList(aProcessId, EThreads, buffer, size);
- while(KErrTooBig == err)
+ RThread lThread;
+ TInt ret = lThread.Open( aThreadId.Id() );
+
+ if( ret != KErrNone )
{
- size*=2;
- test(size<=16*1024);
- test(KErrNone == buffer.ReAlloc(size));
- err = iServSession.GetList(aProcessId, EThreads, buffer, size);
+ RDebug::Printf("ThreadExistsForProcess: thread id=%d opening returned %d",
+ I64LOW( aThreadId.Id() ), ret );
+ lThread.Close();
+ return EFalse;
}
- test(KErrNone == err);
-
- //look through the buffer and check if the target debug thread is there
- TUint8* ptr = (TUint8*)buffer.Ptr();
- const TUint8* ptrEnd = ptr + size;
- while(ptr < ptrEnd)
+
+ RProcess lProcess;
+ ret = lThread.Process( lProcess );
+
+ lThread.Close();
+
+ if( ret != KErrNone )
{
- TThreadListEntry& entry = *(TThreadListEntry*)ptr;
- if(aThreadId.Id() == entry.iThreadId)
- {
- buffer.Close();
- return ETrue;
- }
- ptr += Align4(entry.GetSize());
+ RDebug::Printf("ThreadExistsForProcess: proc opening returned %d", ret );
+ ret = KErrNotFound;
}
- buffer.Close();
- return EFalse;
+ else if( lProcess.Id() != aProcessId )
+ {
+ RDebug::Printf("ThreadExistsForProcess: lProcess.Id()(%d)!= aProcessId(%d)",
+ I64LOW(lProcess.Id().Id()), I64LOW(aProcessId.Id()));
+ ret = KErrNotFound;
+ }
+
+ lProcess.Close();
+
+ return ( ret == KErrNone );
}
// helper function to check whether a process with id aProcessId exists
--- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h Wed Mar 31 23:38:45 2010 +0300
+++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h Wed Apr 14 17:22:59 2010 +0300
@@ -71,7 +71,7 @@
void TestGetXipLibrariesList();
void TestGetListInvalidData();
- void DoTestGetThreadList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0);
+ TBool DoTestGetThreadList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0);
void DoTestGetCodeSegsList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0);
void DoGetList(const Debug::TListId aListId, const Debug::TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId=0);
--- a/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -192,6 +192,8 @@
}
}
+ launchMutex.Wait( 500000 );
+
CleanupStack::PopAndDestroy( &launchMutex );
if( commandLine )
@@ -202,6 +204,8 @@
GLDEF_C TInt E32Main()
{
+ RProcess thisProcess;
+ thisProcess.Rendezvous(KErrNone);
RDebug::Printf( ">Launcher Process()" );
CTrapCleanup* trap = CTrapCleanup::New();
--- a/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2007-2010 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"
@@ -352,6 +352,8 @@
TInt E32Main()
{
+
+ RDebug::Printf("t_rmdebug_app tid=%d,pid=%d", I64LOW(RThread().Id().Id()), I64LOW(RProcess().Id().Id()) ) ;
// setup heap checking and clean up trap
__UHEAP_MARK;
CTrapCleanup* cleanup=CTrapCleanup::New();
--- a/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -110,14 +110,16 @@
// Performs each test in turn
//
{
+ test.Start(_L("ClientAppL"));
TInt err = iServSession.Connect(securityServerVersion);
if (err != KErrNone)
{
User::Panic(_L("Can't open server session"), err);
}
-
+ SetupDebugServerL();
LaunchTargetsInOrderL();
RDebug::Printf( "returning from CMultiTargetAgent::ClientAppL" );
+ test.End();
}
/**
@@ -158,7 +160,7 @@
void CMultiTargetAgent::SetupDebugServerL()
{
RDebug::Printf( "CMultiTargetAgent::SetupDebugServerL" );
-
+ test.Next(_L("SetupDebugServerL\n"));
iTargets.ReserveL( KNumApps );
RBuf targetName;
@@ -235,8 +237,7 @@
TBool thisLaunchCompleted;
- SetupDebugServerL();
-
+ test.Next(_L("LaunchTargetsInOrderL\n"));
for( TInt numLaunches = KNumLaunches; numLaunches > 0; numLaunches-- )
{
for( TInt numApps = KNumApps; numApps > 0; numApps-- )
@@ -362,17 +363,19 @@
}
}
- CleanupStack::PopAndDestroy( &launchSemaphore ); // launchSemaphore
-
- for( TInt i = iTargets.Count()-1; i>=0; i-- )
- {
- RDebug::Printf( "Closing target %d", i );
- iTargets[ i ].Close();
- }
+ launchSemaphore.Signal();
+
+ CleanupStack::PopAndDestroy( &launchSemaphore ); // launchSemaphore
+
+ for( TInt i = iTargets.Count()-1; i>=0; i-- )
+ {
+ RDebug::Printf( "Closing target %d", i );
+ iTargets[ i ].Close();
+ }
- iTargets.Close();
-
- return KErrNone;
+ iTargets.Close();
+
+ return KErrNone;
}
--- a/kerneltest/e32test/system/t_mstim.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/kerneltest/e32test/system/t_mstim.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -84,7 +84,7 @@
TInt r=mstim.GetInfo(aId,info);
CHECK(r);
TEST(info.iCount==1);
- return info.iMin/1000;
+ return (info.iMin+500)/1000;
}
GLDEF_C TInt E32Main()
--- a/package_definition.xml Wed Mar 31 23:38:45 2010 +0300
+++ b/package_definition.xml Wed Apr 14 17:22:59 2010 +0300
@@ -61,6 +61,14 @@
<!-- owned and maintained by usb package. To be moved there as soon as technical limitations are resolved -->
<unit bldFile="kernel/eka/drivers/usbc" mrp="kernel/eka/drivers/usbc/base_e32_drivers_usbcli.mrp"/>
</component>
+ <component id="usbdescriptors" name="USB Descriptors" purpose="optional">
+ <!-- owned and maintained by usb package. To be moved there as soon as technical limitations are resolved -->
+ <unit bldFile="kernel/eka/drivers/usbho/usbdescriptors" mrp="kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp"/>
+ </component>
+ <component id="usbdi_utils" name="USB DI Utils" purpose="optional">
+ <!-- owned and maintained by usb package. To be moved there as soon as technical limitations are resolved -->
+ <unit bldFile="kernel/eka/drivers/usbho/usbdi_utils" mrp="kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp"/>
+ </component>
</collection>
<collection id="driversupport" name="Generic Driver Support" level="hw-if">
<component id="mediadrivers" name="Media Drivers" purpose="optional">
@@ -133,6 +141,9 @@
<component id="kernelhwsrv_metadata" name="Kernel and Hardware Services Metadata" class="config" introduced="^2" purpose="development" target="desktop">
<unit mrp="kernelhwsrv_info/kernelhwsrv_metadata/kernelhwsrv_metadata.mrp"/>
</component>
+ <component id="kernelhwsrv_metadata" name="Kernel and Hardware Services Public Documentation" class="doc" introduced="^3" purpose="development">
+ <unit mrp="kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp"/>
+ </component>
</collection>
</package>
</SystemDefinition>
--- a/userlibandfileserver/fileserver/group/release.txt Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/group/release.txt Wed Apr 14 17:22:59 2010 +0300
@@ -1,3 +1,19 @@
+Version 2.00.2050
+=================
+(Made by vfebvre 24/03/2010)
+
+1. fagortz
+ 1. DEF145067: TTPA-83EAYU: Partition handling for USB drives with 4K block size is incorrect
+
+
+Version 2.00.2049
+=================
+(Made by vfebvre 22/03/2010)
+
+1. michcox
+ 1. DEF145080 SMAD-83NJMP: File server does not check return result of some User::ReAlloc()'s
+
+
Version 2.00.2048
=================
(Made by vfebvre 15/03/2010)
--- a/userlibandfileserver/fileserver/inc/f32ver.h Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/inc/f32ver.h Wed Apr 14 17:22:59 2010 +0300
@@ -58,6 +58,6 @@
@see TVersion
*/
-const TInt KF32BuildVersionNumber=2048;
+const TInt KF32BuildVersionNumber=2050;
//
#endif
--- a/userlibandfileserver/fileserver/sfile/sf_cache.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_cache.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -610,8 +610,11 @@
if(r==KErrNoMemory)
return r;
+ iCache = (TFileCacheRecord**)User::ReAlloc(pIndexes,sizeof(TFileCacheRecord*)*currentIndex);
+ if(!iCache)
+ return KErrNoMemory;
+
iNotPresent = EFalse;
- iCache = (TFileCacheRecord**)User::ReAlloc(pIndexes,sizeof(TFileCacheRecord*)*currentIndex);
iRecordCount = currentIndex;
if (currentIndex>1)
{
--- a/userlibandfileserver/fileserver/sfile/sf_obj.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_obj.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -129,7 +129,10 @@
if (newAlloc!=iAllocated)
{
if (newAlloc)
+ {
iContainers=(CFsObjectCon**)User::ReAlloc(iContainers,newAlloc*sizeof(CFsObjectCon*));
+ __ASSERT_DEBUG(iContainers,User::Panic(_L("FS_LDR panic"),ELdrHeapCorruptionOnRemove));
+ }
else
{
delete iContainers;
@@ -489,7 +492,10 @@
if (newAlloc!=iAllocated)
{
if (newAlloc)
+ {
iObjects=(SFsObjectIxRec*)User::ReAlloc(iObjects,newAlloc*sizeof(SFsObjectIxRec));
+ __ASSERT_DEBUG(iObjects,User::Panic(_L("FS_LDR panic"),ELdrHeapCorruptionOnRemove));
+ }
else
{
delete iObjects;
@@ -679,7 +685,10 @@
if (newAlloc!=iAllocated)
{
if (newAlloc)
+ {
iObjects=(CFsObject**)User::ReAlloc(iObjects,newAlloc*sizeof(CFsObject*));
+ __ASSERT_DEBUG(iObjects,User::Panic(_L("FS_LDR panic"),ELdrHeapCorruptionOnRemove));
+ }
else
{
delete iObjects;
--- a/userlibandfileserver/fileserver/sfile/sf_std.h Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_std.h Wed Apr 14 17:22:59 2010 +0300
@@ -235,7 +235,8 @@
enum TFsPanic
{
- ELdrImportedOrdinalDoesNotExist
+ ELdrImportedOrdinalDoesNotExist,
+ ELdrHeapCorruptionOnRemove
};
//
enum TFsFault
--- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/debug.h Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/debug.h Wed Apr 14 17:22:59 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2008-2010 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"
@@ -22,7 +22,7 @@
#ifndef PXY_DEBUG_H
#define PXY_DEBUG_H
-// #define _HOST_DEBUG_TRACE_
+//#define _HOST_DEBUG_PRINT_
// #define _PROXY_DEBUG_PRINT_
// #define _PROXY_FN_TRACE_
--- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp Wed Apr 14 17:22:59 2010 +0300
@@ -40,14 +40,19 @@
TInt CUsbHostMsProxyDrive::InitialiseOffset(TCapsInfo& aCapsInfo)
{
__MSFNSLOG
- const TInt KPartitionInfoSize = TMsDataMemMap::KSectorSize;
- TBuf8<KPartitionInfoSize> partitionInfo;
- TInt r;
+ RBuf8 partitionInfo;
+ TInt r;
+ TRAP(r, partitionInfo.CreateL(aCapsInfo.iBlockLength));
+ if (r != KErrNone)
+ {
+ return r;
+ }
- r = iUsbHostMsLun.Read(0 , KPartitionInfoSize, (TDes8 &) partitionInfo);
+ r = iUsbHostMsLun.Read(0, aCapsInfo.iBlockLength, partitionInfo);
if (r != KErrNone)
{
__PXYPRINT1(_L("!! Reading medium failed with %d !!"), r);
+ partitionInfo.Close();
return r;
}
TUint8 *iIntBuf = (TUint8 *) partitionInfo.Ptr();
@@ -104,21 +109,27 @@
TMBRPartitionEntry& partitionEntry = pe[partitionIndex];
iMsDataMemMap.InitDataArea(partitionEntry.iFirstSector,
- partitionEntry.iNumSectors);
+ partitionEntry.iNumSectors,
+ aCapsInfo.iBlockLength);
__PXYPRINT2(_L("paritioncount = %d defaultpartition = %d"),
partitionCount, partitionIndex);
- __PXYPRINT2(_L("iFirstSector = x%x iNumSectors = x%x"),
+ __PXYPRINT3(_L("iFirstSector = x%x iNumSectors = x%x iSectorSize = x%x"),
partitionEntry.iFirstSector,
- partitionEntry.iNumSectors);
+ partitionEntry.iNumSectors,
+ aCapsInfo.iBlockLength);
}
else
{
__PXYPRINT(_L("No partition found"));
- iMsDataMemMap.InitDataArea(0, aCapsInfo.iNumberOfBlocks);
- __PXYPRINT2(_L("iFirstSector = x%x iNumSectors = x%x"),
- 0, aCapsInfo.iNumberOfBlocks);
+ iMsDataMemMap.InitDataArea(0, aCapsInfo.iNumberOfBlocks, aCapsInfo.iBlockLength);
+ __PXYPRINT3(_L("iFirstSector = x%x iNumSectors = x%x iSectorSize = x%x"),
+ 0,
+ aCapsInfo.iNumberOfBlocks,
+ aCapsInfo.iBlockLength);
}
}
+
+ partitionInfo.Close();
return KErrNone;
}
@@ -558,6 +569,12 @@
{
c.iMediaAtt |= KMediaAttWriteProtected;
}
+
+ static const TInt K512ByteSectorSize = 0x200; // 512
+ if(K512ByteSectorSize != capsInfo.iBlockLength)
+ {
+ c.iMediaAtt &= ~KMediaAttFormattable;
+ }
__HOSTPRINT4(_L("<<< HOST Caps Block[num=0x%x size=0x%x] Media[size=0x%lx WP=0x%x]"),
capsInfo.iNumberOfBlocks, capsInfo.iBlockLength,
caps().iSize, caps().iMediaAtt);
@@ -571,6 +588,7 @@
else
{
__HOSTPRINT(_L("<<< HOST Caps Unknown Error"));
+ c.iType = EMediaUnknown;
r = KErrUnknown;
}
anInfo = caps.Left(Min(caps.Length(),anInfo.MaxLength()));
@@ -629,7 +647,7 @@
{
__MSFNSLOG
- const TInt KDefaultMaxBytesPerFormat = 0x100 * TMsDataMemMap::KSectorSize; // 128K
+ const TInt KDefaultMaxBytesPerFormat = 0x100 * iMsDataMemMap.BlockLength(); // 128K
if (aInfo.i512ByteSectorsFormatted < 0)
return KErrArgument;
@@ -648,14 +666,14 @@
iMsDataMemMap.InitDataArea(caps().iSize);
}
- TInt64 pos = static_cast<TInt64>(aInfo.i512ByteSectorsFormatted) << TMsDataMemMap::KFormatSectorShift;
+ TInt64 pos = static_cast<TInt64>(aInfo.i512ByteSectorsFormatted) << iMsDataMemMap.FormatSectorShift();
TInt length = aInfo.iMaxBytesPerFormat;
TInt r = Erase(pos, length);
if (r == KErrNone)
{
- length += TMsDataMemMap::KSectorSize - 1;
- length >>= TMsDataMemMap::KFormatSectorShift;
+ length += iMsDataMemMap.BlockLength() - 1;
+ length >>= iMsDataMemMap.FormatSectorShift();
aInfo.i512ByteSectorsFormatted += length;
}
--- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.h Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.h Wed Apr 14 17:22:59 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2008-2010 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"
@@ -26,21 +26,20 @@
class TMsDataMemMap
{
public:
- static const TInt KSectorSize = 0x200; // 512
- static const TInt KFormatSectorShift = 9;
TMsDataMemMap();
void Reset();
- void InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors);
+ void InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors, TUint32 aSectorSize);
void InitDataArea(TUint64 aSize);
- TInt BlockLength() const;
+ TUint32 BlockLength() const;
TUint64 DataSize() const;
TInt64 GetDataPos(TInt64 aPos) const;
TInt TranslateDataPos(TInt64& aPos, TInt& aLength) const;
TInt CheckBlockInRange(TInt64& aPos, TInt aLength) const;
+ TInt FormatSectorShift() const;
private:
// Whole media
@@ -50,6 +49,12 @@
// Data Area
// Offset
TInt64 iDataOffset;
+
+ // Sector Size (Media Block Size)
+ TUint32 iSectorSize;
+
+ // Sector-size dependant
+ TInt iFormatSectorShift;
};
#include "tmsmemmap.inl"
--- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.inl Wed Mar 31 23:38:45 2010 +0300
+++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.inl Wed Apr 14 17:22:59 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2008-2010 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"
@@ -26,9 +26,9 @@
}
-inline TInt TMsDataMemMap::BlockLength() const
+inline TUint32 TMsDataMemMap::BlockLength() const
{
- return KSectorSize;
+ return iSectorSize;
}
@@ -37,11 +37,20 @@
return iSize - iDataOffset;
}
-inline void TMsDataMemMap::InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors)
- {
- iDataOffset = static_cast<TInt64>(aFirstDataSector) * KSectorSize;
- iSize = static_cast<TInt64>(aNumSectors) * KSectorSize;
- }
+inline void TMsDataMemMap::InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors, TUint32 aSectorSize)
+ {
+ iSectorSize = aSectorSize;
+
+ iFormatSectorShift = 0;
+ while(aSectorSize)
+ {
+ ++iFormatSectorShift;
+ aSectorSize >>= 1;
+ }
+
+ iDataOffset = static_cast<TInt64>(aFirstDataSector) * iSectorSize;
+ iSize = static_cast<TInt64>(aNumSectors) * iSectorSize;
+ }
inline void TMsDataMemMap::InitDataArea(TUint64 aSize)
@@ -55,3 +64,8 @@
return aPos + iDataOffset;
}
+inline TInt TMsDataMemMap::FormatSectorShift() const
+ {
+ return iFormatSectorShift;
+ }
+