--- /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;
+ }