|
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 } |