|
1 // Copyright (c) 2000-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 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32/drivers/usbcc/misc.cpp |
|
15 // Platform independent layer (PIL) of the USB Device controller driver: |
|
16 // Implementations of misc. classes defined in usbc.h. |
|
17 // |
|
18 // |
|
19 |
|
20 /** |
|
21 @file misc.cpp |
|
22 @internalTechnology |
|
23 */ |
|
24 |
|
25 #include <drivers/usbc.h> |
|
26 |
|
27 |
|
28 /** Helper function for logical endpoints and endpoint descriptors: |
|
29 Split single Ep size into separate FS/HS sizes. |
|
30 This function modifies its arguments. |
|
31 */ |
|
32 TInt TUsbcEndpointInfo::AdjustEpSizes(TInt& aEpSize_Fs, TInt& aEpSize_Hs) const |
|
33 { |
|
34 if (iType == KUsbEpTypeBulk) |
|
35 { |
|
36 // FS: [8|16|32|64] HS: 512 |
|
37 if (iSize < 64) |
|
38 { |
|
39 aEpSize_Fs = iSize; |
|
40 } |
|
41 else |
|
42 { |
|
43 aEpSize_Fs = 64; |
|
44 } |
|
45 aEpSize_Hs = 512; |
|
46 } |
|
47 else if (iType == KUsbEpTypeInterrupt) |
|
48 { |
|
49 // FS: [0..64] HS: [0..1024] |
|
50 if (iSize < 64) |
|
51 { |
|
52 aEpSize_Fs = iSize; |
|
53 } |
|
54 else |
|
55 { |
|
56 aEpSize_Fs = 64; |
|
57 } |
|
58 aEpSize_Hs = iSize; |
|
59 } |
|
60 else if (iType == KUsbEpTypeIsochronous) |
|
61 { |
|
62 // FS: [0..1023] HS: [0..1024] |
|
63 if (iSize < 1023) |
|
64 { |
|
65 aEpSize_Fs = iSize; |
|
66 } |
|
67 else |
|
68 { |
|
69 aEpSize_Fs = 1023; |
|
70 } |
|
71 aEpSize_Hs = iSize; |
|
72 } |
|
73 else if (iType == KUsbEpTypeControl) |
|
74 { |
|
75 // FS: [8|16|32|64] HS: 64 |
|
76 if (iSize < 64) |
|
77 { |
|
78 aEpSize_Fs = iSize; |
|
79 } |
|
80 else |
|
81 { |
|
82 aEpSize_Fs = 64; |
|
83 } |
|
84 aEpSize_Hs = 64; |
|
85 } |
|
86 else |
|
87 { |
|
88 aEpSize_Fs = aEpSize_Hs = 0; |
|
89 return KErrGeneral; |
|
90 } |
|
91 |
|
92 // For the reason of the following checks see Table 9-14. "Allowed wMaxPacketSize |
|
93 // Values for Different Numbers of Transactions per Microframe". |
|
94 if ((iType == KUsbEpTypeInterrupt) || (iType == KUsbEpTypeIsochronous)) |
|
95 { |
|
96 if (iTransactions == 1) |
|
97 { |
|
98 if (aEpSize_Hs < 513) |
|
99 { |
|
100 __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep size too small: %d < 513. Correcting...", |
|
101 aEpSize_Hs)); |
|
102 aEpSize_Hs = 513; |
|
103 } |
|
104 } |
|
105 else if (iTransactions == 2) |
|
106 { |
|
107 if (aEpSize_Hs < 683) |
|
108 { |
|
109 __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep size too small: %d < 683. Correcting...", |
|
110 aEpSize_Hs)); |
|
111 aEpSize_Hs = 683; |
|
112 } |
|
113 } |
|
114 } |
|
115 return KErrNone; |
|
116 } |
|
117 |
|
118 |
|
119 /** Helper function for logical endpoints and endpoint descriptors: |
|
120 If not set, assign a valid and meaningful value to iInterval_Hs, deriving from iInterval. |
|
121 This function modifies the objects's data member(s). |
|
122 */ |
|
123 TInt TUsbcEndpointInfo::AdjustPollInterval() |
|
124 { |
|
125 if (iInterval_Hs != -1) |
|
126 { |
|
127 // Already done. |
|
128 return KErrNone; |
|
129 } |
|
130 if ((iType == KUsbEpTypeBulk) || (iType == KUsbEpTypeControl)) |
|
131 { |
|
132 // Valid range: 0..255 (maximum NAK rate). |
|
133 // (The host controller will probably ignore this value though - |
|
134 // see the last sentence of section 9.6.6 for details.) |
|
135 iInterval_Hs = 255; |
|
136 } |
|
137 else if (iType == KUsbEpTypeInterrupt) |
|
138 { |
|
139 // HS interval = 2^(iInterval_Hs-1) with a valid iInterval_Hs range of 1..16. |
|
140 // The following table shows the mapping of HS values to actual intervals (and |
|
141 // thus FS values) for the range of possible FS values (1..255). |
|
142 // There is not always a 1:1 mapping possible, but we want at least to make sure |
|
143 // that the HS polling interval is never longer than the FS one (except for 255). |
|
144 // |
|
145 // 1 = 1 |
|
146 // 2 = 2 |
|
147 // 3 = 4 |
|
148 // 4 = 8 |
|
149 // 5 = 16 |
|
150 // 6 = 32 |
|
151 // 7 = 64 |
|
152 // 8 = 128 |
|
153 // 9 = 256 |
|
154 if (iInterval == 255) |
|
155 iInterval_Hs = 9; |
|
156 else if (iInterval >= 128) |
|
157 iInterval_Hs = 8; |
|
158 else if (iInterval >= 64) |
|
159 iInterval_Hs = 7; |
|
160 else if (iInterval >= 32) |
|
161 iInterval_Hs = 6; |
|
162 else if (iInterval >= 16) |
|
163 iInterval_Hs = 5; |
|
164 else if (iInterval >= 8) |
|
165 iInterval_Hs = 4; |
|
166 else if (iInterval >= 4) |
|
167 iInterval_Hs = 3; |
|
168 else if (iInterval >= 2) |
|
169 iInterval_Hs = 2; |
|
170 else if (iInterval == 1) |
|
171 iInterval_Hs = 1; |
|
172 else |
|
173 { |
|
174 // iInterval wasn't set properly by the user |
|
175 iInterval_Hs = 1; |
|
176 return KErrGeneral; |
|
177 } |
|
178 } |
|
179 else if (iType == KUsbEpTypeIsochronous) |
|
180 { |
|
181 // Interpretation is the same for FS and HS. |
|
182 iInterval_Hs = iInterval; |
|
183 } |
|
184 else |
|
185 { |
|
186 // '1' is a valid value for all endpoint types... |
|
187 iInterval_Hs = 1; |
|
188 return KErrGeneral; |
|
189 } |
|
190 return KErrNone; |
|
191 } |
|
192 |
|
193 |
|
194 TUsbcPhysicalEndpoint::TUsbcPhysicalEndpoint() |
|
195 : iEndpointAddr(0), iIfcNumber(NULL), iLEndpoint(NULL), iSettingReserve(EFalse), iHalt(EFalse) |
|
196 { |
|
197 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::TUsbcPhysicalEndpoint")); |
|
198 } |
|
199 |
|
200 |
|
201 TInt TUsbcPhysicalEndpoint::TypeAvailable(TUint aType) const |
|
202 { |
|
203 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::TypeAvailable")); |
|
204 switch (aType) |
|
205 { |
|
206 case KUsbEpTypeControl: |
|
207 return (iCaps.iTypesAndDir & KUsbEpTypeControl); |
|
208 case KUsbEpTypeIsochronous: |
|
209 return (iCaps.iTypesAndDir & KUsbEpTypeIsochronous); |
|
210 case KUsbEpTypeBulk: |
|
211 return (iCaps.iTypesAndDir & KUsbEpTypeBulk); |
|
212 case KUsbEpTypeInterrupt: |
|
213 return (iCaps.iTypesAndDir & KUsbEpTypeInterrupt); |
|
214 default: |
|
215 __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid EP type: %d", aType)); |
|
216 return 0; |
|
217 } |
|
218 } |
|
219 |
|
220 |
|
221 TInt TUsbcPhysicalEndpoint::DirAvailable(TUint aDir) const |
|
222 { |
|
223 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::DirAvailable")); |
|
224 switch (aDir) |
|
225 { |
|
226 case KUsbEpDirIn: |
|
227 return (iCaps.iTypesAndDir & KUsbEpDirIn); |
|
228 case KUsbEpDirOut: |
|
229 return (iCaps.iTypesAndDir & KUsbEpDirOut); |
|
230 default: |
|
231 __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid EP direction: %d", aDir)); |
|
232 return 0; |
|
233 } |
|
234 } |
|
235 |
|
236 |
|
237 TInt TUsbcPhysicalEndpoint::EndpointSuitable(const TUsbcEndpointInfo* aEpInfo, TInt aIfcNumber) const |
|
238 { |
|
239 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::EndpointSuitable")); |
|
240 __KTRACE_OPT(KUSB, Kern::Printf(" looking for EP: type=0x%x dir=0x%x size=%d (ifc_num=%d)", |
|
241 aEpInfo->iType, aEpInfo->iDir, aEpInfo->iSize, aIfcNumber)); |
|
242 if (iSettingReserve) |
|
243 { |
|
244 __KTRACE_OPT(KUSB, Kern::Printf(" -> setting conflict")); |
|
245 return 0; |
|
246 } |
|
247 // (aIfcNumber == -1) means the ep is for a new default interface setting |
|
248 else if (iIfcNumber && (*iIfcNumber != aIfcNumber)) |
|
249 { |
|
250 // If this endpoint has already been claimed (iIfcNumber != NULL), |
|
251 // but by a different interface(-set) than the currently looking one |
|
252 // (*iIfcNumber != aIfcNumber), then it's not available. |
|
253 // This works because we can assign the same physical endpoint |
|
254 // to different alternate settings of the *same* interface, and |
|
255 // because we check for available endpoints for every alternate setting |
|
256 // as a whole. |
|
257 __KTRACE_OPT(KUSB, Kern::Printf(" -> ifc conflict")); |
|
258 return 0; |
|
259 } |
|
260 else if (!TypeAvailable(aEpInfo->iType)) |
|
261 { |
|
262 __KTRACE_OPT(KUSB, Kern::Printf(" -> type conflict")); |
|
263 return 0; |
|
264 } |
|
265 else if (!DirAvailable(aEpInfo->iDir)) |
|
266 { |
|
267 __KTRACE_OPT(KUSB, Kern::Printf(" -> direction conflict")); |
|
268 return 0; |
|
269 } |
|
270 else if (!(iCaps.iSizes & PacketSize2Mask(aEpInfo->iSize)) && !(iCaps.iSizes & KUsbEpSizeCont)) |
|
271 { |
|
272 __KTRACE_OPT(KUSB, Kern::Printf(" -> size conflict")); |
|
273 return 0; |
|
274 } |
|
275 else |
|
276 return 1; |
|
277 } |
|
278 |
|
279 |
|
280 TUsbcPhysicalEndpoint::~TUsbcPhysicalEndpoint() |
|
281 { |
|
282 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::~TUsbcPhysicalEndpoint()")); |
|
283 iLEndpoint = NULL; |
|
284 } |
|
285 |
|
286 |
|
287 TUsbcLogicalEndpoint::TUsbcLogicalEndpoint(DUsbClientController* aController, TUint aEndpointNum, |
|
288 const TUsbcEndpointInfo& aEpInfo, TUsbcInterface* aInterface, |
|
289 TUsbcPhysicalEndpoint* aPEndpoint) |
|
290 : iController(aController), iLEndpointNum(aEndpointNum), iInfo(aEpInfo), iInterface(aInterface), |
|
291 iPEndpoint(aPEndpoint) |
|
292 { |
|
293 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLogicalEndpoint::TUsbcLogicalEndpoint()")); |
|
294 // Adjust FS/HS endpoint sizes |
|
295 if (iInfo.AdjustEpSizes(iEpSize_Fs, iEpSize_Hs) != KErrNone) |
|
296 { |
|
297 __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown endpoint type: %d", iInfo.iType)); |
|
298 } |
|
299 __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iEpSize_Fs=%d iEpSize_Hs=%d (iInfo.iSize=%d)", |
|
300 iEpSize_Fs, iEpSize_Hs, iInfo.iSize)); |
|
301 // Adjust HS polling interval |
|
302 if (iInfo.AdjustPollInterval() != KErrNone) |
|
303 { |
|
304 __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown ep type (%d) or invalid interval value (%d)", |
|
305 iInfo.iType, iInfo.iInterval)); |
|
306 } |
|
307 __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iInfo.iInterval=%d iInfo.iInterval_Hs=%d", |
|
308 iInfo.iInterval, iInfo.iInterval_Hs)); |
|
309 // Additional transactions requested on a non High Bandwidth ep? |
|
310 if ((iInfo.iTransactions > 0) && !aPEndpoint->iCaps.iHighBandwidth) |
|
311 { |
|
312 __KTRACE_OPT(KPANIC, |
|
313 Kern::Printf(" Warning: Additional transactions requested but not a High Bandwidth ep")); |
|
314 } |
|
315 } |
|
316 |
|
317 |
|
318 TUsbcLogicalEndpoint::~TUsbcLogicalEndpoint() |
|
319 { |
|
320 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLogicalEndpoint::~TUsbcLogicalEndpoint: #%d", iLEndpointNum)); |
|
321 // If the real endpoint this endpoint points to is also used by |
|
322 // any other logical endpoint in any other setting of this interface |
|
323 // then we leave the real endpoint marked as used. Otherwise we mark |
|
324 // it as available (set its ifc number pointer to NULL). |
|
325 const TInt n = iInterface->iInterfaceSet->iInterfaces.Count(); |
|
326 for (TInt i = 0; i < n; ++i) |
|
327 { |
|
328 const TUsbcInterface* const ifc = iInterface->iInterfaceSet->iInterfaces[i]; |
|
329 const TInt m = ifc->iEndpoints.Count(); |
|
330 for (TInt j = 0; j < m; ++j) |
|
331 { |
|
332 const TUsbcLogicalEndpoint* const ep = ifc->iEndpoints[j]; |
|
333 if ((ep->iPEndpoint == iPEndpoint) && (ep != this)) |
|
334 { |
|
335 __KTRACE_OPT(KUSB, Kern::Printf(" Physical endpoint still in use -> we leave it as is")); |
|
336 return; |
|
337 } |
|
338 } |
|
339 } |
|
340 __KTRACE_OPT(KUSB, Kern::Printf(" Closing DMA channel")); |
|
341 const TInt idx = iController->EpAddr2Idx(iPEndpoint->iEndpointAddr); |
|
342 // If the endpoint doesn't support DMA (now or ever) the next operation will be a no-op. |
|
343 iController->CloseDmaChannel(idx); |
|
344 __KTRACE_OPT(KUSB, Kern::Printf(" Setting physical ep 0x%02x ifc number to NULL (was %d)", |
|
345 iPEndpoint->iEndpointAddr, *iPEndpoint->iIfcNumber)); |
|
346 iPEndpoint->iIfcNumber = NULL; |
|
347 } |
|
348 |
|
349 |
|
350 TUsbcInterface::TUsbcInterface(TUsbcInterfaceSet* aIfcSet, TUint8 aSetting, TBool aNoEp0Requests) |
|
351 : iEndpoints(2), iInterfaceSet(aIfcSet), iSettingCode(aSetting), iNoEp0Requests(aNoEp0Requests) |
|
352 { |
|
353 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterface::TUsbcInterface()")); |
|
354 } |
|
355 |
|
356 |
|
357 TUsbcInterface::~TUsbcInterface() |
|
358 { |
|
359 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterface::~TUsbcInterface()")); |
|
360 iEndpoints.ResetAndDestroy(); |
|
361 } |
|
362 |
|
363 |
|
364 TUsbcInterfaceSet::TUsbcInterfaceSet(const DBase* aClientId, TUint8 aIfcNum) |
|
365 : iInterfaces(2), iClientId(aClientId), iInterfaceNumber(aIfcNum), iCurrentInterface(0) |
|
366 { |
|
367 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceSet::TUsbcInterfaceSet()")); |
|
368 } |
|
369 |
|
370 |
|
371 TUsbcInterfaceSet::~TUsbcInterfaceSet() |
|
372 { |
|
373 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceSet::~TUsbcInterfaceSet()")); |
|
374 iInterfaces.ResetAndDestroy(); |
|
375 } |
|
376 |
|
377 |
|
378 TUsbcConfiguration::TUsbcConfiguration(TUint8 aConfigVal) |
|
379 : iInterfaceSets(1), iConfigValue(aConfigVal) // iInterfaceSets(1): granularity |
|
380 { |
|
381 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfiguration::TUsbcConfiguration()")); |
|
382 } |
|
383 |
|
384 |
|
385 TUsbcConfiguration::~TUsbcConfiguration() |
|
386 { |
|
387 __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfiguration::~TUsbcConfiguration()")); |
|
388 iInterfaceSets.ResetAndDestroy(); |
|
389 } |
|
390 |
|
391 |
|
392 _LIT(KDriverName, "Usbcc"); |
|
393 |
|
394 DUsbcPowerHandler::DUsbcPowerHandler(DUsbClientController* aController) |
|
395 : DPowerHandler(KDriverName), iController(aController) |
|
396 {} |
|
397 |
|
398 |
|
399 void DUsbcPowerHandler::PowerUp() |
|
400 { |
|
401 if (iController) |
|
402 iController->iPowerUpDfc.Enque(); |
|
403 } |
|
404 |
|
405 |
|
406 void DUsbcPowerHandler::PowerDown(TPowerState) |
|
407 { |
|
408 if (iController) |
|
409 iController->iPowerDownDfc.Enque(); |
|
410 } |
|
411 |
|
412 |
|
413 // -eof- |