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