bluetooth/btstack/linkmgr/hcifacade.cpp
changeset 0 29b1cd4cb562
child 13 20fda83a6398
--- /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