Revision: 201015 RCL_3
authorDremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 14 Apr 2010 17:22:59 +0300
branchRCL_3
changeset 89 1df514389a47
parent 87 2f92ad2dc5db
child 91 b0c9ba7c8f31
child 97 41f0cfe18c80
Revision: 201015 Kit: 201015
kernel/eka/debug/crashMonitor/inc/scmdatasave.h
kernel/eka/debug/crashMonitor/src/scmdatasave.cpp
kernel/eka/drivers/dma/dmapil.cpp
kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp
kernel/eka/drivers/usbho/usbdescriptors/bld.inf
kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp
kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp
kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.mmp
kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.cpp
kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.h
kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp
kernel/eka/drivers/usbho/usbdi_utils/bld.inf
kernel/eka/drivers/usbho/usbdi_utils/usbdi_utils.mmp
kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.cpp
kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.h
kernel/eka/drivers/usbho/usbdi_utils/usbinterface.cpp
kernel/eka/drivers/usbho/usbdi_utils/usbpipe.cpp
kernel/eka/drivers/usbho/usbdi_utils/usbtransfers.cpp
kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.cpp
kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.h
kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.h
kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.inl
kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.cpp
kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.h
kernel/eka/include/d32otgdi_errors.h
kernel/eka/include/drivers/locmedia.h
kernel/eka/include/e32ver.h
kernel/eka/kernel/ekern.mmp
kernel/eka/kernel/kern_int.mmh
kernel/eka/release.txt
kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp
kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp
kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h
kerneltest/e32test/rm_debug/common/t_target_launcher.cpp
kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp
kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp
kerneltest/e32test/system/t_mstim.cpp
package_definition.xml
userlibandfileserver/fileserver/group/release.txt
userlibandfileserver/fileserver/inc/f32ver.h
userlibandfileserver/fileserver/sfile/sf_cache.cpp
userlibandfileserver/fileserver/sfile/sf_obj.cpp
userlibandfileserver/fileserver/sfile/sf_std.h
userlibandfileserver/fileserver/shostmassstorage/msproxy/debug.h
userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp
userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.h
userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.inl
--- 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;
+	}
+