|
1 // Copyright (c) 2007-2010 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 "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 @internalComponent |
|
19 */ |
|
20 |
|
21 #include "hctlusboriginal.h" |
|
22 |
|
23 #include "hctlusboriginalcommand.h" |
|
24 #include "hctlusboriginalaclout.h" |
|
25 #include "hctlusboriginalaclin.h" |
|
26 #include "hctlusboriginalevent.h" |
|
27 #include "controllermanager.h" |
|
28 #include "devicestatemanager.h" |
|
29 #include "hctlusboriginalserver.h" |
|
30 |
|
31 #include "hctlusboriginalutils.h" |
|
32 |
|
33 #include <bluetooth/hci/hctleventobserver.h> |
|
34 #include <bluetooth/hci/hctldataobserver.h> |
|
35 #include <bluetooth/hci/hctlchannelobserver.h> |
|
36 #include <bluetooth/logger.h> |
|
37 |
|
38 |
|
39 #ifdef __FLOG_ACTIVE |
|
40 _LIT8(KLogComponent, LOG_COMPONENT_HCTL_USB_ORIGINAL); |
|
41 #endif |
|
42 |
|
43 _LIT(KUsbdiLddFileName, "usbdi"); |
|
44 |
|
45 CHCTLUsbOriginal* CHCTLUsbOriginal::NewL() |
|
46 { |
|
47 LOG_STATIC_FUNC |
|
48 CHCTLUsbOriginal* self = new(ELeave) CHCTLUsbOriginal(); |
|
49 CleanupStack::PushL(self); |
|
50 self->ConstructL(); |
|
51 CleanupStack::Pop(); |
|
52 return self; |
|
53 } |
|
54 |
|
55 CHCTLUsbOriginal::CHCTLUsbOriginal() |
|
56 { |
|
57 LOG_FUNC |
|
58 } |
|
59 |
|
60 CHCTLUsbOriginal::~CHCTLUsbOriginal() |
|
61 { |
|
62 LOG_FUNC |
|
63 |
|
64 delete iControl; |
|
65 delete iAclOut; |
|
66 delete iAclIn; |
|
67 delete iEvent; |
|
68 |
|
69 iInterface.Close(); |
|
70 iScoInterface.Close(); |
|
71 |
|
72 iFdc.Close(); |
|
73 |
|
74 delete iSecondStageCallBack; |
|
75 |
|
76 delete iServer; |
|
77 delete iControllerMan; |
|
78 HCI_LOG_UNLOAD(this); |
|
79 |
|
80 // User::FreeLogicalDevice(RUsbInterface::Name()); // TODO Maybe this affects others |
|
81 } |
|
82 |
|
83 void CHCTLUsbOriginal::ConstructL() |
|
84 { |
|
85 LOG_FUNC |
|
86 |
|
87 LOG(_L("\tLoading USBDI LDD")); |
|
88 TInt err = User::LoadLogicalDevice(KUsbdiLddFileName); |
|
89 if(err != KErrNone && err != KErrAlreadyExists) |
|
90 { |
|
91 LEAVEIFERRORL(err); |
|
92 } |
|
93 |
|
94 HCI_LOG_LOADL(this, KHCILoggerDatalinkTypeH1); // no frame information - so use the H1 encoding. |
|
95 iControllerMan = CControllerManager::NewL(*this); |
|
96 iDeviceStateMan = CDeviceStateManager::NewL(iInterface, iScoInterface); |
|
97 iServer = CHCTLUsbOriginalServer::NewL(*this); |
|
98 |
|
99 // We need an asynchronous break from the synchronous creation path to complete the set-up. |
|
100 // This is due to the behaviour of the Bluetooth stack. |
|
101 TCallBack secondStageCallBack(AsyncCallBackSecondStage, this); |
|
102 iSecondStageCallBack = new(ELeave) CAsyncCallBack(secondStageCallBack, CActive::EPriorityStandard); |
|
103 iSecondStageCallBack->CallBack(); |
|
104 } |
|
105 |
|
106 TInt CHCTLUsbOriginal::AsyncCallBackSecondStage(TAny* aUsbOriginal) |
|
107 { |
|
108 LOG_STATIC_FUNC |
|
109 |
|
110 CHCTLUsbOriginal* usbOriginal = static_cast<CHCTLUsbOriginal*>(aUsbOriginal); |
|
111 static_cast<void>(usbOriginal->SetPower(EBTOff)); // Can't handle the error, it shouldn't affect operation. |
|
112 |
|
113 TInt err = usbOriginal->iFdc.Connect(); |
|
114 LOG1(_L("\tFDC Connection result = %d"), err); |
|
115 if(err == KErrNone) |
|
116 { |
|
117 // Here we are passive on errors, a failure to connect indicates |
|
118 // that the FDC isn't loaded yet. When it is it will attach to |
|
119 // us. |
|
120 usbOriginal->iFdc.RequestConnection(); // Causes the FDC to call back with tokens. |
|
121 } |
|
122 |
|
123 return EFalse; // Don't call back any more. |
|
124 } |
|
125 |
|
126 |
|
127 |
|
128 TAny* CHCTLUsbOriginal::Interface(TUid aUid) |
|
129 { |
|
130 LOG_FUNC |
|
131 |
|
132 TAny* ret = NULL; |
|
133 switch(aUid.iUid) |
|
134 { |
|
135 case KHCTLInterfaceUid: |
|
136 ret = reinterpret_cast<TAny*>(static_cast<MHCTLInterface*>(this)); |
|
137 break; |
|
138 |
|
139 case KHCTLPowerInterfaceUid: |
|
140 ret = reinterpret_cast<TAny*>(static_cast<MHCTLPowerInterface*>(iControllerMan)); |
|
141 break; |
|
142 |
|
143 case KHCHardResetUid: |
|
144 ret = reinterpret_cast<TAny*>(static_cast<MHardResetInitiator*>(this)); |
|
145 break; |
|
146 default: |
|
147 break; |
|
148 } |
|
149 |
|
150 return ret; |
|
151 } |
|
152 |
|
153 //Implementation of pure virtuals from MHCTLInterface |
|
154 TInt CHCTLUsbOriginal::MhiWriteAclData(const TDesC8& aData) |
|
155 { |
|
156 LOG_FUNC |
|
157 __ASSERT_DEBUG(iChannelObserver, PANIC(KUsbOriginalPanic, ENoChannelObserver)); |
|
158 |
|
159 TInt rerr = KErrNotReady; |
|
160 // Send if the power is on. |
|
161 if(iCurrentPowerState == EBTOn && DevicePresent()) |
|
162 { |
|
163 rerr = iAclOut->Write(aData); |
|
164 HCI_LOG_FRAME_IF_NO_ERROR(rerr, this, KHCILoggerHostToController | KHCILoggerACLDataFrame, aData); |
|
165 } |
|
166 |
|
167 return rerr; |
|
168 } |
|
169 |
|
170 TInt CHCTLUsbOriginal::MhiWriteSynchronousData(const TDesC8& aData) |
|
171 { |
|
172 LOG_FUNC |
|
173 __ASSERT_DEBUG(iChannelObserver, PANIC(KUsbOriginalPanic, ENoChannelObserver)); |
|
174 |
|
175 ASSERT(EFalse); // TODO Not supported yet |
|
176 |
|
177 TInt rerr = KErrNotReady; |
|
178 // Send if the power is on. |
|
179 if(iCurrentPowerState == EBTOn && DevicePresent()) |
|
180 { |
|
181 // TODO insert code here :) |
|
182 HCI_LOG_FRAME_IF_NO_ERROR(rerr, this, KHCILoggerHostToController | KHCILoggerSynchronousDataFrame, aData); |
|
183 } |
|
184 |
|
185 return rerr; |
|
186 } |
|
187 |
|
188 TInt CHCTLUsbOriginal::MhiWriteCommand(const TDesC8& aData) |
|
189 { |
|
190 LOG_FUNC |
|
191 __ASSERT_DEBUG(iChannelObserver, PANIC(KUsbOriginalPanic, ENoChannelObserver)); |
|
192 |
|
193 TInt rerr = KErrNotReady; |
|
194 // Send if the power is on. |
|
195 if(iCurrentPowerState == EBTOn && DevicePresent()) |
|
196 { |
|
197 rerr = iControl->Write(aData); |
|
198 HCI_LOG_FRAME_IF_NO_ERROR(rerr, this, KHCILoggerHostToController | KHCILoggerCommandOrEvent, aData); |
|
199 } |
|
200 |
|
201 return rerr; |
|
202 } |
|
203 |
|
204 void CHCTLUsbOriginal::MhiSetQdpPluginInterfaceFinder(MQdpPluginInterfaceFinder& aQdpPluginInterfaceFinder) |
|
205 { |
|
206 iQdpPluginInterfaceFinder = &aQdpPluginInterfaceFinder; |
|
207 } |
|
208 |
|
209 void CHCTLUsbOriginal::MhriStartHardReset() |
|
210 { |
|
211 LOG_FUNC |
|
212 iControllerMan->HardReset(); |
|
213 } |
|
214 |
|
215 void CHCTLUsbOriginal::MhiGetAclDataTransportOverhead(TUint& aHeaderSize, TUint& aTrailerSize) const |
|
216 { |
|
217 // Return the transport overhead for ACL data. |
|
218 aHeaderSize = KHCTLAclDataHeaderSize; |
|
219 aTrailerSize = KHCTLAclDataTrailerSize; |
|
220 } |
|
221 |
|
222 void CHCTLUsbOriginal::MhiGetSynchronousDataTransportOverhead(TUint& aHeaderSize, TUint& aTrailerSize) const |
|
223 { |
|
224 // Return the transport overhead for Synchronous data. |
|
225 aHeaderSize = KHCTLSynchronousDataHeaderSize; |
|
226 aTrailerSize = KHCTLSynchronousDataTrailerSize; |
|
227 } |
|
228 |
|
229 void CHCTLUsbOriginal::MhiGetCommandTransportOverhead(TUint& aHeaderSize, TUint& aTrailerSize) const |
|
230 { |
|
231 // Return the transport overhead for HCI commands data. |
|
232 aHeaderSize = KHCTLCommandHeaderSize; |
|
233 aTrailerSize = KHCTLCommandTrailerSize; |
|
234 } |
|
235 |
|
236 /** |
|
237 This function is used by the receiver for informing HCI that ACL data has been received |
|
238 The receiver doesn't have reference to iDataObserver. So this is merely a wrapper for iDataObserver |
|
239 */ |
|
240 void CHCTLUsbOriginal::ProcessACLData(const TDesC8& aData) |
|
241 { |
|
242 HCI_LOG_FRAME(this, KHCILoggerControllerToHost | KHCILoggerACLDataFrame, aData); |
|
243 iDataObserver->MhdoProcessAclData(aData); |
|
244 } |
|
245 |
|
246 /** |
|
247 This function is used by the receiver for informing HCI that Synchronous data has been received |
|
248 The receiver doesn't have reference to iDataObserver. So this is merely a wrapper for iDataObserver |
|
249 */ |
|
250 void CHCTLUsbOriginal::ProcessSynchronousData(const TDesC8& aData) |
|
251 { |
|
252 HCI_LOG_FRAME(this, KHCILoggerControllerToHost | KHCILoggerSynchronousDataFrame, aData); |
|
253 iDataObserver->MhdoProcessSynchronousData(aData); |
|
254 } |
|
255 |
|
256 /** |
|
257 This function is used by the receiver for informing HCI that event has been received |
|
258 The receiver doesn't have reference to iEventObserver. So this is merely a wrapper for iDataObserver |
|
259 */ |
|
260 void CHCTLUsbOriginal::ProcessEvent(const TDesC8& aEvent) |
|
261 { |
|
262 HCI_LOG_FRAME(this, KHCILoggerControllerToHost | KHCILoggerCommandOrEvent, aEvent); |
|
263 iEventObserver->MheoProcessEvent(aEvent); |
|
264 } |
|
265 |
|
266 /** |
|
267 QdpPluginInterfaceFinder getter. |
|
268 |
|
269 @return returns iQdpPluginInterfaceFinder which could be NULL |
|
270 if it has not been given one. |
|
271 */ |
|
272 MQdpPluginInterfaceFinder* CHCTLUsbOriginal::QdpPluginInterfaceFinder() |
|
273 { |
|
274 return iQdpPluginInterfaceFinder; |
|
275 } |
|
276 |
|
277 void CHCTLUsbOriginal::MhiSetDataObserver(MHCTLDataObserver& aDataObserver) |
|
278 { |
|
279 iDataObserver = &aDataObserver; |
|
280 } |
|
281 |
|
282 void CHCTLUsbOriginal::MhiSetEventObserver(MHCTLEventObserver& aEventObserver) |
|
283 { |
|
284 iEventObserver = &aEventObserver; |
|
285 } |
|
286 |
|
287 void CHCTLUsbOriginal::MhiSetChannelObserver(MHCTLChannelObserver& aChannelObserver) |
|
288 { |
|
289 iChannelObserver = &aChannelObserver; |
|
290 if(DevicePresent()) |
|
291 { |
|
292 iControl->SetChannelObserver(aChannelObserver); |
|
293 iAclOut->SetChannelObserver(aChannelObserver); |
|
294 } |
|
295 HandleChannelStateChange(); |
|
296 } |
|
297 |
|
298 void CHCTLUsbOriginal::MhiSetControllerStateObserver(MControllerStateObserver& aControllerStateObserver) |
|
299 { |
|
300 iControllerStateObserver = &aControllerStateObserver; |
|
301 iControllerMan->SetControllerStateObserver(aControllerStateObserver); |
|
302 } |
|
303 |
|
304 void CHCTLUsbOriginal::HandleChannelStateChange() |
|
305 { |
|
306 if(iCurrentPowerState == EBTOn && iChannelObserver && DevicePresent()) |
|
307 { |
|
308 iDeviceStateMan->Resume(); |
|
309 iChannelObserver->MhcoChannelOpen(KHCITransportAllChannels); |
|
310 iAclIn->Start(); |
|
311 iEvent->Start(); |
|
312 // The senders will be activated when the first frame needs to be sent. |
|
313 } |
|
314 else |
|
315 { |
|
316 if(iChannelObserver) |
|
317 { |
|
318 iChannelObserver->MhcoChannelClosed(KHCITransportAllChannels); |
|
319 } |
|
320 if(DevicePresent()) |
|
321 { |
|
322 // abort communication with the hardware |
|
323 iControl->Cancel(); |
|
324 iAclOut->Cancel(); |
|
325 iAclIn->Cancel(); |
|
326 iEvent->Cancel(); |
|
327 |
|
328 // try to suspend the device |
|
329 iDeviceStateMan->Suspend(); |
|
330 } |
|
331 } |
|
332 } |
|
333 |
|
334 void CHCTLUsbOriginal::HandlePowerOff() |
|
335 { |
|
336 iCurrentPowerState = EBTOff; |
|
337 HandleChannelStateChange(); |
|
338 } |
|
339 |
|
340 void CHCTLUsbOriginal::HandlePowerOn() |
|
341 { |
|
342 iCurrentPowerState = EBTOn; |
|
343 HandleChannelStateChange(); |
|
344 } |
|
345 |
|
346 TBTPowerState CHCTLUsbOriginal::CurrentPowerState() const |
|
347 { |
|
348 return iCurrentPowerState; |
|
349 } |
|
350 |
|
351 TInt CHCTLUsbOriginal::SetPower(TBTPowerState aState) |
|
352 { |
|
353 return static_cast<MHCTLPowerInterface*>(iControllerMan)->MhpiSetPower(aState); |
|
354 } |
|
355 |
|
356 TBool CHCTLUsbOriginal::DevicePresent() const |
|
357 { |
|
358 if(iControl) |
|
359 { |
|
360 __ASSERT_DEBUG(iAclOut && iAclIn && iEvent, PANIC(KUsbOriginalPanic, EPartiallyOpenedInterface)); |
|
361 return ETrue; |
|
362 } |
|
363 return EFalse; |
|
364 } |
|
365 |
|
366 void CHCTLUsbOriginal::DeviceAttachedL(TUint32 aStandardIf, TUint32 aScoIf) |
|
367 { |
|
368 if(iCurrentPowerState == EBTOn) |
|
369 { |
|
370 // If the stack is already powered up then we cannot handle the attach. |
|
371 // Ideally we would inform the user to disconnect and connect the device again. |
|
372 LEAVEL(KErrAlreadyExists); |
|
373 } |
|
374 |
|
375 CleanupStack::PushL(TCleanupItem(CHCTLUsbOriginal::Rollback, this)); |
|
376 |
|
377 // Open interface (there should be only 1 setting). |
|
378 LEAVEIFERRORL(iInterface.Open(aStandardIf)); |
|
379 TInt aclAltIfCount = iInterface.GetAlternateInterfaceCount(); |
|
380 if(aclAltIfCount != 1) |
|
381 { |
|
382 LEAVEIFERRORL(aclAltIfCount); // if it's an error then leave with that |
|
383 LOG1(_L8("ACL interface has %d alternate interfaces instead of 1"), aclAltIfCount); |
|
384 LEAVEL(KErrTotalLossOfPrecision); |
|
385 } |
|
386 |
|
387 // We don't do SCO yet, so just set alt. int. setting 0 |
|
388 LEAVEIFERRORL(iScoInterface.Open(aScoIf)); |
|
389 LEAVEIFERRORL(iScoInterface.SelectAlternateInterface(0)); |
|
390 |
|
391 // Initialise pipe AOs |
|
392 iControl = CHCTLUsbOriginalCommand::NewL(iInterface); |
|
393 iAclOut = CHCTLUsbOriginalAclOut::NewL(iInterface); |
|
394 iAclIn = CHCTLUsbOriginalAclIn::NewL(*this, iInterface); |
|
395 iEvent = CHCTLUsbOriginalEvent::NewL(*this, iInterface); |
|
396 |
|
397 // Pipe AOs should have registered their trans. descriptors so initialise. |
|
398 LEAVEIFERRORL(iInterface.InitialiseTransferDescriptors()); |
|
399 |
|
400 // Finally set-up channel observers, if needed |
|
401 if(iChannelObserver) |
|
402 { |
|
403 iControl->SetChannelObserver(*iChannelObserver); |
|
404 iAclOut->SetChannelObserver(*iChannelObserver); |
|
405 } |
|
406 |
|
407 // Ensure we tell everyone what has just happened. |
|
408 TInt err = SetPower(EBTOn); |
|
409 if(err != KErrNone && err != KErrAlreadyExists) |
|
410 { |
|
411 LEAVEIFERRORL(err); |
|
412 } |
|
413 |
|
414 CleanupStack::Pop(this); |
|
415 } |
|
416 |
|
417 void CHCTLUsbOriginal::DeviceRemoved() |
|
418 { |
|
419 // Cleanup resources. |
|
420 delete iEvent, iEvent = NULL; |
|
421 delete iAclIn, iAclIn = NULL; |
|
422 delete iAclOut, iAclOut = NULL; |
|
423 delete iControl,iControl = NULL; |
|
424 |
|
425 iScoInterface.Close(); |
|
426 iInterface.Close(); |
|
427 |
|
428 // Ensure we tell everyone what has just happened. |
|
429 static_cast<void>(SetPower(EBTOff)); |
|
430 } |
|
431 |
|
432 void CHCTLUsbOriginal::Rollback(TAny* aPtr) |
|
433 { |
|
434 CHCTLUsbOriginal* self = reinterpret_cast<CHCTLUsbOriginal*>(aPtr); |
|
435 self->DeviceRemoved(); |
|
436 } |