bthci/bthci2/hcicmdq/src/HciCmdQController.cpp
changeset 0 29b1cd4cb562
child 16 9f17f914e828
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  @internalComponent
       
    19 */
       
    20 
       
    21 #include <bluetooth/hcicmdqcontroller.h>
       
    22 #include <bluetooth/hci/hciconsts.h>
       
    23 
       
    24 #include "HciCmdQTimer.h"
       
    25 #include "HciCmdQUtil.h"
       
    26 
       
    27 #include <bluetooth/hardresetinitiator.h>
       
    28 #include <bluetooth/hcicommandqitem.h>
       
    29 #include <bluetooth/hcicommandqueueclient.h>
       
    30 #include <bluetooth/linkmuxnotifier.h>
       
    31 #include <bluetooth/hci/commandstatusevent.h>
       
    32 #include <bluetooth/hci/event.h>
       
    33 #include <bluetooth/hci/commandcompleteevent.h>
       
    34 #include <bluetooth/hci/hcicmdqueuedecisionplugin.h>
       
    35 #include <bluetooth/hci/hcicmdqueuedecisioninterface.h>
       
    36 #include <bluetooth/hci/hciframe.h>
       
    37 #include <bluetooth/hci/hctlinterface.h>
       
    38 #include <bluetooth/hci/hciutil.h>
       
    39 #include <bluetooth/hci/command.h>
       
    40 #include <bluetooth/hci/hcievents.h>
       
    41 #include <bluetooth/hci/completingeventquery.h>
       
    42 
       
    43 #include <bluetooth/logger.h>
       
    44 
       
    45 #ifdef __FLOG_ACTIVE
       
    46 _LIT8(KLogComponent, LOG_COMPONENT_HCICMDQ);
       
    47 #endif
       
    48 
       
    49 #ifdef _DEBUG
       
    50 PANICCATEGORY("hcicmdqcon");
       
    51 #endif
       
    52 
       
    53 _LIT(KHciCommandQueueComponentName, "cmdq");
       
    54 
       
    55 EXPORT_C void MHCICmdQueueUtilities::InjectEvent(const THCIEventBase& aEvent)
       
    56 	{
       
    57 	MhcquiInjectEvent(aEvent);
       
    58 	}
       
    59 
       
    60 EXPORT_C CHCICommandQItem* MHCICmdQueueUtilities::FindOutstandingCommand(THCIOpcode aOpcode)
       
    61 	{
       
    62 	return MhcquiFindOutstandingCommand(aOpcode);
       
    63 	}
       
    64 
       
    65 EXPORT_C /*static*/ CHCICmdQController* CHCICmdQController::NewL()
       
    66 	{
       
    67 	LOG_STATIC_FUNC
       
    68 
       
    69 	CHCICmdQController* self = new (ELeave) CHCICmdQController();
       
    70 	CleanupStack::PushL(self);
       
    71 	self->ConstructL();
       
    72 	CleanupStack::Pop(self);
       
    73 	return self;
       
    74 	}
       
    75 
       
    76 /**
       
    77 Destructor.
       
    78 */
       
    79 EXPORT_C CHCICmdQController::~CHCICmdQController()
       
    80 	{
       
    81 	LOG_FUNC
       
    82 
       
    83 	// All (entry point) command queue clients should have removed any commands they added.
       
    84 #if defined(_DEBUG) && defined(__FLOG_ACTIVE)
       
    85 	// In debug to help debugging by logging the commands left on the queues that should be empty.
       
    86 	if(!iInitCommandQ.IsEmpty())
       
    87 		{
       
    88 		LOG(_L("Initialisation Queue is not empty..."))
       
    89 		LogQueue(iInitCommandQ);
       
    90 		}
       
    91 	if(!iNormalCommandQ.IsEmpty())
       
    92 		{
       
    93 		LOG(_L("Normal Queue is not empty..."))
       
    94 		LogQueue(iNormalCommandQ);
       
    95 		}
       
    96 	if(!iPriorityCommandQ.IsEmpty())
       
    97 		{
       
    98 		LOG(_L("Priority Queue is not empty..."))
       
    99 		LogQueue(iPriorityCommandQ);
       
   100 		}
       
   101 	if(!iWorkaroundCommandQ.IsEmpty())
       
   102 		{
       
   103 		LOG(_L("Workaround Queue is not empty..."))
       
   104 		LogQueue(iWorkaroundCommandQ);
       
   105 		}
       
   106 #endif // _DEBUG && __FLOG_ACTIVE
       
   107 	__ASSERT_ALWAYS(iInitCommandQ.IsEmpty(), PANIC(KHCICmdQPanic, EInitCommandQNotEmptyInDestructor));
       
   108 	__ASSERT_ALWAYS(iNormalCommandQ.IsEmpty(), PANIC(KHCICmdQPanic, ENormalCommandQNotEmptyInDestructor));
       
   109 	__ASSERT_ALWAYS(iPriorityCommandQ.IsEmpty(), PANIC(KHCICmdQPanic, EPriorityCommandQNotEmptyInDestructor));
       
   110 	__ASSERT_ALWAYS(iWorkaroundCommandQ.IsEmpty(), PANIC(KHCICmdQPanic, EWorkaroundCommandQNotEmptyInDestructor));
       
   111 	
       
   112 	// Clean up internally managed queues
       
   113 	TDblQueIter<CHCICommandQItem> sentIter(iSentCommandQ);
       
   114 	CleanUpQueue(sentIter);
       
   115 	TDblQueIter<CHCICommandQItem> resendIter(iResendCommandQ);
       
   116 	CleanUpQueue(resendIter);
       
   117 
       
   118 	__ASSERT_ALWAYS(iSentCommandQ.IsEmpty(), PANIC(KHCICmdQPanic, ESentCommandQNotEmptyInDestructor));
       
   119 	__ASSERT_ALWAYS(iResendCommandQ.IsEmpty(), PANIC(KHCICmdQPanic, EResendCommandQNotEmptyInDestructor));
       
   120 		
       
   121 	delete iQStarvationTimer;
       
   122 	delete iSendingCommand;
       
   123 	delete iQdpPlugin;
       
   124 
       
   125 	// Delete async CallBacks.	If running, these should be cancelled by the
       
   126 	// d'tor of CAsyncOneShot.
       
   127 	delete iAsyncCallBackForReset;
       
   128 	delete iAsyncCallBackForSend;
       
   129 
       
   130 	delete iHciUtil;
       
   131 	CLOSE_LOGGER
       
   132 	}
       
   133 
       
   134 /**
       
   135 Sets the HCTL interface instance to be used by the Command Queue Controller to
       
   136 send command frames over the HCTL.
       
   137 
       
   138 @param aHctlInterface An instance implementing the interface to the HCTL.
       
   139 */
       
   140 EXPORT_C void CHCICmdQController::SetHCTLInterface(MHCTLInterface& aHctlInterface)
       
   141 	{
       
   142 	LOG_FUNC
       
   143 	__ASSERT_DEBUG(!iHctl, PANIC(KHCICmdQPanic, EHctlInterfaceInitialisedTwice));
       
   144 	iHctl = &aHctlInterface;
       
   145 	}
       
   146 
       
   147 /**
       
   148 Sets the HCI Command Allocator interface instance to be used by the Command Queue 
       
   149 Controller to create HCI command frames.
       
   150 
       
   151 @param aCommandAllocator Implementation of command allocator interface.
       
   152 */
       
   153 EXPORT_C void CHCICmdQController::SetHCICommandAllocator(MHCICommandAllocator& aCommandAllocator)
       
   154 	{
       
   155 	LOG_FUNC
       
   156 	__ASSERT_DEBUG(!iCommandAllocator, PANIC(KHCICmdQPanic, EHciCommandAllocatorInterfaceInitialisedTwice));
       
   157 	iCommandAllocator = &aCommandAllocator;
       
   158 	}
       
   159 
       
   160 /**
       
   161 Sets the Link Mux Notifier interface instance to be used by the Command Queue 
       
   162 Controller to provide co-ordinated sending to the HCTL.
       
   163 
       
   164 @param aLinkMuxer An instance implementing the interface to the Link Muxer.
       
   165 */
       
   166 EXPORT_C void CHCICmdQController::SetLinkMuxNotifier(MLinkMuxNotifier& aLinkMuxer)
       
   167 	{
       
   168 	LOG_FUNC
       
   169 	__ASSERT_DEBUG(!iLinkMuxer, PANIC(KHCICmdQPanic, ELinkMuxNotifierInitialisedTwice));	
       
   170 	iLinkMuxer = &aLinkMuxer;
       
   171 	}
       
   172 
       
   173 /**
       
   174 Sets the command queue client that will subsequently receive unmatched events.
       
   175 	
       
   176 @param aUnmatchedEventObserver An instance implementing the command queue client interface.
       
   177 */
       
   178 EXPORT_C void CHCICmdQController::SetHCIUnmatchedEventObserver(MHCICommandQueueClient& aUnmatchedEventObserver)
       
   179 	{
       
   180 	LOG_FUNC
       
   181 	__ASSERT_DEBUG(!iUnmatchedEventObserver, PANIC(KHCICmdQPanic, EUnmatchedEventObserverInitialisedTwice));	
       
   182 	iUnmatchedEventObserver = &aUnmatchedEventObserver;
       
   183 	}
       
   184 
       
   185 /**
       
   186 Sets the Hard Reset Initiator interface instance to be used by the QDP. 
       
   187 This will allow the QDP to request a Hard Reset.
       
   188 
       
   189 @param aHardResetInitiator An instance implementing the interface to the Hard Reset Initiator.
       
   190 */
       
   191 EXPORT_C void CHCICmdQController::SetHardResetInitiator(MHardResetInitiator& aHardResetInitiator)
       
   192 	{
       
   193 	LOG_FUNC
       
   194 	__ASSERT_DEBUG(!iHardResetInitiator, PANIC(KHCICmdQPanic, EHardResetInitiatorInitialisedTwice));	
       
   195 	iHardResetInitiator = &aHardResetInitiator;
       
   196 	iQdp->MhcqdiSetHardResetInitiator(aHardResetInitiator);
       
   197 	}
       
   198 
       
   199 /**
       
   200 Sets the physical links state interface instance to be used by the QDP to query the state of
       
   201 physical links in the stack..
       
   202 
       
   203 @param aStackInfo An instance implementing the interface to the physical links state information.
       
   204 */
       
   205 EXPORT_C void CHCICmdQController::SetPhysicalLinksState(const MPhysicalLinksState& aStackInfo)
       
   206 	{
       
   207 	LOG_FUNC
       
   208 	iQdp->MhcqdiSetPhysicalLinksState(aStackInfo);
       
   209 	}
       
   210 
       
   211 /**
       
   212 This allows the Command Queue to start accepting commands to be queued. Whilst
       
   213 in the Initialise state only Initialisation commands will be sent but other
       
   214 commands will be added to the Normal and Priority queues so they can be sent
       
   215 when we transition to the Started state.
       
   216 @see CHCICmdQController::Start
       
   217 */
       
   218 EXPORT_C void CHCICmdQController::Initialise()
       
   219 	{
       
   220 	LOG_FUNC
       
   221 	
       
   222 	// Can only enter the Initialising state from either the Uninitialised
       
   223 	// state or the Resetting state
       
   224 	switch(iCmdQControllerState)
       
   225 		{
       
   226 		case EUninitialised:
       
   227 			iCmdQControllerState = EInitialising;
       
   228 			break;
       
   229 			
       
   230 		case EResetting:
       
   231 			iCmdQControllerState = EResetInit;
       
   232 			break;
       
   233 		
       
   234 		default:
       
   235 			PANIC(KHCICmdQPanic, EInvalidStateTransition);
       
   236 			break;
       
   237 		};
       
   238 	}
       
   239 	
       
   240 /**
       
   241 Initiates an asynchronous request for reset processing on the command queue. 
       
   242 Asynchronous reset processing is performed by CHCICmdQController::DoReset(), to
       
   243 empty the command queue and perform any other tasks on the Command Queue when 
       
   244 the stack requests a sub-system reset. This will put the Command Queue into a 
       
   245 state where no commands can be sent until CHCICmdQController::Initialise() is 
       
   246 called.
       
   247 @see CHCICmdQController::Initialise
       
   248 */
       
   249 EXPORT_C void CHCICmdQController::Reset()
       
   250 	{
       
   251 	LOG_FUNC
       
   252 	
       
   253 	// Mark the tails of the queues.
       
   254 	StorePurgeMarks();
       
   255 	
       
   256 	// Stop the queue starvation timer and reset the priority insert point.
       
   257 	iQStarvationTimer->Cancel();
       
   258 
       
   259 	iCmdQControllerState = EResetting;
       
   260 
       
   261 	// Cancel the sending callback if it is currently active.
       
   262 	iAsyncCallBackForSend->Cancel();
       
   263 	
       
   264 	// Call async CallBack to initiate Reset processing.
       
   265 	iAsyncCallBackForReset->CallBack();
       
   266 	}
       
   267 
       
   268 /**
       
   269 Signals that the Stack has finished intialising the HCI, and that it is
       
   270 safe to send normal (non-initialisation) commands.
       
   271 Trying to add intialisation commands after this call will result in a panic.
       
   272 @see CHCICmdQController::Reset
       
   273 @panic EInvalidStateTransition if not in the initialising state.
       
   274 @panic EStartCalledWhenInitQNotEmpty if the method is called when the initialisation queue is not empty.
       
   275 @panic EObjectNotInitialised if not all inteface references have been populated.
       
   276 */
       
   277 EXPORT_C void CHCICmdQController::Start()
       
   278 	{
       
   279 	LOG_FUNC
       
   280 
       
   281 	// Can only enter the Started state from the Initialising state
       
   282 	__ASSERT_ALWAYS((iCmdQControllerState == EInitialising), PANIC(KHCICmdQPanic, EInvalidStateTransition));
       
   283 	__ASSERT_ALWAYS((iInitCommandQ.IsEmpty()), PANIC(KHCICmdQPanic, EStartCalledWhenInitQNotEmpty));
       
   284 	__ASSERT_ALWAYS(iHctl &&
       
   285 					iCommandAllocator &&
       
   286 					iLinkMuxer &&
       
   287 					iUnmatchedEventObserver &&
       
   288 					iHardResetInitiator, PANIC(KHCICmdQPanic, EObjectNotInitialised));
       
   289 
       
   290 	iCmdQControllerState = EStarted;
       
   291 	if(AnyCmdsToSend())
       
   292 		{
       
   293 		iAsyncCallBackForSend->CallBack();
       
   294 		}
       
   295 	}
       
   296 
       
   297 /**
       
   298 Called by CLinkMuxer only when the command sub-channel is open.
       
   299 This shall be as a result of this class calling MLinkMuxNotifier::TryToSend.
       
   300 Only one send should be sent during this function. If another command is suitable
       
   301 for sending then MLinkMuxNotifier::TryToSend should be called again to get 
       
   302 permission to do the sending.
       
   303 */
       
   304 EXPORT_C void CHCICmdQController::DoSend()
       
   305 	{
       
   306 	LOG_FUNC;
       
   307 
       
   308 	LOG1(_L("CHCICmdQController::DoSend() - iSendingCommand = 0x%08x"), iSendingCommand);
       
   309 
       
   310 	if(iSendingCommand)
       
   311 		{
       
   312 		// Format and send the command frame.  Operation cannot fail.
       
   313 		iSendingCommand->FormatFrame();
       
   314 		TInt err = iHctl->MhiWriteCommand(iSendingCommand->Frame().HCTLPayload());
       
   315 		LOG1(_L("CHCICmdQController::DoSend() - MhiWriteCommand, Err = %d"), err);
       
   316 
       
   317 		if(err == KErrNone)
       
   318 			{
       
   319 			// Increment the commands sent count.
       
   320 			iSendingCommand->CommandSent();
       
   321 
       
   322 			TUint consumed = iSendingCommand->Command().CreditsConsumed();
       
   323 			// Check if the vendor command has a completion event
       
   324 			MHCICompletingEventQuery* completingEventInterface = NULL;
       
   325 			err = iSendingCommand->Command().Extension_(KCompletingEventExpectUid, reinterpret_cast<TAny*&>(completingEventInterface), NULL);
       
   326 			if( (err == KErrNone && !completingEventInterface->MhceqCompletingEventExpected()) ||
       
   327 				(err == KErrNotSupported && consumed == 0))
       
   328 				{
       
   329 				// Certain commands (e.g. the Number of Host Complete Packets
       
   330 				// command) use no credits and do not normally return any
       
   331 				// event. In this case the command is not moved to the sent
       
   332 				// queue to prevent it from continually growing.
       
   333 				// This call will set iSendingCommand to NULL.
       
   334 				DeleteCommand(iSendingCommand);
       
   335 				}
       
   336 			else
       
   337 				{
       
   338 				// Decrement command credits, move the command to the sent queue and clear the send buffer.
       
   339 				__ASSERT_ALWAYS((consumed <= iCommandCredits),
       
   340 							    PANIC(KHCICmdQPanic, ECommandCreditsCountLessThanZero));
       
   341 				LOG2(_L("CHCICmdQController::DoSend() - iCommandCredits = %d,  consumed = %d"), iCommandCredits, consumed);
       
   342 
       
   343 				// If necessary start completion timer.
       
   344 				TUint timeout(iQdp->MhcqdiTimeoutRequired(*iSendingCommand));
       
   345 				__ASSERT_ALWAYS((timeout <= MhcqMaxHciCommandTimeout()),
       
   346 								PANIC(KHCICmdQPanic, ECommandTimeoutTooBig));
       
   347 
       
   348 				// If a timeout has been specified from the QDP start it.
       
   349 				if(timeout != MHCICmdQueueDecisionInterface::KNoTimeoutRequired)
       
   350 					{
       
   351 					iSendingCommand->StartCompletionTimer(timeout, *this);
       
   352 					}
       
   353 				
       
   354 				iCommandCredits -= consumed;
       
   355 				iSentCommandQ.AddLast(*iSendingCommand);
       
   356 				iSendingCommand = NULL;
       
   357 				}
       
   358 			}
       
   359 		else
       
   360 			{
       
   361 			// Failed to write the command.  Error the client.
       
   362 			if(iSendingCommand->Client())
       
   363 				{
       
   364 				iSendingCommand->Client()->MhcqcCommandErrored(err, &iSendingCommand->Command());
       
   365 				}
       
   366 			DeleteCommand(iSendingCommand); // This will also NULL iSendingCommand
       
   367 			}
       
   368 		}
       
   369 	// Clear the TryToSendBlock and reschedule if required.
       
   370 	ClearBlock(ETryToSendBlock);
       
   371 	if(AnyCmdsToSend())
       
   372 		{
       
   373 		iAsyncCallBackForSend->CallBack();
       
   374 		}
       
   375 	}
       
   376 
       
   377 /**
       
   378 This function is called when the timer for aUncompletedCmdId fires.
       
   379 @panic ETimedOutCommandError if aUncompletedCmdId does not exist on
       
   380 the sent queue.
       
   381 @param aUncompletedCmdId the ID of the uncompleted command.
       
   382 */
       
   383 void CHCICmdQController::CompletionTimeoutFired(TUint aUncompletedCmdId)
       
   384 	{
       
   385 	LOG_FUNC
       
   386 	
       
   387 	CHCICommandQItem* cmd = ScanQueueByQId(iSentCommandQ, aUncompletedCmdId);
       
   388 	__ASSERT_ALWAYS(cmd != NULL, PANIC(KHCICmdQPanic, ETimedOutCommandError));
       
   389 	
       
   390 	ProcessCommandCompletionTimeout(cmd);
       
   391  
       
   392 	if (AnyCmdsToSend())
       
   393 		{
       
   394 		iAsyncCallBackForSend->CallBack();
       
   395 		}
       
   396 	}
       
   397 
       
   398 /**
       
   399 @panic ECanSendDeadlock as a guard against a CanSend block deadlock in
       
   400 	   UDEB builds. In UREL builds,
       
   401 	   MHardResetInitiator::MhriStartHardReset will be called.
       
   402 @panic EResendDeadlock as a guard against a Resend block deadlock in
       
   403 	   UDEB builds. In UREL builds,
       
   404 	   MHardResetInitiator::MhriStartHardReset will be called.
       
   405 @panic EUnknownDeadlock as a guard against priority queue deadlock in
       
   406 	   UDEB builds, i.e. the priority queue hasn't changed at all.
       
   407 	   In UREL builds, MHardResetInitiator::MhriStartHardReset will be called.
       
   408 @param aNextPendingCmdId this was the ID of the next pending
       
   409 	   command when the timer was started. If this hasn't changed then
       
   410 	   panic / ResetCycle as above.
       
   411 */
       
   412 void CHCICmdQController::StarvationTimeoutFired(TUint __DEBUG_ONLY(aNextPendingCmdId))
       
   413 	{
       
   414 	LOG_FUNC
       
   415 
       
   416 #ifdef _DEBUG
       
   417 	// Check for possible dead-lock situation that can occur.
       
   418 	TDblQue<CHCICommandQItem>* queue = QueueSendingNext();
       
   419 	
       
   420 	if (queue)
       
   421 		{
       
   422 		if (queue != &iPriorityCommandQ)
       
   423 			{
       
   424 			CHCICommandQItem* cmd = queue->First();
       
   425 	
       
   426 			if (cmd->CommandQId() == aNextPendingCmdId)
       
   427 				{
       
   428 				if (Blocked(ECanSendBlock, ENoBlocks))
       
   429 					{
       
   430 					PANIC(KHCICmdQPanic, ECanSendDeadlock);
       
   431 					}
       
   432 				else if (Blocked(EResendBlock, ENoBlocks))
       
   433 					{
       
   434 					PANIC(KHCICmdQPanic, EResendDeadlock);
       
   435 					}
       
   436 				}
       
   437 			}
       
   438 		else if (aNextPendingCmdId == KInvalidCommandQueueItemId)
       
   439 			{
       
   440 			// This is priority queue, so we can't point to a single culprit.
       
   441 			// Apparently none of the commands on the queue could be sent.
       
   442 			PANIC(KHCICmdQPanic, EUnknownDeadlock);
       
   443 			}
       
   444 		}
       
   445 	
       
   446 	// Always assert in debug builds for starvation timer conditions.
       
   447 	// This may be removed when more is known about these scenarios.
       
   448 	__ASSERT_DEBUG(EFalse, PANIC(KHCICmdQPanic, EStarvationTimerFired));
       
   449 #endif
       
   450 
       
   451 	// Force possibly stale caching blocks to be recomputed.
       
   452 	ClearBlock(ECachingCommandBlocks);
       
   453 	
       
   454 	iHardResetInitiator->MhriStartHardReset();
       
   455 	}
       
   456 
       
   457 /** 
       
   458 Virtuals from MHCICommandQueue
       
   459 */
       
   460 
       
   461 /*virtual*/ TUint CHCICmdQController::MhcqAddCommandL(CHCICommandQItem* aQueItem)
       
   462 	{
       
   463 	LOG_FUNC	
       
   464 	__ASSERT_ALWAYS(aQueItem != NULL, PANIC(KHCICmdQPanic, EAttemptToAddNullCommand));
       
   465 
       
   466 	return DoAddCommandL(*aQueItem, iNormalCommandQ, EStarted);
       
   467 	}
       
   468 
       
   469 /*virtual*/ TUint CHCICmdQController::MhcqAddCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient)
       
   470 	{
       
   471 	LOG_FUNC
       
   472 	__ASSERT_ALWAYS(aCommandData != NULL, PANIC(KHCICmdQPanic, EAttemptToAddNullCommand));
       
   473 	__ASSERT_ALWAYS(iCommandAllocator != NULL, PANIC(KHCICmdQPanic, EObjectNotInitialised));
       
   474 
       
   475 	CHCICommandQItem* aQueItem = CHCICommandQItem::NewL(*iCommandAllocator, 
       
   476 														aCmdProgressRecipient, 
       
   477 														aCommandData);
       
   478 	return MhcqAddCommandL(aQueItem);
       
   479 	}
       
   480 
       
   481 /*virtual*/ TUint CHCICmdQController::MhcqAddPriorityCommandL(CHCICommandQItem* aQueItem)
       
   482 	{
       
   483 	LOG_FUNC
       
   484 	__ASSERT_ALWAYS(aQueItem != NULL, PANIC(KHCICmdQPanic, EAttemptToAddNullCommand));
       
   485 
       
   486 	return DoAddCommandL(*aQueItem, iPriorityCommandQ, EStarted);
       
   487 	}
       
   488 
       
   489 /*virtual*/ TUint CHCICmdQController::MhcqAddPriorityCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient)
       
   490 	{
       
   491 	LOG_FUNC
       
   492 	__ASSERT_ALWAYS(aCommandData != NULL, PANIC(KHCICmdQPanic, EAttemptToAddNullCommand));
       
   493 	__ASSERT_ALWAYS(iCommandAllocator != NULL, PANIC(KHCICmdQPanic, EObjectNotInitialised));
       
   494 	
       
   495 	CHCICommandQItem* aQueItem = CHCICommandQItem::NewL(*iCommandAllocator, 
       
   496 														aCmdProgressRecipient, 
       
   497 														aCommandData);
       
   498 	return MhcqAddPriorityCommandL(aQueItem);
       
   499 	}
       
   500 
       
   501 /*virtual*/ TUint CHCICmdQController::MhcqAddInitCommandL(CHCICommandQItem* aQueItem)
       
   502 	{
       
   503 	LOG_FUNC
       
   504 	__ASSERT_ALWAYS(aQueItem != NULL, PANIC(KHCICmdQPanic, EAttemptToAddNullCommand));
       
   505 	__ASSERT_ALWAYS((iCmdQControllerState != EStarted), PANIC(KHCICmdQPanic, EInitCmdAfterStart));
       
   506 
       
   507 	TUint ret = DoAddCommandL(*aQueItem, iInitCommandQ, EInitialising);
       
   508 	// Mark as an Initialisation command.
       
   509 	aQueItem->SetInitialisationCmd();
       
   510 	return ret;
       
   511 	}
       
   512 
       
   513 /*virtual*/ TUint CHCICmdQController::MhcqAddInitCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient)
       
   514 	{
       
   515 	LOG_FUNC
       
   516 	__ASSERT_ALWAYS(aCommandData != NULL, PANIC(KHCICmdQPanic, EAttemptToAddNullCommand));
       
   517 	__ASSERT_ALWAYS(iCommandAllocator != NULL, PANIC(KHCICmdQPanic, EObjectNotInitialised));
       
   518 
       
   519 	CHCICommandQItem* aQueItem = CHCICommandQItem::NewL(*iCommandAllocator, 
       
   520 														aCmdProgressRecipient, 
       
   521 														aCommandData);
       
   522 	return MhcqAddInitCommandL(aQueItem);
       
   523 	}
       
   524 
       
   525 /*virtual*/ TInt CHCICmdQController::MhcqRemoveCommand(TUint aCommandId,
       
   526 													   const MHCICommandQueueClient& aCmdOriginator)
       
   527 	{
       
   528 	LOG_FUNC
       
   529 
       
   530 	CHCICommandQItem* pendingCmd = NULL;
       
   531 	CHCICommandQItem* lockedCmd = NULL;
       
   532 	TInt retVal = KErrNotFound;
       
   533 	
       
   534 	pendingCmd = ScanQueueByQId(iNormalCommandQ, aCommandId);
       
   535 	if(!pendingCmd)
       
   536 		{
       
   537 		pendingCmd = ScanQueueByQId(iInitCommandQ, aCommandId);
       
   538 		if (!pendingCmd)
       
   539 			{
       
   540 			pendingCmd = ScanQueueByQId(iPriorityCommandQ, aCommandId);
       
   541 			if (!pendingCmd)
       
   542 				{
       
   543 				pendingCmd = ScanQueueByQId(iWorkaroundCommandQ, aCommandId);
       
   544 				if(!pendingCmd)
       
   545 					{
       
   546 					lockedCmd = ScanQueueByQId(iSentCommandQ, aCommandId);
       
   547 					if(!lockedCmd)
       
   548 						{
       
   549 						lockedCmd = ScanQueueByQId(iResendCommandQ, aCommandId);
       
   550 						}
       
   551 					}
       
   552 				}
       
   553 			}
       
   554 		}
       
   555 	
       
   556 	if(lockedCmd)
       
   557 		{
       
   558 		__ASSERT_ALWAYS(lockedCmd->Client() == &aCmdOriginator, PANIC(KHCICmdQPanic, ETryingToDeleteCommandNotOwned));
       
   559 		retVal = KErrLocked;
       
   560 		}
       
   561 	else if(pendingCmd && pendingCmd->IsParent())
       
   562 		{
       
   563 		__ASSERT_ALWAYS(pendingCmd->Client() == &aCmdOriginator, PANIC(KHCICmdQPanic, ETryingToDeleteCommandNotOwned));
       
   564 		retVal = KErrLocked;
       
   565 		}
       
   566 	else if(pendingCmd)
       
   567 		{
       
   568 		__ASSERT_ALWAYS(pendingCmd->Client() == &aCmdOriginator, PANIC(KHCICmdQPanic, ETryingToDeleteCommandNotOwned));
       
   569 		__ASSERT_ALWAYS(!pendingCmd->IsPreChild(), PANIC(KHCICmdQPanic, ETryingToDeletePreChildCommandById));
       
   570 		__ASSERT_ALWAYS(!pendingCmd->IsPostChild(), PANIC(KHCICmdQPanic, ETryingToDeletePostChildCommandById));		
       
   571 		DeleteCommand(pendingCmd);
       
   572 		retVal = KErrNone;
       
   573 		}
       
   574 
       
   575 	return retVal;
       
   576 	}
       
   577 
       
   578 void CHCICmdQController::HandleCommandRemoval(CHCICommandQItem*& aCmd, TBool aCanDelete)
       
   579 	{
       
   580 	LOG_FUNC
       
   581 	ASSERT_DEBUG(aCmd);
       
   582 	if(aCanDelete && !aCmd->IsParent())
       
   583 		{
       
   584 		// The client should never be the originator of child commands
       
   585 		__ASSERT_ALWAYS(!aCmd->IsPreChild(), PANIC(KHCICmdQPanic, ETryingToDeletePreChildCommand));
       
   586 		__ASSERT_ALWAYS(!aCmd->IsPostChild(), PANIC(KHCICmdQPanic, ETryingToDeletePostChildCommand));
       
   587 		DeleteCommand(aCmd);
       
   588 		}
       
   589 	else
       
   590 		{
       
   591 		aCmd->DetachClient();
       
   592 		}
       
   593 	}
       
   594 
       
   595 void CHCICmdQController::HandleCommandRemoval(CHCICommandQItem& aCmd, TBool aCanDelete)
       
   596 	{
       
   597 	LOG_FUNC
       
   598 	CHCICommandQItem* cmd = &aCmd;
       
   599 	HandleCommandRemoval(cmd, aCanDelete);
       
   600 	}
       
   601 
       
   602 void CHCICmdQController::RemoveAllCommands(TDblQueIter<CHCICommandQItem> aIter,
       
   603 											const MHCICommandQueueClient& aCmdOriginator,
       
   604 											TBool aCanDelete)
       
   605 	{
       
   606 	LOG_FUNC
       
   607 	
       
   608 	for (CHCICommandQItem* item(aIter++);item != NULL;item = aIter++)
       
   609 		{
       
   610 		if(item->Client() == &aCmdOriginator)
       
   611 			{
       
   612 			HandleCommandRemoval(*item, aCanDelete);
       
   613 			}
       
   614 		}
       
   615 	}
       
   616 
       
   617 /*virtual*/ void  CHCICmdQController::MhcqRemoveAllCommands(const MHCICommandQueueClient& aCmdOriginator)
       
   618 	{
       
   619 	LOG_FUNC
       
   620 
       
   621 	TDblQueIter<CHCICommandQItem> initIter(iInitCommandQ);
       
   622 	RemoveAllCommands(initIter, aCmdOriginator, ETrue);
       
   623 
       
   624 	TDblQueIter<CHCICommandQItem> normalIter(iNormalCommandQ);
       
   625 	RemoveAllCommands(normalIter, aCmdOriginator, ETrue);
       
   626 
       
   627 	TDblQueIter<CHCICommandQItem> priorityIter(iPriorityCommandQ);
       
   628 	RemoveAllCommands(priorityIter, aCmdOriginator, ETrue);
       
   629 
       
   630 	TDblQueIter<CHCICommandQItem> workaroundIter(iWorkaroundCommandQ);
       
   631 	RemoveAllCommands(workaroundIter, aCmdOriginator, ETrue);
       
   632 
       
   633 	TDblQueIter<CHCICommandQItem> sentIter(iSentCommandQ);
       
   634 	RemoveAllCommands(sentIter, aCmdOriginator, EFalse);
       
   635 
       
   636 	TDblQueIter<CHCICommandQItem> resendIter(iResendCommandQ);
       
   637 	RemoveAllCommands(resendIter, aCmdOriginator, EFalse);
       
   638 
       
   639 	if(iSendingCommand)
       
   640 		{
       
   641 		if(iSendingCommand->Client() == &aCmdOriginator)
       
   642 			{
       
   643 			HandleCommandRemoval(iSendingCommand, ETrue);
       
   644 			}
       
   645 		}
       
   646 	}
       
   647 
       
   648 void CHCICmdQController::CleanUpQueue(TDblQueIter<CHCICommandQItem> aIter)
       
   649 	{
       
   650 	LOG_FUNC
       
   651 	
       
   652 	for (CHCICommandQItem* item(aIter++);item != NULL;item = aIter++)
       
   653 		{
       
   654 		DeleteCommand(item);
       
   655 		}
       
   656 	}
       
   657 
       
   658 /*virtual*/ TUint CHCICmdQController::MhcqMaxHciCommandTimeout() const
       
   659 	{
       
   660 	LOG_FUNC
       
   661 	
       
   662 	return iMaxHciCommandTimeout;
       
   663 	}
       
   664 
       
   665 /*virtual*/ TAny* CHCICmdQController::MhcqQdpPluginInterface(TUid aUid) const
       
   666 	{
       
   667 	LOG_FUNC
       
   668 
       
   669 	__ASSERT_ALWAYS((aUid != TUid::Uid(KHCICmdQueueDecisionInterfaceUid))
       
   670 					&& (aUid != TUid::Uid(KHCICmdQueueDecisionEventModifierInterfaceUid)),
       
   671 					PANIC(KHCICmdQPanic, EIllegalRequestForQdpInterface));
       
   672 	return (iQdpPlugin) ? iQdpPlugin->Interface(aUid) : NULL;
       
   673 	}
       
   674 
       
   675 /** 
       
   676 Virtuals from MHCICommandEventObserver
       
   677 */
       
   678 
       
   679 /*virtual*/ void CHCICmdQController::MhceoEventNotification(const THCIEventBase& aEvent)
       
   680 	{
       
   681 	LOG_FUNC
       
   682 	
       
   683 	ProcessEvent(aEvent, ETrue);
       
   684 	}
       
   685 
       
   686 void CHCICmdQController::ProcessEvent(const THCIEventBase& aEvent, TBool aSendToQdp)
       
   687 	{
       
   688 	LOG_FUNC
       
   689 	
       
   690 	// Process command credits.
       
   691 	THCIEventCode eventCode(aEvent.EventCode());
       
   692 	if (eventCode == ECommandCompleteEvent)
       
   693 		{
       
   694 
       
   695 		const THCICommandCompleteEvent& event(THCICommandCompleteEvent::Cast(aEvent));
       
   696 		UpdateCommandCredits(event.NumHCICommandPackets());
       
   697 
       
   698 		if (event.CommandOpcode() == KNopOpcode)
       
   699 			{
       
   700 			// This is a special command complete event that does not
       
   701 			// complete an event. Command_Opcode, 0x0000 is a NOP, and
       
   702 			// can be used to change the number of outstanding HCI
       
   703 			// command packets that the Host can send before waiting.
       
   704 
       
   705 			// Nothing else to do for this event, so throw it away
       
   706 			return;
       
   707 			}
       
   708 		}
       
   709 	else if (eventCode == ECommandStatusEvent)
       
   710 		{
       
   711 		TCommandStatusEvent& event = TCommandStatusEvent::Cast(aEvent);
       
   712 		UpdateCommandCredits(event.NumHCICommandPackets());
       
   713 
       
   714 		if (event.CommandOpcode() == KNopOpcode)
       
   715 			{
       
   716 			// Same as above for NOP command complete event.
       
   717 			
       
   718 			// Nothing else to do for this event, so throw it away
       
   719 			return;
       
   720 			}
       
   721 		}
       
   722 
       
   723 	// Iterate through sent queue to try and match the event to a sent command.
       
   724 	CHCICommandQItem* cmd(0);
       
   725 	TDblQueIter<CHCICommandQItem> qIter(iSentCommandQ);
       
   726 	TBool matchesCmd(EFalse);
       
   727 	TBool concludesCmd(EFalse);
       
   728 	TBool continueMatching(EFalse);
       
   729 	TBool eventMatched(EFalse);
       
   730 
       
   731 	while ((qIter != NULL) && (!eventMatched || continueMatching))
       
   732 		{
       
   733 		cmd = qIter++;		
       
   734 		cmd->Command().Match(aEvent, matchesCmd, concludesCmd, continueMatching);
       
   735 		if (matchesCmd)
       
   736 			{
       
   737 			eventMatched = ETrue;
       
   738 			
       
   739 			// If the event concludes the command then remove it from the sent queue
       
   740 			if (concludesCmd)
       
   741 				{
       
   742 				cmd->iLink.Deque();
       
   743 				}
       
   744 			
       
   745 			if (aSendToQdp)
       
   746 				{
       
   747 				// Notify QDP.
       
   748 				if (iQdpEventModifier)
       
   749 					{
       
   750 					THCIEventCode origEventCode = aEvent.EventCode();
       
   751 					iQdpEventModifier->MhcqemiMatchedEventReceived(const_cast<THCIEventBase&>(aEvent), *cmd);
       
   752 					__ASSERT_ALWAYS(origEventCode == aEvent.EventCode(), PANIC(KHCICmdQPanic, EQdpTryingToChangeEventCode));
       
   753 					}
       
   754 				else
       
   755 					{
       
   756 					iQdp->MhcqdiMatchedEventReceived(aEvent, *cmd);
       
   757 					}
       
   758 				}
       
   759 		
       
   760 			// Process the matched event.
       
   761 			if (aEvent.ErrorCode() == EOK)
       
   762 				{
       
   763 				ProcessMatchedEvent(aEvent, cmd, concludesCmd);
       
   764 				}
       
   765 			else
       
   766 				{
       
   767 				ProcessMatchedErrorEvent(aEvent, cmd, concludesCmd, aSendToQdp);
       
   768 				}
       
   769 			}
       
   770 		}
       
   771 
       
   772 	if (!eventMatched)
       
   773 		{
       
   774 		// Process the unmatched event.
       
   775 		ProcessUnmatchedEvent(aEvent, aSendToQdp);
       
   776 		}
       
   777 	
       
   778 	// Reschedule if there are commands queued.
       
   779 	if (AnyCmdsToSend())
       
   780 		{
       
   781 		iAsyncCallBackForSend->CallBack();
       
   782 		}
       
   783 
       
   784 	}
       
   785 
       
   786 void CHCICmdQController::MhcquiInjectEvent(const THCIEventBase& aEvent)
       
   787 	{
       
   788 	LOG_FUNC
       
   789 	
       
   790 	ProcessEvent(aEvent, EFalse);
       
   791 	}
       
   792 
       
   793 CHCICommandQItem* CHCICmdQController::MhcquiFindOutstandingCommand(THCIOpcode aOpcode)
       
   794 	{
       
   795 	LOG_FUNC
       
   796 	
       
   797 	return ScanQueueByOpcode(iSentCommandQ, aOpcode);
       
   798 	}
       
   799 
       
   800 
       
   801 /**
       
   802 Constructor.
       
   803 */
       
   804 CHCICmdQController::CHCICmdQController()
       
   805   : iMaxHciCommandTimeout(KDefaultMaxHciCommandTimeout),
       
   806 	iQueueStarvationTimeout(2 * iMaxHciCommandTimeout),
       
   807 	iInitCommandQ(_FOFF(CHCICommandQItem,iLink)),
       
   808 	iNormalCommandQ(_FOFF(CHCICommandQItem,iLink)),
       
   809 	iPriorityCommandQ(_FOFF(CHCICommandQItem,iLink)),
       
   810 	iWorkaroundCommandQ(_FOFF(CHCICommandQItem,iLink)),
       
   811 	iSentCommandQ(_FOFF(CHCICommandQItem,iLink)),
       
   812 	iResendCommandQ(_FOFF(CHCICommandQItem,iLink)),
       
   813 	iCmdQControllerState(EUninitialised),
       
   814 	iNextCommandQItemId(1)
       
   815 
       
   816 	{
       
   817 	CONNECT_LOGGER
       
   818 	LOG_FUNC
       
   819 	}
       
   820 
       
   821 void CHCICmdQController::ConstructL()
       
   822 	{
       
   823 	LOG_FUNC
       
   824 
       
   825 	// Add Async Callbacks
       
   826 	TCallBack resetCallBack(AsyncCallBackForReset, this);
       
   827 
       
   828 	iAsyncCallBackForReset =
       
   829 		new (ELeave)CAsyncCallBack(resetCallBack, CActive::EPriorityStandard);
       
   830 
       
   831 	TCallBack startCallBack(AsyncCallBackForSend, this);
       
   832 
       
   833 	iAsyncCallBackForSend =
       
   834 		new (ELeave)CAsyncCallBack(startCallBack, CActive::EPriorityStandard);
       
   835 
       
   836 	iQStarvationTimer = CHCICmdQStarvationTimer::NewL();
       
   837 
       
   838 	// Create HCI Utility library
       
   839 	iHciUtil = CHciUtil::NewL(KHciCommandQueueComponentName);
       
   840 
       
   841 	// If we can't open the ini file then this will be treated in the same way
       
   842 	// as not reading a valid UID from the ini file.
       
   843 	TRAP_IGNORE(iHciUtil->OpenIniFileL());
       
   844 	
       
   845 	_LIT(KSection, "QDP");
       
   846 	_LIT(KQdpUidTag, "EcomUid");
       
   847 
       
   848 	TUid qdpImplUid = TUid::Null();
       
   849 	TRAPD(err, qdpImplUid = iHciUtil->GetUidFromFileL(KSection, KQdpUidTag));
       
   850 	
       
   851 	if (err == KErrNone)
       
   852 		{
       
   853 		// Valid UID found, load it
       
   854 		iQdpPlugin = CHCICmdQueueDecisionPlugin::NewL(qdpImplUid);
       
   855 		}
       
   856 	else
       
   857 		{
       
   858 		// No UID found in ini file, attempt to load single instance of 
       
   859 		// implementation
       
   860 		iQdpPlugin = CHCICmdQueueDecisionPlugin::NewL();
       
   861 		}
       
   862 
       
   863 	iQdp = reinterpret_cast<MHCICmdQueueDecisionInterface*>(iQdpPlugin->Interface(TUid::Uid(KHCICmdQueueDecisionInterfaceUid)));
       
   864 	iQdpEventModifier = reinterpret_cast<MHCICmdQueueEventModifierInterface*>(iQdpPlugin->Interface(TUid::Uid(KHCICmdQueueDecisionEventModifierInterfaceUid)));
       
   865 
       
   866 	MHCICmdQueueUtilityUser* qdpUtilityUser = reinterpret_cast<MHCICmdQueueUtilityUser*>(iQdpPlugin->Interface(TUid::Uid(KHCICmdQueueUtilityUserUid)));
       
   867 	
       
   868 	if (qdpUtilityUser)
       
   869 		{
       
   870 		qdpUtilityUser->MhcquuSetUtilitiesProvider(*this);
       
   871 		}
       
   872 	
       
   873 	// Read timeout values
       
   874 	_LIT(KMaxHciCommandTimeoutTag, "MaxHciCommandTimeout");
       
   875 	_LIT(KQueueStarvationTimeoutTag, "QueueStarvationTimeout");
       
   876 
       
   877 	// Don't worry if we cannot read timeouts from file, already initialised
       
   878 	// to default values
       
   879 	TRAP_IGNORE(iMaxHciCommandTimeout = iHciUtil->GetValueFromFileL(KSection, KMaxHciCommandTimeoutTag));
       
   880 	TRAP_IGNORE(iQueueStarvationTimeout = iHciUtil->GetValueFromFileL(KSection, KQueueStarvationTimeoutTag));
       
   881 	
       
   882 	__ASSERT_DEBUG(iMaxHciCommandTimeout < iQueueStarvationTimeout, PANIC(KHCICmdQPanic, EQStarvationTimerNotGreaterThanMaxCmdTimer));
       
   883 	iQdp->MhcqdiSetTimeouts(iQueueStarvationTimeout, iMaxHciCommandTimeout);
       
   884 	iQdp->MhcqdiSetHCICommandQueue(*this);
       
   885 
       
   886 	// Reset the QDP.
       
   887 	iCommandCredits = iQdp->MhcqdiReset();
       
   888 	}
       
   889 
       
   890 /**
       
   891 Tests for the specified TQueueStateBits block(s) being set.
       
   892 */		
       
   893 inline TBool CHCICmdQController::Blocked(TUint aBlocksToCheck, TUint aBlocksToBypass)
       
   894 	{
       
   895 	return Blocked(iCommandQState, aBlocksToCheck, aBlocksToBypass);
       
   896 	}
       
   897 
       
   898 /**
       
   899 Tests for the specified TQueueStateBits block(s) being set.
       
   900 */		
       
   901 inline TBool CHCICmdQController::Blocked(TUint aBlockStatus, TUint aBlocksToCheck, TUint aBlocksToBypass)
       
   902 	{
       
   903 	return (aBlockStatus & (ValidBlocks(aBlocksToCheck) & ValidBlocks(~aBlocksToBypass)));
       
   904 	}
       
   905 
       
   906 /**
       
   907 Clears the specified TQueueStateBits block(s).
       
   908 */
       
   909 inline void	CHCICmdQController::ClearBlock(TUint aBlocks)
       
   910 	{
       
   911 	__ASSERT_DEBUG(!InvalidBlocks(aBlocks), PANIC(KHCICmdQPanic, EIllegalBlock));
       
   912 	iCommandQState &= ValidBlocks(~aBlocks);
       
   913 	}
       
   914 	
       
   915 /**
       
   916 Sets the specified TQueueStateBits block(s).
       
   917 */
       
   918 inline void	CHCICmdQController::SetBlock(TUint aBlocks)
       
   919 	{
       
   920 	__ASSERT_DEBUG(!InvalidBlocks(aBlocks), PANIC(KHCICmdQPanic, EIllegalBlock));
       
   921 	iCommandQState |= ValidBlocks(aBlocks);
       
   922 	}
       
   923 	
       
   924 /**
       
   925 Masks out invalid TQueueStateBits block bit(s).
       
   926 */
       
   927 inline TUint CHCICmdQController::ValidBlocks(TUint aBlocks)
       
   928 	{
       
   929 	return (aBlocks & EAllBlocks);
       
   930 	}
       
   931 	
       
   932 /**
       
   933 Masks out valid TQueueStateBits block bit(s).
       
   934 */
       
   935 inline TUint CHCICmdQController::InvalidBlocks(TUint aBlocks)
       
   936 	{
       
   937 	return (aBlocks & ~EAllBlocks);
       
   938 	}
       
   939 
       
   940 /**
       
   941 Check for queue block bypass conditions. Currently the only such condition
       
   942 is to allow a non-credit consuming command (e.g. the Number of Host Complete
       
   943 Packets command) to bypass the insufficient credits block.
       
   944 */
       
   945 inline TUint CHCICmdQController::CmdBypassBlocks(const CHCICommandQItem& aCmd)
       
   946 	{
       
   947 	TUint bypassBlocks = ENoBlocks;
       
   948 	if (aCmd.Command().CreditsConsumed() == 0)
       
   949 		{
       
   950 		bypassBlocks |= EInsufficientCreditBlock;
       
   951 		}
       
   952 	return bypassBlocks;
       
   953 	}
       
   954 	
       
   955 /**
       
   956 Updates the command credits counter and maintains the EInsufficientCreditBlock
       
   957 */
       
   958 inline void CHCICmdQController::UpdateCommandCredits(TUint8 aCommandCredits)
       
   959 	{
       
   960 	iCommandCredits = aCommandCredits;
       
   961 	
       
   962 	if (iCommandCredits > 0)
       
   963 		{
       
   964 		// We clear block flags when sending priority commands, so there may be some
       
   965 		// commands blocked on insufficient credits, but the block flag not set
       
   966 		// anymore. Hence we want to schedule the callback irrespectably of the status
       
   967 		// of EInsufficientCreditBlock.
       
   968 		if (AnyCmdsToSend())
       
   969 			{
       
   970 			iAsyncCallBackForSend->CallBack();
       
   971 			}
       
   972 		ClearBlock(EInsufficientCreditBlock);
       
   973 		}
       
   974 	else
       
   975 		{
       
   976 		SetBlock(EInsufficientCreditBlock);	
       
   977 		}
       
   978 	}
       
   979 	
       
   980 /**
       
   981 Selects the active command queue (iNormalCommandQ or iInitCommandQ) based on
       
   982 current state.
       
   983 */
       
   984 inline TDblQue<CHCICommandQItem>* CHCICmdQController::ActiveRegularQueue()
       
   985 	{
       
   986 	if (iCmdQControllerState == EStarted)
       
   987 		{
       
   988 		return &iNormalCommandQ;
       
   989 		}
       
   990 	else if ((iCmdQControllerState == EResetInit) || (iCmdQControllerState == EInitialising))
       
   991 		{
       
   992 		return &iInitCommandQ;
       
   993 		}
       
   994 		
       
   995 	return NULL;
       
   996 	}
       
   997 
       
   998 /**
       
   999 Returns the pointer to the queue which contains the command that would be scheduled next.
       
  1000 Does not take the Resend queue into account.
       
  1001 */
       
  1002 TDblQue<CHCICommandQItem>* CHCICmdQController::QueueSendingNext()
       
  1003 	{
       
  1004 	if (!iWorkaroundCommandQ.IsEmpty())
       
  1005 		{
       
  1006 		// Workaround has highest priority (well, second to resend which we don't care about).
       
  1007 		return &iWorkaroundCommandQ;
       
  1008 		}
       
  1009 	else if ((iCmdQControllerState == EStarted) && !iPriorityCommandQ.IsEmpty())
       
  1010 		{
       
  1011 		// Priority comes after Workaround, but we look at it only in EStarted.
       
  1012 		return &iPriorityCommandQ;
       
  1013 		}
       
  1014 	else
       
  1015 		{
       
  1016 		// Normal or Initialisation or NULL, depending on the state we're in.
       
  1017 		return ActiveRegularQueue();
       
  1018 		}
       
  1019 	}
       
  1020 
       
  1021 /**
       
  1022 Returns the item at the head of the specified queue, or NULL if the queue is empty.
       
  1023 */	
       
  1024 inline CHCICommandQItem* CHCICmdQController::FirstQueueItem(TDblQue<CHCICommandQItem>& aQueue)
       
  1025 	{
       
  1026 	return (aQueue.IsEmpty() ? NULL : aQueue.First());
       
  1027 	}
       
  1028 
       
  1029 /**
       
  1030 Returns the item at the tail of the specified queue, or NULL if the queue is empty.
       
  1031 */	
       
  1032 inline CHCICommandQItem* CHCICmdQController::LastQueueItem(TDblQue<CHCICommandQItem>& aQueue)
       
  1033 	{
       
  1034 	return (aQueue.IsEmpty() ? NULL : aQueue.Last());
       
  1035 	}
       
  1036 	
       
  1037 /**
       
  1038 Saves the purge marks for the queues that need them. When a reset is performed,
       
  1039 the queues will be purged up to those marks.
       
  1040 */
       
  1041 void CHCICmdQController::StorePurgeMarks()
       
  1042 	{
       
  1043 	iInitQPurgeMark	 = LastQueueItem(iInitCommandQ);
       
  1044 	iNormalQPurgeMark = LastQueueItem(iNormalCommandQ);
       
  1045 	iPriorityQPurgeMark = LastQueueItem(iPriorityCommandQ);
       
  1046 	iWorkaroundQPurgeMark = LastQueueItem(iWorkaroundCommandQ);
       
  1047 	}
       
  1048 
       
  1049 /**
       
  1050 Purge the queues up to previously saved purge marks.
       
  1051 */
       
  1052 void CHCICmdQController::PurgeAllQueues()
       
  1053 	{
       
  1054 	// Purge the queues to the recorded tail markers.
       
  1055 	PurgeQueue(iInitCommandQ, iInitQPurgeMark);
       
  1056 	PurgeQueue(iNormalCommandQ, iNormalQPurgeMark);
       
  1057 	PurgeQueue(iPriorityCommandQ, iPriorityQPurgeMark);
       
  1058 	PurgeQueue(iWorkaroundCommandQ, iWorkaroundQPurgeMark);
       
  1059 	
       
  1060 	iInitQPurgeMark = iNormalQPurgeMark = iPriorityQPurgeMark = iWorkaroundQPurgeMark = NULL;
       
  1061 	
       
  1062 	// Purge the sent and resend queues entirely.
       
  1063 	PurgeQueue(iSentCommandQ, LastQueueItem(iSentCommandQ));
       
  1064 	PurgeQueue(iResendCommandQ, LastQueueItem(iResendCommandQ));
       
  1065 	}
       
  1066 
       
  1067 
       
  1068 /**
       
  1069 Removes and deletes items from the head of the queue up to and including the marked
       
  1070 item.
       
  1071 */	
       
  1072 void CHCICmdQController::PurgeQueue(TDblQue<CHCICommandQItem>& aQueue,
       
  1073 									CHCICommandQItem* aMark)
       
  1074 	{
       
  1075 	LOG_FUNC
       
  1076 
       
  1077 	// A null aMark implies that there are no commands to purge.
       
  1078 	if(aMark)
       
  1079 		{
       
  1080 		TDblQueIter<CHCICommandQItem> qIter(aQueue);
       
  1081 		TBool found = EFalse;
       
  1082 
       
  1083 		// Ensure that the mark is in the queue.
       
  1084 		while(qIter && !found)
       
  1085 			{
       
  1086 			if(aMark == qIter++)
       
  1087 				{
       
  1088 				found = ETrue;
       
  1089 				}
       
  1090 			}
       
  1091 
       
  1092 		// If the mark was found remove comands upto and including
       
  1093 		// the mark.
       
  1094 		if(found)
       
  1095 			{
       
  1096 			// Reset the queue iterator.
       
  1097 			qIter.SetToFirst();
       
  1098 			found = EFalse;
       
  1099 			CHCICommandQItem* item = NULL;
       
  1100 
       
  1101 			while(qIter && !found)
       
  1102 				{
       
  1103 				item = qIter++;
       
  1104 				if(item == aMark)
       
  1105 					{
       
  1106 					// Mark found.  Exit the loop after this element has been removed.
       
  1107 					found = ETrue;
       
  1108 					}
       
  1109 				DeleteCommand(item);
       
  1110 				}
       
  1111 			}
       
  1112 		}
       
  1113 	}
       
  1114 
       
  1115 /**
       
  1116 Returns the first item with the specified opcode which is closest to the head of the 
       
  1117 specified queue, or NULL if there is no such opcode on the queue.
       
  1118 */	
       
  1119 inline CHCICommandQItem* CHCICmdQController::ScanQueueByOpcode(TDblQue<CHCICommandQItem>& aQueue, THCIOpcode aOpcode)
       
  1120 	{
       
  1121 	LOG_FUNC
       
  1122 
       
  1123 	CHCICommandQItem* item = NULL;		
       
  1124 	TDblQueIter<CHCICommandQItem> qIter(aQueue);
       
  1125 	
       
  1126 	while (((item = qIter) != NULL) && (item->Command().Opcode() != aOpcode))
       
  1127 		{
       
  1128 		qIter++;
       
  1129 		}
       
  1130 	
       
  1131 	return item;
       
  1132 	}
       
  1133 
       
  1134 /**
       
  1135 Returns the item with the specified command queue ID from the specified queue, or NULL 
       
  1136 if there is no such command on the queue.
       
  1137 */
       
  1138 inline CHCICommandQItem* CHCICmdQController::ScanQueueByQId(TDblQue<CHCICommandQItem>& aQueue, TUint aCmdId)
       
  1139 	{
       
  1140 	LOG_FUNC
       
  1141 
       
  1142 	CHCICommandQItem* item = NULL;		
       
  1143 	TDblQueIter<CHCICommandQItem> qIter(aQueue);
       
  1144 	
       
  1145 	while (((item = qIter) != NULL) && (item->CommandQId() != aCmdId))
       
  1146 		{
       
  1147 		qIter++;
       
  1148 		}
       
  1149 	
       
  1150 	return item;
       
  1151 	}
       
  1152 
       
  1153 /**
       
  1154 Performs command queue EResetting state processing. EResetting state is
       
  1155 reached by a call to CHCICmdQController::Reset().
       
  1156 */	
       
  1157 void CHCICmdQController::DoReset()
       
  1158 	{
       
  1159 	LOG_FUNC
       
  1160 
       
  1161 	// Should only be reached if Reset has been called
       
  1162 	__ASSERT_ALWAYS((iCmdQControllerState == EResetInit) || 
       
  1163 					(iCmdQControllerState == EResetting), 
       
  1164 					PANIC(KHCICmdQPanic, EInvalidStateTransition));
       
  1165 
       
  1166 	// Delete the parent command of possibly ongoing workaround.
       
  1167 	// Wee need to do it here separately, because the command
       
  1168 	// is not reachable any other way if it's in post-workaround phase
       
  1169 	// - it's already been removed from its queue.
       
  1170 	DeleteCommand(iParentCommand);
       
  1171 
       
  1172 	PurgeAllQueues();
       
  1173 
       
  1174 	// Reset the QDP.
       
  1175 	iCommandCredits = iQdp->MhcqdiReset();
       
  1176 	
       
  1177 	// Delete any command waiting to be sent.
       
  1178 	DeleteCommand(iSendingCommand);
       
  1179 	
       
  1180 	// Clear the block flags and execute state transition.
       
  1181 	iCommandQState = 0;
       
  1182 	
       
  1183 	// Initialise could have been called during async break so check which
       
  1184 	// state we should move into
       
  1185 	if (iCmdQControllerState == EResetInit)
       
  1186 		{
       
  1187 		iCmdQControllerState = EInitialising;
       
  1188 		}
       
  1189 	else
       
  1190 		{
       
  1191 		// Acording to the ASSERT this must be EResetting
       
  1192 		iCmdQControllerState = EUninitialised;
       
  1193 		}
       
  1194 		
       
  1195 	// Reschedule if there are commands queued and we're ready to send.
       
  1196 	if ((iCmdQControllerState == EInitialising) && CmdsQueued(&iInitCommandQ))
       
  1197 		{
       
  1198 		iAsyncCallBackForSend->CallBack();
       
  1199 		}
       
  1200 	}
       
  1201 
       
  1202 /**
       
  1203 The main queue processing routine. Schedules the next command and asks
       
  1204 HCTL to send.
       
  1205 */
       
  1206 void CHCICmdQController::TryToSend()
       
  1207 	{
       
  1208 	LOG_FUNC
       
  1209 
       
  1210 	__ASSERT_DEBUG((iCmdQControllerState == EInitialising) || (iCmdQControllerState == EStarted),
       
  1211 				   PANIC(KHCICmdQPanic, ETryToSendWhileUnoperational));
       
  1212 	
       
  1213 	if ((iCmdQControllerState != EInitialising) && (iCmdQControllerState != EStarted))
       
  1214 		{
       
  1215 		// This is just a safety net. We shouldn't have been scheduled to run
       
  1216 		// if we're not ready. But even if we've been mistakenly scheduled or
       
  1217 		// the state changed in the meantime, this return makes it harmless.
       
  1218 		return;
       
  1219 		}
       
  1220 	
       
  1221 	TBool stopProcessing(ProcessResendQueue());
       
  1222 	if (!stopProcessing)
       
  1223 		{
       
  1224 		stopProcessing = ProcessWorkaroundQueue();
       
  1225 		if (!stopProcessing)
       
  1226 			{
       
  1227 			if (iCmdQControllerState == EStarted)
       
  1228 				{
       
  1229 				stopProcessing = ProcessPriorityQueue();
       
  1230 				}
       
  1231 			if (!stopProcessing)
       
  1232 				{
       
  1233 				TDblQue<CHCICommandQItem>* queue = ActiveRegularQueue();
       
  1234 				if (queue != NULL)
       
  1235 					{
       
  1236 					ProcessRegularQueue(*queue);
       
  1237 					}
       
  1238 				}
       
  1239 			}
       
  1240 		}
       
  1241 	}
       
  1242 
       
  1243 /**
       
  1244 Returns ETrue if our current state allows commands to be queued.
       
  1245 */
       
  1246 inline TBool CHCICmdQController::CanAddCommands()
       
  1247 	{
       
  1248 	switch (iCmdQControllerState)
       
  1249 		{
       
  1250 	case EStarted:
       
  1251 	case EResetInit:
       
  1252 	case EInitialising:
       
  1253 		return ETrue;
       
  1254 	default:
       
  1255 		return EFalse;
       
  1256 		}
       
  1257 	}
       
  1258 
       
  1259 /**
       
  1260 Tests if there are items queued on the specified queue.
       
  1261 */
       
  1262 inline TBool CHCICmdQController::CmdsQueued(TDblQue<CHCICommandQItem>* aQueue)
       
  1263 	{
       
  1264 	if (aQueue != NULL)
       
  1265 		{
       
  1266 		return (!aQueue->IsEmpty());
       
  1267 		}
       
  1268 	return EFalse;
       
  1269 	}
       
  1270 
       
  1271 /**
       
  1272 Tests if there are items queued on any of the queues active in current state.
       
  1273 */
       
  1274 inline TBool CHCICmdQController::AnyCmdsToSend()
       
  1275 	{
       
  1276 	TDblQue<CHCICommandQItem>* activeQ = ActiveRegularQueue();
       
  1277 
       
  1278 	// Need to check those two no matter which state we're in.
       
  1279 	TBool commonQueuesEmpty = iWorkaroundCommandQ.IsEmpty() && iResendCommandQ.IsEmpty();
       
  1280 
       
  1281 	if (activeQ == &iInitCommandQ)
       
  1282 		{
       
  1283 		return !iInitCommandQ.IsEmpty() || !commonQueuesEmpty;
       
  1284 		}
       
  1285 	else
       
  1286 		{
       
  1287 		return !iNormalCommandQ.IsEmpty() || !iPriorityCommandQ.IsEmpty() || !commonQueuesEmpty;
       
  1288 		}
       
  1289 	}
       
  1290 
       
  1291 /**
       
  1292 Returns the next Command Queue Item Id
       
  1293 */
       
  1294 inline TUint CHCICmdQController::NextCommandQueueItemId()
       
  1295 	{
       
  1296 	__ASSERT_DEBUG(iNextCommandQItemId != KInvalidCommandQueueItemId,
       
  1297 				   PANIC(KHCICmdQPanic, EInvalidCommandQueueItemId));
       
  1298 	iNextCommandQItemId++;
       
  1299 	if(iNextCommandQItemId == KInvalidCommandQueueItemId)
       
  1300 		{
       
  1301 		iNextCommandQItemId++;
       
  1302 		}
       
  1303 	return iNextCommandQItemId;
       
  1304 	}
       
  1305 	
       
  1306 /**
       
  1307 Processes the resend queue.
       
  1308 Returns ETrue if the scheduling loop shouldn't process lower priority queues
       
  1309 (which is when it schedules a command for resend) and EFalse if the loop should
       
  1310 go on.
       
  1311 */
       
  1312 TBool CHCICmdQController::ProcessResendQueue()
       
  1313 	{
       
  1314 	LOG_FUNC
       
  1315 
       
  1316 	if (!CmdsQueued(&iResendCommandQ))
       
  1317 		{
       
  1318 		return EFalse;
       
  1319 		}
       
  1320 	
       
  1321 	CHCICommandQItem* cmd = iResendCommandQ.First();
       
  1322 	TUint bypassBlocks = CmdBypassBlocks(*cmd);
       
  1323 	if (Blocked(EResendQueueBlocks, bypassBlocks))
       
  1324 		{
       
  1325 		// We're the highest priority queue, but allow the other queues to try
       
  1326 		// and send if we have commands queued but are blocked - "Only one
       
  1327 		// active resend at a time" is still fulfilled.
       
  1328 		return EFalse;
       
  1329 		}
       
  1330 
       
  1331 	if (OkToSendCommand(cmd, bypassBlocks))
       
  1332 		{
       
  1333 		// Process command.
       
  1334 		SendCommand(*cmd);
       
  1335 		SetBlock(EResendBlock);
       
  1336 		return ETrue;
       
  1337 		}
       
  1338 
       
  1339 	return EFalse;
       
  1340 	}
       
  1341 
       
  1342 /**
       
  1343 Processes the workaround queue.
       
  1344 Returns ETrue if the scheduling loop shouldn't process lower priority queues
       
  1345 (which is when the queue is non-empty) and EFalse if the loop should go on.
       
  1346 */
       
  1347 TBool CHCICmdQController::ProcessWorkaroundQueue()
       
  1348 	{
       
  1349 	LOG_FUNC
       
  1350 
       
  1351 	if (!CmdsQueued(&iWorkaroundCommandQ))
       
  1352 		{
       
  1353 		return EFalse;
       
  1354 		}
       
  1355 
       
  1356 	CHCICommandQItem* cmd = iWorkaroundCommandQ.First();
       
  1357 	switch (cmd->Type())
       
  1358 		{
       
  1359 	case CHCICommandQItem::EIndeterminate:
       
  1360 		// Start of workaround sequence, set up the first command.
       
  1361 		cmd->SetType(CHCICommandQItem::EParent);
       
  1362 		SetUpNextWorkaroundCmd(NULL, NULL);
       
  1363 		cmd = iWorkaroundCommandQ.First();
       
  1364 		UpdateStarvationTimer();
       
  1365 		break;
       
  1366 		
       
  1367 	case CHCICommandQItem::EPreChild:
       
  1368 	case CHCICommandQItem::EPostChild:
       
  1369 	case CHCICommandQItem::EParent:
       
  1370 		// In the middle of a workaround.
       
  1371 		// Nothing to do here really, command setup has been done by calling
       
  1372 		// SetUpNextWorkaroundCmd() in Process*Event on completion of the previous
       
  1373 		// command in the workaround sequence.
       
  1374 		break;
       
  1375 	
       
  1376 	default:
       
  1377 		__ASSERT_DEBUG(EFalse, PANIC(KHCICmdQPanic, EInvalidCmdQueueItemType));
       
  1378 		break;
       
  1379 		}
       
  1380 
       
  1381 #ifdef _DEBUG
       
  1382 	// We should only ever have at maximum one parent and one child on the 
       
  1383 	// workaround queue at any time.
       
  1384 	TDblQueIter<CHCICommandQItem> iter(iWorkaroundCommandQ);
       
  1385 	TUint count = 0;
       
  1386 	while(iter++)
       
  1387 		{
       
  1388 		count++;
       
  1389 		}
       
  1390 	__ASSERT_DEBUG(count <= 2, PANIC(KHCICmdQPanic, ETooManyItemsOnWorkaroundQueue));
       
  1391 #endif // _DEBUG
       
  1392 	
       
  1393 	// Now that we're sure we have pre-workaraound set up we can check blocks.
       
  1394 	TUint bypassBlocks = CmdBypassBlocks(*cmd);
       
  1395 	if (Blocked(ESendQueueBlocks, bypassBlocks))
       
  1396 		{
       
  1397 		// Don't allow lower priority queues to send until we're empty.
       
  1398 		return ETrue;
       
  1399 		}
       
  1400 	
       
  1401 	if (OkToSendCommand(cmd, bypassBlocks))
       
  1402 		{
       
  1403 		SendCommand(*cmd); 
       
  1404 		UpdateStarvationTimer();
       
  1405 		SetBlock(EWorkaroundBlock);
       
  1406 		}
       
  1407 
       
  1408 	// Don't allow lower priority queues to send until we're empty.
       
  1409 	return ETrue;
       
  1410 	}
       
  1411 
       
  1412 /**
       
  1413 Processes the priority queue.
       
  1414 Returns ETrue if the scheduling loop shouldn't process lower priority queues
       
  1415 (which is when the queue is non-empty) and EFalse if the loop should go on.
       
  1416 */
       
  1417 TBool CHCICmdQController::ProcessPriorityQueue()
       
  1418 	{
       
  1419 	LOG_FUNC
       
  1420 
       
  1421 	if (!CmdsQueued(&iPriorityCommandQ))
       
  1422 		{
       
  1423 		return EFalse;
       
  1424 		}
       
  1425 	else if (Blocked(ESendQueueBlocks, ECachingCommandBlocks))
       
  1426 		{
       
  1427 		// Check blocks excluding ECachingCommandBlocks
       
  1428 		// The blocks we're checking don't depend on particular commands, so we can
       
  1429 		// safely return here.
       
  1430 		// Don't allow lower priority queues to send until we're empty.
       
  1431 		return ETrue;
       
  1432 		}
       
  1433 
       
  1434 	// Search the queue for the first non-blocking command.
       
  1435 	// Note that this is still just heurisitics, because even if we find a non-blocking
       
  1436 	// command, it may still yield a blocking workaround.
       
  1437 	CHCICommandQItem* cmd = NULL;
       
  1438 	TDblQueIter<CHCICommandQItem> i(iPriorityCommandQ);
       
  1439 	while ((cmd = i++) != NULL)
       
  1440 		{
       
  1441 		// For every command we clear the cached blocks as they apply to the last command
       
  1442 		// we attempted to send, using OkToSendCommand. As the priority queue can send out
       
  1443 		// of order, i.e. not just the head command, the cached blocks need to be
       
  1444 		// re-evaluated for each command until we find the one we intend to send.
       
  1445 		ClearBlock(ECachingCommandBlocks);
       
  1446 		if (OkToSendCommand(cmd, CmdBypassBlocks(*cmd)))
       
  1447 			{
       
  1448 			// Found available command.
       
  1449 			if (iQdp->MhcqdiDoesCommandRequireWorkaround(*cmd))
       
  1450 				{
       
  1451 				// Start of workaround sequence.
       
  1452 				// Move onto the workaround queue and kick the scheduling loop.
       
  1453 				cmd->iLink.Deque();
       
  1454 				iWorkaroundCommandQ.AddLast(*cmd);
       
  1455 				iAsyncCallBackForSend->CallBack();
       
  1456 				}
       
  1457 			else
       
  1458 				{
       
  1459 				// Non-workaround.
       
  1460 				cmd->SetType(CHCICommandQItem::ENormal);
       
  1461 				SendCommand(*cmd);
       
  1462 				UpdateStarvationTimer();
       
  1463 				}
       
  1464 			break;
       
  1465 			}
       
  1466 		}
       
  1467 
       
  1468 	// At this point we are in one of the following states:
       
  1469 	//  - All priority commands are either blocked or have errored and been deleted in 
       
  1470 	//    OkToSendCommand. If any commands are errored then the scheduling loop will 
       
  1471 	//    also have been kick. 
       
  1472 	//  - A priority command has been added to the workaround queue and the scheduling 
       
  1473 	//    loop has been kick.
       
  1474 	//  - A priority command has been sent.
       
  1475 	//
       
  1476 	// In any one of these conditions we want to stop processing further queues so can
       
  1477 	// always return true.
       
  1478 	return ETrue;
       
  1479 	}
       
  1480 
       
  1481 /**
       
  1482 Processes a regular queue - normal or initialization command queue.
       
  1483 */
       
  1484 void CHCICmdQController::ProcessRegularQueue(TDblQue<CHCICommandQItem>& aQueue)
       
  1485 	{
       
  1486 	LOG_FUNC
       
  1487 
       
  1488 	if (!CmdsQueued(&aQueue))
       
  1489 		{
       
  1490 		return;
       
  1491 		}
       
  1492 
       
  1493 	CHCICommandQItem* cmd = aQueue.First();
       
  1494 	TUint bypassBlocks = CmdBypassBlocks(*cmd);
       
  1495 	if (Blocked(ESendQueueBlocks, bypassBlocks))
       
  1496 		{
       
  1497 		return;
       
  1498 		}
       
  1499 
       
  1500 	if (cmd->Type() == CHCICommandQItem::EIndeterminate)
       
  1501 		{
       
  1502 		// It's the first time we're looking into cmd. See if it needs a workaround.
       
  1503 		if (iQdp->MhcqdiDoesCommandRequireWorkaround(*cmd))
       
  1504 			{
       
  1505 			// Start of workaround sequence.
       
  1506 			// Move it onto the workaround queue and kick the scheduling loop.
       
  1507 			cmd->iLink.Deque();
       
  1508 			iWorkaroundCommandQ.AddLast(*cmd);
       
  1509 			iAsyncCallBackForSend->CallBack();
       
  1510 			
       
  1511 			return;
       
  1512 			}
       
  1513 		else
       
  1514 			{
       
  1515 			// Non-workaround.
       
  1516 			cmd->SetType(CHCICommandQItem::ENormal);
       
  1517 			}
       
  1518 		}
       
  1519 	if (OkToSendCommand(cmd, bypassBlocks))
       
  1520 		{
       
  1521 		SendCommand(*cmd); 
       
  1522 		UpdateStarvationTimer();
       
  1523 		}
       
  1524 	}
       
  1525 
       
  1526 /**
       
  1527 Process workaround related commands, and is invoked every time a
       
  1528 workaround completes.  As the QDP interface needs to be passed the
       
  1529 concluding event of each workaround command, and events are used
       
  1530 synchronously and have a limited lifetime, this means workaround
       
  1531 handling has to be done at the same time as the event processing.
       
  1532 
       
  1533 This processing ensures that the head of the workaround queue contains
       
  1534 the next command in the workaround. It also tidies up and deletes
       
  1535 commands as necessary. Child commands are deleted once their events
       
  1536 have been reported to the QDP. The parent command lives until the end
       
  1537 of the workaround.
       
  1538 */
       
  1539 void CHCICmdQController::SetUpNextWorkaroundCmd(CHCICommandQItem* aPreviousCmd,
       
  1540 												const THCIEventBase* aPreviousCmdResult)
       
  1541 	{
       
  1542 	LOG_FUNC
       
  1543 
       
  1544 	// Update blocks.
       
  1545 	ClearBlock(EWorkaroundBlock);
       
  1546 
       
  1547 	// Get parent
       
  1548 	if (iParentCommand == NULL)
       
  1549 		{
       
  1550 		iParentCommand = iWorkaroundCommandQ.First();
       
  1551 		}
       
  1552 
       
  1553 	__ASSERT_ALWAYS(iParentCommand, PANIC(KHCICmdQPanic, EObjectNotInitialised));
       
  1554 
       
  1555 	// Determine next command in the workaround sequence.
       
  1556 	CHCICommandQItem* child = NULL;
       
  1557 	CHCICommandQItem::TType type;
       
  1558 
       
  1559 	if (iParentCommand->SentCount() == 0)
       
  1560 		{
       
  1561 		child = iQdp->MhcqdiGetPreChildCommand(*iParentCommand, aPreviousCmd, aPreviousCmdResult);
       
  1562 		if (child != NULL)
       
  1563 			{
       
  1564 			// Pre-workaround.
       
  1565 			type = CHCICommandQItem::EPreChild;
       
  1566 			}
       
  1567 		else
       
  1568 			{
       
  1569 			// Transitioning to post-workaround.
       
  1570 			type = CHCICommandQItem::EParent;
       
  1571 			}
       
  1572 		}
       
  1573 	else
       
  1574 		{
       
  1575 		__ASSERT_ALWAYS(aPreviousCmd, PANIC(KHCICmdQPanic, EObjectNotInitialised));
       
  1576 		if (aPreviousCmd->Type() == CHCICommandQItem::EParent)
       
  1577 			{
       
  1578 			// Transitioning to post-workaround.
       
  1579 			child = iQdp->MhcqdiGetPostChildCommand(*iParentCommand, NULL, aPreviousCmdResult);
       
  1580 			}
       
  1581 		else
       
  1582 			{
       
  1583 			// Post-workaround.
       
  1584 			child = iQdp->MhcqdiGetPostChildCommand(*iParentCommand, aPreviousCmd, aPreviousCmdResult);
       
  1585 			}
       
  1586 			
       
  1587 		type = CHCICommandQItem::EPostChild;
       
  1588 		}
       
  1589 	
       
  1590 	// Delete previous command (if not parent).
       
  1591 	if ((aPreviousCmd != NULL) &&
       
  1592 		(aPreviousCmd->Type() != CHCICommandQItem::EParent))
       
  1593 		{
       
  1594 		DeleteCommand(aPreviousCmd);
       
  1595 		}
       
  1596 
       
  1597 	if (child != NULL)
       
  1598 		{
       
  1599 		// Enqueue child to head of queue.
       
  1600 		child->SetType(type);
       
  1601 		iWorkaroundCommandQ.AddFirst(*child);
       
  1602 		}
       
  1603 	else if (type != CHCICommandQItem::EParent)
       
  1604 		{
       
  1605 		// Give the QDP a chance to update state within the stack if required
       
  1606 		THCIEventBase* fakedEvent = NULL;
       
  1607 		while ((fakedEvent = iQdp->MhcqdiGetFakedUnsolicitedEvent(*iParentCommand, fakedEvent)) != NULL)
       
  1608 			{
       
  1609 			iUnmatchedEventObserver->MhcqcCommandEventReceived(*fakedEvent, NULL);
       
  1610 			}
       
  1611 			
       
  1612 		// End of workaround sequence, delete parent.
       
  1613 		DeleteCommand(iParentCommand);
       
  1614 		}
       
  1615 	}
       
  1616 
       
  1617 /**
       
  1618 A helper for restarting the Starvation Timer during command addition/sendout.
       
  1619 Determines the next command that will be sent and restarts the timer with
       
  1620 the ID of that command.
       
  1621 Caveat: this always restarts (or cancels, hence Update rather than just Restart in the name)
       
  1622 the timer, so use it only when you know that the command that will be sent next has really changed.
       
  1623 */
       
  1624 void CHCICmdQController::UpdateStarvationTimer()
       
  1625 	{
       
  1626 	// Determine the id of the next command to be executed.
       
  1627 	// Don't care about resend queue, the starvation timer shouldn't be restarted on resends.	
       
  1628 
       
  1629 	TUint cmdId = KInvalidCommandQueueItemId;
       
  1630 
       
  1631 	if (!iWorkaroundCommandQ.IsEmpty())
       
  1632 		{
       
  1633 		cmdId = iWorkaroundCommandQ.First()->CommandQId();
       
  1634 		}
       
  1635 	else if ((iCmdQControllerState == EStarted) && !iPriorityCommandQ.IsEmpty())
       
  1636 		{
       
  1637 		// Only send off priority queue in EStarted (i.e. not in EInitialising)
       
  1638 		// Never know which priority command will be sent next.
       
  1639 		cmdId = KInvalidCommandQueueItemId;
       
  1640 		}
       
  1641 	else
       
  1642 		{
       
  1643 		TDblQue<CHCICommandQItem>* queue = ActiveRegularQueue();
       
  1644 		if (queue && !queue->IsEmpty())
       
  1645 			{
       
  1646 			cmdId = queue->First()->CommandQId();
       
  1647 			}
       
  1648 		else
       
  1649 			{
       
  1650 			// No command to send.
       
  1651 			iQStarvationTimer->Cancel();
       
  1652 			return;
       
  1653 			}
       
  1654 		}
       
  1655 	iQStarvationTimer->Restart(iQueueStarvationTimeout, cmdId, *this);
       
  1656 	}
       
  1657 
       
  1658 /**
       
  1659 Dequeues and deletes aItem from its queue.
       
  1660 */
       
  1661 void CHCICmdQController::DeleteCommand(CHCICommandQItem* &aItem)
       
  1662 	{
       
  1663 	LOG_FUNC
       
  1664 
       
  1665 	if (!aItem)
       
  1666 		{
       
  1667 		return;
       
  1668 		}
       
  1669 	aItem->iLink.Deque();
       
  1670 	iQdp->MhcqdiCommandAboutToBeDeleted(*aItem);
       
  1671 	delete aItem;
       
  1672 	aItem = NULL;
       
  1673 	UpdateStarvationTimer();
       
  1674 	}
       
  1675 
       
  1676 /**
       
  1677 Helper to be called on command addition.
       
  1678 Returns ETrue if the command that will be sent next changed after we added a command to aQueue.
       
  1679 Ignores the Resend queue.
       
  1680 */
       
  1681 TBool CHCICmdQController::NextCommandChanged(const TDblQue<CHCICommandQItem> &aQueue)
       
  1682 	{
       
  1683 	LOG_FUNC
       
  1684 
       
  1685 	if (&aQueue != QueueSendingNext())
       
  1686 		{
       
  1687 		// We added a command to aQueue, but it's still another queue
       
  1688 		// that sends next, so we didn't change the next command to be sent.
       
  1689 		return EFalse;
       
  1690 		}
       
  1691 	else // aQueue is sending next.
       
  1692 		{
       
  1693 		if (&aQueue == &iPriorityCommandQ)
       
  1694 			{
       
  1695 			// PriorityQ is not FIFO, so any added command can potentially
       
  1696 			// be sent next irrespectably of whether the queue was empty or not.
       
  1697 			return ETrue;
       
  1698 			}
       
  1699 		else
       
  1700 			{
       
  1701 			// Rest of queues is FIFO, so the next command to be sent changed
       
  1702 			// if the queue had been empty when we added the command.
       
  1703 			return aQueue.First() == aQueue.Last();
       
  1704 			}
       
  1705 		}
       
  1706 	}
       
  1707 
       
  1708 /**
       
  1709 The general command addition routine. Adds aQueItem to aQueue and schedules
       
  1710 the command processing loop if current state is equal to aActiveState.
       
  1711 */
       
  1712 TUint CHCICmdQController::DoAddCommandL(CHCICommandQItem& aQueItem,
       
  1713 		TDblQue<CHCICommandQItem> &aQueue, TCmdQControllerStates aActiveState)
       
  1714 	{
       
  1715 	LOG_FUNC	
       
  1716 
       
  1717 	// Ensure we are in a state that allows commands to be added.
       
  1718 	if(!CanAddCommands())
       
  1719 		{
       
  1720 		delete &aQueItem;
       
  1721 		User::Leave(KErrHardwareNotAvailable);
       
  1722 		}
       
  1723 		
       
  1724 	// Assign a unique CommandQId.
       
  1725 	aQueItem.SetCommandQId(NextCommandQueueItemId());
       
  1726 
       
  1727 	aQueue.AddLast(aQueItem);
       
  1728 	// Restart queue starvation timer if this is the next command to be sent.
       
  1729 	if (NextCommandChanged(aQueue))
       
  1730 		{
       
  1731 		// If this is priority queue, we don't really know which command should be executed
       
  1732 		// next, so we feed the timer with KInvalidCommandQueueItemId in that case.
       
  1733 		TUint cmdId = KInvalidCommandQueueItemId;
       
  1734 		if (&aQueue != &iPriorityCommandQ)
       
  1735 			{
       
  1736 			cmdId = aQueItem.CommandQId();
       
  1737 			}
       
  1738 		iQStarvationTimer->Restart(iQueueStarvationTimeout, cmdId, *this);
       
  1739 		}
       
  1740 
       
  1741 	// Only schedule if we're in the state in which given queue should be considered for scheduling.
       
  1742 	if (iCmdQControllerState == aActiveState)
       
  1743 		{
       
  1744 		iAsyncCallBackForSend->CallBack();
       
  1745 		}
       
  1746 
       
  1747 	return aQueItem.CommandQId();
       
  1748 	}
       
  1749 
       
  1750 /**
       
  1751 Evaluates various blocking conditions to determine if the command can be sent.
       
  1752 aCmdQItem is passed by reference to pointer as it can be deleted and NULLified in case of error.
       
  1753 @return whether the command can be sent.
       
  1754 */
       
  1755 TBool CHCICmdQController::OkToSendCommand(CHCICommandQItem*& aCmdQItem, TUint aBypassBlocks)
       
  1756 	{
       
  1757 	TInt result = KErrNone;
       
  1758 	LOG_FUNC
       
  1759 	
       
  1760 	__ASSERT_ALWAYS(aCmdQItem, PANIC(KHCICmdQPanic, ENullCmdQItemPtr));
       
  1761 	
       
  1762 	if((iCommandCredits < aCmdQItem->Command().CreditsConsumed()) && 
       
  1763 	   (!(aBypassBlocks & EInsufficientCreditBlock))) 
       
  1764 		{
       
  1765 		// Insufficient HCI credits. Block and suspend processing queue.
       
  1766 		SetBlock(EInsufficientCreditBlock);
       
  1767 		}
       
  1768 	else 
       
  1769 		{
       
  1770 		CHCICommandQItem* const duplicate = ScanQueueByOpcode(iSentCommandQ,
       
  1771 															  aCmdQItem->Command().Opcode());
       
  1772 		if (duplicate && !(aBypassBlocks & EDuplicatedOpcodeBlock))
       
  1773 			{
       
  1774 			// Duplicate command pending. Block and suspend processing queue.
       
  1775 			SetBlock(EDuplicatedOpcodeBlock);
       
  1776 
       
  1777 			// Need to mark the duplicate so that EDuplicatedOpcodeBlock is cleared
       
  1778 			// on its completion.
       
  1779 			duplicate->SetDuplicatedOpcode(ETrue);
       
  1780 			}
       
  1781 		else
       
  1782 			{
       
  1783 			const TDblQue<const CHCICommandQItem>* sentQ = (reinterpret_cast<const TDblQue<const CHCICommandQItem>*>(&iSentCommandQ));
       
  1784 
       
  1785 			result = iQdp->MhcqdiCanSend(*aCmdQItem, *sentQ);
       
  1786 			// KErrNone if aCommand is to be sent, EBlock if Command
       
  1787 			// is to be delayed.
       
  1788 			if(result < 0)
       
  1789 				{
       
  1790 				if(aCmdQItem->Client())
       
  1791 					{
       
  1792 					aCmdQItem->Client()->MhcqcCommandErrored(result, &aCmdQItem->Command());	
       
  1793 					}
       
  1794 				
       
  1795 				// Dequeue, delete & set to NULL.
       
  1796 				DeleteCommand(aCmdQItem);
       
  1797 				
       
  1798 				if(AnyCmdsToSend())
       
  1799 					{
       
  1800 					iAsyncCallBackForSend->CallBack();
       
  1801 					}
       
  1802 				}
       
  1803 			else if(result == MHCICmdQueueDecisionInterface::EBlock && !(aBypassBlocks & ECanSendBlock))
       
  1804 				{
       
  1805 				// QDP should never block when the sent queue is empty (would permanently block the queue.
       
  1806 				__ASSERT_ALWAYS((!iSentCommandQ.IsEmpty()), PANIC(KHCICmdQPanic, ECanSendBlockWhenEmpty));
       
  1807 				SetBlock(ECanSendBlock);
       
  1808 				}
       
  1809 			}
       
  1810 		}
       
  1811 
       
  1812 	return ((!Blocked(ECachingCommandBlocks, aBypassBlocks))&&(result==KErrNone));
       
  1813 	}
       
  1814 	
       
  1815 /**
       
  1816 Submits a request to the link muxer for permission to send a command. 
       
  1817 */
       
  1818 void CHCICmdQController::SendCommand(CHCICommandQItem& aCmdQItem)
       
  1819 	{
       
  1820 	LOG_FUNC
       
  1821 
       
  1822 	__ASSERT_DEBUG(!iSendingCommand, PANIC(KHCICmdQPanic, ETryToSendWhilstSending));
       
  1823  
       
  1824 	iSendingCommand = &aCmdQItem;
       
  1825 	// Dequeue command.
       
  1826 	iSendingCommand->iLink.Deque();
       
  1827 
       
  1828 	// Initiate send request to HCTL, and block the queue.
       
  1829 	iLinkMuxer->TryToSend();
       
  1830 	SetBlock(ETryToSendBlock);
       
  1831 	}
       
  1832 
       
  1833 /**
       
  1834 Process matched non-error events.
       
  1835 */
       
  1836 void CHCICmdQController::ProcessMatchedEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool aConcludesCmd)
       
  1837 	{
       
  1838 	LOG_FUNC
       
  1839 	
       
  1840 	// If required by the command, a Command Status Event should always be received before any other event related to a command.
       
  1841 	THCIEventCode eventCode(aEvent.EventCode());	
       
  1842 	if (eventCode == ECommandStatusEvent)
       
  1843 		{
       
  1844 		if (aCmd->Command().ExpectsCommandStatusEvent())
       
  1845 			{
       
  1846 			aCmd->SetReceivedCmdStatusEvent(ETrue);
       
  1847 			}
       
  1848 		else
       
  1849 			{
       
  1850 			// assert in debug that we don't get here.
       
  1851 			}
       
  1852 		}
       
  1853 	else 
       
  1854 		{
       
  1855 		// Non Command Status Event, clear possible CanSend block.
       
  1856 		ClearBlock(ECanSendBlock);
       
  1857 		}
       
  1858 		
       
  1859 	CHCICommandQItem::TType type = aCmd->Type();
       
  1860 	if ((type != CHCICommandQItem::EPreChild) &&
       
  1861 		(type != CHCICommandQItem::EPostChild))
       
  1862 		{
       
  1863 		// Command client is notified of non-workaround command events.
       
  1864 		if(aCmd->Client())
       
  1865 			{
       
  1866 			aCmd->Client()->MhcqcCommandEventReceived(aEvent, &aCmd->Command());
       
  1867 			}
       
  1868 		}
       
  1869 	
       
  1870 	if (aConcludesCmd)
       
  1871 		{
       
  1872 		// Check that if a command status is expected then it has been got before being concluded.
       
  1873 
       
  1874 		// Cancel completion timer.
       
  1875 		aCmd->CancelCompletionTimer();
       
  1876 		
       
  1877 		// Update blocks, cleared blocks will be re-evaluated on next Run Queue
       
  1878 		if (aCmd->SentCount() > 1)
       
  1879 			{
       
  1880 			ClearBlock(EResendBlock);
       
  1881 			}
       
  1882 		if (aCmd->DuplicatedOpcode())
       
  1883 			{
       
  1884 			ClearBlock(EDuplicatedOpcodeBlock);
       
  1885 			}
       
  1886 						
       
  1887 		// Process completed command.					
       
  1888 		if (type == CHCICommandQItem::ENormal)
       
  1889 			{
       
  1890 			// Non-workaround command. Delete processed command.
       
  1891 			DeleteCommand(aCmd);
       
  1892 			}
       
  1893 		else
       
  1894 			{
       
  1895 			// Workaround in progress. Set up next workaround command.
       
  1896 			SetUpNextWorkaroundCmd(aCmd, &aEvent);
       
  1897 			}
       
  1898 		}
       
  1899 	}
       
  1900 
       
  1901 /**
       
  1902 Process matched error events.
       
  1903 */
       
  1904 void CHCICmdQController::ProcessMatchedErrorEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool /* aConcludesCmd */, TBool aSendToQdp)
       
  1905 	{
       
  1906 	LOG_FUNC
       
  1907 	
       
  1908 	// Cancel completion timer. 
       
  1909 	aCmd->CancelCompletionTimer(); 
       
  1910 		
       
  1911 	/*
       
  1912 	
       
  1913 	Update blocks. The following blocks are not cleared:
       
  1914 	
       
  1915 	1. The Resend block untouched to avoid interfering with an in-progress resend and 
       
  1916 	   to ensure that only a single resend is active at a time.	
       
  1917 	2. The TryToSend block which is strictly managed by the HCTL flow control methods 
       
  1918 	   (SendCommand and DoSend). 
       
  1919 	3. The Workaround block to prevent possibly bypassing a valid workaround block
       
  1920 	   on completion of a resend.
       
  1921 	
       
  1922 	All other cleared blocks (the caching blocks) will be re-evaluated before sending
       
  1923 	the next command.
       
  1924 	*/
       
  1925 	ClearBlock(ECachingCommandBlocks);
       
  1926 	
       
  1927 	// Remove item from sent queue.
       
  1928 	aCmd->iLink.Deque();
       
  1929 
       
  1930 	if (aSendToQdp && iQdp->MhcqdiMatchedErrorEventReceived(aEvent, *aCmd) == MHCICmdQueueDecisionInterface::EResendErroredCommand)
       
  1931 		{
       
  1932 		// Clear the command status event flag and enqueue to the resend queue
       
  1933 		aCmd->SetReceivedCmdStatusEvent(EFalse);
       
  1934 		if (aCmd->SentCount() > 1)
       
  1935 			{
       
  1936 			// Command was previously resent, enqueue to head of resend queue and clear Resend block
       
  1937 			iResendCommandQ.AddFirst(*aCmd);
       
  1938 			ClearBlock(EResendBlock);
       
  1939 			}
       
  1940 		else
       
  1941 			{
       
  1942 			// Command has not previously been resent, enqueue to tail of resend queue.
       
  1943 			iResendCommandQ.AddLast(*aCmd);			
       
  1944 			}
       
  1945 		}
       
  1946 	else
       
  1947 		{
       
  1948 		CHCICommandQItem::TType type = aCmd->Type();
       
  1949 
       
  1950 		if ((type != CHCICommandQItem::EPreChild) &&
       
  1951 			(type != CHCICommandQItem::EPostChild))
       
  1952 			{
       
  1953 			// Command error event received, notify client if non-child command
       
  1954 			if(aCmd->Client())
       
  1955 				{
       
  1956 				aCmd->Client()->MhcqcCommandEventReceived(aEvent, &aCmd->Command());	
       
  1957 				}
       
  1958 			}
       
  1959 
       
  1960 		// Process completed command.					
       
  1961 		if (type == CHCICommandQItem::ENormal)
       
  1962 			{
       
  1963 			// Non-workaround command. Delete processed command.
       
  1964 			DeleteCommand(aCmd);
       
  1965 			}
       
  1966 		else
       
  1967 			{
       
  1968 			// Workaround in progress. Set up next workaround command.
       
  1969 			SetUpNextWorkaroundCmd(aCmd, &aEvent);
       
  1970 			}											
       
  1971 		}
       
  1972 	}
       
  1973 
       
  1974 /**
       
  1975 Processes unmatched events.
       
  1976 */
       
  1977 void CHCICmdQController::ProcessUnmatchedEvent(const THCIEventBase& aEvent, TBool aSendToQdp)
       
  1978 	{
       
  1979 	LOG_FUNC
       
  1980 	
       
  1981 	if (aSendToQdp)
       
  1982 		{
       
  1983 		// Notify QDP.
       
  1984 		if (iQdpEventModifier)
       
  1985 			{
       
  1986 			THCIEventCode origEventCode = aEvent.EventCode();
       
  1987 			iQdpEventModifier->MhcqemiUnmatchedEventReceived(const_cast<THCIEventBase&>(aEvent));
       
  1988 			__ASSERT_ALWAYS(origEventCode == aEvent.EventCode(), PANIC(KHCICmdQPanic, EQdpTryingToChangeEventCode));
       
  1989 			}
       
  1990 		else
       
  1991 			{
       
  1992 			iQdp->MhcqdiUnmatchedEventReceived(aEvent);
       
  1993 			}
       
  1994 		}
       
  1995 
       
  1996 	iUnmatchedEventObserver->MhcqcCommandEventReceived(aEvent, NULL);
       
  1997 	}
       
  1998 
       
  1999 /**
       
  2000 Processes timed out commands.
       
  2001 */
       
  2002 void CHCICmdQController::ProcessCommandCompletionTimeout(CHCICommandQItem* aCmd)
       
  2003 	{
       
  2004 	LOG_FUNC
       
  2005 		
       
  2006 	/*
       
  2007 	
       
  2008 	Update blocks. The following blocks are not cleared:
       
  2009 	
       
  2010 	1. The Resend block untouched to avoid interfering with an in-progress resend and 
       
  2011 	   to ensure that only a single resend is active at a time.	
       
  2012 	2. The TryToSend block which is strictly managed by the HCTL flow control methods 
       
  2013 	   (SendCommand and DoSend). 
       
  2014 	3. The Workaround block to prevent possibly bypassing a valid workaround block
       
  2015 	   on completion of a resend.
       
  2016 	
       
  2017 	All other cleared blocks (the caching blocks) will be re-evaluated before sending
       
  2018 	the next command.
       
  2019 	*/
       
  2020 	ClearBlock(ECachingCommandBlocks);
       
  2021 	
       
  2022 	// Remove item from sent queue.
       
  2023 	aCmd->iLink.Deque();
       
  2024 
       
  2025 	TUint refundedCredits = 0;
       
  2026 	MHCICmdQueueDecisionInterface::TCommandTimedOutAction action;
       
  2027 	const TDblQue<const CHCICommandQItem>* sentQ = (reinterpret_cast<const TDblQue<const CHCICommandQItem>*>(&iSentCommandQ));
       
  2028 
       
  2029 	action = iQdp->MhcqdiCommandTimedOut(*aCmd, *sentQ, iCommandCredits, refundedCredits);
       
  2030 	
       
  2031 	// Take back any refunded credits
       
  2032 	iCommandCredits += refundedCredits;
       
  2033 
       
  2034 	if (action == MHCICmdQueueDecisionInterface::EContinueWithTimeoutEvent)
       
  2035 		{
       
  2036 		CHCICommandQItem::TType type = aCmd->Type();
       
  2037 
       
  2038 		if ((type != CHCICommandQItem::EPreChild) &&
       
  2039 			(type != CHCICommandQItem::EPostChild))
       
  2040 			{
       
  2041 			// Command error event received, notify client if non-child command
       
  2042 			if(aCmd->Client())
       
  2043 				{
       
  2044 				aCmd->Client()->MhcqcCommandErrored(CHciUtil::SymbianErrorCode(EHardwareFail), &aCmd->Command());	
       
  2045 				}
       
  2046 			}
       
  2047 
       
  2048 		// Process completed command.					
       
  2049 		if (type == CHCICommandQItem::ENormal)
       
  2050 			{
       
  2051 			// Non-workaround command. Delete processed command.
       
  2052 			DeleteCommand(aCmd);
       
  2053 			}
       
  2054 		else
       
  2055 			{
       
  2056 			SetUpNextWorkaroundCmd(aCmd, NULL);
       
  2057 			}											
       
  2058 		}
       
  2059 	else if (action == MHCICmdQueueDecisionInterface::EResendTimedOutCommand)
       
  2060 		{
       
  2061 		// Clear the command status event flag and enqueue to the resend queue
       
  2062 		aCmd->SetReceivedCmdStatusEvent(EFalse);
       
  2063 		if (aCmd->SentCount() > 1)
       
  2064 			{
       
  2065 			// Command was previously resent, enqueue to head of resend queue and clear Resend block
       
  2066 			iResendCommandQ.AddFirst(*aCmd);
       
  2067 			ClearBlock(EResendBlock);
       
  2068 			}
       
  2069 		else
       
  2070 			{
       
  2071 			// Command has not previously been resent, enqueue to tail of resend queue.
       
  2072 			iResendCommandQ.AddLast(*aCmd);
       
  2073 			}
       
  2074 		}
       
  2075 	}
       
  2076 
       
  2077 // Static async CallBack methods.
       
  2078 /*static*/ TInt CHCICmdQController::AsyncCallBackForReset(TAny* aCmdQController)
       
  2079 	{
       
  2080 	CHCICmdQController* cmdQController = static_cast<CHCICmdQController*>(aCmdQController);
       
  2081 	cmdQController->DoReset();
       
  2082 	return EFalse;	// Don't call back any more.
       
  2083 	}
       
  2084 	
       
  2085 /*static*/ TInt CHCICmdQController::AsyncCallBackForSend(TAny* aCmdQController)
       
  2086 	{
       
  2087 	CHCICmdQController* cmdQController = static_cast<CHCICmdQController*>(aCmdQController);
       
  2088 	cmdQController->TryToSend();
       
  2089 	return EFalse;	// Don't call back any more.
       
  2090 	}
       
  2091 
       
  2092 #ifdef _DEBUG
       
  2093 void CHCICmdQController::LogQueue(TDblQue<CHCICommandQItem>& aQueue)
       
  2094 	{
       
  2095 	TDblQueIter<CHCICommandQItem> iter(aQueue);
       
  2096 	while(CHCICommandQItem* item = iter++)
       
  2097 		{
       
  2098 		THCIOpcode opcode = item->Command().Opcode();
       
  2099 		const TUint16 KOgfMask = 0xfc00;
       
  2100 		TUint8 ogf = (opcode&KOgfMask) >> 10; // OGF starts at bit 10.
       
  2101 		TUint16 ocf = (opcode&~KOgfMask);
       
  2102 		LOG4(_L("Command OGF(0x%02x) OCF(0x%04x) item 0x%08x owned by 0x%08x"), ogf, ocf, item, item->Client());
       
  2103 		}
       
  2104 	}
       
  2105 #endif // _DEBUG
       
  2106 
       
  2107