|
1 // Copyright (c) 2006-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 "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 // The conduit to the HCI and HW - formulates and Qs commands, and implements HCI events |
|
15 // |
|
16 // |
|
17 |
|
18 #include <bluetooth/logger.h> |
|
19 #include "hcifacade.h" |
|
20 #include "linkmgr.h" |
|
21 #include "hostresolver.h" |
|
22 #include "linkutil.h" |
|
23 |
|
24 #include "AclDataQController.h" |
|
25 #include "linkmuxer.h" |
|
26 #include "linkconsts.h" |
|
27 |
|
28 #include <e32std.h> |
|
29 #include <e32cmn.h> |
|
30 #include <bt_sock.h> |
|
31 #include <es_ini.h> |
|
32 #include <e32base.h> |
|
33 |
|
34 #include <bluetooth/hcicommandqueue.h> |
|
35 #include <bluetooth/hcicommandqitem.h> |
|
36 #include <bluetooth/hcicmdqcontroller.h> |
|
37 |
|
38 #include <bluetooth/hci/controllerinitialisationinterface.h> |
|
39 #include <bluetooth/hci/hcidataframer.h> |
|
40 #include <bluetooth/hci/readlocalsupportedfeaturescommand.h> |
|
41 #include <bluetooth/hci/hostbuffersizecommand.h> |
|
42 #include <bluetooth/hci/resetcommand.h> |
|
43 #include <bluetooth/hci/readbdaddrcommand.h> |
|
44 #include <bluetooth/hci/readlocalversioninfocommand.h> |
|
45 #include <bluetooth/hci/writeconnectionaccepttimeoutcommand.h> |
|
46 #include <bluetooth/hci/writevoicesettingcommand.h> |
|
47 #include <bluetooth/hci/readclassofdevicecommand.h> |
|
48 #include <bluetooth/hci/readbuffersizecommand.h> |
|
49 #include <bluetooth/hci/setcontrollertohostflowcontrolcommand.h> |
|
50 |
|
51 #ifdef __FLOG_ACTIVE |
|
52 _LIT8(KLogComponent, LOG_COMPONENT_HCI_FACADE); |
|
53 #endif |
|
54 |
|
55 // definitions |
|
56 const TBasebandTime TBasebandPolicy::KPageTimeoutR0 = static_cast<TBasebandTime>(2.56 /*seconds*/ / KBasebandSlotTime); // in baseband slots |
|
57 const TBasebandTime TBasebandPolicy::KPageTimeoutR1 = static_cast<TBasebandTime>(5.12 /*seconds*/ / KBasebandSlotTime); // in baseband slots |
|
58 const TBasebandTime TBasebandPolicy::KPageTimeoutR2 = static_cast<TBasebandTime>(10.24 /*seconds*/ / KBasebandSlotTime); // in baseband slots |
|
59 const TReal TBasebandPolicy::KBestEffortTimeMultiplier = 2; |
|
60 const TReal TBasebandPolicy::KQuickTimeMultiplier = 0.5; |
|
61 |
|
62 _LIT(KHciUtilComponentName, "bluetooth_stack"); |
|
63 |
|
64 CHCIFacade* CHCIFacade::NewL(CLinkMgrProtocol& aProtocol) |
|
65 { |
|
66 LOG_STATIC_FUNC |
|
67 CHCIFacade* p= new (ELeave) CHCIFacade(aProtocol); |
|
68 CleanupStack::PushL(p); |
|
69 p->ConstructL(); |
|
70 CleanupStack::Pop(); |
|
71 return p; |
|
72 } |
|
73 |
|
74 void CHCIFacade::ConstructL() |
|
75 /** |
|
76 2nd phase construct the HCI Facade. |
|
77 |
|
78 This is where the stack loads both the HCI CommandQ and the CoreHCI and |
|
79 then distributes the required APIs between the different components. |
|
80 **/ |
|
81 { |
|
82 LOG_FUNC |
|
83 // Create HCI CommandQ |
|
84 iCmdController = CHCICmdQController::NewL(); |
|
85 |
|
86 // Create HCI Utility library |
|
87 iHciUtil = CHciUtil::NewL(KHciUtilComponentName); |
|
88 |
|
89 // If we can't open the ini file then this will be treated in the same way |
|
90 // as not reading a valid UID from the ini file. |
|
91 TRAP_IGNORE(iHciUtil->OpenIniFileL()); |
|
92 |
|
93 // Create Core HCI plugin |
|
94 _LIT(KSection, "CoreHci"); |
|
95 _LIT(KCoreHciUidTag, "EcomUid"); |
|
96 |
|
97 TUid coreHciImplUid = TUid::Null(); |
|
98 TRAPD(err, coreHciImplUid = iHciUtil->GetUidFromFileL(KSection, KCoreHciUidTag)); |
|
99 |
|
100 if (err == KErrNone) |
|
101 { |
|
102 // Valid UID found, load it |
|
103 iCoreHciPlugin = CCoreHCIPlugin::NewL(coreHciImplUid); |
|
104 } |
|
105 else |
|
106 { |
|
107 // No UID found in ini file, attempt to load single instance of |
|
108 // implementation |
|
109 iCoreHciPlugin = CCoreHCIPlugin::NewL(); |
|
110 } |
|
111 |
|
112 // Get Core HCI APIs |
|
113 iCoreHci = static_cast<MCoreHci*>(iCoreHciPlugin->Interface(TUid::Uid(KCoreHciInterfaceUid))); |
|
114 iHctl = static_cast<MHCTLInterface*>(iCoreHciPlugin->Interface(TUid::Uid(KHCTLInterfaceUid))); |
|
115 |
|
116 iControllerInitialisor = static_cast<MControllerInitialisationInterface*> |
|
117 (iCoreHciPlugin->Interface(TUid::Uid(KControllerInitialisationInterfaceUid))); |
|
118 if (iControllerInitialisor != NULL) |
|
119 { |
|
120 // attempt to get the Controller Initialisation Abort Extension API |
|
121 iControllerInitAbortExtension = static_cast<MControllerInitialisationAbortExtensionInterface*> |
|
122 (iCoreHciPlugin->Interface(TUid::Uid(KControllerInitialisationAbortExtenstionInterfaceUid))); |
|
123 } |
|
124 |
|
125 iDataFramer = static_cast<MHCIDataFramer*>(iCoreHciPlugin->Interface(TUid::Uid(KHCIDataFramerInterfaceUid))); |
|
126 iHardResetInitiator = static_cast<MHardResetInitiator*>(iCoreHciPlugin->Interface(TUid::Uid(KHCHardResetUid))); |
|
127 |
|
128 // Panic if we don't get the required interfaces, note that the initialisor |
|
129 // interface is optional |
|
130 __ASSERT_ALWAYS(iCoreHci && iHctl && iDataFramer && iHardResetInitiator, |
|
131 Panic(EHCIIncompleteInterfaces)); |
|
132 |
|
133 // Provide direct APIs |
|
134 iCmdController->SetLinkMuxNotifier(*this); |
|
135 iCmdController->SetHCIUnmatchedEventObserver(*this); |
|
136 iCmdController->SetHardResetInitiator(*this); |
|
137 iCmdController->SetPhysicalLinksState(*this); |
|
138 |
|
139 iCoreHci->MchSetHardResetInitiator(*this); |
|
140 iCoreHci->MchSetPhysicalLinksState(*this); |
|
141 iCoreHci->MchSetDataEventObserver(*this); |
|
142 iCoreHci->MchSetDataObserver(*this); |
|
143 iCoreHci->MchSetChannelObserver(*this); |
|
144 iCoreHci->MchSetControllerStateObserver(*this); |
|
145 |
|
146 // Provide Core HCI with CommandQ components |
|
147 iCoreHci->MchSetCommandEventObserver(*(static_cast<MHCICommandEventObserver*>(iCmdController))); |
|
148 iCoreHci->MchSetHCICommandQueue(*(static_cast<MHCICommandQueue*>(iCmdController))); |
|
149 |
|
150 // Provide CommandQ with HCI components |
|
151 iCmdController->SetHCTLInterface(*iHctl); |
|
152 iCmdController->SetHCICommandAllocator(*(static_cast<MHCICommandAllocator*>(iCoreHciPlugin->Interface(TUid::Uid(KHCICommandAllocatorInterfaceUid))))); |
|
153 |
|
154 // Initialise initialisor plugin if present |
|
155 if (iControllerInitialisor != NULL) |
|
156 { |
|
157 // Provide Initialisor with Stack |
|
158 iControllerInitialisor->MciiSetControllerInitialisationObserver(*this); |
|
159 |
|
160 // Provide Initialisor with CommandQ |
|
161 iControllerInitialisor->MciiSetHCICommandQueue(*(static_cast<MHCICommandQueue*>(iCmdController))); |
|
162 } |
|
163 |
|
164 // Attempt to supply the HCI with the Client Usage API |
|
165 MHCIClientUsageCallback* hciClientUsageCallback = static_cast<MHCIClientUsageCallback*> |
|
166 (iCoreHciPlugin->Interface(TUid::Uid(KHCIClientUsageCallbackUid))); |
|
167 |
|
168 if (hciClientUsageCallback) |
|
169 { |
|
170 // Support for the Client Usage Callback API is optional for CoreHCI plugins, pass the HCI |
|
171 // the Client Usage API if supported. |
|
172 hciClientUsageCallback->MhcucSetClientUsage(*this); |
|
173 } |
|
174 |
|
175 iAFHTimer=CAFHTimer::NewL(*this); |
|
176 |
|
177 // Read low power mode override timeout from the configuration file |
|
178 _LIT(KLPMSection, "lowpowermodeconfiguration"); |
|
179 _LIT(KLPMTag, "overridelpmtimeout_microseconds"); |
|
180 |
|
181 TUint overrideLPMTimeout = 0; |
|
182 TRAP(err, overrideLPMTimeout = iHciUtil->GetValueFromFileL(KLPMSection, KLPMTag)); |
|
183 |
|
184 if (err == KErrNone) |
|
185 { |
|
186 // LPM override timeout found, pass the value into link manager |
|
187 iLinkMgrProtocol.SetOverrideLPMTimeout(overrideLPMTimeout); |
|
188 } |
|
189 |
|
190 iLastPowerState = EBTOn; |
|
191 |
|
192 // used later to ensure that we have enough data to call SetEventMask |
|
193 iReadLocalSupportedFeaturesComplete = EFalse; |
|
194 iReadLocalVersionComplete = EFalse; |
|
195 |
|
196 #ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL |
|
197 iMBufPool = CHostMBufPool::NewL(*this); |
|
198 #endif |
|
199 } |
|
200 |
|
201 void CHCIFacade::SetLinkMuxer(CLinkMuxer& aLinkMuxer) |
|
202 { |
|
203 LOG_FUNC |
|
204 iLinkMuxer=&aLinkMuxer; |
|
205 } |
|
206 |
|
207 |
|
208 void CHCIFacade::SetPhysicalLinksMgr(CPhysicalLinksManager& aLinksMgr) |
|
209 { |
|
210 LOG_FUNC |
|
211 iLinksMgr = &aLinksMgr; |
|
212 } |
|
213 |
|
214 TInt CHCIFacade::SendInitialisationCommand(CHCICommandBase* aCommand) |
|
215 /* |
|
216 This method takes ownership of the command. |
|
217 */ |
|
218 { |
|
219 LOG_FUNC |
|
220 __ASSERT_ALWAYS(aCommand != NULL, Panic(EHCICommandNullItem)); |
|
221 __ASSERT_ALWAYS(iInitState==EResetting || iInitState==EPostReset, Panic(EHCICtrlrInitAddingInitialisationCommandInBadState)); |
|
222 if(iInitState==EResetting) |
|
223 { |
|
224 __ASSERT_ALWAYS(iOutstandingCommands.Count()==0, Panic(EHCICtrlrInitOnlyOneResetCmdAllowed)); |
|
225 } |
|
226 |
|
227 TInt err = KErrNone; |
|
228 TUint qid = 0; |
|
229 |
|
230 // Ownership of the command is passed to the queue. |
|
231 // MhcqAddInitCommandL guarantees to take ownership even if it |
|
232 // leaves. |
|
233 |
|
234 // see CHCIFacade::MhcqcCommandEventReceived for completion |
|
235 TRAP(err, qid = iCmdController->MhcqAddInitCommandL(aCommand, *this)); |
|
236 if (err != KErrNone) |
|
237 { |
|
238 iInitialisationError = ETrue; |
|
239 |
|
240 LOG1(_L("Error! CHCIFacade::SendInitialisationCommand %d"), err); |
|
241 return err; |
|
242 } |
|
243 |
|
244 // We need to know when we have completed initialisation of the stack so that |
|
245 // we can Start() the HCI Command Queue. To do this we keep a list of all the |
|
246 // initialisation command opcodes and then remove them from the list when we |
|
247 // get the corresponding completion event. The stack initialisation is complete |
|
248 // when the list of opcodes is empty. |
|
249 if ((err = AddOutstandingCommandOpCode(aCommand->Opcode())) != KErrNone) |
|
250 { |
|
251 if (iCmdController->MhcqRemoveCommand(qid, *this) != KErrNone) |
|
252 { |
|
253 Panic(EHCICtrlrInitFailedToRemoveCmd); |
|
254 } |
|
255 iInitialisationError = ETrue; |
|
256 |
|
257 LOG1(_L("Error! CHCIFacade::SendInitialisationCommand %d"), err); |
|
258 return err; |
|
259 } |
|
260 |
|
261 return KErrNone; |
|
262 } |
|
263 |
|
264 void CHCIFacade::InitL(const TBTLocalDevice& aDeviceConfig) |
|
265 /** |
|
266 The start-up strategy |
|
267 |
|
268 If there is an Initialisor the pre-reset initialisation method will |
|
269 be called on it at this point. When the Initialisor pre-reset method |
|
270 completes the stack will be called back to enable it to send the HCI |
|
271 reset command, see McioPreResetCommandComplete(). |
|
272 |
|
273 If there is no Initialisor then this method will call the pre-reset |
|
274 complete method directly allowing the stack to send the HCI reset |
|
275 command. |
|
276 **/ |
|
277 { |
|
278 LOG_FUNC |
|
279 // Only re-initialise the stack is the current state is not pre-reset. |
|
280 if(iInitState != EPreReset) |
|
281 { |
|
282 // Initialise the Command Queue |
|
283 iCmdController->Initialise(); |
|
284 iInitState = EPreReset; |
|
285 |
|
286 // DeviceClass is cached and retrieved from HCI if not currently |
|
287 // set in aDeviceConfig |
|
288 iDeviceClass = aDeviceConfig.DeviceClass(); |
|
289 |
|
290 // Get the Local Name from the Persist storage |
|
291 TInt err(iLinkMgrProtocol.SetLocalDeviceName(aDeviceConfig.DeviceName())); |
|
292 if (KErrNone != err && KErrNotSupported != err) |
|
293 { |
|
294 User::Leave(err); |
|
295 } |
|
296 if (iControllerInitialisor != NULL) |
|
297 { |
|
298 // see CHCIFacade::McioPreResetCommandComplete |
|
299 iControllerInitialisor->MciiPreResetCommand(); |
|
300 } |
|
301 else |
|
302 { |
|
303 // There is no initialisation plugin so behave as if there |
|
304 // were and it had completed its pre reset phase |
|
305 McioPreResetCommandComplete(KErrNone); |
|
306 } |
|
307 } |
|
308 } |
|
309 |
|
310 CHCIFacade::CHCIFacade(CLinkMgrProtocol& aProtocol) |
|
311 : iLinkMgrProtocol(aProtocol), |
|
312 iInitState(EIdle), |
|
313 iInitialisationError(EFalse) |
|
314 { |
|
315 LOG_FUNC |
|
316 } |
|
317 |
|
318 CHCIFacade::~CHCIFacade() |
|
319 { |
|
320 LOG_FUNC |
|
321 delete iAFHTimer; |
|
322 #ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL |
|
323 delete iMBufPool; |
|
324 #endif |
|
325 |
|
326 delete iCoreHciPlugin; |
|
327 |
|
328 if(iCmdController) |
|
329 { |
|
330 iCmdController->MhcqRemoveAllCommands(*this); |
|
331 delete iCmdController; |
|
332 } |
|
333 |
|
334 iOutstandingCommands.Close(); |
|
335 delete iHciUtil; |
|
336 } |
|
337 |
|
338 CHctlAclDataFrame* CHCIFacade::NewACLDataFrameL(TUint16 aSize) const |
|
339 { |
|
340 LOG_FUNC |
|
341 return (iDataFramer->MhdfNewAclDataFrameL(aSize)); |
|
342 } |
|
343 |
|
344 #ifdef STACK_SCO_DATA |
|
345 CHctlSynchronousDataFrame* CHCIFacade::NewSynchronousDataFrameL(TUint8 aSCODataLen) const |
|
346 { |
|
347 LOG_FUNC |
|
348 return (iDataFramer->MhdfNewSynchronousDataFrameL(aSCODataLen)); |
|
349 } |
|
350 #endif |
|
351 |
|
352 THCITransportChannel CHCIFacade::HCTLState() const |
|
353 { |
|
354 LOG_FUNC |
|
355 return iHCTLState; // give to muxer |
|
356 } |
|
357 |
|
358 |
|
359 |
|
360 void CHCIFacade::HandlePowerStatusChange(TBTPowerState aStatus) |
|
361 /** |
|
362 This method assumes that the power is actually changing, i.e. from off to on or |
|
363 from on to off, and it is the responsibility of the caller, the hctl in non-error |
|
364 conditions, to ensure this. |
|
365 |
|
366 The only real dangerous transition is from on to on as this would intialise the |
|
367 stack even if it is currently in an on state with or without existing state and |
|
368 connections. |
|
369 **/ |
|
370 { |
|
371 LOG_FUNC |
|
372 switch(aStatus) |
|
373 { |
|
374 case EBTOn: |
|
375 // Start-up Bluetooth |
|
376 // Avoid from ON to ON |
|
377 __ASSERT_DEBUG (iLastPowerState == EBTOff, Panic(EHCIPowerStateError)); |
|
378 |
|
379 iLastPowerState = aStatus; |
|
380 //recovery the channels |
|
381 iLinkMgrProtocol.LinkMuxer().ChannelsFree(iHCTLState); |
|
382 |
|
383 TRAPD(err, InitL(iLinkMgrProtocol.LocalDevice())); |
|
384 // Hopefully this should just work it won't rename the device though |
|
385 // since that is persisted |
|
386 if (err) |
|
387 { |
|
388 HandlePowerStatusChange(EBTOff); |
|
389 return; |
|
390 } |
|
391 else |
|
392 { |
|
393 // Reset the inquiry manager |
|
394 iLinkMgrProtocol.InquiryMgr().SetHWState(CBTInquiryMgr::EIdle); |
|
395 // Clear debug mode |
|
396 iLinkMgrProtocol.SecMan().ClearDebugMode(); |
|
397 } |
|
398 break; |
|
399 |
|
400 case EBTOff: |
|
401 // Reset the Command Queue |
|
402 // Avoid from OFF to OFF |
|
403 __ASSERT_DEBUG (iLastPowerState == EBTOn, Panic(EHCIPowerStateError)); |
|
404 |
|
405 iLastPowerState = aStatus; |
|
406 |
|
407 // Determine if we are waiting for a callback from the initialisation plugin |
|
408 if ((iInitState == EPreReset) || (iInitState == EReset)) |
|
409 { |
|
410 // cancel initialisation callback if possible |
|
411 if (iControllerInitAbortExtension != NULL) |
|
412 { |
|
413 iControllerInitAbortExtension->MciaeiAbortInitialisation(); |
|
414 } |
|
415 } |
|
416 iInitState = EIdle; |
|
417 |
|
418 iCmdController->Reset(); |
|
419 iOutstandingCommands.Reset(); |
|
420 |
|
421 // Ensure that no command or data messages are output by blocking all channels |
|
422 // |
|
423 iLinkMgrProtocol.LinkMuxer().ChannelsClosed(KHCITransportAllChannels); |
|
424 iLinkMgrProtocol.Error(KErrHardwareNotAvailable); |
|
425 // Reset UI |
|
426 iLinkMgrProtocol.SetUIConnecting(EFalse); |
|
427 iLinkMgrProtocol.SetUINumPhysicalLinks(0); |
|
428 // The h/w CoD has been reset, so we need to clear our persistent value, to reflect this |
|
429 iLinkMgrProtocol.ClearPendingLocalDeviceSettingsCod(); |
|
430 |
|
431 // Removes any pending AFH Channel Classification command |
|
432 // and cancels timer. |
|
433 // NB This ensures AFH host channel classification command blocking is |
|
434 // not in place if power comes back on. |
|
435 iAFHTimer->Reset(); |
|
436 break; |
|
437 |
|
438 default: |
|
439 Panic(EHCIUnknownPowerState); |
|
440 break; |
|
441 } |
|
442 |
|
443 // Successfully changed power state |
|
444 iLinkMgrProtocol.UpdateLocalDevicePower(aStatus); |
|
445 } |
|
446 |
|
447 TInt CHCIFacade::ChangeMode(TBTLinkMode aMode, THCIConnHandle aConnHandle) |
|
448 { |
|
449 LOG_FUNC |
|
450 TRAPD(err, DoChangeModeL(aMode, aConnHandle)); |
|
451 return err; |
|
452 } |
|
453 |
|
454 void CHCIFacade::DoChangeModeL(TBTLinkMode aMode, THCIConnHandle aConnHandle) |
|
455 { |
|
456 LOG_FUNC |
|
457 switch (aMode) |
|
458 { |
|
459 case ESniffMode: |
|
460 { |
|
461 SniffL(aConnHandle); |
|
462 break; |
|
463 } |
|
464 case EParkMode: |
|
465 { |
|
466 ParkL(aConnHandle); |
|
467 break; |
|
468 } |
|
469 case EHoldMode: |
|
470 { |
|
471 HoldL(aConnHandle); |
|
472 break; |
|
473 } |
|
474 case EScatterMode: |
|
475 case EActiveMode: |
|
476 __ASSERT_DEBUG(0, Panic(EHCICommandBadArgument)); |
|
477 break; |
|
478 } |
|
479 } |
|
480 |
|
481 TInt CHCIFacade::ExitMode(TBTLinkMode aMode, THCIConnHandle aConnHandle) |
|
482 { |
|
483 LOG_FUNC |
|
484 TRAPD(err, DoExitModeL(aMode, aConnHandle)); |
|
485 return err; |
|
486 } |
|
487 |
|
488 void CHCIFacade::DoExitModeL(TBTLinkMode aMode, THCIConnHandle aConnHandle) |
|
489 { |
|
490 LOG_FUNC |
|
491 switch (aMode) |
|
492 { |
|
493 case ESniffMode: |
|
494 { |
|
495 ExitSniffL(aConnHandle); |
|
496 break; |
|
497 } |
|
498 case EParkMode: |
|
499 { |
|
500 ExitParkL(aConnHandle); |
|
501 break; |
|
502 } |
|
503 // Not possile to prematurely exit hold mode |
|
504 default: |
|
505 { |
|
506 break; |
|
507 } |
|
508 } |
|
509 } |
|
510 |
|
511 void CHCIFacade::SetupFlowControlL(TFlowControlMode aMode) |
|
512 /** |
|
513 Set up flow control scheme to be used. |
|
514 SetupFlowControlL should only be called once on init because it may leave. |
|
515 |
|
516 If TFlowControlMode is chosen to be EFlowControlFromHostControllerOnly or |
|
517 ETwoWayFlowControlEnabled, then it is the responsibility of the HCI client |
|
518 to issue the appropriate HostBufferSize(..) command. |
|
519 */ |
|
520 { |
|
521 LOG_FUNC |
|
522 switch (aMode) |
|
523 { |
|
524 case ENoFlowControl: |
|
525 { |
|
526 #ifndef _DEBUG |
|
527 Panic(ELinkMgrBadFlowControlSetInReleaseBuild); |
|
528 #endif |
|
529 break; |
|
530 } |
|
531 case EFlowControlToHostControllerOnly: |
|
532 { |
|
533 // the host will not tell the Controller about its buffers |
|
534 |
|
535 User::LeaveIfError( |
|
536 SendInitialisationCommand(CReadBufferSizeCommand::NewL())); |
|
537 break; |
|
538 } |
|
539 case EFlowControlFromHostControllerOnly: |
|
540 { |
|
541 #ifdef _DEBUG |
|
542 CHCICommandBase *command = CHostBufferSizeCommand::NewL(KLinkMgrIncomingBufferSize, |
|
543 KStackSCOBuffersSize, KStackACLBuffersNum, |
|
544 KStackSCOBuffersNum); |
|
545 |
|
546 User::LeaveIfError(SendInitialisationCommand(command)); |
|
547 |
|
548 command = CSetControllerToHostFlowControlCommand::NewL(ETrue); |
|
549 |
|
550 User::LeaveIfError(SendInitialisationCommand(command)); |
|
551 |
|
552 #else |
|
553 Panic(ELinkMgrBadFlowControlSetInReleaseBuild); |
|
554 #endif |
|
555 break; |
|
556 } |
|
557 case ETwoWayFlowControlEnabled: |
|
558 { |
|
559 CHCICommandBase *command = CHostBufferSizeCommand::NewL(KLinkMgrIncomingBufferSize, |
|
560 KStackSCOBuffersSize, KStackACLBuffersNum, |
|
561 KStackSCOBuffersNum); |
|
562 |
|
563 User::LeaveIfError(SendInitialisationCommand(command)); |
|
564 |
|
565 command = CSetControllerToHostFlowControlCommand::NewL(ETrue); |
|
566 |
|
567 User::LeaveIfError(SendInitialisationCommand(command)); |
|
568 |
|
569 break; |
|
570 } |
|
571 default: |
|
572 Panic(ELinkMgrNoSuchFlowControlMode); |
|
573 break; |
|
574 } |
|
575 } |
|
576 |
|
577 |
|
578 // simple forwarding functions so that all stack usage to HCI is via Facade. |
|
579 |
|
580 TInt CHCIFacade::WriteACLData(const CHctlAclDataFrame& aFrame) const |
|
581 { |
|
582 LOG_FUNC |
|
583 return iHctl->MhiWriteAclData(aFrame.HCTLPayload()); |
|
584 } |
|
585 |
|
586 TInt CHCIFacade::WriteSCOData(const CHctlSynchronousDataFrame& aFrame) const |
|
587 { |
|
588 LOG_FUNC |
|
589 return iHctl->MhiWriteSynchronousData(aFrame.HCTLPayload()); |
|
590 } |
|
591 |
|
592 void CHCIFacade::FormatACLData(CHctlAclDataFrame& aFrame, THCIConnHandle aHandle, |
|
593 TUint8 aOptions, const TDesC8& aData) const |
|
594 { |
|
595 LOG_FUNC |
|
596 TUint8 flags = aOptions; |
|
597 TAclPacketBoundaryFlag pbFlag = static_cast<TAclPacketBoundaryFlag>(flags & KPacketPBFlagMask); |
|
598 TAclPacketBroadcastFlag bcFlag = static_cast<TAclPacketBroadcastFlag>((flags & KPacketBCFlagMask) >> KPacketPBtoBCFlagShift); |
|
599 iDataFramer->MhdfFormatAclData(aFrame, aHandle, pbFlag, bcFlag, aData); |
|
600 } |
|
601 |
|
602 void CHCIFacade::FormatSCOData(CHctlSynchronousDataFrame& aFrame, THCIConnHandle aHandle, |
|
603 const TDesC8& aData) const |
|
604 { |
|
605 LOG_FUNC |
|
606 iDataFramer->MhdfFormatSynchronousData(aFrame, aHandle, aData); |
|
607 } |
|
608 |
|
609 void CHCIFacade::MhriStartHardReset() |
|
610 { |
|
611 LOG_FUNC |
|
612 /* |
|
613 Could have forced a... |
|
614 HandlePowerStatusChange(EBTOff); |
|
615 here - but instead let HCTL call this. |
|
616 */ |
|
617 iHardResetInitiator->MhriStartHardReset(); |
|
618 } |
|
619 |
|
620 TUint16 CHCIFacade::ReadACLReportingInterval() const |
|
621 { |
|
622 LOG_FUNC |
|
623 return 0; |
|
624 } |
|
625 |
|
626 TUint16 CHCIFacade::ReadACLFramingOverhead() const |
|
627 { |
|
628 LOG_FUNC |
|
629 return 0; |
|
630 } |
|
631 |
|
632 #ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL |
|
633 RMBufChain CHCIFacade::TakeInboundACLDataBufferFromPool(const THCIConnHandle& aForConnHandle) |
|
634 { |
|
635 LOG_FUNC |
|
636 return iMBufPool->TakeBuffer(aForConnHandle); |
|
637 } |
|
638 #endif |
|
639 |
|
640 // MControllerInitialisationObserver |
|
641 void CHCIFacade::McioPreResetCommandComplete(TInt aError) |
|
642 { |
|
643 LOG_FUNC |
|
644 CHCICommandBase* command(NULL); |
|
645 TInt err; |
|
646 |
|
647 // check that we are in the correct state |
|
648 __ASSERT_ALWAYS(iInitState == EPreReset, Panic(EIncorrectStateOnPreResetCallback)); |
|
649 iInitState = EResetting; |
|
650 |
|
651 if (aError != KErrNone) |
|
652 { |
|
653 // The initialisor plugin has failed pre reset initialisation |
|
654 err = aError; |
|
655 } |
|
656 else |
|
657 { |
|
658 // Send Reset command |
|
659 TRAP(err, command = CResetCommand::NewL()); |
|
660 |
|
661 if (err == KErrNone) |
|
662 { |
|
663 err = SendInitialisationCommand(command); |
|
664 } |
|
665 } |
|
666 |
|
667 if (err != KErrNone) |
|
668 { |
|
669 // Initialisation has failed. At this point all we can do is power down |
|
670 // Bluetooth. This means that initialisation can be attempted again by |
|
671 // turning on the power but this again could fail. |
|
672 HandlePowerStatusChange(EBTOff); |
|
673 } |
|
674 } |
|
675 |
|
676 void CHCIFacade::DoSendPostResetCommandsL() |
|
677 { |
|
678 LOG_FUNC |
|
679 User::LeaveIfError(SendInitialisationCommand(CReadLocalSupportedFeaturesCommand::NewL())); |
|
680 User::LeaveIfError(SendInitialisationCommand(CReadBdaddrCommand::NewL())); |
|
681 User::LeaveIfError(SendInitialisationCommand(CReadLocalVersionInfoCommand::NewL())); |
|
682 |
|
683 #ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL |
|
684 #pragma message("Transport FlowControl = Two Way") |
|
685 |
|
686 SetupFlowControlL(ETwoWayFlowControlEnabled); |
|
687 |
|
688 #else |
|
689 #pragma message("Transport FlowControl = None from HostController") |
|
690 |
|
691 SetupFlowControlL(EFlowControlToHostControllerOnly); |
|
692 |
|
693 #endif |
|
694 |
|
695 User::LeaveIfError(SendInitialisationCommand(CWriteConnectionAcceptTimeoutCommand::NewL(KHCIDefaultAcceptTimeout))); |
|
696 User::LeaveIfError(SendInitialisationCommand(CWriteVoiceSettingCommand::NewL(KBTVoiceSetting))); |
|
697 |
|
698 if (iDeviceClass) |
|
699 { |
|
700 // Some phones never set their CoD in s/w, we don't want to |
|
701 // overwrite their h/w settings |
|
702 LOG1(_L("DoSendPostResetCommandsL - SetDeviceClassL (0x%x)"), iDeviceClass); |
|
703 iLinkMgrProtocol.SetDeviceClassL(iDeviceClass); |
|
704 } |
|
705 else |
|
706 { |
|
707 // We want to update the P&S value with the h/w value |
|
708 User::LeaveIfError(SendInitialisationCommand(CReadClassOfDeviceCommand::NewL())); |
|
709 } |
|
710 |
|
711 TRAPD(err, iLinkMgrProtocol.SetInquiryAndPageScanningL()); |
|
712 if(err != KErrNone && err != KErrNotSupported) |
|
713 { |
|
714 User::Leave(err); |
|
715 } |
|
716 } |
|
717 |
|
718 void CHCIFacade::McioPostResetCommandComplete(TInt aError) |
|
719 { |
|
720 LOG_FUNC |
|
721 TInt err; |
|
722 |
|
723 // check that we are in the correct state |
|
724 __ASSERT_ALWAYS(iInitState == EReset, Panic(EIncorrectStateOnPostResetCallback)); |
|
725 iInitState = EPostReset; |
|
726 |
|
727 if (aError == KErrNone) |
|
728 { |
|
729 // Send post reset commands required by stack |
|
730 TRAP(err, DoSendPostResetCommandsL()); |
|
731 } |
|
732 else |
|
733 { |
|
734 // The initialisor plugin has failed post reset initialisation |
|
735 err = aError; |
|
736 } |
|
737 |
|
738 if (err != KErrNone) |
|
739 { |
|
740 // Initialisation has failed. At this point all we can do is power down |
|
741 // Bluetooth. This means that initialisation can be attempted again by |
|
742 // turning on the power but this again could fail. |
|
743 HandlePowerStatusChange(EBTOff); |
|
744 } |
|
745 } |
|
746 |
|
747 // MHCIDataObserver |
|
748 void CHCIFacade::MhdoProcessAclData(THCIConnHandle aConnH, TAclPacketBoundaryFlag aBoundaryFlag, TAclPacketBroadcastFlag aBroadcastFlag, const TDesC8& aData) |
|
749 { |
|
750 LOG_FUNC |
|
751 // Stack currently works with the old flag passing mechanism. So recombine into the old |
|
752 // flag type before continuing. |
|
753 TUint8 flag = (aBoundaryFlag | (aBroadcastFlag << KPacketPBtoBCFlagShift)) << KPacketPBBCFlagShift; |
|
754 |
|
755 LOG3(_L("Link [HCIFacade_Events.cpp]: CHCIFacade data received on handle %d, flags %d, length %d"), aConnH, flag, aData.Length()); |
|
756 |
|
757 iLinksMgr->ACLDataReceived(aConnH, flag, aData); |
|
758 } |
|
759 |
|
760 void CHCIFacade::MhdoProcessSynchronousData(THCIConnHandle aConnH, TUint8 /*aReserved*/, const TDesC8& aData) |
|
761 { |
|
762 LOG_FUNC |
|
763 iLinksMgr->SCODataReceived(aConnH, aData); |
|
764 } |
|
765 |
|
766 // MHCTLChannelObserver |
|
767 void CHCIFacade::MhcoChannelOpen(THCITransportChannel aChannels) |
|
768 /** |
|
769 The HCI has notified us that transport channels have become free |
|
770 **/ |
|
771 { |
|
772 LOG_FUNC |
|
773 LOG1(_L("Transport channels 0x%04x now free"), aChannels); |
|
774 |
|
775 // record the channel status |
|
776 iHCTLState |= aChannels; |
|
777 |
|
778 if (iLinkMuxer) |
|
779 { |
|
780 iLinkMuxer->ChannelsFree(aChannels); //try to send on this channel |
|
781 } |
|
782 } |
|
783 |
|
784 void CHCIFacade::MhcoChannelClosed(THCITransportChannel aChannels) |
|
785 { |
|
786 LOG_FUNC |
|
787 // record the channel status |
|
788 iHCTLState &= (~aChannels) & KHCITransportAllChannels; |
|
789 |
|
790 // Tell the Muxer these channels are closed, if Muxer is ready |
|
791 if (iLinkMuxer) |
|
792 { |
|
793 iLinkMuxer->ChannelsClosed(aChannels); |
|
794 } |
|
795 } |
|
796 |
|
797 // MControllerStateObserver |
|
798 void CHCIFacade::McsoProcessPowerChange(TInt aError, TControllerChangeType aChangeType, TBTPowerState aState) |
|
799 { |
|
800 LOG_FUNC |
|
801 if(aError!=KErrNone) |
|
802 //Don't do anything - assume error implies no change took place |
|
803 { |
|
804 return; |
|
805 } |
|
806 |
|
807 if(aChangeType==MControllerStateObserver::EBTNonFatalChange) |
|
808 //Don't do anything - controller change will not affect us |
|
809 { |
|
810 return; |
|
811 } |
|
812 |
|
813 // For now continue to use HandlePowerStatusChange as common code for power states and hard reset states |
|
814 HandlePowerStatusChange(aState); |
|
815 } |
|
816 |
|
817 void CHCIFacade::McsoProcessHardResetPhaseChange(TInt aError, TControllerChangeType aChangeType, TBTHardResetState aState) |
|
818 { |
|
819 LOG_FUNC |
|
820 if(aError!=KErrNone) |
|
821 { |
|
822 //We may need to inform user somehow that reset has failed - depends on |
|
823 //nature of error. What if error is KErrInUse? Should we set a timer |
|
824 //and try again? |
|
825 return; |
|
826 } |
|
827 |
|
828 if(aChangeType==MControllerStateObserver::EBTNonFatalChange) |
|
829 //Don't do anything - controller change will not affect us |
|
830 { |
|
831 return; |
|
832 } |
|
833 |
|
834 switch(aState) |
|
835 { |
|
836 case EBTResetStarted: |
|
837 HandlePowerStatusChange(EBTOff); |
|
838 break; |
|
839 case EBTResetComplete: |
|
840 HandlePowerStatusChange(EBTOn); |
|
841 break; |
|
842 default: |
|
843 Panic(EHCIUnknownHardResetState); |
|
844 break; |
|
845 } |
|
846 } |
|
847 |
|
848 // MPhysicalLinksState - Simply forward the request to iLinksMgr |
|
849 TInt CHCIFacade::MplsGetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType) const |
|
850 { |
|
851 LOG_FUNC |
|
852 if (iLinksMgr) |
|
853 { |
|
854 return iLinksMgr->GetConnectionHandles(aConnectionHandles, aLinkType); |
|
855 } |
|
856 return KErrNotReady; |
|
857 } |
|
858 |
|
859 TInt CHCIFacade::MplsGetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType) const |
|
860 { |
|
861 LOG_FUNC |
|
862 if (iLinksMgr) |
|
863 { |
|
864 return iLinksMgr->GetNumPendingHandles(aConnectionHandles, aLinkType); |
|
865 } |
|
866 return KErrNotReady; |
|
867 } |
|
868 |
|
869 TInt CHCIFacade::MplsGetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const |
|
870 { |
|
871 LOG_FUNC |
|
872 if (iLinksMgr) |
|
873 { |
|
874 return iLinksMgr->GetConnectionHandles(aConnectionHandles, aLinkType, aBDAddr); |
|
875 } |
|
876 return KErrNotReady; |
|
877 } |
|
878 |
|
879 TInt CHCIFacade::MplsGetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const |
|
880 { |
|
881 LOG_FUNC |
|
882 if (iLinksMgr) |
|
883 { |
|
884 return iLinksMgr->GetNumPendingHandles(aConnectionHandles, aLinkType, aBDAddr); |
|
885 } |
|
886 return KErrNotReady; |
|
887 } |
|
888 |
|
889 TInt CHCIFacade::MplsGetRemoteAddress(TBTDevAddr& aBDAddr, THCIConnHandle aConnectionHandle) const |
|
890 { |
|
891 LOG_FUNC |
|
892 if (iLinksMgr) |
|
893 { |
|
894 return iLinksMgr->GetRemoteAddress(aBDAddr, aConnectionHandle); |
|
895 } |
|
896 return KErrNotReady; |
|
897 } |
|
898 |
|
899 TInt CHCIFacade::MplsGetRemoteDeviceClass(TBTDeviceClass& aDeviceClass, const TBTDevAddr& aBDAddr) const |
|
900 { |
|
901 LOG_FUNC |
|
902 if (iLinksMgr) |
|
903 { |
|
904 return iLinksMgr->GetRemoteDeviceClass(aDeviceClass, aBDAddr); |
|
905 } |
|
906 return KErrNotReady; |
|
907 } |
|
908 |
|
909 TInt CHCIFacade::MplsGetRemoteSupportedFeatures(TBTFeatures& aRemoteSupportedFeatures, const TBTDevAddr& aBDAddr) const |
|
910 { |
|
911 LOG_FUNC |
|
912 if (iLinksMgr) |
|
913 { |
|
914 return iLinksMgr->GetRemoteSupportedFeatures(aRemoteSupportedFeatures, aBDAddr); |
|
915 } |
|
916 return KErrNotReady; |
|
917 } |
|
918 |
|
919 TInt CHCIFacade::MplsGetLinkPolicySettings(TLinkPolicy& aLinkPolicySettings, const TBTDevAddr& aBDAddr) const |
|
920 { |
|
921 LOG_FUNC |
|
922 if (iLinksMgr) |
|
923 { |
|
924 return iLinksMgr->GetLinkPolicySettings(aLinkPolicySettings, aBDAddr); |
|
925 } |
|
926 return KErrNotReady; |
|
927 } |
|
928 |
|
929 TInt CHCIFacade::MplsGetBasebandLinkState(TBTBasebandLinkState& aBasebandLinkState, const TBTDevAddr& aBDAddr) const |
|
930 { |
|
931 LOG_FUNC |
|
932 if (iLinksMgr) |
|
933 { |
|
934 return iLinksMgr->GetBasebandLinkState(aBasebandLinkState, aBDAddr); |
|
935 } |
|
936 return KErrNotReady; |
|
937 } |
|
938 |
|
939 // MLinkMuxNotifier |
|
940 void CHCIFacade::TryToSend() |
|
941 { |
|
942 LOG_FUNC |
|
943 if (iLinkMuxer) |
|
944 { |
|
945 iLinkMuxer->TryToSend(); |
|
946 } |
|
947 } |
|
948 |
|
949 // from MHCIClientUsage |
|
950 void CHCIFacade::MhcuOpenClientReference() |
|
951 { |
|
952 iLinkMgrProtocol.LocalOpen(); |
|
953 } |
|
954 |
|
955 void CHCIFacade::MhcuCloseClientReference() |
|
956 { |
|
957 iLinkMgrProtocol.LocalClose(); |
|
958 } |
|
959 |
|
960 // Should only be tracking outstanding commands during cmdQ initialisation |
|
961 TInt CHCIFacade::AddOutstandingCommandOpCode(THCIOpcode aOpCode) |
|
962 { |
|
963 LOG_FUNC |
|
964 __ASSERT_ALWAYS(iInitState != EInitialised, Panic(EHCICmdQNotInitialising)); |
|
965 TUint32 opcode = static_cast<TUint32>(aOpCode); |
|
966 return iOutstandingCommands.Append(opcode); |
|
967 } |
|
968 |
|
969 // Should only be tracking outstanding commands during cmdQ initialisation |
|
970 TInt CHCIFacade::FindOutstandingCommandOpCode(THCIOpcode aOpCode) const |
|
971 { |
|
972 LOG_FUNC |
|
973 __ASSERT_ALWAYS(iInitState != EInitialised, Panic(EHCICmdQNotInitialising)); |
|
974 TUint32 opcode = static_cast<TUint32>(aOpCode); |
|
975 return iOutstandingCommands.Find(opcode); |
|
976 } |
|
977 |
|
978 // TBasebandPolicy |
|
979 |
|
980 void TBasebandPolicy::InitialPolicy(const TBasebandPolicyParams& aParams) |
|
981 { |
|
982 LOG_FUNC |
|
983 iPageTimePolicy = aParams.iPageTimePolicy; |
|
984 } |
|
985 |
|
986 TInt TBasebandPolicy::TryToChangePolicy(const TBasebandPolicyParams& aNewParams) |
|
987 { |
|
988 LOG_FUNC |
|
989 // just deal with pagetime for now |
|
990 TBasebandPageTimePolicy& current = iPageTimePolicy; |
|
991 |
|
992 switch (current) |
|
993 { |
|
994 case EPagingDontCare: |
|
995 break; |
|
996 |
|
997 case EPagingNormal: |
|
998 current = aNewParams.iPageTimePolicy; |
|
999 break; |
|
1000 |
|
1001 case EPagingBestEffort: |
|
1002 //only change if user wants Quick paging |
|
1003 current = (aNewParams.iPageTimePolicy == EPagingQuick) ? aNewParams.iPageTimePolicy : current; |
|
1004 break; |
|
1005 |
|
1006 case EPagingQuick: |
|
1007 //only change if user wants Best effort paging |
|
1008 current = (aNewParams.iPageTimePolicy == EPagingBestEffort) ? aNewParams.iPageTimePolicy : current; |
|
1009 break; |
|
1010 |
|
1011 default: |
|
1012 LOG(_L("TBasebandPolicy: bogus policy requested for pagetimeout")); |
|
1013 return KErrArgument; |
|
1014 } |
|
1015 |
|
1016 LOG1(_L("TBasebandPolicy: now using page time policy %d"), aNewParams.iPageTimePolicy); |
|
1017 return (current == aNewParams.iPageTimePolicy) ? KErrNone : KErrInUse; |
|
1018 } |
|
1019 |
|
1020 |
|
1021 TBasebandPageTimePolicy TBasebandPolicy::PageTimePolicy() const |
|
1022 { |
|
1023 LOG_FUNC |
|
1024 return iPageTimePolicy; |
|
1025 } |
|
1026 |
|
1027 //class CAFHTimer |
|
1028 CAFHTimer* CAFHTimer::NewL(CHCIFacade& aParent) |
|
1029 { |
|
1030 LOG_STATIC_FUNC |
|
1031 CAFHTimer* self = new (ELeave) CAFHTimer(aParent); |
|
1032 CleanupStack::PushL(self); |
|
1033 self->ConstructL(); |
|
1034 CleanupStack::Pop(); |
|
1035 return self; |
|
1036 } |
|
1037 |
|
1038 void CAFHTimer::ConstructL() |
|
1039 { |
|
1040 LOG_FUNC |
|
1041 CTimer::ConstructL(); |
|
1042 CActiveScheduler::Add(this); |
|
1043 } |
|
1044 |
|
1045 CAFHTimer::CAFHTimer(CHCIFacade& aParent) |
|
1046 : CTimer(CActive::EPriorityStandard), iParent(aParent), iPending(EFalse) |
|
1047 { |
|
1048 LOG_FUNC |
|
1049 } |
|
1050 |
|
1051 void CAFHTimer::SetPending(const TBTAFHHostChannelClassification& aHCC) |
|
1052 { |
|
1053 LOG_FUNC |
|
1054 iHCC.Copy(aHCC); |
|
1055 iPending=ETrue; |
|
1056 } |
|
1057 |
|
1058 void CAFHTimer::RemovePendingHostChannelClassifications() |
|
1059 { |
|
1060 LOG_FUNC |
|
1061 iHCC.Reset(); |
|
1062 iPending=EFalse; |
|
1063 } |
|
1064 |
|
1065 void CAFHTimer::Reset() |
|
1066 { |
|
1067 LOG_FUNC |
|
1068 RemovePendingHostChannelClassifications(); |
|
1069 Cancel(); |
|
1070 } |
|
1071 |
|
1072 void CAFHTimer::RunL() |
|
1073 { |
|
1074 LOG_FUNC |
|
1075 if(iPending) |
|
1076 { |
|
1077 if(iStatus==KErrNone) |
|
1078 { |
|
1079 iParent.SetAFHHostChannelClassificationL(iHCC); |
|
1080 } |
|
1081 RemovePendingHostChannelClassifications(); |
|
1082 } |
|
1083 } |
|
1084 |
|
1085 TInt CAFHTimer::RunError(TInt /*aError*/) |
|
1086 { |
|
1087 LOG_FUNC |
|
1088 return KErrNone; |
|
1089 } |
|
1090 |
|
1091 #ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL |
|
1092 |
|
1093 CHostMBufPool* CHostMBufPool::NewL(CHCIFacade& aHCIFacade) |
|
1094 { |
|
1095 LOG_FUNC |
|
1096 CHostMBufPool* self = new (ELeave) CHostMBufPool(aHCIFacade); |
|
1097 CleanupStack::PushL(self); |
|
1098 self->ConstructL(); |
|
1099 CleanupStack::Pop(self); |
|
1100 return self; |
|
1101 } |
|
1102 |
|
1103 void CHostMBufPool::DeletePool(TSglQue<TPoolBuffer>& aQueue) |
|
1104 { |
|
1105 LOG_FUNC |
|
1106 TPoolBuffer* tmpItem = NULL; |
|
1107 TSglQueIter<TPoolBuffer> iter(aQueue); |
|
1108 while(iter) |
|
1109 { |
|
1110 tmpItem=iter++; |
|
1111 aQueue.Remove(*tmpItem); |
|
1112 delete tmpItem; |
|
1113 } |
|
1114 } |
|
1115 |
|
1116 CHostMBufPool::~CHostMBufPool() |
|
1117 { |
|
1118 LOG_FUNC |
|
1119 Cancel(); |
|
1120 DeletePool(iBufferPool); |
|
1121 DeletePool(iWaitingAllocPool); |
|
1122 } |
|
1123 |
|
1124 CHostMBufPool::CHostMBufPool(CHCIFacade& aHCIFacade) : |
|
1125 CActive(0),iHCIFacade(aHCIFacade),iBufferPool(_FOFF(TPoolBuffer,iLink)), |
|
1126 iWaitingAllocPool(_FOFF(TPoolBuffer,iLink)),iCurrAckHandle(KErrNotFound),iCurrCompletedPackets(0) |
|
1127 { |
|
1128 LOG_FUNC |
|
1129 } |
|
1130 |
|
1131 void CHostMBufPool::ConstructL() |
|
1132 /** |
|
1133 2nd phase constructor for the Host MBuf Pool. |
|
1134 |
|
1135 This method will attempt to reserve enough MBufs from the global pool |
|
1136 for bluetooth use. |
|
1137 @leave KErrNoMemory If the required number of MBufs couldn't be reserved |
|
1138 */ |
|
1139 { |
|
1140 LOG_FUNC |
|
1141 LOG2(_L("CHostMBufPool: now reserving %d size %d MBufChains"),KStackACLBuffersNum,KLinkMgrIncomingBufferSize); |
|
1142 |
|
1143 for (TInt i=0;i<=KStackACLBuffersNum-1;i++) |
|
1144 { |
|
1145 TPoolBuffer* thisBuffer = new (ELeave) TPoolBuffer(); |
|
1146 CleanupStack::PushL(thisBuffer); |
|
1147 thisBuffer->iCurrentHandle=KErrNotFound; //we assert on this later |
|
1148 thisBuffer->iMBufChain.AllocL(KLinkMgrIncomingBufferSize); |
|
1149 iBufferPool.AddFirst(*thisBuffer); |
|
1150 CleanupStack::Pop(thisBuffer); |
|
1151 } |
|
1152 |
|
1153 CActiveScheduler::Add(this); |
|
1154 } |
|
1155 |
|
1156 void CHostMBufPool::DoCancel() |
|
1157 { |
|
1158 LOG_FUNC |
|
1159 iMBufRequester.Cancel(); |
|
1160 } |
|
1161 |
|
1162 RMBufChain CHostMBufPool::TakeBuffer(const THCIConnHandle& aConnHandle) |
|
1163 /** |
|
1164 Takes a buffer from the pool and schedules an asynchronous allocation |
|
1165 of the next buffer. Only when that allocation has succeeded will the host |
|
1166 controller be signalled with a host_number_of_completed_packets. Hence, |
|
1167 if we cannot allocate a buffer from the global MBuf pool, the host controller |
|
1168 will be flowed off and no data will be lost. |
|
1169 */ |
|
1170 { |
|
1171 LOG_FUNC |
|
1172 TPoolBuffer* ready = iBufferPool.First(); |
|
1173 iBufferPool.Remove(*ready); |
|
1174 __ASSERT_DEBUG(!ready->iMBufChain.IsEmpty(),Panic(ELinkMgrHostControllerHasOverflowedHost)); |
|
1175 __ASSERT_DEBUG(ready->iCurrentHandle==KErrNotFound,Panic(ELinkMgrHostControllerHasOverflowedHost)); |
|
1176 ready->iCurrentHandle = aConnHandle; |
|
1177 |
|
1178 RMBufChain retChain; |
|
1179 retChain.Assign(ready->iMBufChain); |
|
1180 |
|
1181 if (IsActive()) |
|
1182 { |
|
1183 //This buffer will be reclaimed from the global pool |
|
1184 //after the one(s) we're currently trying to reclaim |
|
1185 LOG(_L("CHostMBufPool: TakeBuffer, buffer taken while alloc outstanding: queued alloc")); |
|
1186 iWaitingAllocPool.AddLast(*ready); |
|
1187 } |
|
1188 else |
|
1189 { |
|
1190 LOG(_L("CHostMBufPool: TakeBuffer, buffer taken")); |
|
1191 iBufferPool.AddLast(*ready); //NB the Controller cannot use this |
|
1192 //buffer until it is alloced as it will |
|
1193 //be flowed off. |
|
1194 iMBufRequester.Alloc(ready->iMBufChain,KLinkMgrIncomingBufferSize,iStatus); |
|
1195 SetActive(); |
|
1196 } |
|
1197 |
|
1198 return retChain; |
|
1199 } |
|
1200 |
|
1201 void CHostMBufPool::RunL() |
|
1202 { |
|
1203 LOG_FUNC |
|
1204 if (iStatus.Int()!=KErrNone) |
|
1205 { |
|
1206 LOG1(_L("Error! CHostMBufPool:: RunL %d"),iStatus.Int()); |
|
1207 __DEBUGGER(); |
|
1208 } |
|
1209 else |
|
1210 { |
|
1211 TPoolBuffer* justAllocd = iBufferPool.Last(); |
|
1212 |
|
1213 |
|
1214 if (iCurrAckHandle==KErrNotFound) |
|
1215 { |
|
1216 //This is the first completion we have ever seen |
|
1217 iCurrAckHandle=justAllocd->iCurrentHandle; |
|
1218 } |
|
1219 |
|
1220 TBool ackNow=((justAllocd->iCurrentHandle!=iCurrAckHandle)); |
|
1221 |
|
1222 if (!ackNow) |
|
1223 { |
|
1224 iCurrCompletedPackets++; |
|
1225 LOG2(_L("CHostMBufPool: CompletedPackets++ for conn: %d [->%d]"),justAllocd->iCurrentHandle,iCurrCompletedPackets); |
|
1226 |
|
1227 if (iCurrCompletedPackets>=KStackACLBuffersTideMarkNum) |
|
1228 { |
|
1229 ackNow=ETrue; |
|
1230 } |
|
1231 } |
|
1232 |
|
1233 if (ackNow) |
|
1234 { |
|
1235 TInt err=KErrNone; |
|
1236 |
|
1237 if (iCurrCompletedPackets>0) |
|
1238 { |
|
1239 LOG2(_L("CHostMBufPool: Sending HostNumberOfCompletedPackets for conn: %d [%d completed]"),iCurrAckHandle,iCurrCompletedPackets); |
|
1240 //Acknowledge the completed packets |
|
1241 TRAP(err, iHCIFacade.HostNumberOfCompletedPacketsL(iCurrAckHandle,iCurrCompletedPackets)); |
|
1242 //if this failed we probably couldn't alloc the memory for the command frame, |
|
1243 //the HC is still flowed off. |
|
1244 __ASSERT_DEBUG(err==KErrNone,Panic(ELinkMgrCouldNotSendHostNumberOfCompletedPackets)); |
|
1245 } |
|
1246 |
|
1247 iCurrCompletedPackets= (justAllocd->iCurrentHandle!=iCurrAckHandle) ? 1:0; |
|
1248 iCurrAckHandle=justAllocd->iCurrentHandle; |
|
1249 } |
|
1250 |
|
1251 justAllocd->iCurrentHandle=KErrNotFound; |
|
1252 |
|
1253 if (!iWaitingAllocPool.IsEmpty()) |
|
1254 { |
|
1255 TPoolBuffer* needsAlloc = iWaitingAllocPool.First(); |
|
1256 iBufferPool.AddLast(*needsAlloc); |
|
1257 iWaitingAllocPool.Remove(*needsAlloc); |
|
1258 iMBufRequester.Alloc(needsAlloc->iMBufChain,KLinkMgrIncomingBufferSize,iStatus); |
|
1259 SetActive(); |
|
1260 } |
|
1261 } |
|
1262 } |
|
1263 |
|
1264 #endif |