bthci/bthci2/hcicmdq/interface/HciCmdQController.h
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalTechnology
       
    19 */
       
    20 
       
    21 #ifndef HCICMDQCONTROLLER_H
       
    22 #define HCICMDQCONTROLLER_H
       
    23 
       
    24 #include <e32base.h>
       
    25 
       
    26 #include <bluetooth/hcicommandeventobserver.h>
       
    27 #include <bluetooth/hcicommandqueue.h>
       
    28 #include <bluetooth/hci/hciopcodes.h>
       
    29 #include <bttypes.h> // For THCIConnHandle
       
    30 #include <bluetooth/hci/hcicmdqueuedecisioninterface.h>
       
    31 
       
    32 class CHCICmdQueueDecisionPlugin;
       
    33 class CHCICommandQItem;
       
    34 class MHCICmdQueueDecisionInterface;
       
    35 class MHCICmdQueueEventModifierInterface;
       
    36 class MHCICommandAllocator;
       
    37 class MHCICommandQueueClient;
       
    38 class MHardResetInitiator;
       
    39 class MHCTLInterface;
       
    40 class MLinkMuxNotifier;
       
    41 class MPhysicalLinksState;
       
    42 class CHCICmdQStarvationTimer;
       
    43 class CHciUtil;
       
    44 
       
    45 // Callback interface for the timer.
       
    46 NONSHARABLE_CLASS(MHCITimerClient)
       
    47 	{
       
    48 public:
       
    49 	virtual void CompletionTimeoutFired(TUint aUncompletedCmdId) = 0;
       
    50 	virtual void StarvationTimeoutFired(TUint aNextPendingCmdId) = 0;
       
    51 	};
       
    52 
       
    53 NONSHARABLE_CLASS(CHCICmdQController) : public CBase,
       
    54 										public MHCICommandEventObserver, 
       
    55 										public MHCICommandQueue,
       
    56 										public MHCITimerClient,
       
    57 										public MHCICmdQueueUtilities
       
    58 	{
       
    59 public: // exported
       
    60 	IMPORT_C static CHCICmdQController* NewL();
       
    61 	IMPORT_C ~CHCICmdQController();
       
    62 
       
    63 	IMPORT_C void SetHCTLInterface(MHCTLInterface& aHctlInterface);
       
    64 	IMPORT_C void SetHCICommandAllocator(MHCICommandAllocator& aCommandAllocator);
       
    65 	IMPORT_C void SetLinkMuxNotifier(MLinkMuxNotifier& aLinkMuxer);
       
    66 	IMPORT_C void SetHCIUnmatchedEventObserver(MHCICommandQueueClient& aUnmatchedEventObserver);
       
    67 	IMPORT_C void SetHardResetInitiator(MHardResetInitiator& aHardResetInitiator);
       
    68 	IMPORT_C void SetPhysicalLinksState(const MPhysicalLinksState& aStackInfo);
       
    69 											 
       
    70 	IMPORT_C void Initialise();
       
    71 	IMPORT_C void Reset();
       
    72 	IMPORT_C void Start();
       
    73 	IMPORT_C void DoSend();
       
    74 
       
    75 public: // un-exported virtuals from MHCITimerClient
       
    76 	virtual void CompletionTimeoutFired(TUint aUncompletedCmdId);
       
    77 	virtual void StarvationTimeoutFired(TUint aWasNextPendingCmdId);
       
    78 	
       
    79 public: // virtuals from MHCICommandQueue
       
    80 	virtual TUint MhcqAddCommandL(CHCICommandQItem* aQueItem);
       
    81 	virtual TUint MhcqAddCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient);
       
    82 	virtual TUint MhcqAddPriorityCommandL(CHCICommandQItem* aQueItem);
       
    83 	virtual TUint MhcqAddPriorityCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient);
       
    84 	virtual TUint MhcqAddInitCommandL(CHCICommandQItem* aQueItem);
       
    85 	virtual TUint MhcqAddInitCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient);
       
    86 	virtual TInt  MhcqRemoveCommand(TUint aCommandId, const MHCICommandQueueClient& aCmdOriginator);
       
    87 	virtual void  MhcqRemoveAllCommands(const MHCICommandQueueClient& aCmdOriginator);
       
    88 	virtual TUint MhcqMaxHciCommandTimeout() const;
       
    89 	virtual TAny* MhcqQdpPluginInterface(TUid aUid) const;
       
    90 		
       
    91 private: // virtuals from MHCICommandEventObserver	
       
    92 	virtual void MhceoEventNotification(const THCIEventBase& aEvent);
       
    93 
       
    94 	// Helpers
       
    95 	void RemoveAllCommands(TDblQueIter<CHCICommandQItem> aIter,
       
    96 						   const MHCICommandQueueClient& aCmdOriginator,
       
    97 						   TBool aCanDelete);
       
    98 	void HandleCommandRemoval(CHCICommandQItem& aCmd, TBool aCanDelete);
       
    99 	void HandleCommandRemoval(CHCICommandQItem*& aCmd, TBool aCanDelete);
       
   100 	void CleanUpQueue(TDblQueIter<CHCICommandQItem> aIter);
       
   101 
       
   102 private: // virtuals from MHCICmdQueueUtilities
       
   103 	void MhcquiInjectEvent(const THCIEventBase& aEvent);
       
   104 	CHCICommandQItem* MhcquiFindOutstandingCommand(THCIOpcode aOpcode);
       
   105 	
       
   106 private:
       
   107 	/**
       
   108 	Command queue block bit flags.
       
   109 	*/
       
   110 	enum
       
   111 		{
       
   112 		ENoBlocks					= 0x00000000,
       
   113 		/**
       
   114 		Indicates that there is a workaround command on the sent
       
   115 		queue, so another command cannot be sent
       
   116 		*/
       
   117 		EWorkaroundBlock			= 0x00000001,
       
   118 
       
   119 		/**
       
   120 		Indicates the current head of the non-priority queues has been
       
   121 		blocked from MHCICmdQueueDecisionInterface::MhcqdiCanSend()
       
   122 		*/
       
   123 		ECanSendBlock				= 0x00000002,
       
   124 
       
   125 		/**
       
   126 		Indicates that the current head of the non-priority queues has the
       
   127 		same opcode as one on the sent queue.
       
   128 		*/
       
   129 		EDuplicatedOpcodeBlock		= 0x00000004,
       
   130 
       
   131 		/**
       
   132 		Indicates that the current head of the non-priority queues does not have
       
   133 		enough HCI credits.
       
   134 		*/
       
   135 		EInsufficientCreditBlock	= 0x00000008,
       
   136 
       
   137 		/**
       
   138 		Indicates that there is a resent command on the sent queue, so
       
   139 		another command cannot be resent.
       
   140 		*/
       
   141 		EResendBlock				= 0x00000010,
       
   142 
       
   143 		/**
       
   144 		Indicates that an HCTL send request
       
   145 		(MLinkMuxNotifier::TryToSend) is in progress, so another
       
   146 		command cannot be scheduled until we get a DoSend() callback.
       
   147 		*/
       
   148 		ETryToSendBlock				= 0x00000020,
       
   149 
       
   150 		EAllBlocks					= EWorkaroundBlock |
       
   151 									  ECanSendBlock |
       
   152 									  EDuplicatedOpcodeBlock |
       
   153 									  EInsufficientCreditBlock |
       
   154 									  EResendBlock | ETryToSendBlock,
       
   155 
       
   156 		/**
       
   157 		These three are different from the TryToSend, Resend and Workaround
       
   158 		blocks in that they only cache the effect of the last call to OkToSendCommand
       
   159 		for the most recently processed non-priority command. This means that
       
   160 		when they're all 0, OkToSendCommand needs to be called to re-evaluate
       
   161 		corresponding conditions.
       
   162 		*/
       
   163 		ECachingCommandBlocks		= ECanSendBlock |
       
   164 									  EDuplicatedOpcodeBlock |
       
   165 									  EInsufficientCreditBlock,
       
   166 
       
   167 		/**
       
   168 		Do not include the Resend block for any of the queues waiting to send a command
       
   169 		for the first time. Regardless of whether the Resend block is set we would need
       
   170 		a credit to send a command and if we get more than one credit (the first 
       
   171 		potentially being used by a resent command) then we should use them.
       
   172 		*/
       
   173 		ESendQueueBlocks			= EAllBlocks & ~EResendBlock,
       
   174 
       
   175 		/**
       
   176 		For the Resend queue we do not want to include the Workaround block as it maybe
       
   177 		a workaround command being resent.
       
   178 		*/
       
   179 		EResendQueueBlocks			= EAllBlocks & ~EWorkaroundBlock,
       
   180 		};
       
   181 
       
   182 	/**
       
   183 	Command queue controller state
       
   184 	*/
       
   185 	enum TCmdQControllerStates
       
   186 		{
       
   187 		/**
       
   188 		Power down state state. In this state no commands will be sent or queued.
       
   189 		Any attempt to queue a new command will fail.
       
   190 		
       
   191 		Reached on completion of async Reset() if in EResetting state.
       
   192 		*/
       
   193 		EUninitialised	= 0,
       
   194 		
       
   195 		/**
       
   196 		Asynchronous reset pending state.
       
   197 		
       
   198 		Reached by calling Reset().
       
   199 		*/
       
   200 		EResetting		= 1,
       
   201 
       
   202 		/**
       
   203 		Asynchronous reset pending state.
       
   204 		
       
   205 		Reached by calling Initialise() while async Reset() outstanding.
       
   206 		*/
       
   207 		EResetInit		= 2,
       
   208 		
       
   209 		/**
       
   210 		Initialisation state. In this state only initilisation commands will be 
       
   211 		sent, normal and priority commands are held on their queues.
       
   212 		
       
   213 		Reached by Initialise() or completion of async Reset() if in 
       
   214 		EResetInit state.
       
   215 		*/
       
   216 		EInitialising	= 3,
       
   217 		
       
   218 		/**
       
   219 		Operational state.
       
   220 		
       
   221 		Reached by calling Start().
       
   222 		*/
       
   223 		EStarted		= 4,
       
   224 		};
       
   225 
       
   226 	CHCICmdQController();
       
   227 	void ConstructL();
       
   228 	
       
   229 	inline TBool Blocked(TUint aBlocksToCheck, TUint aBlocksToBypass);
       
   230 	inline TBool Blocked(TUint aBlockStatus, TUint aBlocksToCheck, TUint aBlocksToBypass);
       
   231 	inline void	ClearBlock(TUint aBlocks);
       
   232 	inline void	SetBlock(TUint aBlocks);
       
   233 	inline TUint ValidBlocks(TUint aBlocks);
       
   234 	inline TUint InvalidBlocks(TUint aBlocks);
       
   235 	inline TUint CmdBypassBlocks(const CHCICommandQItem& aCmd);
       
   236 	
       
   237 	inline void UpdateCommandCredits(TUint8 aCommandCredits);
       
   238 
       
   239 	inline TUint NextCommandQueueItemId();
       
   240 	
       
   241 	inline TDblQue<CHCICommandQItem>* ActiveRegularQueue();
       
   242 	inline CHCICommandQItem* FirstQueueItem(TDblQue<CHCICommandQItem>& aQueue);
       
   243 	inline CHCICommandQItem* LastQueueItem(TDblQue<CHCICommandQItem>& aQueue);
       
   244 
       
   245 	inline void StorePurgeMarks();
       
   246 	inline void PurgeAllQueues();
       
   247 	void PurgeQueue(TDblQue<CHCICommandQItem>& aQueue, CHCICommandQItem* aMark);
       
   248 	
       
   249 	inline CHCICommandQItem* ScanQueueByOpcode(TDblQue<CHCICommandQItem>& aQueue, THCIOpcode aOpcode);
       
   250 	inline CHCICommandQItem* ScanQueueByQId(TDblQue<CHCICommandQItem>& aQueue, TUint aCmdId);
       
   251 #ifdef _DEBUG
       
   252 	void LogQueue(TDblQue<CHCICommandQItem>& aQueue);
       
   253 #endif // _DEBUG
       
   254 
       
   255 	inline TBool CanAddCommands();
       
   256 	inline TBool CmdsQueued(TDblQue<CHCICommandQItem>* aQueue);
       
   257 	inline TBool AnyCmdsToSend();
       
   258 	inline TDblQue<CHCICommandQItem>* QueueSendingNext();
       
   259 	inline TBool NextCommandChanged(const TDblQue<CHCICommandQItem> &aQueue);
       
   260 
       
   261 	void DoReset();
       
   262 	void TryToSend();
       
   263 	TBool ProcessResendQueue();
       
   264 	TBool ProcessWorkaroundQueue();
       
   265 	TBool ProcessPriorityQueue();
       
   266 	void ProcessRegularQueue(TDblQue<CHCICommandQItem>& aQueue);
       
   267 		
       
   268 	void SetUpNextWorkaroundCmd(CHCICommandQItem* aPreviousCmd, const THCIEventBase* aPreviousCmdResult);
       
   269 	void UpdateStarvationTimer();
       
   270 
       
   271 	TUint DoAddCommandL(CHCICommandQItem& aQueItem,	TDblQue<CHCICommandQItem> &aQueue, TCmdQControllerStates aActiveState);
       
   272 	void DeleteCommand(CHCICommandQItem* &aItem);
       
   273 	TBool OkToSendCommand(CHCICommandQItem*& aCmdQItem, TUint aBypassBlocks);
       
   274 	void SendCommand(CHCICommandQItem& aCmdQItem);
       
   275 		
       
   276 	void ProcessMatchedEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool aConcludesCmd);
       
   277 	void ProcessMatchedErrorEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool aConcludesCmd, TBool aSendToQdp);
       
   278 	void ProcessUnmatchedEvent(const THCIEventBase& aEvent, TBool aSendToQdp);
       
   279 	void ProcessCommandCompletionTimeout(CHCICommandQItem* aCmd);
       
   280 	void ProcessEvent(const THCIEventBase& aEvent, TBool aSendToQdp);
       
   281 
       
   282 	// Static async CallBack methods.
       
   283 	static TInt AsyncCallBackForReset(TAny* aCmdQController);
       
   284 	static TInt AsyncCallBackForSend(TAny* aCmdQController);
       
   285 
       
   286 private:
       
   287 	TUint iMaxHciCommandTimeout;
       
   288 	TUint iQueueStarvationTimeout;
       
   289 
       
   290 	const static TUint KDefaultMaxHciCommandTimeout = 60000; // 60 seconds.
       
   291 	
       
   292 	MLinkMuxNotifier*				iLinkMuxer;
       
   293 	MHCICommandQueueClient*			iUnmatchedEventObserver;
       
   294 	MHCTLInterface*					iHctl;
       
   295 	MHardResetInitiator*			iHardResetInitiator;
       
   296 	MHCICommandAllocator*			iCommandAllocator;
       
   297 	MHCICmdQueueDecisionInterface*	iQdp;
       
   298 	MHCICmdQueueEventModifierInterface*	iQdpEventModifier;
       
   299 	
       
   300 	/**
       
   301 	This timer gets reset every time the next command to send changes.
       
   302 	If that command stays the same for too long, we probably have a deadlock of some sorts.
       
   303 	*/
       
   304 	CHCICmdQStarvationTimer*		iQStarvationTimer;
       
   305 	
       
   306 	/**
       
   307 	The queue of initialisation commands that have not yet been processed.
       
   308 	*/
       
   309 	TDblQue<CHCICommandQItem>		iInitCommandQ;
       
   310 	
       
   311 	/**
       
   312 	The queue of normal commands that have not yet been processed.
       
   313 	*/
       
   314 	TDblQue<CHCICommandQItem>		iNormalCommandQ;
       
   315 
       
   316 	/**
       
   317 	The queue of priority commands that have not yet been processed.
       
   318 	Note: it's not FIFO - the order of execution of commands is determined
       
   319 	dynamically.
       
   320 	*/
       
   321 	TDblQue<CHCICommandQItem>		iPriorityCommandQ;
       
   322 
       
   323 	/**
       
   324 	The queue of workarounds for commands on the other queues.
       
   325 	A command is moved here when time comes to execute it but QDP deems it to
       
   326 	be in need of workaround.
       
   327 	*/
       
   328 	TDblQue<CHCICommandQItem>		iWorkaroundCommandQ;
       
   329 
       
   330 	/**
       
   331 	The queue of commands that have been sent to the controller but have not
       
   332 	yet had a response.
       
   333 	*/
       
   334 	TDblQue<CHCICommandQItem>		iSentCommandQ;
       
   335 	
       
   336 	/**
       
   337 	The queue of commands that are waiting to be re-sent to the controller.
       
   338 	*/
       
   339 	TDblQue<CHCICommandQItem>		iResendCommandQ;
       
   340 
       
   341 
       
   342 	/**
       
   343 	Recorded tails of the queues for Reset processing.
       
   344 	*/
       
   345 	CHCICommandQItem*				iInitQPurgeMark;
       
   346 	CHCICommandQItem*				iNormalQPurgeMark;
       
   347 	CHCICommandQItem*				iPriorityQPurgeMark;
       
   348 	CHCICommandQItem*				iWorkaroundQPurgeMark;
       
   349 	
       
   350 	/**
       
   351 	Currently processing send command. This is maintained to ensure both that the 
       
   352 	correct command is processed by DoSend, and that there is only ever one outstanding 
       
   353 	call to MLinkMuxNotifier::TryToSend at any given time
       
   354 	*/
       
   355 	CHCICommandQItem*				iSendingCommand;
       
   356 
       
   357 	/**
       
   358 	Currently processing parent command. This is maintained to simplify priority
       
   359 	command processing while a workaround is in progress, and to ensure that 
       
   360 	the parent's iQdpData is available to the QDP until the workaround completes.
       
   361 	*/
       
   362 	CHCICommandQItem*				iParentCommand;
       
   363 	
       
   364 	/**
       
   365 	Number of HCI command packets the queue controller can send to the HCI. This
       
   366 	corresponds to the Num_HCI_Command_Packets event parameter. This is decremented
       
   367 	whenever a command is sent to the HCTL, and is updated on receipt of Command Status
       
   368 	and Command Complete (including NOP) events.
       
   369 	*/
       
   370 	TUint8							iCommandCredits;
       
   371 	
       
   372 	/**
       
   373 	The CHCICmdQController state variable
       
   374 	*/
       
   375 	TCmdQControllerStates			iCmdQControllerState;
       
   376 	
       
   377 	/**
       
   378 	This is a bit mask of the possible TQueueStateBits states
       
   379 	*/
       
   380 	TUint							iCommandQState;
       
   381 	
       
   382 	/**
       
   383 	The QDP that the Command Queue will use.
       
   384 	*/
       
   385 	CHCICmdQueueDecisionPlugin*		iQdpPlugin;
       
   386 
       
   387 	/**
       
   388 	A counter generating IDs to uniquely identify commands.
       
   389 	*/
       
   390 	TUint							iNextCommandQItemId;
       
   391 	
       
   392 	/**
       
   393 	HCI Utility library
       
   394 	*/
       
   395 	CHciUtil* iHciUtil;
       
   396 	
       
   397 	/**
       
   398 	Async Callbacks
       
   399 	*/
       
   400 	CAsyncCallBack* iAsyncCallBackForReset;
       
   401 	CAsyncCallBack* iAsyncCallBackForSend;
       
   402 
       
   403 	};
       
   404 
       
   405 #endif // HCICMDQCONTROLLER_H