|
1 /* |
|
2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Adheres to the UsbMan USB Class Controller API and talks to C32 |
|
16 * to manage the stub1.CSY that is used to provide a virtual |
|
17 * serial port service to clients |
|
18 * |
|
19 */ |
|
20 |
|
21 /** |
|
22 @file |
|
23 */ |
|
24 |
|
25 #include "Stub1CC.h" |
|
26 #include <usb_std.h> |
|
27 #include <es_ini.h> |
|
28 #include <d32usbc.h> |
|
29 #include <usb/usblogger.h> |
|
30 |
|
31 #ifdef __FLOG_ACTIVE |
|
32 _LIT8(KLogComponent, "STUB1CC"); |
|
33 #endif |
|
34 |
|
35 |
|
36 #include "usbmaninternalconstants.h" |
|
37 |
|
38 |
|
39 // Panic category |
|
40 _LIT( Kstub1CcPanicCategory, "Usbstub1Cc" ); |
|
41 |
|
42 |
|
43 |
|
44 /** |
|
45 * Panic codes for the USB stub1 Class Controller. |
|
46 */ |
|
47 enum Tstub1CcPanic |
|
48 { |
|
49 /** Class called while in an illegal state */ |
|
50 EBadApiCall = 0, |
|
51 /** Asynchronous function called (not needed, as all requests complete synchronously) */ |
|
52 EUnusedFunction = 1, |
|
53 /** Error reading ini file. */ |
|
54 EPanicBadIniFile = 2, |
|
55 /** Bad value for the iNumberOfstub1Functions member.*/ |
|
56 EPanicBadNumberOfstub1Functions = 3, |
|
57 |
|
58 EPanicUnexpectedStatus, |
|
59 EPanicUnexpectedState |
|
60 |
|
61 }; |
|
62 _LIT16(KIfcName, "SubCC 1 Interface"); |
|
63 const TInt KMaxPacketTypeInterrupt = 64; |
|
64 const TInt KPollInterval = 128; |
|
65 |
|
66 |
|
67 |
|
68 /** |
|
69 * Constructs a CUsbstub1ClassController object |
|
70 * |
|
71 * @param aOwner USB Device that owns and manages the class |
|
72 * |
|
73 * @return A new CUsbstub1ClassController object |
|
74 */ |
|
75 CUsbstub1ClassController* CUsbstub1ClassController::NewL( |
|
76 MUsbClassControllerNotify& aOwner) |
|
77 { |
|
78 CUsbstub1ClassController* r = new (ELeave) CUsbstub1ClassController(aOwner); |
|
79 CleanupStack::PushL(r); |
|
80 r->ConstructL(); |
|
81 CleanupStack::Pop(); |
|
82 return r; |
|
83 } |
|
84 |
|
85 /** |
|
86 * Destructor |
|
87 */ |
|
88 CUsbstub1ClassController::~CUsbstub1ClassController() |
|
89 { |
|
90 Cancel(); |
|
91 |
|
92 iTimer.Close(); |
|
93 |
|
94 #ifndef __WINS__ |
|
95 iLdd.Close(); |
|
96 #endif |
|
97 } |
|
98 |
|
99 |
|
100 |
|
101 /** |
|
102 * Constructor. |
|
103 * |
|
104 * @param aOwner USB Device that owns and manages the class |
|
105 */ |
|
106 CUsbstub1ClassController::CUsbstub1ClassController( |
|
107 MUsbClassControllerNotify& aOwner) |
|
108 : CUsbClassControllerPlugIn(aOwner, Kstub1StartupPriority), |
|
109 iStartDelay(Kstub1CCDefaultDelay), |
|
110 iStopDelay(Kstub1CCDefaultDelay), |
|
111 iFailToStart(EFalse), |
|
112 iFailToStop(EFalse) |
|
113 |
|
114 { |
|
115 iTimer.CreateLocal(); |
|
116 } |
|
117 |
|
118 |
|
119 |
|
120 /** |
|
121 * 2nd Phase Construction. |
|
122 */ |
|
123 void CUsbstub1ClassController::ConstructL() |
|
124 { |
|
125 //read INI file |
|
126 TInt ret; |
|
127 CESockIniData* ini = 0; |
|
128 _LIT(KIniFile, "c:\\testdata\\config\\stub1cc.ini"); |
|
129 TRAP(ret, ini=CESockIniData::NewL(KIniFile)); |
|
130 if(ret!=KErrNone) |
|
131 return; |
|
132 |
|
133 CleanupStack::PushL(ini); |
|
134 |
|
135 TInt val; |
|
136 if ((ini->FindVar(_L("0x10203285"),_L("StartDelay"), val))) |
|
137 { |
|
138 iStartDelay = val; |
|
139 } |
|
140 if ((ini->FindVar(_L("0x10203285"),_L("StopDelay"), val))) |
|
141 { |
|
142 iStopDelay = val; |
|
143 } |
|
144 if ((ini->FindVar(_L("0x10203285"),_L("FailToStart"), val)) && val!=0) |
|
145 { |
|
146 iFailToStart = ETrue; |
|
147 } |
|
148 if ((ini->FindVar(_L("0x10203285"),_L("FailToStop"), val)) && val!=0 ) |
|
149 { |
|
150 iFailToStop = ETrue; |
|
151 } |
|
152 CleanupStack::PopAndDestroy(ini); |
|
153 } |
|
154 |
|
155 /** |
|
156 * Called by UsbMan when it wants to start the USB stub1 class. This always |
|
157 * completes immediately. |
|
158 * |
|
159 * @param aStatus The caller's request status, filled in with an error code |
|
160 */ |
|
161 void CUsbstub1ClassController::Start(TRequestStatus& aStatus) |
|
162 { |
|
163 LOG_FUNC |
|
164 |
|
165 aStatus = KRequestPending; |
|
166 iReportStatus = &aStatus; |
|
167 //If we are already started then just complete the request. |
|
168 if (iState == EUsbServiceStarted) |
|
169 { |
|
170 User::RequestComplete(iReportStatus, KErrNone); |
|
171 return; |
|
172 } |
|
173 |
|
174 if (iFailToStart) |
|
175 { |
|
176 User::RequestComplete(iReportStatus, KErrGeneral); |
|
177 return; |
|
178 } |
|
179 |
|
180 iState = EUsbServiceStarting; |
|
181 #ifndef __WINS__ |
|
182 TInt ret = iLdd.Open(0); |
|
183 LOGTEXT2(_L8("Open LDD, ret=%d"), ret); |
|
184 ret = SetUpInterface(); |
|
185 LOGTEXT2(_L8("SetUpInterface(), ret=%d"), ret); |
|
186 #endif |
|
187 iTimer.After(iStatus, iStartDelay*1000); //convert from usec to msec |
|
188 SetActive(); |
|
189 } |
|
190 |
|
191 /** |
|
192 * Called by UsbMan when it wants to stop the USB stub1 class. |
|
193 * |
|
194 * @param aStatus The caller's request status: always set to KErrNone |
|
195 */ |
|
196 void CUsbstub1ClassController::Stop(TRequestStatus& aStatus) |
|
197 { |
|
198 LOG_FUNC |
|
199 |
|
200 aStatus = KRequestPending; |
|
201 iReportStatus = &aStatus; |
|
202 //If we are already idle then just complete the request. |
|
203 if (iState == EUsbServiceIdle) |
|
204 { |
|
205 User::RequestComplete(iReportStatus, KErrNone); |
|
206 return; |
|
207 } |
|
208 |
|
209 if (iFailToStop) |
|
210 { |
|
211 User::RequestComplete(iReportStatus, KErrGeneral); |
|
212 return; |
|
213 } |
|
214 |
|
215 iState = EUsbServiceStopping; |
|
216 |
|
217 #ifndef __WINS__ |
|
218 iLdd.Close(); |
|
219 #endif |
|
220 |
|
221 iTimer.After(iStatus, iStopDelay*1000); //convert from usec to msec |
|
222 SetActive(); |
|
223 } |
|
224 |
|
225 /** |
|
226 * Gets information about the descriptor which this class provides. |
|
227 * |
|
228 * @param aDescriptorInfo Descriptor info structure filled in by this function |
|
229 */ |
|
230 void CUsbstub1ClassController::GetDescriptorInfo(TUsbDescriptor& aDescriptorInfo) const |
|
231 { |
|
232 LOG_FUNC |
|
233 |
|
234 aDescriptorInfo.iLength = Kstub1DescriptorLength; |
|
235 aDescriptorInfo.iNumInterfaces = Kstub1NumberOfInterfacesPerstub1Function; |
|
236 } |
|
237 |
|
238 |
|
239 /** |
|
240 * Standard active object RunL. |
|
241 */ |
|
242 void CUsbstub1ClassController::RunL() |
|
243 { |
|
244 LOG_FUNC |
|
245 |
|
246 __ASSERT_DEBUG( iStatus == KErrNone, _USB_PANIC(Kstub1CcPanicCategory, EPanicUnexpectedStatus) ); |
|
247 switch (iState) |
|
248 { |
|
249 case EUsbServiceStarting: |
|
250 iState = EUsbServiceStarted; |
|
251 break; |
|
252 case EUsbServiceStopping: |
|
253 iState = EUsbServiceIdle; |
|
254 break; |
|
255 default: |
|
256 _USB_PANIC(Kstub1CcPanicCategory, EPanicUnexpectedState); |
|
257 } |
|
258 *iReportStatus = KErrNone; |
|
259 User::RequestComplete(iReportStatus, iStatus.Int()); |
|
260 } |
|
261 |
|
262 /** |
|
263 * Standard active object cancellation function. Never called because this |
|
264 * class has no asynchronous requests. |
|
265 */ |
|
266 void CUsbstub1ClassController::DoCancel() |
|
267 { |
|
268 |
|
269 if (IsActive()) |
|
270 { |
|
271 iTimer.Cancel(); |
|
272 } |
|
273 switch (iState) |
|
274 { |
|
275 case EUsbServiceStarting: |
|
276 iState = EUsbServiceIdle; |
|
277 break; |
|
278 case EUsbServiceStopping: |
|
279 iState = EUsbServiceStarted; |
|
280 break; |
|
281 default: |
|
282 _USB_PANIC(Kstub1CcPanicCategory, EPanicUnexpectedState); |
|
283 } |
|
284 *iReportStatus = KErrNone; |
|
285 User::RequestComplete(iReportStatus, KErrCancel); |
|
286 } |
|
287 |
|
288 /** |
|
289 * Standard active object error function. Never called because this class has |
|
290 * no asynchronous requests, and hence its RunL is never called. |
|
291 * |
|
292 * @param aError The error code (unused) |
|
293 * @return Always KErrNone to avoid an active scheduler panic |
|
294 */ |
|
295 TInt CUsbstub1ClassController::RunError(TInt /*aError*/) |
|
296 { |
|
297 __ASSERT_DEBUG( EFalse, _USB_PANIC(Kstub1CcPanicCategory, EUnusedFunction) ); |
|
298 return KErrNone; |
|
299 } |
|
300 |
|
301 TInt CUsbstub1ClassController::SetUpInterface() |
|
302 /** |
|
303 * Set up the interface for use. This involves finding a "Interrupt IN" |
|
304 * endpoint and, if found, configuring the interface. |
|
305 */ |
|
306 { |
|
307 LOGTEXT(_L8(">>CCdcControlInterface::SetUpInterface")); |
|
308 |
|
309 TUsbDeviceCaps dCaps; |
|
310 TInt ret = iLdd.DeviceCaps(dCaps); |
|
311 LOGTEXT(_L8("\tchecking result of DeviceCaps")); |
|
312 if ( ret ) |
|
313 { |
|
314 LOGTEXT2(_L8("<<CCdcControlInterface::SetUpInterface ret=%d"), ret); |
|
315 return ret; |
|
316 } |
|
317 |
|
318 const TUint KRequiredNumberOfEndpoints = 1; // in addition to endpoint 0. |
|
319 |
|
320 const TUint totalEndpoints = static_cast<TUint>(dCaps().iTotalEndpoints); |
|
321 LOGTEXT2(_L8("\tiTotalEndpoints = %d"), totalEndpoints); |
|
322 if ( totalEndpoints < KRequiredNumberOfEndpoints ) |
|
323 { |
|
324 LOGTEXT2(_L8("<<CCdcControlInterface::SetUpInterface ret=%d"), |
|
325 KErrGeneral); |
|
326 return KErrGeneral; |
|
327 } |
|
328 |
|
329 // Endpoints |
|
330 TUsbcEndpointData data[KUsbcMaxEndpoints]; |
|
331 TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data)); |
|
332 ret = iLdd.EndpointCaps(dataptr); |
|
333 LOGTEXT(_L8("\tchecking result of EndpointCaps")); |
|
334 if ( ret ) |
|
335 { |
|
336 LOGTEXT2(_L8("<<CCdcControlInterface::SetUpInterface ret=%d"), ret); |
|
337 return ret; |
|
338 } |
|
339 |
|
340 // Set the active interface |
|
341 TUsbcInterfaceInfoBuf ifc; |
|
342 TBool epFound = EFalse; |
|
343 for ( TUint i = 0 ; i < totalEndpoints ; i++ ) |
|
344 { |
|
345 const TUsbcEndpointCaps* caps = &data[i].iCaps; |
|
346 __ASSERT_DEBUG(caps,_USB_PANIC(Kstub1CcPanicCategory, EPanicUnexpectedStatus)); |
|
347 |
|
348 if (data[i].iInUse) |
|
349 { |
|
350 continue; |
|
351 } |
|
352 |
|
353 if ((caps->iTypesAndDir & (KUsbEpTypeInterrupt | KUsbEpDirIn)) == |
|
354 (KUsbEpTypeInterrupt | KUsbEpDirIn)) |
|
355 { |
|
356 // EEndpoint1 is interrupt endpoint |
|
357 ifc().iEndpointData[0].iType = KUsbEpTypeInterrupt; |
|
358 ifc().iEndpointData[0].iDir = KUsbEpDirIn; |
|
359 |
|
360 //get the max packet size it can potentially support |
|
361 //it's possible that it can support Isoch (1023) which is greater |
|
362 //than max for Int at 64 |
|
363 TInt maxSize = Min(caps->MaxPacketSize(), KMaxPacketTypeInterrupt); |
|
364 |
|
365 ifc().iEndpointData[0].iSize = maxSize; |
|
366 |
|
367 ifc().iEndpointData[0].iInterval = KPollInterval; |
|
368 epFound = ETrue; |
|
369 break; |
|
370 } |
|
371 } |
|
372 LOGTEXT(_L8("\tchecking epFound")); |
|
373 if ( !epFound ) |
|
374 { |
|
375 LOGTEXT2(_L8("<<CCdcControlInterface::SetUpInterface ret=%d"), |
|
376 KErrGeneral); |
|
377 return KErrGeneral; |
|
378 } |
|
379 |
|
380 TName ifcName(KIfcName); |
|
381 ifc().iString = &ifcName; |
|
382 ifc().iTotalEndpointsUsed = KRequiredNumberOfEndpoints; |
|
383 // Codes taken from USBCDC 1.1. |
|
384 ifc().iClass.iClassNum = 0x02; // Table 15- Communication Interface Class |
|
385 ifc().iClass.iSubClassNum = 0x02; // Table 16- Abstract Control Model |
|
386 ifc().iClass.iProtocolNum = 0x01; // Table 17- Hayes compatible |
|
387 |
|
388 LOGTEXT(_L8("\tabout to call SetInterface")); |
|
389 // Zero effectively indicates that alternate interfaces are not used. |
|
390 ret = iLdd.SetInterface(0, ifc); |
|
391 |
|
392 LOGTEXT2(_L8("<<CCdcControlInterface::SetUpInterface ret=%d"), ret); |
|
393 return ret; |
|
394 } |
|
395 |
|
396 // |
|
397 // End of file |