diff -r 000000000000 -r 29b1cd4cb562 bthci/hci2implementations/corehcis/symbian/src/hciserverrequestmgr.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bthci/hci2implementations/corehcis/symbian/src/hciserverrequestmgr.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,658 @@ +// 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: +// + +/** + @file + @internalComponent +*/ + +#include "hciserverrequestmgr.h" +#include "HciCorePluginImpl.h" +#include "corehciutil.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_HCISERVER); +#endif + +const TInt KHCIServerIpcDesOutParam = 2; + +void CHCIServerRequestManager::BlockAsync(CHCISession& aSession, const RMessage2& aMessage) + { + LOG_FUNC + + iAsyncTaskMessage = aMessage; + iAsyncTaskSession = &aSession; + iBlockMask |= MaskBit(); + } + +void CHCIServerRequestManager::CompleteAsyncTask(TInt aError) + { + LOG_FUNC + + //check message is not already complete + if(iAsyncTaskMessage.Handle()) + { + iAsyncTaskMessage.Complete(aError); + } + else + { + __ASSERT_DEBUG(EFalse, PANIC(KHciServerPanicCat, EMessageAlreadyCompleted)); + } + + // Remove Async block + iAsyncTaskSession = 0; + iBlockMask &= ~MaskBit(); + } + +TBool CHCIServerRequestManager::IsAsyncBlocked() + { + LOG_FUNC + + return (iBlockMask & MaskBit()); + } + +CHCIServerRequestManager::CHCIServerRequestManager(CCoreHCIPluginImpl& aHCI) + : iHCI(aHCI) + { + LOG_FUNC + } + +void CHCIServerRequestManager::ConstructL() + { + LOG_FUNC + } + +void CHCIServerRequestManager::ServiceL(CHCISession& aSession, const RMessage2& aMessage) + { + if(aMessage.Function() == EServiceSpecificRequest) + { + if(HasCapabilities(aMessage)) + { + DoServiceL(aSession, aMessage); + } + // else HasCapabilities failed (and has dealt with aMessage). + } + else + { + // The client has issued a bad HCI Server request, we only expect a server specific + // request to be made (the specific request being encoded in the TIpcArgs). + PanicClient(aMessage, EUnknownHciServerFunction); + } + } + +// +// HCI Direct Access Service +// +CHCIDirectAccessManager* CHCIDirectAccessManager::NewL(CCoreHCIPluginImpl& aHCI) + { + LOG_STATIC_FUNC + + CHCIDirectAccessManager* self = new (ELeave) CHCIDirectAccessManager(aHCI); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CHCIDirectAccessManager::SetHCICommandQueue(MHCICommandQueue& aHCICommandQueue) + { + LOG_FUNC + + __ASSERT_ALWAYS(!iHCICommandQueue, PANIC(KCoreHciPanicCat, EInterfaceAlreadyInitialised)); + iHCICommandQueue = &aHCICommandQueue; + } + +/*virtual*/ TBool CHCIDirectAccessManager::HasCapabilities(const RMessage2& aMessage) + { + LOG_FUNC + + TBool allowed = EFalse; + + switch (aMessage.Int0()) + { + case KHCIDirectAccessVendorCommand: + // Drop through + case KHCIDirectAccessCancel: // requires Network Control + Local Services + allowed = aMessage.HasCapability(ECapabilityNetworkControl) && aMessage.HasCapability(ECapabilityLocalServices); + break; + + default: + PanicClient(aMessage, EUnknownDirectAccessFunction); + return EFalse; + } + + if(!allowed) + { + aMessage.Complete(KErrPermissionDenied); + } + + return allowed; + } + +/*virtual*/ void CHCIDirectAccessManager::DoServiceL(CHCISession& aSession, const RMessage2& aMessage) + { + LOG_FUNC + + TInt request = aMessage.Int0(); + + switch (request) + { + case KHCIDirectAccessCancel: + if (iAsyncTaskSession != &aSession) + { + return; //drop - not for current async task + } + + // clear cache + iMessage = NULL; + + // perform cancellation procedure + CompleteAsyncTask(KErrCancel); + break; + + case KHCIDirectAccessVendorCommand: + { + if (IsAsyncBlocked()) + { + aMessage.Complete(KErrInUse); + return; + } + + const TInt len = User::LeaveIfError(aMessage.GetDesLength(1)); + + // Check the Vendor Command is at least 3 bytes long for the opcode + // and the length + if (len < 3) + { + PanicClient(aMessage, EInvalidVendorCommand); + break; + } + + HBufC8* buf = HBufC8::NewLC(len); + TPtr8 params(buf->Des()); + aMessage.ReadL(1, params); + + // Extract the opcode and create the new command + TUint16 opcode = LittleEndian::Get16(params.Ptr()); + + if (iHCICommandQueue) + { + CVendorDebugCommand* cmd = CVendorDebugCommand::NewL(opcode); + + // Remove the opcode and length from the Vendor Command parameters, + // these will be added again to the command frame once it has been + // formatted + cmd->Command() = params.RightTPtr(params.Length() - 3); + + // cmd will be deleted in MhcqAddCommandL if Leaves. + TUint qid = iHCICommandQueue->MhcqAddCommandL(cmd, *this); + + // Block only after we succeed in adding a command. + BlockAsync(aSession, aMessage); + + // Cache to return completion data to client + iMessage = &aMessage; + } + else + { + // Slight possible race that a request is made before we have been + // given the command queue to work with - so don't panic just error. + aMessage.Complete(KErrNotReady); + } + CleanupStack::PopAndDestroy(buf); + } + break; + + default: + // Unknown message, panic client + PanicClient(aMessage, EUnknownDirectAccessFunction); + break; + } + } + +/*virtual*/ void CHCIDirectAccessManager::MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* /*aCommand*/) + { + LOG_FUNC + + // clear cache + iMessage = NULL; + + CompleteAsyncTask(aErrorCode); + } + +/*virtual*/ void CHCIDirectAccessManager::MhcqcCommandEventReceived(const THCIEventBase& aEvent, const CHCICommandBase* aCommand) + { + LOG_FUNC + + // We are not the unmatched event observer therefore we must always get a + // command + __ASSERT_DEBUG(aCommand, PANIC(KCoreHciPanicCat, EReceivedUnmatchedEvent)); + + // It is possible to receive an event but not have a message to complete. This + // could happen if a request was cancelled after a Vendor Specific command was + // sent, in this case we do nothing. + if (iMessage) + { + TInt err = KErrNone; + + const THCIEventCode eventcode(aEvent.EventCode()); + switch(eventcode) + { + case ECommandCompleteEvent: + { + if ((aCommand->Opcode() & KVendorDebugOGF) == KVendorDebugOGF) + { + const TVendorDebugCompleteEvent& event = TVendorDebugCompleteEvent::Cast(aEvent); + + // Return the event + err = iMessage->Write(KHCIServerIpcDesOutParam, event.VendorDebugData()); + } + else + { + __ASSERT_DEBUG(EFalse, PANIC(KHciServerPanicCat, ENonVendorOpcodeCompleted)); + } + } + break; + + case EVendorDebugEvent: + { + const TVendorDebugEvent& event = TVendorDebugEvent::Cast(aEvent); + + // Return the event + err = iMessage->Write(KHCIServerIpcDesOutParam, event.VendorDebugData()); + } + break; + + default: + __ASSERT_DEBUG(EFalse, PANIC(KCoreHciPanicCat, EReceivedUnknownEvent)); + break; + } + + CompleteAsyncTask(err); + } + } + +/*virtual*/ void CHCIDirectAccessManager::CompleteAsyncTask(TInt aError) + { + LOG_FUNC + + if (!IsAsyncBlocked()) + { + return; //drop + } + + CHCIServerRequestManager::CompleteAsyncTask(aError); + } + +CHCIDirectAccessManager::CHCIDirectAccessManager(CCoreHCIPluginImpl& aHCI) +: CHCIServerRequestManager(aHCI) + { + LOG_FUNC + } + + +TUint CHCIDirectAccessManager::MaskBit() const + { + LOG_FUNC + + return EHCIDirectAccessMaskBit; + } + +// +// Power Control Service +// +CBTPowerControlManager* CBTPowerControlManager::NewL(CCoreHCIPluginImpl& aHCI) + { + LOG_STATIC_FUNC + + CBTPowerControlManager* self = new (ELeave) CBTPowerControlManager(aHCI); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +TBool CBTPowerControlManager::HasCapabilities(const RMessage2& aMessage) + { + LOG_FUNC + + TBool allowed(EFalse); + + switch (aMessage.Int0()) + { + case KHCICancelPower: + // fall through + case EHCISetPower: // requires Network Control + Local Services + allowed = aMessage.HasCapability(ECapabilityNetworkControl) && aMessage.HasCapability(ECapabilityLocalServices); + break; + + case EHCIGetPower: // requires Local Services + allowed = aMessage.HasCapability(ECapabilityLocalServices); + break; + + default: + PanicClient(aMessage, EUnknownPowerControlFunction); + return EFalse; + } + + if(!allowed) + { + aMessage.Complete(KErrPermissionDenied); + } + + return allowed; + } + +/*virtual*/ void CBTPowerControlManager::DoServiceL(CHCISession& aSession, const RMessage2& aMessage) + { + LOG_FUNC + + TInt request = aMessage.Int0(); + TInt err; + TBTPowerState state; + + switch (request) + { + case KHCICancelPower: + if(iAsyncTaskSession!=&aSession) + { + return; //drop - not for current async task + } + + //perform cancellation procedure + CompleteAsyncTask(KErrCancel); + break; + + case EHCISetPower: + if(IsAsyncBlocked()) + { + aMessage.Complete(KErrInUse); + return; + } + + //Should be called before set power because it could complete synchronously + BlockAsync(aSession, aMessage); + state = static_cast(aMessage.Int3()); + err = iHCI.SetPower(state, NULL); + if(err != KErrNone) + { + aMessage.Complete(err); + return; + } + break; + + case EHCIGetPower: + { + err = iHCI.GetPower(state, NULL); + if(err != KErrNone) + { + aMessage.Complete(err); + return; + } + + TPckg pckg(state); + TRAP(err, aMessage.WriteL(EPSStateReturnSlot, pckg)); + aMessage.Complete(err); + } + break; //synchronous so do not block + + default: + // Unknown message + PanicClient(aMessage, EUnknownPowerControlFunction); + break; + } + } + +/*virtual*/ void CBTPowerControlManager::CompleteAsyncTask(TInt aError) + { + LOG_FUNC + + if(!IsAsyncBlocked()) + { + return; //drop + } + + CHCIServerRequestManager::CompleteAsyncTask(aError); + } + +void CBTPowerControlManager::CompleteRequest(TInt aError) + { + CompleteAsyncTask(aError); + } + +CBTPowerControlManager::CBTPowerControlManager(CCoreHCIPluginImpl& aHCI) +: CHCIServerRequestManager(aHCI) + { + LOG_FUNC + } + + +TUint CBTPowerControlManager::MaskBit() const + { + LOG_FUNC + + return EBTPowerControlMaskBit; + } + +// +// Bluetooth HCI Utils Service +// +CBluetoothDutModeManager* CBluetoothDutModeManager::NewL(CCoreHCIPluginImpl& aHCI) + { + LOG_STATIC_FUNC + + CBluetoothDutModeManager* self = new (ELeave) CBluetoothDutModeManager(aHCI); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +TBool CBluetoothDutModeManager::HasCapabilities(const RMessage2& aMessage) + { + LOG_FUNC + + TBool allowed(EFalse); + + switch (aMessage.Int0()) + { + case RBluetoothDutMode::EHCIActivateDutMode: + // fall through + case RBluetoothDutMode::EHCIDeactivateDutMode: // requires Network Control + Local Services + allowed = aMessage.HasCapability(ECapabilityNetworkControl) && aMessage.HasCapability(ECapabilityLocalServices); + break; + + default: + PanicClient(aMessage, EUnknownBluetoothDutModeFunction); + return EFalse; + } + + if(!allowed) + { + aMessage.Complete(KErrPermissionDenied); + } + + return allowed; + } + +/*virtual*/ void CBluetoothDutModeManager::DoServiceL(CHCISession& /*aSession*/, const RMessage2& aMessage) + { + LOG_FUNC + + TInt request = aMessage.Int0(); + TInt err = KErrNotSupported; + + switch (request) + { + case RBluetoothDutMode::EHCIActivateDutMode: + // Implementation is adaptation specific and therefore not supported in our reference HCI Server + LOG(_L("EHCIActivateDutMode")); + aMessage.Complete(err); + break; + + case RBluetoothDutMode::EHCIDeactivateDutMode: + // Implementation is adaptation specific and therefore not supported in our reference HCI Server + LOG(_L("EHCIDeactivateDutMode")); + aMessage.Complete(err); + break; + + default: + // Unknown message + PanicClient(aMessage, EUnknownBluetoothDutModeFunction); + break; + } + } + +CBluetoothDutModeManager::CBluetoothDutModeManager(CCoreHCIPluginImpl& aHCI) +: CHCIServerRequestManager(aHCI) + { + LOG_FUNC + } + + +TUint CBluetoothDutModeManager::MaskBit() const + { + LOG_FUNC + + return EBluetoothDutModeMaskBit; + } + +// +// A2DP Optimiser Service +// +CA2dpOptimiserManager* CA2dpOptimiserManager::NewL(CCoreHCIPluginImpl& aHCI) + { + LOG_STATIC_FUNC + + CA2dpOptimiserManager* self = new (ELeave) CA2dpOptimiserManager(aHCI); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +TBool CA2dpOptimiserManager::HasCapabilities(const RMessage2& aMessage) + { + LOG_FUNC + + TBool allowed(EFalse); + + switch (aMessage.Int0()) + { + case RA2dpOptimiser::EHCIA2dpOptimiseAcl: + // fall through + case RA2dpOptimiser::EHCIA2dpRemoveAclOptimisation: // requires Network Control + Local Services + allowed = aMessage.HasCapability(ECapabilityNetworkControl) && aMessage.HasCapability(ECapabilityLocalServices); + break; + + default: + PanicClient(aMessage, EUnknownA2dpOptimiserFunction); + return EFalse; + } + + if(!allowed) + { + aMessage.Complete(KErrPermissionDenied); + } + + return allowed; + } + +/*virtual*/ void CA2dpOptimiserManager::DoServiceL(CHCISession& /*aSession*/, const RMessage2& aMessage) + { + LOG_FUNC + + TInt request = aMessage.Int0(); + TInt err = KErrNotSupported; + TBuf<20> targetAddrBuf; + + switch (request) + { + case RA2dpOptimiser::EHCIA2dpOptimiseAcl: + // Implementation is adaptation specific and therefore not supported in our reference HCI Server + if (aMessage.GetDesLength(1) == sizeof(TA2dpOptimisationParams)) + { + TPckgBuf args; + + aMessage.ReadL(1, args); + args().RemoteDeviceAddress().GetReadable(targetAddrBuf); + LOG3(_L("EHCIA2dpOptimiseAcl BT Addr: %S, Peak Bandwidth: %d, Access Latency: %d\n"), + &targetAddrBuf, args().PeakBandwidth(), args().AccessLatency()); + + aMessage.Complete(err); + } + else + { + PanicClient(aMessage, EInvalidArgument); + } + break; + + case RA2dpOptimiser::EHCIA2dpRemoveAclOptimisation: + // Implementation is adaptation specific and therefore not supported in our reference HCI Server + if (aMessage.GetDesLength(1) == sizeof(TBTDevAddr)) + { + TPckgBuf addrBuf; + + aMessage.ReadL(1, addrBuf); + addrBuf().GetReadable(targetAddrBuf); + LOG1(_L("EHCIA2dpRemoveAclOptimisation BT Addr: %S\n"), &targetAddrBuf); + + aMessage.Complete(err); + } + else + { + PanicClient(aMessage, EInvalidArgument); + } + break; + + default: + // Unknown message + PanicClient(aMessage, EUnknownA2dpOptimiserFunction); + break; + } + } + +CA2dpOptimiserManager::CA2dpOptimiserManager(CCoreHCIPluginImpl& aHCI) +: CHCIServerRequestManager(aHCI) + { + LOG_FUNC + } + + +TUint CA2dpOptimiserManager::MaskBit() const + { + LOG_FUNC + + return EA2dpOptimiserMaskBit; + } +