--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/hcifacade.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1264 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// The conduit to the HCI and HW - formulates and Qs commands, and implements HCI events
+//
+//
+
+#include <bluetooth/logger.h>
+#include "hcifacade.h"
+#include "linkmgr.h"
+#include "hostresolver.h"
+#include "linkutil.h"
+
+#include "AclDataQController.h"
+#include "linkmuxer.h"
+#include "linkconsts.h"
+
+#include <e32std.h>
+#include <e32cmn.h>
+#include <bt_sock.h>
+#include <es_ini.h>
+#include <e32base.h>
+
+#include <bluetooth/hcicommandqueue.h>
+#include <bluetooth/hcicommandqitem.h>
+#include <bluetooth/hcicmdqcontroller.h>
+
+#include <bluetooth/hci/controllerinitialisationinterface.h>
+#include <bluetooth/hci/hcidataframer.h>
+#include <bluetooth/hci/readlocalsupportedfeaturescommand.h>
+#include <bluetooth/hci/hostbuffersizecommand.h>
+#include <bluetooth/hci/resetcommand.h>
+#include <bluetooth/hci/readbdaddrcommand.h>
+#include <bluetooth/hci/readlocalversioninfocommand.h>
+#include <bluetooth/hci/writeconnectionaccepttimeoutcommand.h>
+#include <bluetooth/hci/writevoicesettingcommand.h>
+#include <bluetooth/hci/readclassofdevicecommand.h>
+#include <bluetooth/hci/readbuffersizecommand.h>
+#include <bluetooth/hci/setcontrollertohostflowcontrolcommand.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_HCI_FACADE);
+#endif
+
+// definitions
+const TBasebandTime TBasebandPolicy::KPageTimeoutR0 = static_cast<TBasebandTime>(2.56 /*seconds*/ / KBasebandSlotTime); // in baseband slots
+const TBasebandTime TBasebandPolicy::KPageTimeoutR1 = static_cast<TBasebandTime>(5.12 /*seconds*/ / KBasebandSlotTime); // in baseband slots
+const TBasebandTime TBasebandPolicy::KPageTimeoutR2 = static_cast<TBasebandTime>(10.24 /*seconds*/ / KBasebandSlotTime); // in baseband slots
+const TReal TBasebandPolicy::KBestEffortTimeMultiplier = 2;
+const TReal TBasebandPolicy::KQuickTimeMultiplier = 0.5;
+
+_LIT(KHciUtilComponentName, "bluetooth_stack");
+
+CHCIFacade* CHCIFacade::NewL(CLinkMgrProtocol& aProtocol)
+ {
+ LOG_STATIC_FUNC
+ CHCIFacade* p= new (ELeave) CHCIFacade(aProtocol);
+ CleanupStack::PushL(p);
+ p->ConstructL();
+ CleanupStack::Pop();
+ return p;
+ }
+
+void CHCIFacade::ConstructL()
+/**
+ 2nd phase construct the HCI Facade.
+
+ This is where the stack loads both the HCI CommandQ and the CoreHCI and
+ then distributes the required APIs between the different components.
+**/
+ {
+ LOG_FUNC
+ // Create HCI CommandQ
+ iCmdController = CHCICmdQController::NewL();
+
+ // Create HCI Utility library
+ iHciUtil = CHciUtil::NewL(KHciUtilComponentName);
+
+ // If we can't open the ini file then this will be treated in the same way
+ // as not reading a valid UID from the ini file.
+ TRAP_IGNORE(iHciUtil->OpenIniFileL());
+
+ // Create Core HCI plugin
+ _LIT(KSection, "CoreHci");
+ _LIT(KCoreHciUidTag, "EcomUid");
+
+ TUid coreHciImplUid = TUid::Null();
+ TRAPD(err, coreHciImplUid = iHciUtil->GetUidFromFileL(KSection, KCoreHciUidTag));
+
+ if (err == KErrNone)
+ {
+ // Valid UID found, load it
+ iCoreHciPlugin = CCoreHCIPlugin::NewL(coreHciImplUid);
+ }
+ else
+ {
+ // No UID found in ini file, attempt to load single instance of
+ // implementation
+ iCoreHciPlugin = CCoreHCIPlugin::NewL();
+ }
+
+ // Get Core HCI APIs
+ iCoreHci = static_cast<MCoreHci*>(iCoreHciPlugin->Interface(TUid::Uid(KCoreHciInterfaceUid)));
+ iHctl = static_cast<MHCTLInterface*>(iCoreHciPlugin->Interface(TUid::Uid(KHCTLInterfaceUid)));
+
+ iControllerInitialisor = static_cast<MControllerInitialisationInterface*>
+ (iCoreHciPlugin->Interface(TUid::Uid(KControllerInitialisationInterfaceUid)));
+ if (iControllerInitialisor != NULL)
+ {
+ // attempt to get the Controller Initialisation Abort Extension API
+ iControllerInitAbortExtension = static_cast<MControllerInitialisationAbortExtensionInterface*>
+ (iCoreHciPlugin->Interface(TUid::Uid(KControllerInitialisationAbortExtenstionInterfaceUid)));
+ }
+
+ iDataFramer = static_cast<MHCIDataFramer*>(iCoreHciPlugin->Interface(TUid::Uid(KHCIDataFramerInterfaceUid)));
+ iHardResetInitiator = static_cast<MHardResetInitiator*>(iCoreHciPlugin->Interface(TUid::Uid(KHCHardResetUid)));
+
+ // Panic if we don't get the required interfaces, note that the initialisor
+ // interface is optional
+ __ASSERT_ALWAYS(iCoreHci && iHctl && iDataFramer && iHardResetInitiator,
+ Panic(EHCIIncompleteInterfaces));
+
+ // Provide direct APIs
+ iCmdController->SetLinkMuxNotifier(*this);
+ iCmdController->SetHCIUnmatchedEventObserver(*this);
+ iCmdController->SetHardResetInitiator(*this);
+ iCmdController->SetPhysicalLinksState(*this);
+
+ iCoreHci->MchSetHardResetInitiator(*this);
+ iCoreHci->MchSetPhysicalLinksState(*this);
+ iCoreHci->MchSetDataEventObserver(*this);
+ iCoreHci->MchSetDataObserver(*this);
+ iCoreHci->MchSetChannelObserver(*this);
+ iCoreHci->MchSetControllerStateObserver(*this);
+
+ // Provide Core HCI with CommandQ components
+ iCoreHci->MchSetCommandEventObserver(*(static_cast<MHCICommandEventObserver*>(iCmdController)));
+ iCoreHci->MchSetHCICommandQueue(*(static_cast<MHCICommandQueue*>(iCmdController)));
+
+ // Provide CommandQ with HCI components
+ iCmdController->SetHCTLInterface(*iHctl);
+ iCmdController->SetHCICommandAllocator(*(static_cast<MHCICommandAllocator*>(iCoreHciPlugin->Interface(TUid::Uid(KHCICommandAllocatorInterfaceUid)))));
+
+ // Initialise initialisor plugin if present
+ if (iControllerInitialisor != NULL)
+ {
+ // Provide Initialisor with Stack
+ iControllerInitialisor->MciiSetControllerInitialisationObserver(*this);
+
+ // Provide Initialisor with CommandQ
+ iControllerInitialisor->MciiSetHCICommandQueue(*(static_cast<MHCICommandQueue*>(iCmdController)));
+ }
+
+ // Attempt to supply the HCI with the Client Usage API
+ MHCIClientUsageCallback* hciClientUsageCallback = static_cast<MHCIClientUsageCallback*>
+ (iCoreHciPlugin->Interface(TUid::Uid(KHCIClientUsageCallbackUid)));
+
+ if (hciClientUsageCallback)
+ {
+ // Support for the Client Usage Callback API is optional for CoreHCI plugins, pass the HCI
+ // the Client Usage API if supported.
+ hciClientUsageCallback->MhcucSetClientUsage(*this);
+ }
+
+ iAFHTimer=CAFHTimer::NewL(*this);
+
+ // Read low power mode override timeout from the configuration file
+ _LIT(KLPMSection, "lowpowermodeconfiguration");
+ _LIT(KLPMTag, "overridelpmtimeout_microseconds");
+
+ TUint overrideLPMTimeout = 0;
+ TRAP(err, overrideLPMTimeout = iHciUtil->GetValueFromFileL(KLPMSection, KLPMTag));
+
+ if (err == KErrNone)
+ {
+ // LPM override timeout found, pass the value into link manager
+ iLinkMgrProtocol.SetOverrideLPMTimeout(overrideLPMTimeout);
+ }
+
+ iLastPowerState = EBTOn;
+
+ // used later to ensure that we have enough data to call SetEventMask
+ iReadLocalSupportedFeaturesComplete = EFalse;
+ iReadLocalVersionComplete = EFalse;
+
+#ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL
+ iMBufPool = CHostMBufPool::NewL(*this);
+#endif
+ }
+
+void CHCIFacade::SetLinkMuxer(CLinkMuxer& aLinkMuxer)
+ {
+ LOG_FUNC
+ iLinkMuxer=&aLinkMuxer;
+ }
+
+
+void CHCIFacade::SetPhysicalLinksMgr(CPhysicalLinksManager& aLinksMgr)
+ {
+ LOG_FUNC
+ iLinksMgr = &aLinksMgr;
+ }
+
+TInt CHCIFacade::SendInitialisationCommand(CHCICommandBase* aCommand)
+ /*
+ This method takes ownership of the command.
+ */
+ {
+ LOG_FUNC
+ __ASSERT_ALWAYS(aCommand != NULL, Panic(EHCICommandNullItem));
+ __ASSERT_ALWAYS(iInitState==EResetting || iInitState==EPostReset, Panic(EHCICtrlrInitAddingInitialisationCommandInBadState));
+ if(iInitState==EResetting)
+ {
+ __ASSERT_ALWAYS(iOutstandingCommands.Count()==0, Panic(EHCICtrlrInitOnlyOneResetCmdAllowed));
+ }
+
+ TInt err = KErrNone;
+ TUint qid = 0;
+
+ // Ownership of the command is passed to the queue.
+ // MhcqAddInitCommandL guarantees to take ownership even if it
+ // leaves.
+
+ // see CHCIFacade::MhcqcCommandEventReceived for completion
+ TRAP(err, qid = iCmdController->MhcqAddInitCommandL(aCommand, *this));
+ if (err != KErrNone)
+ {
+ iInitialisationError = ETrue;
+
+ LOG1(_L("Error! CHCIFacade::SendInitialisationCommand %d"), err);
+ return err;
+ }
+
+ // We need to know when we have completed initialisation of the stack so that
+ // we can Start() the HCI Command Queue. To do this we keep a list of all the
+ // initialisation command opcodes and then remove them from the list when we
+ // get the corresponding completion event. The stack initialisation is complete
+ // when the list of opcodes is empty.
+ if ((err = AddOutstandingCommandOpCode(aCommand->Opcode())) != KErrNone)
+ {
+ if (iCmdController->MhcqRemoveCommand(qid, *this) != KErrNone)
+ {
+ Panic(EHCICtrlrInitFailedToRemoveCmd);
+ }
+ iInitialisationError = ETrue;
+
+ LOG1(_L("Error! CHCIFacade::SendInitialisationCommand %d"), err);
+ return err;
+ }
+
+ return KErrNone;
+ }
+
+void CHCIFacade::InitL(const TBTLocalDevice& aDeviceConfig)
+/**
+ The start-up strategy
+
+ If there is an Initialisor the pre-reset initialisation method will
+ be called on it at this point. When the Initialisor pre-reset method
+ completes the stack will be called back to enable it to send the HCI
+ reset command, see McioPreResetCommandComplete().
+
+ If there is no Initialisor then this method will call the pre-reset
+ complete method directly allowing the stack to send the HCI reset
+ command.
+**/
+ {
+ LOG_FUNC
+ // Only re-initialise the stack is the current state is not pre-reset.
+ if(iInitState != EPreReset)
+ {
+ // Initialise the Command Queue
+ iCmdController->Initialise();
+ iInitState = EPreReset;
+
+ // DeviceClass is cached and retrieved from HCI if not currently
+ // set in aDeviceConfig
+ iDeviceClass = aDeviceConfig.DeviceClass();
+
+ // Get the Local Name from the Persist storage
+ TInt err(iLinkMgrProtocol.SetLocalDeviceName(aDeviceConfig.DeviceName()));
+ if (KErrNone != err && KErrNotSupported != err)
+ {
+ User::Leave(err);
+ }
+ if (iControllerInitialisor != NULL)
+ {
+ // see CHCIFacade::McioPreResetCommandComplete
+ iControllerInitialisor->MciiPreResetCommand();
+ }
+ else
+ {
+ // There is no initialisation plugin so behave as if there
+ // were and it had completed its pre reset phase
+ McioPreResetCommandComplete(KErrNone);
+ }
+ }
+ }
+
+CHCIFacade::CHCIFacade(CLinkMgrProtocol& aProtocol)
+ : iLinkMgrProtocol(aProtocol),
+ iInitState(EIdle),
+ iInitialisationError(EFalse)
+ {
+ LOG_FUNC
+ }
+
+CHCIFacade::~CHCIFacade()
+ {
+ LOG_FUNC
+ delete iAFHTimer;
+ #ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL
+ delete iMBufPool;
+ #endif
+
+ delete iCoreHciPlugin;
+
+ if(iCmdController)
+ {
+ iCmdController->MhcqRemoveAllCommands(*this);
+ delete iCmdController;
+ }
+
+ iOutstandingCommands.Close();
+ delete iHciUtil;
+ }
+
+CHctlAclDataFrame* CHCIFacade::NewACLDataFrameL(TUint16 aSize) const
+ {
+ LOG_FUNC
+ return (iDataFramer->MhdfNewAclDataFrameL(aSize));
+ }
+
+#ifdef STACK_SCO_DATA
+CHctlSynchronousDataFrame* CHCIFacade::NewSynchronousDataFrameL(TUint8 aSCODataLen) const
+ {
+ LOG_FUNC
+ return (iDataFramer->MhdfNewSynchronousDataFrameL(aSCODataLen));
+ }
+#endif
+
+THCITransportChannel CHCIFacade::HCTLState() const
+ {
+ LOG_FUNC
+ return iHCTLState; // give to muxer
+ }
+
+
+
+void CHCIFacade::HandlePowerStatusChange(TBTPowerState aStatus)
+/**
+ This method assumes that the power is actually changing, i.e. from off to on or
+ from on to off, and it is the responsibility of the caller, the hctl in non-error
+ conditions, to ensure this.
+
+ The only real dangerous transition is from on to on as this would intialise the
+ stack even if it is currently in an on state with or without existing state and
+ connections.
+**/
+ {
+ LOG_FUNC
+ switch(aStatus)
+ {
+ case EBTOn:
+ // Start-up Bluetooth
+ // Avoid from ON to ON
+ __ASSERT_DEBUG (iLastPowerState == EBTOff, Panic(EHCIPowerStateError));
+
+ iLastPowerState = aStatus;
+ //recovery the channels
+ iLinkMgrProtocol.LinkMuxer().ChannelsFree(iHCTLState);
+
+ TRAPD(err, InitL(iLinkMgrProtocol.LocalDevice()));
+ // Hopefully this should just work it won't rename the device though
+ // since that is persisted
+ if (err)
+ {
+ HandlePowerStatusChange(EBTOff);
+ return;
+ }
+ else
+ {
+ // Reset the inquiry manager
+ iLinkMgrProtocol.InquiryMgr().SetHWState(CBTInquiryMgr::EIdle);
+ // Clear debug mode
+ iLinkMgrProtocol.SecMan().ClearDebugMode();
+ }
+ break;
+
+ case EBTOff:
+ // Reset the Command Queue
+ // Avoid from OFF to OFF
+ __ASSERT_DEBUG (iLastPowerState == EBTOn, Panic(EHCIPowerStateError));
+
+ iLastPowerState = aStatus;
+
+ // Determine if we are waiting for a callback from the initialisation plugin
+ if ((iInitState == EPreReset) || (iInitState == EReset))
+ {
+ // cancel initialisation callback if possible
+ if (iControllerInitAbortExtension != NULL)
+ {
+ iControllerInitAbortExtension->MciaeiAbortInitialisation();
+ }
+ }
+ iInitState = EIdle;
+
+ iCmdController->Reset();
+ iOutstandingCommands.Reset();
+
+ // Ensure that no command or data messages are output by blocking all channels
+ //
+ iLinkMgrProtocol.LinkMuxer().ChannelsClosed(KHCITransportAllChannels);
+ iLinkMgrProtocol.Error(KErrHardwareNotAvailable);
+ // Reset UI
+ iLinkMgrProtocol.SetUIConnecting(EFalse);
+ iLinkMgrProtocol.SetUINumPhysicalLinks(0);
+ // The h/w CoD has been reset, so we need to clear our persistent value, to reflect this
+ iLinkMgrProtocol.ClearPendingLocalDeviceSettingsCod();
+
+ // Removes any pending AFH Channel Classification command
+ // and cancels timer.
+ // NB This ensures AFH host channel classification command blocking is
+ // not in place if power comes back on.
+ iAFHTimer->Reset();
+ break;
+
+ default:
+ Panic(EHCIUnknownPowerState);
+ break;
+ }
+
+ // Successfully changed power state
+ iLinkMgrProtocol.UpdateLocalDevicePower(aStatus);
+ }
+
+TInt CHCIFacade::ChangeMode(TBTLinkMode aMode, THCIConnHandle aConnHandle)
+ {
+ LOG_FUNC
+ TRAPD(err, DoChangeModeL(aMode, aConnHandle));
+ return err;
+ }
+
+void CHCIFacade::DoChangeModeL(TBTLinkMode aMode, THCIConnHandle aConnHandle)
+ {
+ LOG_FUNC
+ switch (aMode)
+ {
+ case ESniffMode:
+ {
+ SniffL(aConnHandle);
+ break;
+ }
+ case EParkMode:
+ {
+ ParkL(aConnHandle);
+ break;
+ }
+ case EHoldMode:
+ {
+ HoldL(aConnHandle);
+ break;
+ }
+ case EScatterMode:
+ case EActiveMode:
+ __ASSERT_DEBUG(0, Panic(EHCICommandBadArgument));
+ break;
+ }
+ }
+
+TInt CHCIFacade::ExitMode(TBTLinkMode aMode, THCIConnHandle aConnHandle)
+ {
+ LOG_FUNC
+ TRAPD(err, DoExitModeL(aMode, aConnHandle));
+ return err;
+ }
+
+void CHCIFacade::DoExitModeL(TBTLinkMode aMode, THCIConnHandle aConnHandle)
+ {
+ LOG_FUNC
+ switch (aMode)
+ {
+ case ESniffMode:
+ {
+ ExitSniffL(aConnHandle);
+ break;
+ }
+ case EParkMode:
+ {
+ ExitParkL(aConnHandle);
+ break;
+ }
+ // Not possile to prematurely exit hold mode
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+void CHCIFacade::SetupFlowControlL(TFlowControlMode aMode)
+/**
+ Set up flow control scheme to be used.
+ SetupFlowControlL should only be called once on init because it may leave.
+
+ If TFlowControlMode is chosen to be EFlowControlFromHostControllerOnly or
+ ETwoWayFlowControlEnabled, then it is the responsibility of the HCI client
+ to issue the appropriate HostBufferSize(..) command.
+*/
+ {
+ LOG_FUNC
+ switch (aMode)
+ {
+ case ENoFlowControl:
+ {
+#ifndef _DEBUG
+ Panic(ELinkMgrBadFlowControlSetInReleaseBuild);
+#endif
+ break;
+ }
+ case EFlowControlToHostControllerOnly:
+ {
+ // the host will not tell the Controller about its buffers
+
+ User::LeaveIfError(
+ SendInitialisationCommand(CReadBufferSizeCommand::NewL()));
+ break;
+ }
+ case EFlowControlFromHostControllerOnly:
+ {
+#ifdef _DEBUG
+ CHCICommandBase *command = CHostBufferSizeCommand::NewL(KLinkMgrIncomingBufferSize,
+ KStackSCOBuffersSize, KStackACLBuffersNum,
+ KStackSCOBuffersNum);
+
+ User::LeaveIfError(SendInitialisationCommand(command));
+
+ command = CSetControllerToHostFlowControlCommand::NewL(ETrue);
+
+ User::LeaveIfError(SendInitialisationCommand(command));
+
+#else
+ Panic(ELinkMgrBadFlowControlSetInReleaseBuild);
+#endif
+ break;
+ }
+ case ETwoWayFlowControlEnabled:
+ {
+ CHCICommandBase *command = CHostBufferSizeCommand::NewL(KLinkMgrIncomingBufferSize,
+ KStackSCOBuffersSize, KStackACLBuffersNum,
+ KStackSCOBuffersNum);
+
+ User::LeaveIfError(SendInitialisationCommand(command));
+
+ command = CSetControllerToHostFlowControlCommand::NewL(ETrue);
+
+ User::LeaveIfError(SendInitialisationCommand(command));
+
+ break;
+ }
+ default:
+ Panic(ELinkMgrNoSuchFlowControlMode);
+ break;
+ }
+ }
+
+
+// simple forwarding functions so that all stack usage to HCI is via Facade.
+
+TInt CHCIFacade::WriteACLData(const CHctlAclDataFrame& aFrame) const
+ {
+ LOG_FUNC
+ return iHctl->MhiWriteAclData(aFrame.HCTLPayload());
+ }
+
+TInt CHCIFacade::WriteSCOData(const CHctlSynchronousDataFrame& aFrame) const
+ {
+ LOG_FUNC
+ return iHctl->MhiWriteSynchronousData(aFrame.HCTLPayload());
+ }
+
+void CHCIFacade::FormatACLData(CHctlAclDataFrame& aFrame, THCIConnHandle aHandle,
+ TUint8 aOptions, const TDesC8& aData) const
+ {
+ LOG_FUNC
+ TUint8 flags = aOptions;
+ TAclPacketBoundaryFlag pbFlag = static_cast<TAclPacketBoundaryFlag>(flags & KPacketPBFlagMask);
+ TAclPacketBroadcastFlag bcFlag = static_cast<TAclPacketBroadcastFlag>((flags & KPacketBCFlagMask) >> KPacketPBtoBCFlagShift);
+ iDataFramer->MhdfFormatAclData(aFrame, aHandle, pbFlag, bcFlag, aData);
+ }
+
+void CHCIFacade::FormatSCOData(CHctlSynchronousDataFrame& aFrame, THCIConnHandle aHandle,
+ const TDesC8& aData) const
+ {
+ LOG_FUNC
+ iDataFramer->MhdfFormatSynchronousData(aFrame, aHandle, aData);
+ }
+
+void CHCIFacade::MhriStartHardReset()
+ {
+ LOG_FUNC
+ /*
+ Could have forced a...
+ HandlePowerStatusChange(EBTOff);
+ here - but instead let HCTL call this.
+ */
+ iHardResetInitiator->MhriStartHardReset();
+ }
+
+TUint16 CHCIFacade::ReadACLReportingInterval() const
+ {
+ LOG_FUNC
+ return 0;
+ }
+
+TUint16 CHCIFacade::ReadACLFramingOverhead() const
+ {
+ LOG_FUNC
+ return 0;
+ }
+
+#ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL
+RMBufChain CHCIFacade::TakeInboundACLDataBufferFromPool(const THCIConnHandle& aForConnHandle)
+ {
+ LOG_FUNC
+ return iMBufPool->TakeBuffer(aForConnHandle);
+ }
+#endif
+
+// MControllerInitialisationObserver
+void CHCIFacade::McioPreResetCommandComplete(TInt aError)
+ {
+ LOG_FUNC
+ CHCICommandBase* command(NULL);
+ TInt err;
+
+ // check that we are in the correct state
+ __ASSERT_ALWAYS(iInitState == EPreReset, Panic(EIncorrectStateOnPreResetCallback));
+ iInitState = EResetting;
+
+ if (aError != KErrNone)
+ {
+ // The initialisor plugin has failed pre reset initialisation
+ err = aError;
+ }
+ else
+ {
+ // Send Reset command
+ TRAP(err, command = CResetCommand::NewL());
+
+ if (err == KErrNone)
+ {
+ err = SendInitialisationCommand(command);
+ }
+ }
+
+ if (err != KErrNone)
+ {
+ // Initialisation has failed. At this point all we can do is power down
+ // Bluetooth. This means that initialisation can be attempted again by
+ // turning on the power but this again could fail.
+ HandlePowerStatusChange(EBTOff);
+ }
+ }
+
+void CHCIFacade::DoSendPostResetCommandsL()
+ {
+ LOG_FUNC
+ User::LeaveIfError(SendInitialisationCommand(CReadLocalSupportedFeaturesCommand::NewL()));
+ User::LeaveIfError(SendInitialisationCommand(CReadBdaddrCommand::NewL()));
+ User::LeaveIfError(SendInitialisationCommand(CReadLocalVersionInfoCommand::NewL()));
+
+#ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL
+#pragma message("Transport FlowControl = Two Way")
+
+ SetupFlowControlL(ETwoWayFlowControlEnabled);
+
+#else
+#pragma message("Transport FlowControl = None from HostController")
+
+ SetupFlowControlL(EFlowControlToHostControllerOnly);
+
+#endif
+
+ User::LeaveIfError(SendInitialisationCommand(CWriteConnectionAcceptTimeoutCommand::NewL(KHCIDefaultAcceptTimeout)));
+ User::LeaveIfError(SendInitialisationCommand(CWriteVoiceSettingCommand::NewL(KBTVoiceSetting)));
+
+ if (iDeviceClass)
+ {
+ // Some phones never set their CoD in s/w, we don't want to
+ // overwrite their h/w settings
+ LOG1(_L("DoSendPostResetCommandsL - SetDeviceClassL (0x%x)"), iDeviceClass);
+ iLinkMgrProtocol.SetDeviceClassL(iDeviceClass);
+ }
+ else
+ {
+ // We want to update the P&S value with the h/w value
+ User::LeaveIfError(SendInitialisationCommand(CReadClassOfDeviceCommand::NewL()));
+ }
+
+ TRAPD(err, iLinkMgrProtocol.SetInquiryAndPageScanningL());
+ if(err != KErrNone && err != KErrNotSupported)
+ {
+ User::Leave(err);
+ }
+ }
+
+void CHCIFacade::McioPostResetCommandComplete(TInt aError)
+ {
+ LOG_FUNC
+ TInt err;
+
+ // check that we are in the correct state
+ __ASSERT_ALWAYS(iInitState == EReset, Panic(EIncorrectStateOnPostResetCallback));
+ iInitState = EPostReset;
+
+ if (aError == KErrNone)
+ {
+ // Send post reset commands required by stack
+ TRAP(err, DoSendPostResetCommandsL());
+ }
+ else
+ {
+ // The initialisor plugin has failed post reset initialisation
+ err = aError;
+ }
+
+ if (err != KErrNone)
+ {
+ // Initialisation has failed. At this point all we can do is power down
+ // Bluetooth. This means that initialisation can be attempted again by
+ // turning on the power but this again could fail.
+ HandlePowerStatusChange(EBTOff);
+ }
+ }
+
+// MHCIDataObserver
+void CHCIFacade::MhdoProcessAclData(THCIConnHandle aConnH, TAclPacketBoundaryFlag aBoundaryFlag, TAclPacketBroadcastFlag aBroadcastFlag, const TDesC8& aData)
+ {
+ LOG_FUNC
+ // Stack currently works with the old flag passing mechanism. So recombine into the old
+ // flag type before continuing.
+ TUint8 flag = (aBoundaryFlag | (aBroadcastFlag << KPacketPBtoBCFlagShift)) << KPacketPBBCFlagShift;
+
+ LOG3(_L("Link [HCIFacade_Events.cpp]: CHCIFacade data received on handle %d, flags %d, length %d"), aConnH, flag, aData.Length());
+
+ iLinksMgr->ACLDataReceived(aConnH, flag, aData);
+ }
+
+void CHCIFacade::MhdoProcessSynchronousData(THCIConnHandle aConnH, TUint8 /*aReserved*/, const TDesC8& aData)
+ {
+ LOG_FUNC
+ iLinksMgr->SCODataReceived(aConnH, aData);
+ }
+
+// MHCTLChannelObserver
+void CHCIFacade::MhcoChannelOpen(THCITransportChannel aChannels)
+/**
+ The HCI has notified us that transport channels have become free
+**/
+ {
+ LOG_FUNC
+ LOG1(_L("Transport channels 0x%04x now free"), aChannels);
+
+ // record the channel status
+ iHCTLState |= aChannels;
+
+ if (iLinkMuxer)
+ {
+ iLinkMuxer->ChannelsFree(aChannels); //try to send on this channel
+ }
+ }
+
+void CHCIFacade::MhcoChannelClosed(THCITransportChannel aChannels)
+ {
+ LOG_FUNC
+ // record the channel status
+ iHCTLState &= (~aChannels) & KHCITransportAllChannels;
+
+ // Tell the Muxer these channels are closed, if Muxer is ready
+ if (iLinkMuxer)
+ {
+ iLinkMuxer->ChannelsClosed(aChannels);
+ }
+ }
+
+// MControllerStateObserver
+void CHCIFacade::McsoProcessPowerChange(TInt aError, TControllerChangeType aChangeType, TBTPowerState aState)
+ {
+ LOG_FUNC
+ if(aError!=KErrNone)
+ //Don't do anything - assume error implies no change took place
+ {
+ return;
+ }
+
+ if(aChangeType==MControllerStateObserver::EBTNonFatalChange)
+ //Don't do anything - controller change will not affect us
+ {
+ return;
+ }
+
+ // For now continue to use HandlePowerStatusChange as common code for power states and hard reset states
+ HandlePowerStatusChange(aState);
+ }
+
+void CHCIFacade::McsoProcessHardResetPhaseChange(TInt aError, TControllerChangeType aChangeType, TBTHardResetState aState)
+ {
+ LOG_FUNC
+ if(aError!=KErrNone)
+ {
+ //We may need to inform user somehow that reset has failed - depends on
+ //nature of error. What if error is KErrInUse? Should we set a timer
+ //and try again?
+ return;
+ }
+
+ if(aChangeType==MControllerStateObserver::EBTNonFatalChange)
+ //Don't do anything - controller change will not affect us
+ {
+ return;
+ }
+
+ switch(aState)
+ {
+ case EBTResetStarted:
+ HandlePowerStatusChange(EBTOff);
+ break;
+ case EBTResetComplete:
+ HandlePowerStatusChange(EBTOn);
+ break;
+ default:
+ Panic(EHCIUnknownHardResetState);
+ break;
+ }
+ }
+
+// MPhysicalLinksState - Simply forward the request to iLinksMgr
+TInt CHCIFacade::MplsGetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetConnectionHandles(aConnectionHandles, aLinkType);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetNumPendingHandles(aConnectionHandles, aLinkType);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetConnectionHandles(aConnectionHandles, aLinkType, aBDAddr);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetNumPendingHandles(aConnectionHandles, aLinkType, aBDAddr);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetRemoteAddress(TBTDevAddr& aBDAddr, THCIConnHandle aConnectionHandle) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetRemoteAddress(aBDAddr, aConnectionHandle);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetRemoteDeviceClass(TBTDeviceClass& aDeviceClass, const TBTDevAddr& aBDAddr) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetRemoteDeviceClass(aDeviceClass, aBDAddr);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetRemoteSupportedFeatures(TBTFeatures& aRemoteSupportedFeatures, const TBTDevAddr& aBDAddr) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetRemoteSupportedFeatures(aRemoteSupportedFeatures, aBDAddr);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetLinkPolicySettings(TLinkPolicy& aLinkPolicySettings, const TBTDevAddr& aBDAddr) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetLinkPolicySettings(aLinkPolicySettings, aBDAddr);
+ }
+ return KErrNotReady;
+ }
+
+TInt CHCIFacade::MplsGetBasebandLinkState(TBTBasebandLinkState& aBasebandLinkState, const TBTDevAddr& aBDAddr) const
+ {
+ LOG_FUNC
+ if (iLinksMgr)
+ {
+ return iLinksMgr->GetBasebandLinkState(aBasebandLinkState, aBDAddr);
+ }
+ return KErrNotReady;
+ }
+
+// MLinkMuxNotifier
+void CHCIFacade::TryToSend()
+ {
+ LOG_FUNC
+ if (iLinkMuxer)
+ {
+ iLinkMuxer->TryToSend();
+ }
+ }
+
+// from MHCIClientUsage
+void CHCIFacade::MhcuOpenClientReference()
+ {
+ iLinkMgrProtocol.LocalOpen();
+ }
+
+void CHCIFacade::MhcuCloseClientReference()
+ {
+ iLinkMgrProtocol.LocalClose();
+ }
+
+// Should only be tracking outstanding commands during cmdQ initialisation
+TInt CHCIFacade::AddOutstandingCommandOpCode(THCIOpcode aOpCode)
+ {
+ LOG_FUNC
+ __ASSERT_ALWAYS(iInitState != EInitialised, Panic(EHCICmdQNotInitialising));
+ TUint32 opcode = static_cast<TUint32>(aOpCode);
+ return iOutstandingCommands.Append(opcode);
+ }
+
+// Should only be tracking outstanding commands during cmdQ initialisation
+TInt CHCIFacade::FindOutstandingCommandOpCode(THCIOpcode aOpCode) const
+ {
+ LOG_FUNC
+ __ASSERT_ALWAYS(iInitState != EInitialised, Panic(EHCICmdQNotInitialising));
+ TUint32 opcode = static_cast<TUint32>(aOpCode);
+ return iOutstandingCommands.Find(opcode);
+ }
+
+// TBasebandPolicy
+
+void TBasebandPolicy::InitialPolicy(const TBasebandPolicyParams& aParams)
+ {
+ LOG_FUNC
+ iPageTimePolicy = aParams.iPageTimePolicy;
+ }
+
+TInt TBasebandPolicy::TryToChangePolicy(const TBasebandPolicyParams& aNewParams)
+ {
+ LOG_FUNC
+ // just deal with pagetime for now
+ TBasebandPageTimePolicy& current = iPageTimePolicy;
+
+ switch (current)
+ {
+ case EPagingDontCare:
+ break;
+
+ case EPagingNormal:
+ current = aNewParams.iPageTimePolicy;
+ break;
+
+ case EPagingBestEffort:
+ //only change if user wants Quick paging
+ current = (aNewParams.iPageTimePolicy == EPagingQuick) ? aNewParams.iPageTimePolicy : current;
+ break;
+
+ case EPagingQuick:
+ //only change if user wants Best effort paging
+ current = (aNewParams.iPageTimePolicy == EPagingBestEffort) ? aNewParams.iPageTimePolicy : current;
+ break;
+
+ default:
+ LOG(_L("TBasebandPolicy: bogus policy requested for pagetimeout"));
+ return KErrArgument;
+ }
+
+ LOG1(_L("TBasebandPolicy: now using page time policy %d"), aNewParams.iPageTimePolicy);
+ return (current == aNewParams.iPageTimePolicy) ? KErrNone : KErrInUse;
+ }
+
+
+TBasebandPageTimePolicy TBasebandPolicy::PageTimePolicy() const
+ {
+ LOG_FUNC
+ return iPageTimePolicy;
+ }
+
+//class CAFHTimer
+CAFHTimer* CAFHTimer::NewL(CHCIFacade& aParent)
+ {
+ LOG_STATIC_FUNC
+ CAFHTimer* self = new (ELeave) CAFHTimer(aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CAFHTimer::ConstructL()
+ {
+ LOG_FUNC
+ CTimer::ConstructL();
+ CActiveScheduler::Add(this);
+ }
+
+CAFHTimer::CAFHTimer(CHCIFacade& aParent)
+: CTimer(CActive::EPriorityStandard), iParent(aParent), iPending(EFalse)
+ {
+ LOG_FUNC
+ }
+
+void CAFHTimer::SetPending(const TBTAFHHostChannelClassification& aHCC)
+ {
+ LOG_FUNC
+ iHCC.Copy(aHCC);
+ iPending=ETrue;
+ }
+
+void CAFHTimer::RemovePendingHostChannelClassifications()
+ {
+ LOG_FUNC
+ iHCC.Reset();
+ iPending=EFalse;
+ }
+
+void CAFHTimer::Reset()
+ {
+ LOG_FUNC
+ RemovePendingHostChannelClassifications();
+ Cancel();
+ }
+
+void CAFHTimer::RunL()
+ {
+ LOG_FUNC
+ if(iPending)
+ {
+ if(iStatus==KErrNone)
+ {
+ iParent.SetAFHHostChannelClassificationL(iHCC);
+ }
+ RemovePendingHostChannelClassifications();
+ }
+ }
+
+TInt CAFHTimer::RunError(TInt /*aError*/)
+ {
+ LOG_FUNC
+ return KErrNone;
+ }
+
+#ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL
+
+CHostMBufPool* CHostMBufPool::NewL(CHCIFacade& aHCIFacade)
+ {
+ LOG_FUNC
+ CHostMBufPool* self = new (ELeave) CHostMBufPool(aHCIFacade);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CHostMBufPool::DeletePool(TSglQue<TPoolBuffer>& aQueue)
+ {
+ LOG_FUNC
+ TPoolBuffer* tmpItem = NULL;
+ TSglQueIter<TPoolBuffer> iter(aQueue);
+ while(iter)
+ {
+ tmpItem=iter++;
+ aQueue.Remove(*tmpItem);
+ delete tmpItem;
+ }
+ }
+
+CHostMBufPool::~CHostMBufPool()
+ {
+ LOG_FUNC
+ Cancel();
+ DeletePool(iBufferPool);
+ DeletePool(iWaitingAllocPool);
+ }
+
+CHostMBufPool::CHostMBufPool(CHCIFacade& aHCIFacade) :
+ CActive(0),iHCIFacade(aHCIFacade),iBufferPool(_FOFF(TPoolBuffer,iLink)),
+ iWaitingAllocPool(_FOFF(TPoolBuffer,iLink)),iCurrAckHandle(KErrNotFound),iCurrCompletedPackets(0)
+ {
+ LOG_FUNC
+ }
+
+void CHostMBufPool::ConstructL()
+/**
+2nd phase constructor for the Host MBuf Pool.
+
+This method will attempt to reserve enough MBufs from the global pool
+for bluetooth use.
+@leave KErrNoMemory If the required number of MBufs couldn't be reserved
+*/
+ {
+ LOG_FUNC
+ LOG2(_L("CHostMBufPool: now reserving %d size %d MBufChains"),KStackACLBuffersNum,KLinkMgrIncomingBufferSize);
+
+ for (TInt i=0;i<=KStackACLBuffersNum-1;i++)
+ {
+ TPoolBuffer* thisBuffer = new (ELeave) TPoolBuffer();
+ CleanupStack::PushL(thisBuffer);
+ thisBuffer->iCurrentHandle=KErrNotFound; //we assert on this later
+ thisBuffer->iMBufChain.AllocL(KLinkMgrIncomingBufferSize);
+ iBufferPool.AddFirst(*thisBuffer);
+ CleanupStack::Pop(thisBuffer);
+ }
+
+ CActiveScheduler::Add(this);
+ }
+
+void CHostMBufPool::DoCancel()
+ {
+ LOG_FUNC
+ iMBufRequester.Cancel();
+ }
+
+RMBufChain CHostMBufPool::TakeBuffer(const THCIConnHandle& aConnHandle)
+/**
+Takes a buffer from the pool and schedules an asynchronous allocation
+of the next buffer. Only when that allocation has succeeded will the host
+controller be signalled with a host_number_of_completed_packets. Hence,
+if we cannot allocate a buffer from the global MBuf pool, the host controller
+will be flowed off and no data will be lost.
+*/
+ {
+ LOG_FUNC
+ TPoolBuffer* ready = iBufferPool.First();
+ iBufferPool.Remove(*ready);
+ __ASSERT_DEBUG(!ready->iMBufChain.IsEmpty(),Panic(ELinkMgrHostControllerHasOverflowedHost));
+ __ASSERT_DEBUG(ready->iCurrentHandle==KErrNotFound,Panic(ELinkMgrHostControllerHasOverflowedHost));
+ ready->iCurrentHandle = aConnHandle;
+
+ RMBufChain retChain;
+ retChain.Assign(ready->iMBufChain);
+
+ if (IsActive())
+ {
+ //This buffer will be reclaimed from the global pool
+ //after the one(s) we're currently trying to reclaim
+ LOG(_L("CHostMBufPool: TakeBuffer, buffer taken while alloc outstanding: queued alloc"));
+ iWaitingAllocPool.AddLast(*ready);
+ }
+ else
+ {
+ LOG(_L("CHostMBufPool: TakeBuffer, buffer taken"));
+ iBufferPool.AddLast(*ready); //NB the Controller cannot use this
+ //buffer until it is alloced as it will
+ //be flowed off.
+ iMBufRequester.Alloc(ready->iMBufChain,KLinkMgrIncomingBufferSize,iStatus);
+ SetActive();
+ }
+
+ return retChain;
+ }
+
+void CHostMBufPool::RunL()
+ {
+ LOG_FUNC
+ if (iStatus.Int()!=KErrNone)
+ {
+ LOG1(_L("Error! CHostMBufPool:: RunL %d"),iStatus.Int());
+ __DEBUGGER();
+ }
+ else
+ {
+ TPoolBuffer* justAllocd = iBufferPool.Last();
+
+
+ if (iCurrAckHandle==KErrNotFound)
+ {
+ //This is the first completion we have ever seen
+ iCurrAckHandle=justAllocd->iCurrentHandle;
+ }
+
+ TBool ackNow=((justAllocd->iCurrentHandle!=iCurrAckHandle));
+
+ if (!ackNow)
+ {
+ iCurrCompletedPackets++;
+ LOG2(_L("CHostMBufPool: CompletedPackets++ for conn: %d [->%d]"),justAllocd->iCurrentHandle,iCurrCompletedPackets);
+
+ if (iCurrCompletedPackets>=KStackACLBuffersTideMarkNum)
+ {
+ ackNow=ETrue;
+ }
+ }
+
+ if (ackNow)
+ {
+ TInt err=KErrNone;
+
+ if (iCurrCompletedPackets>0)
+ {
+ LOG2(_L("CHostMBufPool: Sending HostNumberOfCompletedPackets for conn: %d [%d completed]"),iCurrAckHandle,iCurrCompletedPackets);
+ //Acknowledge the completed packets
+ TRAP(err, iHCIFacade.HostNumberOfCompletedPacketsL(iCurrAckHandle,iCurrCompletedPackets));
+ //if this failed we probably couldn't alloc the memory for the command frame,
+ //the HC is still flowed off.
+ __ASSERT_DEBUG(err==KErrNone,Panic(ELinkMgrCouldNotSendHostNumberOfCompletedPackets));
+ }
+
+ iCurrCompletedPackets= (justAllocd->iCurrentHandle!=iCurrAckHandle) ? 1:0;
+ iCurrAckHandle=justAllocd->iCurrentHandle;
+ }
+
+ justAllocd->iCurrentHandle=KErrNotFound;
+
+ if (!iWaitingAllocPool.IsEmpty())
+ {
+ TPoolBuffer* needsAlloc = iWaitingAllocPool.First();
+ iBufferPool.AddLast(*needsAlloc);
+ iWaitingAllocPool.Remove(*needsAlloc);
+ iMBufRequester.Alloc(needsAlloc->iMBufChain,KLinkMgrIncomingBufferSize,iStatus);
+ SetActive();
+ }
+ }
+ }
+
+#endif