|
1 // Copyright (c) 2008-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 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalTechnology |
|
19 */ |
|
20 |
|
21 #include <e32base.h> |
|
22 #include <e32base_private.h> |
|
23 #include <d32usbdi.h> |
|
24 |
|
25 #include <d32usbtransfers.h> |
|
26 #include "msctypes.h" |
|
27 #include "mscutils.h" |
|
28 #include "shared.h" |
|
29 #include "msgservice.h" |
|
30 #include "botmsctypes.h" |
|
31 #include "mprotocol.h" |
|
32 #include "mtransport.h" |
|
33 #include "cbulkonlytransport.h" |
|
34 #include "cusbhostmslogicalunit.h" |
|
35 #include "cusbhostmsdevice.h" |
|
36 #include "cusbmssuspendresume.h" |
|
37 |
|
38 #include "msdebug.h" |
|
39 #include "debug.h" |
|
40 |
|
41 |
|
42 CUsbHostMsDevice* CUsbHostMsDevice::NewL(THostMassStorageConfig& aConfig) |
|
43 { |
|
44 __MSFNSLOG |
|
45 CUsbHostMsDevice* r = new (ELeave) CUsbHostMsDevice(aConfig); |
|
46 CleanupStack::PushL(r); |
|
47 r->ConstructL(); |
|
48 CleanupStack::Pop(); |
|
49 return r; |
|
50 } |
|
51 |
|
52 void CUsbHostMsDevice::ConstructL() |
|
53 { |
|
54 __MSFNLOG |
|
55 iTimer = CPeriodic::NewL(CActive::EPriorityStandard); |
|
56 iTimerRunning = EFalse; |
|
57 } |
|
58 |
|
59 |
|
60 CUsbHostMsDevice::CUsbHostMsDevice(THostMassStorageConfig& aConfig) |
|
61 : iConfig(aConfig), |
|
62 iState(EActive) |
|
63 { |
|
64 __MSFNLOG |
|
65 |
|
66 } |
|
67 |
|
68 |
|
69 CUsbHostMsDevice::~CUsbHostMsDevice() |
|
70 { |
|
71 __MSFNLOG |
|
72 delete iTransport; |
|
73 delete iDeviceSuspendResume; |
|
74 if (iTimer && iTimerRunning) |
|
75 { |
|
76 iTimer->Cancel(); |
|
77 } |
|
78 delete iTimer; |
|
79 } |
|
80 |
|
81 |
|
82 MTransport* CUsbHostMsDevice::InitialiseTransportL(TTransportType aTransportId) |
|
83 { |
|
84 __MSFNLOG |
|
85 switch(aTransportId) |
|
86 { |
|
87 case BulkOnlyTransport: |
|
88 return CBulkOnlyTransport::NewL(iConfig.iInterfaceToken); |
|
89 default: |
|
90 // Panic; |
|
91 __HOSTPRINT(_L("Unsupported Transport class requested")); |
|
92 User::Leave(KErrNotSupported); |
|
93 return NULL; |
|
94 } |
|
95 } |
|
96 |
|
97 void CUsbHostMsDevice::InitialiseL(const RMessage2& aMessage) |
|
98 { |
|
99 __MSFNLOG |
|
100 iTransport = InitialiseTransportL((TTransportType) iConfig.iTransportId); |
|
101 TRAPD(r, iDeviceSuspendResume = CUsbMsIfaceSuspendResume::NewL(iTransport, this)); |
|
102 if(r != KErrNone) |
|
103 { |
|
104 delete iTransport; |
|
105 User::Leave(r); |
|
106 } |
|
107 iTransport->GetMaxLun(&iMaxLun, aMessage); |
|
108 } |
|
109 |
|
110 |
|
111 void CUsbHostMsDevice::UnInitialiseL() |
|
112 { |
|
113 __MSFNLOG |
|
114 StopTimer(); |
|
115 iLuList.RemoveAllLuL(); |
|
116 } |
|
117 |
|
118 |
|
119 TInt CUsbHostMsDevice::AddLunL(TLun aLun) |
|
120 { |
|
121 __MSFNLOG |
|
122 TInt r = KErrNone; |
|
123 StartTimer(); |
|
124 CUsbHostMsLogicalUnit* lu = CUsbHostMsLogicalUnit::NewL(aLun); |
|
125 CleanupStack::PushL(lu); |
|
126 |
|
127 TRAP(r, lu->InitialiseProtocolL(aLun, iConfig, *iTransport)); |
|
128 |
|
129 if (r == KErrNone) |
|
130 { |
|
131 TRAP(r, iLuList.AddLuL(lu)); |
|
132 } |
|
133 |
|
134 if (r != KErrNone) |
|
135 { |
|
136 CleanupStack::PopAndDestroy(lu); |
|
137 } |
|
138 else |
|
139 { |
|
140 CleanupStack::Pop(lu); |
|
141 } |
|
142 return r; |
|
143 } |
|
144 |
|
145 |
|
146 void CUsbHostMsDevice::RemoveLunL(TLun aLun) |
|
147 { |
|
148 __MSFNLOG |
|
149 if(iLuList.Count() <= 1) |
|
150 StopTimer(); |
|
151 iLuList.RemoveLuL(aLun); |
|
152 } |
|
153 |
|
154 |
|
155 void CUsbHostMsDevice::InitLunL(TLun aLun) |
|
156 { |
|
157 __MSFNLOG |
|
158 SetLunL(aLun); |
|
159 iLuList.GetLuL(aLun).InitL(); |
|
160 } |
|
161 |
|
162 |
|
163 void CUsbHostMsDevice::SuspendLunL(TLun aLun) |
|
164 { |
|
165 __MSFNLOG |
|
166 iLuList.GetLuL(aLun).ReadyToSuspend(); |
|
167 |
|
168 // check whether all the luns are suspended, if so then request usb |
|
169 // interface suspension to the transport layer |
|
170 for (TInt i = 0; i < iLuList.Count(); i++) |
|
171 { |
|
172 CUsbHostMsLogicalUnit& lu = iLuList.GetLuL(i); |
|
173 if (!lu.IsReadyToSuspend() && lu.IsConnected()) |
|
174 return; |
|
175 } |
|
176 |
|
177 for (TInt i = 0; i < iLuList.Count(); i++) |
|
178 { |
|
179 CUsbHostMsLogicalUnit& lu = iLuList.GetLuL(i); |
|
180 SetLunL(lu.Lun()); |
|
181 lu.SuspendL(); |
|
182 } |
|
183 |
|
184 StopTimer(); |
|
185 iDeviceSuspendResume->Suspend(); |
|
186 iState = ESuspended; |
|
187 } |
|
188 |
|
189 TBool CUsbHostMsDevice::IsActive() |
|
190 { |
|
191 __MSFNLOG |
|
192 return (iState == EActive)? ETrue : EFalse; |
|
193 } |
|
194 |
|
195 TBool CUsbHostMsDevice::IsSuspended() |
|
196 { |
|
197 __MSFNLOG |
|
198 return (iState == ESuspended)? ETrue : EFalse; |
|
199 } |
|
200 |
|
201 void CUsbHostMsDevice::ResumeL(TRequestStatus &aStatus) |
|
202 { |
|
203 __MSFNLOG |
|
204 if (iState == ESuspended) |
|
205 { |
|
206 StartTimer(); |
|
207 iDeviceSuspendResume->Resume(aStatus); |
|
208 } |
|
209 else |
|
210 { |
|
211 __HOSTPRINT(_L("CUsbHostMsDevice: Wierd we are not suspended but were asked to resume")); |
|
212 } |
|
213 } |
|
214 |
|
215 |
|
216 TLun CUsbHostMsDevice::GetAndSetLunL(const RMessage2& aMessage) |
|
217 { |
|
218 __MSFNLOG |
|
219 // Subssessions need a positive value to store in the handles. We represent Luns as LunId+1 |
|
220 // We represent LunId in MSC from 0 to MaxLun-1 as represented in BOT so subtract 1 from the Id |
|
221 // received from RMessage |
|
222 |
|
223 TInt lun = aMessage.Int3() - 1; |
|
224 if (lun < 0) |
|
225 { |
|
226 User::Leave(KErrArgument); |
|
227 } |
|
228 SetLunL(static_cast<TLun>(lun)); |
|
229 return static_cast<TLun>(lun); |
|
230 } |
|
231 |
|
232 |
|
233 CUsbHostMsLogicalUnit& CUsbHostMsDevice::GetLuL(TInt aLunNum) const |
|
234 { |
|
235 return iLuList.GetLuL(aLunNum); |
|
236 } |
|
237 |
|
238 void CUsbHostMsDevice::SetLunL(TLun aLun) |
|
239 { |
|
240 __MSFNLOG |
|
241 if (aLun <= iMaxLun) |
|
242 { |
|
243 __HOSTPRINT1(_L("SetLun %d"), aLun); |
|
244 iTransport->SetLun(aLun); |
|
245 CUsbHostMsLogicalUnit& lu = iLuList.GetLuL(aLun); |
|
246 if (lu.IsReadyToSuspend()) |
|
247 { |
|
248 lu.CancelReadyToSuspend(); |
|
249 } |
|
250 } |
|
251 } |
|
252 |
|
253 /** |
|
254 Starts timer to periodically check LUN. If the timer is not yet running then |
|
255 start it. |
|
256 */ |
|
257 void CUsbHostMsDevice::StartTimer() |
|
258 { |
|
259 __MSFNLOG |
|
260 if (!iTimerRunning) |
|
261 { |
|
262 // Period of the LUN Ready check |
|
263 const TTimeIntervalMicroSeconds32 KInterval = iConfig.iStatusPollingInterval * 1000 * 1000; |
|
264 TCallBack callback(TimerCallback, this); |
|
265 __HOSTPRINT(_L("Starting timer")); |
|
266 iTimer->Start(KInterval, KInterval, callback); |
|
267 iTimerRunning = ETrue; |
|
268 } |
|
269 } |
|
270 |
|
271 |
|
272 /** |
|
273 Ensure that the Timer is stopped |
|
274 */ |
|
275 void CUsbHostMsDevice::StopTimer() |
|
276 { |
|
277 __MSFNLOG |
|
278 if (iTimer && iTimerRunning) |
|
279 { |
|
280 __HOSTPRINT(_L("Stopping timer")); |
|
281 if (iTimer->IsActive()) |
|
282 { |
|
283 iTimer->Cancel(); |
|
284 } |
|
285 iTimerRunning = EFalse; |
|
286 } |
|
287 } |
|
288 |
|
289 /** |
|
290 A static wrapper for the DoLunReadyCheckEvent member function for use as a timer |
|
291 callback function. |
|
292 |
|
293 @param obj 'this' pointer |
|
294 @return not used in CPeriodic callback (see TCallback) |
|
295 */ |
|
296 TInt CUsbHostMsDevice::TimerCallback(TAny* obj) |
|
297 { |
|
298 __MSFNSLOG |
|
299 CUsbHostMsDevice* device = static_cast<CUsbHostMsDevice*>(obj); |
|
300 TRAPD(err, device->DoLunReadyCheckEventL()); |
|
301 return err; |
|
302 } |
|
303 |
|
304 void CUsbHostMsDevice::DoLunReadyCheckEventL() |
|
305 { |
|
306 __MSFNLOG |
|
307 TInt err; |
|
308 for (TInt i = 0; i < iLuList.Count(); i++) |
|
309 { |
|
310 CUsbHostMsLogicalUnit& lu = iLuList.GetLuL(i); |
|
311 SetLunL(lu.Lun()); |
|
312 TRAP(err, lu.DoLunReadyCheckL()); |
|
313 } |
|
314 } |
|
315 |
|
316 void CUsbHostMsDevice::DoHandleRemoteWakeupL() |
|
317 { |
|
318 __MSFNLOG |
|
319 DoResumeLogicalUnitsL(); |
|
320 DoLunReadyCheckEventL(); // For remote wakeup we do not wait for timer to expire |
|
321 |
|
322 // check whether all the luns are suspended, if so then request usb |
|
323 // interface suspension to the transport layer |
|
324 for (TInt i = 0; i < iLuList.Count(); i++) |
|
325 { |
|
326 CUsbHostMsLogicalUnit& lu = iLuList.GetLuL(i); |
|
327 // Has any of the logical units have got its state changed? |
|
328 if ( (lu.IsReadyToSuspend() && !lu.IsConnected()) || |
|
329 (!lu.IsReadyToSuspend() && lu.IsConnected()) ) |
|
330 { |
|
331 StartTimer(); // Now start the timer |
|
332 return; |
|
333 } |
|
334 } |
|
335 |
|
336 for (TInt i = 0; i < iLuList.Count(); i++) |
|
337 { |
|
338 CUsbHostMsLogicalUnit& lu = iLuList.GetLuL(i); |
|
339 SetLunL(lu.Lun()); |
|
340 lu.SuspendL(); |
|
341 } |
|
342 |
|
343 iDeviceSuspendResume->Suspend(); |
|
344 iState = ESuspended; |
|
345 } |
|
346 |
|
347 void CUsbHostMsDevice::DoResumeLogicalUnitsL() |
|
348 { |
|
349 __MSFNLOG |
|
350 for (TInt i = 0; i < iLuList.Count(); i++) |
|
351 { |
|
352 CUsbHostMsLogicalUnit& lu = iLuList.GetLuL(i); |
|
353 SetLunL(lu.Lun()); |
|
354 lu.ResumeL(); |
|
355 } |
|
356 } |
|
357 |
|
358 void CUsbHostMsDevice::ResumeCompletedL() |
|
359 { |
|
360 __MSFNLOG |
|
361 iState = EActive; |
|
362 DoResumeLogicalUnitsL(); |
|
363 } |