bluetooth/btstack/linkmgr/AclDataQ.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 1999-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 // Link Autonomous ACL data packet Queue class implementation.
       
    15 // This autonomous Q pre-allocates a number of CHCIACLPacketBuffers.
       
    16 // It is at this point where the single pool of buffers in the HC is modelled 
       
    17 // SW-side.
       
    18 // This is the alternative chosen over having each baseband SAP have its own 
       
    19 // Queue.
       
    20 // 
       
    21 //
       
    22 
       
    23 #include <bluetooth/logger.h>
       
    24 #include "AclDataQ.h"
       
    25 #include "linkqitem.h"
       
    26 #include "linkmgr.h"
       
    27 #include "hcifacade.h"
       
    28 #include "L2CapPDU.h"
       
    29 
       
    30 #ifdef __FLOG_ACTIVE
       
    31 _LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
       
    32 #endif
       
    33 
       
    34 /**
       
    35 	Instantiates a new ACL Data Q.
       
    36 
       
    37 	If this is called with zero number of items, it emulates a 'NULL' pattern 
       
    38 	for the data Q. This is necessary on init when we don't yet know what size 
       
    39 	of packet buffers we're going to use.
       
    40 */
       
    41 CAclDataQ* CAclDataQ::NewL(CLinkMgrProtocol& aProtocol, 
       
    42 						   TUint aNumberOfItems, 
       
    43 						   TUint16 aDataSize, 
       
    44 						   TUint16 aFramingOverhead)
       
    45 	{
       
    46 	LOG_STATIC_FUNC
       
    47 	LOG3(_L("CAclDataQ::NewL aNumberOfItems = %d, aDataSize = %d, aFramingOverhead = %d"),
       
    48 		aNumberOfItems, aDataSize, aFramingOverhead);
       
    49 
       
    50 	CAclDataQ* self = new(ELeave) CAclDataQ;
       
    51 	CleanupStack::PushL(self);
       
    52 	self->ConstructL(aProtocol, aNumberOfItems, aDataSize, aFramingOverhead);
       
    53 	CleanupStack::Pop(self);
       
    54 
       
    55 	LOG1(_L("CAclDataQ::NewL self = 0x%08x"), self);
       
    56 	return self;
       
    57 	}
       
    58 
       
    59 CAclDataQ::CAclDataQ()
       
    60  : iPreHardwareBuffer(_FOFF(CACLDataItem,iLink)), 
       
    61    iSpareDataPool(_FOFF(CACLDataItem,iLink)),
       
    62    iPendingData(_FOFF(CACLDataItem,iLink))
       
    63 	{
       
    64 	LOG_FUNC
       
    65 	}
       
    66 
       
    67 CAclDataQ::~CAclDataQ() 
       
    68 	{
       
    69 	LOG_FUNC
       
    70 	// delete the two Qs
       
    71 	CACLDataItem* tmpItem;
       
    72 
       
    73 	while ( ( tmpItem = RemoveFirstSpareItem() ) != NULL )
       
    74 		{
       
    75 		delete tmpItem;
       
    76 		}
       
    77 
       
    78 	while(!iPreHardwareBuffer.IsEmpty())
       
    79 		{
       
    80 		tmpItem=iPreHardwareBuffer.First();
       
    81 		iPreHardwareBuffer.Remove(*tmpItem);
       
    82 		delete tmpItem;
       
    83 		}
       
    84 	}
       
    85 
       
    86 /**
       
    87 	Pre-allocates all the Packet Buffer space as a pool.
       
    88 	Client of this function decides the number of items - this function does 
       
    89 	not provide any less than that, even in low memory conditions.
       
    90 */
       
    91 void CAclDataQ::ConstructL(CLinkMgrProtocol& aProtocol, 
       
    92 						   TUint aNumberOfItems, 
       
    93 						   TUint16 aDataSize, 
       
    94 						   TUint16 aFramingOverhead)
       
    95 	{
       
    96 	LOG_FUNC
       
    97 
       
    98 	for ( TUint allocIdx = 0 ; allocIdx < aNumberOfItems ; allocIdx++ )
       
    99 		{
       
   100 		CACLDataItem* tmpPacketBuf = CACLDataItem::NewL();
       
   101 		CleanupStack::PushL(tmpPacketBuf);
       
   102 
       
   103 		tmpPacketBuf->Frame() = 
       
   104 			aProtocol.HCIFacade().NewACLDataFrameL(static_cast<TUint16>(aDataSize+aFramingOverhead));
       
   105 	
       
   106 		CleanupStack::Pop(tmpPacketBuf);
       
   107 		iSpareDataPool.AddLast(*tmpPacketBuf);
       
   108 		}
       
   109 	
       
   110 	// we managed to allocate as much as we were asked to
       
   111 	iCeiling = aNumberOfItems;
       
   112 	iItemSize = aDataSize;
       
   113 	}
       
   114 
       
   115 /**
       
   116 	Takes the first item off the spare item pool and returns ownership of it 
       
   117 	to the caller, or NULL if there are no spare items.
       
   118 */
       
   119 CACLDataItem* CAclDataQ::RemoveFirstSpareItem()
       
   120 	{
       
   121 	LOG_FUNC
       
   122 
       
   123 	CACLDataItem* ret = NULL;
       
   124 	if ( !iSpareDataPool.IsEmpty() )
       
   125 		{
       
   126 		ret = iSpareDataPool.First();
       
   127 		iSpareDataPool.Remove(*ret);
       
   128 		}
       
   129 
       
   130 	LOG1(_L("CAclDataQ::RemoveFirstSpareItem ret = 0x%08x"), ret);
       
   131 	return ret;
       
   132 	}
       
   133 
       
   134 void CAclDataQ::AddItem(CACLDataItem& aAclItem)
       
   135 /** 
       
   136 	Place the given item on the outbound Q. Takes ownership of it.
       
   137 */
       
   138 	{
       
   139 	LOG_FUNC
       
   140 	LOG1(_L("CAclDataQ::AddItem &aAclItem = 0x%08x"), &aAclItem);
       
   141 
       
   142 	iLevel++;
       
   143 	__ASSERT_DEBUG(iLevel<=iCeiling,Panic(ELinkMgrFIFOLevelAboveCeiling));
       
   144 
       
   145 	// Add to the outbound Q - when sent move to end of spare Q
       
   146 	iPreHardwareBuffer.AddLast(aAclItem);
       
   147 	}
       
   148 
       
   149 /**
       
   150 	Moves all Packet Buffers on the outbound Q, belonging to this connection, 
       
   151 	to the spare item pool.
       
   152 	Updates the iLevel of the Q.
       
   153 */
       
   154 void CAclDataQ::InvalidateByConnH(THCIConnHandle aConnH, const CHCIFacade& /*aHCIFacade*/)
       
   155 	{
       
   156 	LOG_FUNC
       
   157 	LOG1(_L("CAclDataQ::InvalidateByConnH aConnH = %d"), aConnH);
       
   158 
       
   159 	CACLDataItem* item = 0;
       
   160 	// Check both the pending and pre-hardware queues for frames
       
   161 	// on the connection handle.  Inform the fragment sender that
       
   162 	// the element has been sent-  this will ensure that all
       
   163 	// resources are cleaned up, and no re-sends are attempted.
       
   164 	TSglQueIter<CACLDataItem> pendingDataIter(iPendingData);
       
   165 	while(pendingDataIter)
       
   166 		{
       
   167 		item = pendingDataIter++;
       
   168 		if((*(item->Frame())).ConnectionHandle() == aConnH)
       
   169 			{
       
   170 			iPendingData.Remove(*item);
       
   171 			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
       
   172 			elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
       
   173 			iSpareDataPool.AddLast(*item);
       
   174 			}
       
   175 		}			
       
   176 
       
   177 	TSglQueIter<CACLDataItem> preHardwareIter(iPreHardwareBuffer);
       
   178 	while(preHardwareIter)
       
   179 		{
       
   180 		item = preHardwareIter++;
       
   181 		if((*(item->Frame())).ConnectionHandle() == aConnH)
       
   182 			{
       
   183 			iPreHardwareBuffer.Remove(*item);
       
   184 			iLevel--;
       
   185 			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
       
   186 			elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
       
   187 			iSpareDataPool.AddLast(*item);
       
   188 			}
       
   189 		}
       
   190 	LOG1(_L("CAclDataQ::InvalidateByConnH iLevel = %d"), iLevel);
       
   191 	}
       
   192 
       
   193 void CAclDataQ::PendingItem(CACLDataItem& aItem)
       
   194 /**
       
   195 	An item has been sent to the host controller so move it from the PreHardware queue
       
   196 	to the pending sent notification queue.
       
   197 */
       
   198 	{
       
   199 	LOG_FUNC
       
   200 	LOG1(_L("CAclDataQ::InvalidateItem &aItem = 0x%08x"), &aItem);
       
   201 
       
   202 	iPreHardwareBuffer.Remove(aItem);
       
   203 	iPendingData.AddLast(aItem);
       
   204 	iLevel--;
       
   205 	 
       
   206 	// if it went below zero it would become too big (because unsigned)
       
   207 	__ASSERT_DEBUG(iLevel<iCeiling,Panic(EHCIFIFOLevelBelowZero));
       
   208 	}
       
   209 
       
   210 void CAclDataQ::ItemsSent(TUint aNumberOfItemsSent)
       
   211 	{
       
   212 	LOG_FUNC
       
   213 	CACLDataItem* item = 0;
       
   214 	// If a flush has occurred then a number of completed packets event can
       
   215 	// be received when no data is in the pending queue.
       
   216 	for(TUint i=0;i<aNumberOfItemsSent;i++)
       
   217 		{
       
   218 		if(!iPendingData.IsEmpty())
       
   219 			{
       
   220 			item = iPendingData.First();
       
   221 
       
   222 			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
       
   223 			elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
       
   224 
       
   225 			iPendingData.Remove(*item);
       
   226 			iSpareDataPool.AddLast(*item);
       
   227 			}
       
   228 		}
       
   229 	}
       
   230 
       
   231 void CAclDataQ::ProcessFlush(const CHCIFacade& /*aHCIFacade*/, THCIConnHandle aConnH)
       
   232 	{
       
   233 	LOG_FUNC
       
   234 	CACLDataItem* item = 0;
       
   235 
       
   236 	// The order of clearing flushed items from the queues must be
       
   237 	// maintained.  The nearest to being sent must be reported first so
       
   238 	// that if the PDU is to be re-sent it is placed at the start of
       
   239 	// the re-sent queue. 
       
   240 	TSglQueIter<CACLDataItem> pendingDataIter(iPendingData);
       
   241 	while(pendingDataIter)
       
   242 		{
       
   243 		item = pendingDataIter++;
       
   244 		if((*(item->Frame())).ConnectionHandle() == aConnH)
       
   245 			{
       
   246 			iPendingData.Remove(*item);
       
   247 			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
       
   248 			elementHandle->DataPlaneElement().DataElementFlushed(elementHandle->ElementID());
       
   249 			iSpareDataPool.AddLast(*item);
       
   250 			}
       
   251 		}			
       
   252 
       
   253 	TSglQueIter<CACLDataItem> preHardwareIter(iPreHardwareBuffer);
       
   254 	while(preHardwareIter)
       
   255 		{
       
   256 		item = preHardwareIter++;
       
   257 		if((*(item->Frame())).ConnectionHandle() == aConnH)
       
   258 			{
       
   259 			iPreHardwareBuffer.Remove(*item);
       
   260 			iLevel--;
       
   261 			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
       
   262 			elementHandle->DataPlaneElement().DataElementFlushed(elementHandle->ElementID());
       
   263 			iSpareDataPool.AddLast(*item);
       
   264 			}
       
   265 		}
       
   266 	}
       
   267 
       
   268 
       
   269 CACLDataItem* CAclDataQ::FirstItemByConnectionHandle(const CHCIFacade& /*aHCIFacade*/,
       
   270 												   const THCIConnHandle aConnH)
       
   271 /**
       
   272 	Returns first packet on the data fifo on a given connection handle
       
   273 */
       
   274 	{
       
   275 	LOG_FUNC
       
   276 	LOG1(_L("CAclDataQ::FirstItemByConnectionHandle aConnH = %d"), aConnH);
       
   277 
       
   278 	CACLDataItem* item = NULL;
       
   279 	TSglQueIter<CACLDataItem> iter(iPreHardwareBuffer);
       
   280 
       
   281 	FOREVER
       
   282 		{
       
   283 		item = iter++;
       
   284 
       
   285 		if ( item == NULL ) // ended the iterator
       
   286 			{
       
   287 			break;
       
   288 			}
       
   289 
       
   290 		if ((*(item->Frame())).ConnectionHandle() == aConnH)
       
   291 			{
       
   292 			break;
       
   293 			}
       
   294 		}
       
   295 	LOG1(_L("CAclDataQ::FirstItemByConnectionHandle item = 0x%08x"), item);
       
   296 	return item;
       
   297 	}
       
   298 
       
   299 /**
       
   300  Returns the first item on the outbound queue and sets aConnH to its 
       
   301  connection handle.
       
   302  */
       
   303 CACLDataItem* CAclDataQ::FirstItem(const CHCIFacade& /*aHCIFacade*/,
       
   304 								   THCIConnHandle& aConnH)
       
   305 	{
       
   306 	LOG_FUNC
       
   307 	__ASSERT_DEBUG(iLevel>0,Panic(ELinkMgrFIFOLevelZeroOrBelowZero));
       
   308 
       
   309 	CACLDataItem* item = iPreHardwareBuffer.First();
       
   310 	aConnH = (*(item->Frame())).ConnectionHandle();
       
   311 
       
   312 	LOG2(_L("CAclDataQ::FirstItem aConnH = %d, item = 0x%08x"), aConnH, item);
       
   313 	return item;
       
   314 	}
       
   315 
       
   316 /**
       
   317 	Resets data items onto spare Q and sets the fill level to zero.
       
   318 	Hence it acts like the buffer is empty, thus we can utilise it again in 
       
   319 	full.
       
   320 	This call must be made from the Data Controller ONLY when a Reset occurs.
       
   321 	
       
   322 	Note: It does not zero the contents of the buffers.
       
   323 */
       
   324 void CAclDataQ::InvalidateAll()
       
   325 	{
       
   326 	LOG_FUNC
       
   327 
       
   328 	CACLDataItem* item = 0;
       
   329 	// Check both the pending and pre-hardware queues for frames
       
   330 	// on the connection handle.  Inform the fragment sender that
       
   331 	// the element has been sent-  this will ensure that all
       
   332 	// resources are cleaned up, and no re-sends are attempted.
       
   333 	TSglQueIter<CACLDataItem> pendingDataIter(iPendingData);
       
   334 	while(pendingDataIter)
       
   335 		{
       
   336 		item = pendingDataIter++;
       
   337 		iPendingData.Remove(*item);
       
   338 		TDataPlaneElementHandle* elementHandle = item->ElementHandle();
       
   339 		elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
       
   340 		iSpareDataPool.AddLast(*item);
       
   341 		}			
       
   342 
       
   343 	TSglQueIter<CACLDataItem> preHardwareIter(iPreHardwareBuffer);
       
   344 	while(preHardwareIter)
       
   345 		{
       
   346 		item = preHardwareIter++;
       
   347 		iPreHardwareBuffer.Remove(*item);
       
   348 		TDataPlaneElementHandle* elementHandle = item->ElementHandle();
       
   349 		elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
       
   350 		iSpareDataPool.AddLast(*item);
       
   351 		}
       
   352 	iLevel=0;
       
   353 
       
   354 	iLevel = 0;
       
   355 	}
       
   356 
       
   357 //
       
   358 // End of file