diff -r 000000000000 -r 29b1cd4cb562 bthci/bthci2/hcicmdq/interface/HciCmdQController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bthci/bthci2/hcicmdq/interface/HciCmdQController.h Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,405 @@ +// 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 + @internalTechnology +*/ + +#ifndef HCICMDQCONTROLLER_H +#define HCICMDQCONTROLLER_H + +#include + +#include +#include +#include +#include // For THCIConnHandle +#include + +class CHCICmdQueueDecisionPlugin; +class CHCICommandQItem; +class MHCICmdQueueDecisionInterface; +class MHCICmdQueueEventModifierInterface; +class MHCICommandAllocator; +class MHCICommandQueueClient; +class MHardResetInitiator; +class MHCTLInterface; +class MLinkMuxNotifier; +class MPhysicalLinksState; +class CHCICmdQStarvationTimer; +class CHciUtil; + +// Callback interface for the timer. +NONSHARABLE_CLASS(MHCITimerClient) + { +public: + virtual void CompletionTimeoutFired(TUint aUncompletedCmdId) = 0; + virtual void StarvationTimeoutFired(TUint aNextPendingCmdId) = 0; + }; + +NONSHARABLE_CLASS(CHCICmdQController) : public CBase, + public MHCICommandEventObserver, + public MHCICommandQueue, + public MHCITimerClient, + public MHCICmdQueueUtilities + { +public: // exported + IMPORT_C static CHCICmdQController* NewL(); + IMPORT_C ~CHCICmdQController(); + + IMPORT_C void SetHCTLInterface(MHCTLInterface& aHctlInterface); + IMPORT_C void SetHCICommandAllocator(MHCICommandAllocator& aCommandAllocator); + IMPORT_C void SetLinkMuxNotifier(MLinkMuxNotifier& aLinkMuxer); + IMPORT_C void SetHCIUnmatchedEventObserver(MHCICommandQueueClient& aUnmatchedEventObserver); + IMPORT_C void SetHardResetInitiator(MHardResetInitiator& aHardResetInitiator); + IMPORT_C void SetPhysicalLinksState(const MPhysicalLinksState& aStackInfo); + + IMPORT_C void Initialise(); + IMPORT_C void Reset(); + IMPORT_C void Start(); + IMPORT_C void DoSend(); + +public: // un-exported virtuals from MHCITimerClient + virtual void CompletionTimeoutFired(TUint aUncompletedCmdId); + virtual void StarvationTimeoutFired(TUint aWasNextPendingCmdId); + +public: // virtuals from MHCICommandQueue + virtual TUint MhcqAddCommandL(CHCICommandQItem* aQueItem); + virtual TUint MhcqAddCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient); + virtual TUint MhcqAddPriorityCommandL(CHCICommandQItem* aQueItem); + virtual TUint MhcqAddPriorityCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient); + virtual TUint MhcqAddInitCommandL(CHCICommandQItem* aQueItem); + virtual TUint MhcqAddInitCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient); + virtual TInt MhcqRemoveCommand(TUint aCommandId, const MHCICommandQueueClient& aCmdOriginator); + virtual void MhcqRemoveAllCommands(const MHCICommandQueueClient& aCmdOriginator); + virtual TUint MhcqMaxHciCommandTimeout() const; + virtual TAny* MhcqQdpPluginInterface(TUid aUid) const; + +private: // virtuals from MHCICommandEventObserver + virtual void MhceoEventNotification(const THCIEventBase& aEvent); + + // Helpers + void RemoveAllCommands(TDblQueIter aIter, + const MHCICommandQueueClient& aCmdOriginator, + TBool aCanDelete); + void HandleCommandRemoval(CHCICommandQItem& aCmd, TBool aCanDelete); + void HandleCommandRemoval(CHCICommandQItem*& aCmd, TBool aCanDelete); + void CleanUpQueue(TDblQueIter aIter); + +private: // virtuals from MHCICmdQueueUtilities + void MhcquiInjectEvent(const THCIEventBase& aEvent); + CHCICommandQItem* MhcquiFindOutstandingCommand(THCIOpcode aOpcode); + +private: + /** + Command queue block bit flags. + */ + enum + { + ENoBlocks = 0x00000000, + /** + Indicates that there is a workaround command on the sent + queue, so another command cannot be sent + */ + EWorkaroundBlock = 0x00000001, + + /** + Indicates the current head of the non-priority queues has been + blocked from MHCICmdQueueDecisionInterface::MhcqdiCanSend() + */ + ECanSendBlock = 0x00000002, + + /** + Indicates that the current head of the non-priority queues has the + same opcode as one on the sent queue. + */ + EDuplicatedOpcodeBlock = 0x00000004, + + /** + Indicates that the current head of the non-priority queues does not have + enough HCI credits. + */ + EInsufficientCreditBlock = 0x00000008, + + /** + Indicates that there is a resent command on the sent queue, so + another command cannot be resent. + */ + EResendBlock = 0x00000010, + + /** + Indicates that an HCTL send request + (MLinkMuxNotifier::TryToSend) is in progress, so another + command cannot be scheduled until we get a DoSend() callback. + */ + ETryToSendBlock = 0x00000020, + + EAllBlocks = EWorkaroundBlock | + ECanSendBlock | + EDuplicatedOpcodeBlock | + EInsufficientCreditBlock | + EResendBlock | ETryToSendBlock, + + /** + These three are different from the TryToSend, Resend and Workaround + blocks in that they only cache the effect of the last call to OkToSendCommand + for the most recently processed non-priority command. This means that + when they're all 0, OkToSendCommand needs to be called to re-evaluate + corresponding conditions. + */ + ECachingCommandBlocks = ECanSendBlock | + EDuplicatedOpcodeBlock | + EInsufficientCreditBlock, + + /** + Do not include the Resend block for any of the queues waiting to send a command + for the first time. Regardless of whether the Resend block is set we would need + a credit to send a command and if we get more than one credit (the first + potentially being used by a resent command) then we should use them. + */ + ESendQueueBlocks = EAllBlocks & ~EResendBlock, + + /** + For the Resend queue we do not want to include the Workaround block as it maybe + a workaround command being resent. + */ + EResendQueueBlocks = EAllBlocks & ~EWorkaroundBlock, + }; + + /** + Command queue controller state + */ + enum TCmdQControllerStates + { + /** + Power down state state. In this state no commands will be sent or queued. + Any attempt to queue a new command will fail. + + Reached on completion of async Reset() if in EResetting state. + */ + EUninitialised = 0, + + /** + Asynchronous reset pending state. + + Reached by calling Reset(). + */ + EResetting = 1, + + /** + Asynchronous reset pending state. + + Reached by calling Initialise() while async Reset() outstanding. + */ + EResetInit = 2, + + /** + Initialisation state. In this state only initilisation commands will be + sent, normal and priority commands are held on their queues. + + Reached by Initialise() or completion of async Reset() if in + EResetInit state. + */ + EInitialising = 3, + + /** + Operational state. + + Reached by calling Start(). + */ + EStarted = 4, + }; + + CHCICmdQController(); + void ConstructL(); + + inline TBool Blocked(TUint aBlocksToCheck, TUint aBlocksToBypass); + inline TBool Blocked(TUint aBlockStatus, TUint aBlocksToCheck, TUint aBlocksToBypass); + inline void ClearBlock(TUint aBlocks); + inline void SetBlock(TUint aBlocks); + inline TUint ValidBlocks(TUint aBlocks); + inline TUint InvalidBlocks(TUint aBlocks); + inline TUint CmdBypassBlocks(const CHCICommandQItem& aCmd); + + inline void UpdateCommandCredits(TUint8 aCommandCredits); + + inline TUint NextCommandQueueItemId(); + + inline TDblQue* ActiveRegularQueue(); + inline CHCICommandQItem* FirstQueueItem(TDblQue& aQueue); + inline CHCICommandQItem* LastQueueItem(TDblQue& aQueue); + + inline void StorePurgeMarks(); + inline void PurgeAllQueues(); + void PurgeQueue(TDblQue& aQueue, CHCICommandQItem* aMark); + + inline CHCICommandQItem* ScanQueueByOpcode(TDblQue& aQueue, THCIOpcode aOpcode); + inline CHCICommandQItem* ScanQueueByQId(TDblQue& aQueue, TUint aCmdId); +#ifdef _DEBUG + void LogQueue(TDblQue& aQueue); +#endif // _DEBUG + + inline TBool CanAddCommands(); + inline TBool CmdsQueued(TDblQue* aQueue); + inline TBool AnyCmdsToSend(); + inline TDblQue* QueueSendingNext(); + inline TBool NextCommandChanged(const TDblQue &aQueue); + + void DoReset(); + void TryToSend(); + TBool ProcessResendQueue(); + TBool ProcessWorkaroundQueue(); + TBool ProcessPriorityQueue(); + void ProcessRegularQueue(TDblQue& aQueue); + + void SetUpNextWorkaroundCmd(CHCICommandQItem* aPreviousCmd, const THCIEventBase* aPreviousCmdResult); + void UpdateStarvationTimer(); + + TUint DoAddCommandL(CHCICommandQItem& aQueItem, TDblQue &aQueue, TCmdQControllerStates aActiveState); + void DeleteCommand(CHCICommandQItem* &aItem); + TBool OkToSendCommand(CHCICommandQItem*& aCmdQItem, TUint aBypassBlocks); + void SendCommand(CHCICommandQItem& aCmdQItem); + + void ProcessMatchedEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool aConcludesCmd); + void ProcessMatchedErrorEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool aConcludesCmd, TBool aSendToQdp); + void ProcessUnmatchedEvent(const THCIEventBase& aEvent, TBool aSendToQdp); + void ProcessCommandCompletionTimeout(CHCICommandQItem* aCmd); + void ProcessEvent(const THCIEventBase& aEvent, TBool aSendToQdp); + + // Static async CallBack methods. + static TInt AsyncCallBackForReset(TAny* aCmdQController); + static TInt AsyncCallBackForSend(TAny* aCmdQController); + +private: + TUint iMaxHciCommandTimeout; + TUint iQueueStarvationTimeout; + + const static TUint KDefaultMaxHciCommandTimeout = 60000; // 60 seconds. + + MLinkMuxNotifier* iLinkMuxer; + MHCICommandQueueClient* iUnmatchedEventObserver; + MHCTLInterface* iHctl; + MHardResetInitiator* iHardResetInitiator; + MHCICommandAllocator* iCommandAllocator; + MHCICmdQueueDecisionInterface* iQdp; + MHCICmdQueueEventModifierInterface* iQdpEventModifier; + + /** + This timer gets reset every time the next command to send changes. + If that command stays the same for too long, we probably have a deadlock of some sorts. + */ + CHCICmdQStarvationTimer* iQStarvationTimer; + + /** + The queue of initialisation commands that have not yet been processed. + */ + TDblQue iInitCommandQ; + + /** + The queue of normal commands that have not yet been processed. + */ + TDblQue iNormalCommandQ; + + /** + The queue of priority commands that have not yet been processed. + Note: it's not FIFO - the order of execution of commands is determined + dynamically. + */ + TDblQue iPriorityCommandQ; + + /** + The queue of workarounds for commands on the other queues. + A command is moved here when time comes to execute it but QDP deems it to + be in need of workaround. + */ + TDblQue iWorkaroundCommandQ; + + /** + The queue of commands that have been sent to the controller but have not + yet had a response. + */ + TDblQue iSentCommandQ; + + /** + The queue of commands that are waiting to be re-sent to the controller. + */ + TDblQue iResendCommandQ; + + + /** + Recorded tails of the queues for Reset processing. + */ + CHCICommandQItem* iInitQPurgeMark; + CHCICommandQItem* iNormalQPurgeMark; + CHCICommandQItem* iPriorityQPurgeMark; + CHCICommandQItem* iWorkaroundQPurgeMark; + + /** + Currently processing send command. This is maintained to ensure both that the + correct command is processed by DoSend, and that there is only ever one outstanding + call to MLinkMuxNotifier::TryToSend at any given time + */ + CHCICommandQItem* iSendingCommand; + + /** + Currently processing parent command. This is maintained to simplify priority + command processing while a workaround is in progress, and to ensure that + the parent's iQdpData is available to the QDP until the workaround completes. + */ + CHCICommandQItem* iParentCommand; + + /** + Number of HCI command packets the queue controller can send to the HCI. This + corresponds to the Num_HCI_Command_Packets event parameter. This is decremented + whenever a command is sent to the HCTL, and is updated on receipt of Command Status + and Command Complete (including NOP) events. + */ + TUint8 iCommandCredits; + + /** + The CHCICmdQController state variable + */ + TCmdQControllerStates iCmdQControllerState; + + /** + This is a bit mask of the possible TQueueStateBits states + */ + TUint iCommandQState; + + /** + The QDP that the Command Queue will use. + */ + CHCICmdQueueDecisionPlugin* iQdpPlugin; + + /** + A counter generating IDs to uniquely identify commands. + */ + TUint iNextCommandQItemId; + + /** + HCI Utility library + */ + CHciUtil* iHciUtil; + + /** + Async Callbacks + */ + CAsyncCallBack* iAsyncCallBackForReset; + CAsyncCallBack* iAsyncCallBackForSend; + + }; + +#endif // HCICMDQCONTROLLER_H