kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp
changeset 149 d9f1e5bfe28c
equal deleted inserted replaced
135:5e441a173c63 149:d9f1e5bfe28c
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Description:
       
    12 // Symbian USBDI Descriptor Parsing Framework.
       
    13 // 
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <d32usbdescriptors.h>
       
    22 #include "usbdescutils.h"
       
    23 
       
    24 
       
    25 // ---------------------
       
    26 // UsbDescriptorParser
       
    27 // ---------------------
       
    28 
       
    29 /**
       
    30 The main parsing function of the USB descriptor parsing framework.
       
    31 
       
    32 This will perform a best effort parse of a USB descriptor tree.  It is best effort in the
       
    33 fact that upon encountering a form of syntatic corruption in the source data it will error
       
    34 the parse attempt, but also return the incomplete descriptor tree up to the parsing error.
       
    35 
       
    36 @param aUsbDes The source data that will be parsed.
       
    37 @param aDesc The pointer that will be updated to the top-level descriptor.
       
    38 
       
    39 @return KErrNone if successful, a system-wide error code otherwise.
       
    40 
       
    41 @publishedPartner
       
    42 @prototype
       
    43 */
       
    44 EXPORT_C /*static*/ TInt UsbDescriptorParser::Parse(const TDesC8& aUsbDes, TUsbGenericDescriptor*& aDesc)
       
    45 	{
       
    46 	TInt ret = KErrNone;
       
    47 	aDesc = NULL;
       
    48 	TPtrC8 des(aUsbDes);
       
    49 
       
    50 	// First we must find the top level descriptor (the one we will return to the caller).
       
    51 	TRAP(ret, aDesc = FindParserAndParseAndCheckL(des, NULL));
       
    52 	if(ret == KErrNone)
       
    53 		{
       
    54 		if(!aDesc)
       
    55 			{
       
    56 			ret = KErrNotFound;
       
    57 			}
       
    58 		else
       
    59 			{
       
    60 			// Now we have a top level descriptor - we now try to build up the descriptor
       
    61 			// tree if there are more descriptors available.
       
    62 			TRAP(ret, ParseDescriptorTreeL(des, *aDesc));
       
    63 			}
       
    64 		}
       
    65 
       
    66 	// Ensure that all the data has been parsed if successful.
       
    67 	if(ret == KErrNone && des.Length() > 0)
       
    68 		{
       
    69 		// If no parser was found for some data then we should have been errored with KErrNotFound.
       
    70 		__ASSERT_DEBUG(EFalse, UsbDescFault(UsbdiFaults::EUsbDescSuccessButDataLeftUnparsed));
       
    71 		ret = KErrUnknown;
       
    72 		}
       
    73 
       
    74 	// release the allocated descriptor if there was an error
       
    75 	if(ret != KErrNone && aDesc)
       
    76 		{
       
    77 		delete aDesc;
       
    78 		aDesc = NULL;
       
    79 		}
       
    80 
       
    81 	return ret;
       
    82 	}
       
    83 
       
    84 /**
       
    85 The function to register a custom parsing routine in the USB descriptor parser framework.
       
    86 
       
    87 The routine is registered locally to the current thread, and so if an application wishes
       
    88 to perform the same custom parsing in multiple threads, it must call this function with
       
    89 the appropriate routine in each thread context.
       
    90 
       
    91 If the custom routine becomes unapplicable after being registered, the application may 
       
    92 unregister it using the UsbDescriptorParser::UnregisterCustomParser function.
       
    93 @see UsbDescriptorParser::UnregisterCustomParser
       
    94 
       
    95 @param aParserFunc The routine which will be added to the USB descriptor parsing framework.
       
    96 
       
    97 @publishedPartner
       
    98 @prototype
       
    99 */
       
   100 EXPORT_C /*static*/ void UsbDescriptorParser::RegisterCustomParserL(TUsbDescriptorParserL aParserFunc)
       
   101 	{
       
   102 	TBool newlyCreatedList = EFalse;
       
   103 	CUsbCustomDescriptorParserList* parserList = static_cast<CUsbCustomDescriptorParserList*>(Dll::Tls());
       
   104 	if(!parserList)
       
   105 		{
       
   106 		parserList = CUsbCustomDescriptorParserList::NewL();
       
   107 		newlyCreatedList = ETrue;
       
   108 		CleanupStack::PushL(parserList);
       
   109 		}
       
   110 	
       
   111 	parserList->RegisterParserL(aParserFunc);
       
   112 
       
   113 	if(newlyCreatedList)
       
   114 		{
       
   115 		Dll::SetTls(parserList);
       
   116 		CleanupStack::Pop(parserList);
       
   117 		}
       
   118 	}
       
   119 
       
   120 /**
       
   121 The function to unregister a custom parsing routine in the USB descriptor parser framework.
       
   122 
       
   123 This routine will only unregister the routine from the current thread context.  If the routine
       
   124 is registered in multiple threads and it is no longer wanted in any thread, an application 
       
   125 must call this function in each thread context that the routine is registered.
       
   126 
       
   127 It is safe to call this function even if RegisterCustomParserL has never been called successfully.
       
   128 
       
   129 @see UsbDescriptorParser::RegisterCustomParserL
       
   130 
       
   131 @param aParserFunc The routine which will be removed from the USB descriptor parsing framework.
       
   132 
       
   133 @publishedPartner
       
   134 @prototype
       
   135 */
       
   136 EXPORT_C /*static*/ void UsbDescriptorParser::UnregisterCustomParser(TUsbDescriptorParserL aParserFunc)
       
   137 	{
       
   138 	CUsbCustomDescriptorParserList* parserList = static_cast<CUsbCustomDescriptorParserList*>(Dll::Tls());
       
   139 	if(parserList)
       
   140 		{
       
   141 		parserList->UnregisterParser(aParserFunc);
       
   142 		if(parserList->NumOfRegisteredParsers() <= 0)
       
   143 			{
       
   144 			Dll::FreeTls();
       
   145 			delete parserList;
       
   146 			}
       
   147 		}
       
   148 	}
       
   149 
       
   150 /*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseAndCheckL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc)
       
   151 	{
       
   152 	TUsbGenericDescriptor* ret = FindParserAndParseL(aUsbDes, aPreviousDesc);
       
   153 	// We need to ensure that the parsers have correctly initialised the USB descriptor objects.
       
   154 	// It is important that we check as it is possible that a custom parser did the parsing.
       
   155 	__ASSERT_ALWAYS(!ret || (!ret->iParent && !ret->iFirstChild && !ret->iNextPeer),
       
   156 		UsbDescPanic(UsbdiPanics::EUsbDescNonNullPointersAfterParsing));
       
   157 	return ret;
       
   158 	}
       
   159 
       
   160 // Utility macro to tidy up the parsing routine.
       
   161 #define RETURN_IF_PARSEDL(aRet, aParserL, aUsbDes, aPreviousDesc)\
       
   162 	{\
       
   163 	aRet = aParserL(aUsbDes, aPreviousDesc);\
       
   164 	if(aRet)\
       
   165 		{\
       
   166 		return aRet;\
       
   167 		}\
       
   168 	}
       
   169 
       
   170 /*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc)
       
   171 	{
       
   172 	// Special termination case.
       
   173 	if(aUsbDes.Length() == 0)
       
   174 		{
       
   175 		return NULL;
       
   176 		}
       
   177 
       
   178 	TUsbGenericDescriptor* des;
       
   179 
       
   180 	// Try the default parsing routines.
       
   181 	RETURN_IF_PARSEDL(des, TUsbDeviceDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   182 	RETURN_IF_PARSEDL(des, TUsbDeviceQualifierDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   183 	RETURN_IF_PARSEDL(des, TUsbConfigurationDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   184 	RETURN_IF_PARSEDL(des, TUsbOtherSpeedDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   185 	RETURN_IF_PARSEDL(des, TUsbInterfaceAssociationDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   186 	RETURN_IF_PARSEDL(des, TUsbInterfaceDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   187 	RETURN_IF_PARSEDL(des, TUsbEndpointDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   188 	RETURN_IF_PARSEDL(des, TUsbOTGDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   189 	RETURN_IF_PARSEDL(des, TUsbStringDescriptor::ParseL, aUsbDes, aPreviousDesc);
       
   190 
       
   191 	// Then we try the custom parsers that have been registered.
       
   192 	const CUsbCustomDescriptorParserList* parserList = static_cast<const CUsbCustomDescriptorParserList*>(Dll::Tls());
       
   193 	if(parserList)
       
   194 		{
       
   195 		TInt numOfParsers = parserList->NumOfRegisteredParsers()-1;
       
   196 		for(TInt index=0; index<numOfParsers; ++index)
       
   197 			{
       
   198 			TUsbDescriptorParserL parserL = parserList->RegisteredParser(index);
       
   199 			RETURN_IF_PARSEDL(des, parserL, aUsbDes, aPreviousDesc);
       
   200 			}
       
   201 		}
       
   202 
       
   203 	// Then we try the unknown descriptor parser.
       
   204 	RETURN_IF_PARSEDL(des, UnknownUsbDescriptorParserL, aUsbDes, aPreviousDesc);
       
   205 
       
   206 	// Otherwise we haven't found anybody to parse the binary data.
       
   207 	User::Leave(KErrNotFound); // inform caller that there is no parser for the data.
       
   208 	return NULL;
       
   209 	}
       
   210 	
       
   211 /*static*/ void UsbDescriptorParser::ParseDescriptorTreeL(TPtrC8& aUsbDes, TUsbGenericDescriptor& aPreviousDesc)
       
   212 	{
       
   213 	TUsbGenericDescriptor* desc = &aPreviousDesc;
       
   214 	while(desc)
       
   215 		{
       
   216 		TUsbGenericDescriptor* preDesc = desc;
       
   217 		desc = FindParserAndParseAndCheckL(aUsbDes, desc);
       
   218 		if(desc)
       
   219 			{
       
   220 			CleanupStack::PushL(desc);
       
   221 			BuildTreeL(*desc, *preDesc);
       
   222 			CleanupStack::Pop(desc);
       
   223 			}
       
   224 		}
       
   225 	}
       
   226 
       
   227 /*static*/ void UsbDescriptorParser::BuildTreeL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aPreviousDesc)
       
   228 	{
       
   229 	// We assume that the new descriptor has been properly initialised with NULL pointers.
       
   230 	__ASSERT_DEBUG(!aNewDesc.iFirstChild && !aNewDesc.iNextPeer && !aNewDesc.iParent,
       
   231 		UsbDescFault(UsbdiFaults::EUsbDescTreePointersAlreadySet));
       
   232 
       
   233 	// Find first "top" parent claiming this new descriptor as a child.
       
   234 	TUsbGenericDescriptor* parent = &aPreviousDesc;
       
   235 	TUsbGenericDescriptor* topLevel = &aPreviousDesc;
       
   236 	while(parent)
       
   237 		{
       
   238 		if(aNewDesc.IsParent(*parent) || parent->IsChild(aNewDesc))
       
   239 			{
       
   240 			break; // we have found a parent.
       
   241 			}
       
   242 		topLevel = parent; // Save the current one for use if we cannot find a parent
       
   243 		parent = parent->iParent; // Scroll back up the tree.
       
   244 		}
       
   245 	__ASSERT_DEBUG(topLevel, UsbDescFault(UsbdiFaults::EUsbDescNoTopLevelDescriptorFound));
       
   246 
       
   247 	if(parent)
       
   248 		{
       
   249 		// We should be able to place the descriptor directly as a child of this descriptor,
       
   250 		// however it is not that simple because of IADs (Interface Association Descriptors).
       
   251 		// The ECN states "All of the interface numbers in the set of associated interfaces must be
       
   252 		// contiguous" meaning that if an IAD has two interfaces starting at 1 then the configuration
       
   253 		// bundle may have interface descriptors in '1 then 3 then 2' order. As such we need to be able
       
   254 		// to go backwards to find the most suitable binding.  The general way for doing this is to
       
   255 		// find the right-most, lowest descriptor that descriptor considers a parent.
       
   256         // Where the tree is arranged with peers horizontally linked left to
       
   257         // right, with children linked vertically top to bottom.
       
   258 		TUsbGenericDescriptor& suitableParent = FindSuitableParentL(aNewDesc, *parent);
       
   259 
       
   260 		TUsbGenericDescriptor* peer = suitableParent.iFirstChild;
       
   261 		if(peer)
       
   262 			{
       
   263 			TUsbGenericDescriptor* lastPeer;
       
   264 			do
       
   265 				{
       
   266 				lastPeer = peer;
       
   267 				peer = peer->iNextPeer;
       
   268 				}
       
   269 			while(peer);
       
   270 			lastPeer->iNextPeer = &aNewDesc;
       
   271 			}
       
   272 		else
       
   273 			{
       
   274 			// we are the first child so just update.
       
   275 			suitableParent.iFirstChild = &aNewDesc;
       
   276 			}
       
   277 		aNewDesc.iParent = &suitableParent;
       
   278 		}
       
   279 	else if(aNewDesc.IsPeer(*topLevel) || topLevel->IsPeer(aNewDesc))
       
   280 		{
       
   281 		// There is no explicit parent in the tree so, we may just have a group of top-level peers
       
   282 		// in the bundle.  If the previous descriptor is a peer then we shall just tag on its tier.
       
   283 		TUsbGenericDescriptor* lastPeer;
       
   284 		TUsbGenericDescriptor* peer = topLevel;
       
   285 		do
       
   286 			{
       
   287 			lastPeer = peer;
       
   288 			peer = peer->iNextPeer;
       
   289 			}
       
   290 		while(peer);
       
   291 		lastPeer->iNextPeer = &aNewDesc;
       
   292 		}
       
   293 	else
       
   294 		{
       
   295 		// The descriptor could not be bound into the tree, indicating that the bundle of descriptors
       
   296 		// is unvalid.
       
   297 		User::Leave(KErrUsbBadDescriptorTopology);
       
   298 		}
       
   299 	}
       
   300 	
       
   301 /*static*/ TUsbGenericDescriptor& UsbDescriptorParser::FindSuitableParentL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aTopParent)
       
   302 	{
       
   303 	// This implements the algorithm to search down from the top parent found in the tree to the right most, lowest descriptor
       
   304 	// that will accept the new descriptor as a child.
       
   305 
       
   306 	TUsbGenericDescriptor* bestMatch = &aTopParent;
       
   307 
       
   308 	TUsbGenericDescriptor* desc = aTopParent.iFirstChild;
       
   309 	if(desc)
       
   310 		{
       
   311 		// Do a depth first search.
       
   312 		FOREVER
       
   313 			{
       
   314 			// First see if the descriptor is suitable.
       
   315 			__ASSERT_DEBUG(desc, UsbDescFault(UsbdiFaults::EUsbDescRunOffTree));
       
   316 			if(aNewDesc.IsParent(*desc) || desc->IsChild(aNewDesc))
       
   317 				{
       
   318 				bestMatch = desc;
       
   319 				}
       
   320 			// Now walk to the next point in the tree.
       
   321 			if(desc->iFirstChild)
       
   322 				{
       
   323 				desc = desc->iFirstChild;
       
   324 				}
       
   325 			else if(desc->iNextPeer)
       
   326 				{
       
   327 				desc = desc->iNextPeer;
       
   328 				}
       
   329 			else
       
   330 				{
       
   331 				// We've run to the end of a bottom tier, so go back up.
       
   332 				do
       
   333 					{
       
   334 					__ASSERT_DEBUG(desc->iParent, UsbDescFault(UsbdiFaults::EUsbDescTreeMemberHasNoParent));
       
   335 					desc = desc->iParent;
       
   336 					}
       
   337 				while(!desc->iNextPeer && desc != &aTopParent);
       
   338 				if(desc == &aTopParent)
       
   339 					{
       
   340 					// This means that we must have got back to the original
       
   341 					// parent.  So we don't do any more.
       
   342 					break;
       
   343 					}
       
   344 				desc = desc->iNextPeer;
       
   345 				}
       
   346 			}
       
   347 		}
       
   348 	return *bestMatch;
       
   349 	}
       
   350 
       
   351 /*static*/ TUsbGenericDescriptor* UsbDescriptorParser::UnknownUsbDescriptorParserL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
       
   352 	{
       
   353 	TUsbGenericDescriptor* unknownDes = NULL;
       
   354 
       
   355 	const TInt KMinUnknownDesLength = 2; // Length and type fields
       
   356 	if(	aUsbDes.Length() >= KMinUnknownDesLength)
       
   357 		{
       
   358 		// We require unknown descriptors to have at least the length and type fields.
       
   359 		// Any more exotic descriptors should have a custom parser for the framework to use.
       
   360 		TUint8 unknownDesLen = aUsbDes[TUsbGenericDescriptor::KbLengthOffset];
       
   361 
       
   362 		// Robustness check - check the length field is valid.
       
   363 		if(aUsbDes.Length() < unknownDesLen || unknownDesLen < KMinUnknownDesLength)
       
   364 			{
       
   365 			User::Leave(KErrCorrupt);
       
   366 			}
       
   367 
       
   368 		unknownDes = new(ELeave) TUsbGenericDescriptor;
       
   369 		// Set the standard fields
       
   370 		unknownDes->ibLength = unknownDesLen;
       
   371 		unknownDes->ibDescriptorType = aUsbDes[TUsbGenericDescriptor::KbDescriptorTypeOffset] ;
       
   372 		// Set the blob appropriately
       
   373 		unknownDes->iBlob.Set(aUsbDes.Left(unknownDesLen));
       
   374 		// Update the data-left-to-parse Symbian descriptor
       
   375 		aUsbDes.Set(aUsbDes.Mid(unknownDesLen));
       
   376 		}
       
   377 
       
   378 	return unknownDes;
       
   379 	}