bthci/hci2implementations/qdps/symbian/src/hcisymbianqdp.cpp
changeset 0 29b1cd4cb562
child 1 b4a7eebaaebf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bthci/hci2implementations/qdps/symbian/src/hcisymbianqdp.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,309 @@
+// 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 "hcisymbianqdp.h"
+#include "hcieventmodifiable.h"
+#include <bluetooth/hcicommandqitem.h>
+#include <bluetooth/hci/hciopcodes.h>
+#include <bluetooth/hci/hciconsts.h>
+#include <bluetooth/hci/command.h>
+#include <bluetooth/hci/event.h>
+#include <bluetooth/hci/commandcompleteevent.h>
+#include <bluetooth/hci/disconnectioncompleteevent.h>
+#include <bluetooth/hci/readclockoffsetevent.h>
+#include <bluetooth/hci/authenticationcompleteevent.h>
+#include <bluetooth/hci/readlocalversioninfocompleteevent.h>
+#include <bluetooth/logger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_QDP_SYMBIAN);
+#endif
+
+/*static*/ CHCISymbianQdp* CHCISymbianQdp::NewL()
+	{
+	LOG_STATIC_FUNC
+	
+	CHCISymbianQdp* self = new (ELeave) CHCISymbianQdp();
+	return self;
+	}
+
+// Private constructor.
+CHCISymbianQdp::CHCISymbianQdp()
+	{
+	LOG_FUNC
+	}
+
+TAny* CHCISymbianQdp::Interface(TUid aUid)
+	{
+	TAny* ret = NULL;
+	
+	switch(aUid.iUid)
+		{
+		case KHCICmdQueueDecisionInterfaceUid:
+			ret = reinterpret_cast<TAny*>(static_cast<MHCICmdQueueDecisionInterface*>(this));
+			break;
+		case KHCICmdQueueDecisionEventModifierInterfaceUid:
+			ret = reinterpret_cast<TAny*>(static_cast<MHCICmdQueueEventModifierInterface*>(this));
+			break;
+		case KHCICmdQueueUtilityUserUid:
+			ret = reinterpret_cast<TAny*>(static_cast<MHCICmdQueueUtilityUser*>(this));
+			break;
+		default:
+			break;
+		};
+
+	return ret;
+	}
+
+// MHCICmdQueueDecisionInterface
+TBool CHCISymbianQdp::MhcqdiDoesCommandRequireWorkaround(const CHCICommandQItem& /* aParent */)
+	{
+	LOG_FUNC
+	
+	// No Workarounds required.
+	return EFalse;
+	}
+	
+CHCICommandQItem* CHCISymbianQdp::MhcqdiGetPreChildCommand(const CHCICommandQItem& /* aParent */, 
+														   const CHCICommandQItem* /* aPreviousWorkaroundCmd */,
+														   const THCIEventBase* /*aPreviousCmdResult*/)
+	{
+	LOG_FUNC
+	
+	// No Workarounds required (see MhcqdiDoesCommandRequireWorkaround), should never be called.
+	return NULL;
+	}
+
+CHCICommandQItem* CHCISymbianQdp::MhcqdiGetPostChildCommand(const CHCICommandQItem& /* aParent */, 
+															const CHCICommandQItem* /* aPreviousPostChild */, 
+															const THCIEventBase* /*aPreviousCmdResult*/)
+	{
+	LOG_FUNC
+	
+	// No Workarounds required (see MhcqdiDoesCommandRequireWorkaround), should never be called.
+	return NULL;
+	}
+	
+THCIEventBase* CHCISymbianQdp::MhcqdiGetFakedUnsolicitedEvent(const CHCICommandQItem& /*aParent*/,
+															  const THCIEventBase* /*aPreviousFakedEvent*/)
+	{
+	LOG_FUNC
+	
+	// No Workarounds required (see MhcqdiDoesCommandRequireWorkaround), should never be called.
+	return NULL;
+	}
+	
+void CHCISymbianQdp::MhcqdiCommandAboutToBeDeleted(const CHCICommandQItem& /*aDyingCmd*/)
+	{
+	LOG_FUNC
+	
+	// Notification function. No need to do anything.
+	}
+	
+TInt CHCISymbianQdp::MhcqdiCanSend(CHCICommandQItem& /*aCommand*/, const TDblQue<const CHCICommandQItem>& aSentCommands)
+	{
+	LOG_FUNC
+
+   if (!aSentCommands.IsEmpty())
+   		{
+        // Def088959 - The following unhandled commands are blocked to avoid operational errors.
+        // Note: This workaround currently resides in this Symbian QDP, but may require further
+        // modification or placement depending on target hardware characteristics. This workaround
+        // may not be required for all controllers.
+        
+        THCIOpcode opcode=aSentCommands.Last()->Command().Opcode();
+        if (opcode == KHoldModeOpcode ||
+        			opcode == KSniffModeOpcode ||
+        			opcode == KExitSniffModeOpcode ||
+        			opcode == KSwitchRoleOpcode ||
+        			opcode == KParkModeOpcode ||
+        			opcode == KExitParkModeOpcode)
+	        {
+        	return EBlock;
+	        }
+   		}
+   //otherwise allow command queue to proceed   
+	return EContinue;
+	}
+	
+TUint CHCISymbianQdp::MhcqdiTimeoutRequired(const CHCICommandQItem& /* aCmdAboutToBeSent */)
+	{
+	LOG_FUNC
+	
+	// No timeout required.
+	return MHCICmdQueueDecisionInterface::KNoTimeoutRequired;
+	}
+	
+void CHCISymbianQdp::MhcqdiMatchedEventReceived(const THCIEventBase& aEvent, const CHCICommandQItem& /*aRelatedCommand*/)
+	{
+	LOG_FUNC
+	
+	// Cache the HCI version number of the controller. This allows
+	// us to ignore errors from specific versions of controllers
+	if (   aEvent.EventCode() == ECommandCompleteEvent
+		&& THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() == KReadLocalVersionInfoOpcode)
+		{
+		const TReadLocalVersionInfoCompleteEvent& readLocalVersionCompleteEvent = TReadLocalVersionInfoCompleteEvent::Cast(aEvent);
+		iHCIVersion = readLocalVersionCompleteEvent.Version();
+		}
+	}
+
+void CHCISymbianQdp::MhcqemiMatchedEventReceived(THCIEventBase& aEvent, const CHCICommandQItem& aRelatedCommand)
+	{
+	LOG_FUNC
+	
+#ifdef BROKEN_CASIRA_1_1
+	FirmwareFixIgnoreErrorOnSetEventMaskForCasira(aEvent);
+#endif // BROKEN_CASIRA_1_1
+	
+#ifdef BROKEN_BELKIN_2_1
+	FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(aEvent);
+#endif // BROKEN_BELKIN_2_1
+
+	MhcqdiMatchedEventReceived(aEvent, aRelatedCommand);
+	}
+
+
+MHCICmdQueueDecisionInterface::TCommandErroredAction CHCISymbianQdp::MhcqdiMatchedErrorEventReceived(const THCIEventBase& /*aErrorEvent*/, 
+																									 const CHCICommandQItem& /*aRelatedCommand*/)
+	{
+	LOG_FUNC
+	
+	// Never resend.
+	return MHCICmdQueueDecisionInterface::EContinueWithError;
+	}
+	
+void CHCISymbianQdp::MhcqdiUnmatchedEventReceived(const THCIEventBase& /*aEvent*/)
+	{
+	LOG_FUNC
+	
+	// Notification function. No need to do anything.
+	}
+
+void CHCISymbianQdp::FirmwareFixIgnoreErrorOnSetEventMaskForCasira(THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	// Casiras with 1.1 firmware return an EInvalidHCIParameter error
+	// when SetEventMask is called. We still want to call SetEventMask but
+	// on this (old/buggy) firmware, ignore the returned EInvalidHCIParameter
+	
+	if (    aEvent.ErrorCode() == EInvalidHCIParameter
+	    &&  aEvent.EventCode() == ECommandCompleteEvent
+		&& KSetEventMaskOpcode == THCICommandCompleteEvent::Cast(aEvent).CommandOpcode()
+		&&         iHCIVersion == EHWHCIv1_1)
+		{
+		THCIEventBase& modevent = const_cast<THCIEventBase&>(aEvent);
+		THCIEventModifiable& event = reinterpret_cast<THCIEventModifiable&>(modevent);
+		event.SetErrorCode(EOK);
+		}
+	}
+
+void CHCISymbianQdp::FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	// For Belkin 2.1 controllers, if we receive a "Disconnection Complete Event"
+	// then look for a "Authentication Requested" command or "Read Clock Offset" on
+	// the sent queue, and if found, then fake up an completion event (with reason
+	// code copied from the Disconnection Complete Event) and inject this into the
+	// queue. This is because the Belkin 2.1 controllers fail to send a completion
+	// event for "Read Clock Offset" and "Request Authentication" (and maybe others)
+	// themselves (i.e. these are firmware bugs we're working around)
+
+	if (aEvent.EventCode() == EDisconnectionCompleteEvent && iHCIVersion == EHWHCIv2_1)
+		{
+		const TDisconnectionCompleteEvent& disconnEvent = TDisconnectionCompleteEvent::Cast(aEvent);
+		THCIConnectionHandle handle = disconnEvent.ConnectionHandle();
+		THCIErrorCode reason = static_cast<THCIErrorCode>(disconnEvent.Reason());
+		
+		if (iProvider->FindOutstandingCommand(KAuthenticationRequestedOpcode) != NULL)
+			{
+			TBuf8<KHCIMaxEventSize> eventBuf1;
+			TAuthenticationCompleteEvent authenticationCompleteEvent(reason, handle, eventBuf1);
+			iProvider->InjectEvent(authenticationCompleteEvent);
+			}
+		
+		if (iProvider->FindOutstandingCommand(KReadClockOffsetOpcode) != NULL)
+			{
+			TBuf8<KHCIMaxEventSize> eventBuf2;
+			THCIClockOffset clockOffset = 0;
+			TReadClockOffsetEvent readClockOffsetEvent(reason, handle, clockOffset, eventBuf2);
+			iProvider->InjectEvent(readClockOffsetEvent);
+			}
+		}
+	}
+
+void CHCISymbianQdp::MhcqemiUnmatchedEventReceived(THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	
+#ifdef BROKEN_BELKIN_2_1
+	FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(aEvent);
+#endif // BROKEN_BELKIN_2_1
+	
+	MhcqdiUnmatchedEventReceived(aEvent);
+	}
+	
+MHCICmdQueueDecisionInterface::TCommandTimedOutAction CHCISymbianQdp::MhcqdiCommandTimedOut(const CHCICommandQItem& /*aCommand*/,
+																							const TDblQue<const CHCICommandQItem>& /*aSentCommands*/,
+																							TUint /*aCurrentCommandCredits*/,
+																							TUint& aCreditsToBeRefunded)
+	{
+	LOG_FUNC
+	
+	// No Timeout ever set, should never be called.
+	aCreditsToBeRefunded = KHCIDefaultCmdCredits;
+	return EContinueWithTimeoutEvent;
+	}
+	
+void CHCISymbianQdp::MhcqdiSetPhysicalLinksState(const MPhysicalLinksState& /*aPhysicalLinkState*/)
+	{
+	LOG_FUNC
+	}
+	
+void CHCISymbianQdp::MhcqdiSetHardResetInitiator(const MHardResetInitiator& /*aHardResetInitiator*/)
+	{
+	LOG_FUNC
+	}
+	
+void CHCISymbianQdp::MhcqdiSetHCICommandQueue(MHCICommandQueue& /*aHCICommandQueue*/)
+	{
+	LOG_FUNC
+	}
+
+void CHCISymbianQdp::MhcqdiSetTimeouts(TUint /*aQueueStarvationTimeout*/,
+                                       TUint /*aMaxHciCommandTimeout*/)
+	{
+	LOG_FUNC
+	}
+	
+TUint CHCISymbianQdp::MhcqdiReset()
+	{
+	LOG_FUNC
+	
+	// Return the initial number of command credits for the queue.
+	return KHCIDefaultCmdCredits;
+	}
+
+void CHCISymbianQdp::MhcquuSetUtilitiesProvider(MHCICmdQueueUtilities& aProvider)
+	{
+	LOG_FUNC
+	
+	iProvider = &aProvider;
+	}