bluetooth/btstack/linkmgr/AclDataQ.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/AclDataQ.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,358 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Link Autonomous ACL data packet Queue class implementation.
+// This autonomous Q pre-allocates a number of CHCIACLPacketBuffers.
+// It is at this point where the single pool of buffers in the HC is modelled 
+// SW-side.
+// This is the alternative chosen over having each baseband SAP have its own 
+// Queue.
+// 
+//
+
+#include <bluetooth/logger.h>
+#include "AclDataQ.h"
+#include "linkqitem.h"
+#include "linkmgr.h"
+#include "hcifacade.h"
+#include "L2CapPDU.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
+#endif
+
+/**
+	Instantiates a new ACL Data Q.
+
+	If this is called with zero number of items, it emulates a 'NULL' pattern 
+	for the data Q. This is necessary on init when we don't yet know what size 
+	of packet buffers we're going to use.
+*/
+CAclDataQ* CAclDataQ::NewL(CLinkMgrProtocol& aProtocol, 
+						   TUint aNumberOfItems, 
+						   TUint16 aDataSize, 
+						   TUint16 aFramingOverhead)
+	{
+	LOG_STATIC_FUNC
+	LOG3(_L("CAclDataQ::NewL aNumberOfItems = %d, aDataSize = %d, aFramingOverhead = %d"),
+		aNumberOfItems, aDataSize, aFramingOverhead);
+
+	CAclDataQ* self = new(ELeave) CAclDataQ;
+	CleanupStack::PushL(self);
+	self->ConstructL(aProtocol, aNumberOfItems, aDataSize, aFramingOverhead);
+	CleanupStack::Pop(self);
+
+	LOG1(_L("CAclDataQ::NewL self = 0x%08x"), self);
+	return self;
+	}
+
+CAclDataQ::CAclDataQ()
+ : iPreHardwareBuffer(_FOFF(CACLDataItem,iLink)), 
+   iSpareDataPool(_FOFF(CACLDataItem,iLink)),
+   iPendingData(_FOFF(CACLDataItem,iLink))
+	{
+	LOG_FUNC
+	}
+
+CAclDataQ::~CAclDataQ() 
+	{
+	LOG_FUNC
+	// delete the two Qs
+	CACLDataItem* tmpItem;
+
+	while ( ( tmpItem = RemoveFirstSpareItem() ) != NULL )
+		{
+		delete tmpItem;
+		}
+
+	while(!iPreHardwareBuffer.IsEmpty())
+		{
+		tmpItem=iPreHardwareBuffer.First();
+		iPreHardwareBuffer.Remove(*tmpItem);
+		delete tmpItem;
+		}
+	}
+
+/**
+	Pre-allocates all the Packet Buffer space as a pool.
+	Client of this function decides the number of items - this function does 
+	not provide any less than that, even in low memory conditions.
+*/
+void CAclDataQ::ConstructL(CLinkMgrProtocol& aProtocol, 
+						   TUint aNumberOfItems, 
+						   TUint16 aDataSize, 
+						   TUint16 aFramingOverhead)
+	{
+	LOG_FUNC
+
+	for ( TUint allocIdx = 0 ; allocIdx < aNumberOfItems ; allocIdx++ )
+		{
+		CACLDataItem* tmpPacketBuf = CACLDataItem::NewL();
+		CleanupStack::PushL(tmpPacketBuf);
+
+		tmpPacketBuf->Frame() = 
+			aProtocol.HCIFacade().NewACLDataFrameL(static_cast<TUint16>(aDataSize+aFramingOverhead));
+	
+		CleanupStack::Pop(tmpPacketBuf);
+		iSpareDataPool.AddLast(*tmpPacketBuf);
+		}
+	
+	// we managed to allocate as much as we were asked to
+	iCeiling = aNumberOfItems;
+	iItemSize = aDataSize;
+	}
+
+/**
+	Takes the first item off the spare item pool and returns ownership of it 
+	to the caller, or NULL if there are no spare items.
+*/
+CACLDataItem* CAclDataQ::RemoveFirstSpareItem()
+	{
+	LOG_FUNC
+
+	CACLDataItem* ret = NULL;
+	if ( !iSpareDataPool.IsEmpty() )
+		{
+		ret = iSpareDataPool.First();
+		iSpareDataPool.Remove(*ret);
+		}
+
+	LOG1(_L("CAclDataQ::RemoveFirstSpareItem ret = 0x%08x"), ret);
+	return ret;
+	}
+
+void CAclDataQ::AddItem(CACLDataItem& aAclItem)
+/** 
+	Place the given item on the outbound Q. Takes ownership of it.
+*/
+	{
+	LOG_FUNC
+	LOG1(_L("CAclDataQ::AddItem &aAclItem = 0x%08x"), &aAclItem);
+
+	iLevel++;
+	__ASSERT_DEBUG(iLevel<=iCeiling,Panic(ELinkMgrFIFOLevelAboveCeiling));
+
+	// Add to the outbound Q - when sent move to end of spare Q
+	iPreHardwareBuffer.AddLast(aAclItem);
+	}
+
+/**
+	Moves all Packet Buffers on the outbound Q, belonging to this connection, 
+	to the spare item pool.
+	Updates the iLevel of the Q.
+*/
+void CAclDataQ::InvalidateByConnH(THCIConnHandle aConnH, const CHCIFacade& /*aHCIFacade*/)
+	{
+	LOG_FUNC
+	LOG1(_L("CAclDataQ::InvalidateByConnH aConnH = %d"), aConnH);
+
+	CACLDataItem* item = 0;
+	// Check both the pending and pre-hardware queues for frames
+	// on the connection handle.  Inform the fragment sender that
+	// the element has been sent-  this will ensure that all
+	// resources are cleaned up, and no re-sends are attempted.
+	TSglQueIter<CACLDataItem> pendingDataIter(iPendingData);
+	while(pendingDataIter)
+		{
+		item = pendingDataIter++;
+		if((*(item->Frame())).ConnectionHandle() == aConnH)
+			{
+			iPendingData.Remove(*item);
+			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
+			elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
+			iSpareDataPool.AddLast(*item);
+			}
+		}			
+
+	TSglQueIter<CACLDataItem> preHardwareIter(iPreHardwareBuffer);
+	while(preHardwareIter)
+		{
+		item = preHardwareIter++;
+		if((*(item->Frame())).ConnectionHandle() == aConnH)
+			{
+			iPreHardwareBuffer.Remove(*item);
+			iLevel--;
+			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
+			elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
+			iSpareDataPool.AddLast(*item);
+			}
+		}
+	LOG1(_L("CAclDataQ::InvalidateByConnH iLevel = %d"), iLevel);
+	}
+
+void CAclDataQ::PendingItem(CACLDataItem& aItem)
+/**
+	An item has been sent to the host controller so move it from the PreHardware queue
+	to the pending sent notification queue.
+*/
+	{
+	LOG_FUNC
+	LOG1(_L("CAclDataQ::InvalidateItem &aItem = 0x%08x"), &aItem);
+
+	iPreHardwareBuffer.Remove(aItem);
+	iPendingData.AddLast(aItem);
+	iLevel--;
+	 
+	// if it went below zero it would become too big (because unsigned)
+	__ASSERT_DEBUG(iLevel<iCeiling,Panic(EHCIFIFOLevelBelowZero));
+	}
+
+void CAclDataQ::ItemsSent(TUint aNumberOfItemsSent)
+	{
+	LOG_FUNC
+	CACLDataItem* item = 0;
+	// If a flush has occurred then a number of completed packets event can
+	// be received when no data is in the pending queue.
+	for(TUint i=0;i<aNumberOfItemsSent;i++)
+		{
+		if(!iPendingData.IsEmpty())
+			{
+			item = iPendingData.First();
+
+			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
+			elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
+
+			iPendingData.Remove(*item);
+			iSpareDataPool.AddLast(*item);
+			}
+		}
+	}
+
+void CAclDataQ::ProcessFlush(const CHCIFacade& /*aHCIFacade*/, THCIConnHandle aConnH)
+	{
+	LOG_FUNC
+	CACLDataItem* item = 0;
+
+	// The order of clearing flushed items from the queues must be
+	// maintained.  The nearest to being sent must be reported first so
+	// that if the PDU is to be re-sent it is placed at the start of
+	// the re-sent queue. 
+	TSglQueIter<CACLDataItem> pendingDataIter(iPendingData);
+	while(pendingDataIter)
+		{
+		item = pendingDataIter++;
+		if((*(item->Frame())).ConnectionHandle() == aConnH)
+			{
+			iPendingData.Remove(*item);
+			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
+			elementHandle->DataPlaneElement().DataElementFlushed(elementHandle->ElementID());
+			iSpareDataPool.AddLast(*item);
+			}
+		}			
+
+	TSglQueIter<CACLDataItem> preHardwareIter(iPreHardwareBuffer);
+	while(preHardwareIter)
+		{
+		item = preHardwareIter++;
+		if((*(item->Frame())).ConnectionHandle() == aConnH)
+			{
+			iPreHardwareBuffer.Remove(*item);
+			iLevel--;
+			TDataPlaneElementHandle* elementHandle = item->ElementHandle();
+			elementHandle->DataPlaneElement().DataElementFlushed(elementHandle->ElementID());
+			iSpareDataPool.AddLast(*item);
+			}
+		}
+	}
+
+
+CACLDataItem* CAclDataQ::FirstItemByConnectionHandle(const CHCIFacade& /*aHCIFacade*/,
+												   const THCIConnHandle aConnH)
+/**
+	Returns first packet on the data fifo on a given connection handle
+*/
+	{
+	LOG_FUNC
+	LOG1(_L("CAclDataQ::FirstItemByConnectionHandle aConnH = %d"), aConnH);
+
+	CACLDataItem* item = NULL;
+	TSglQueIter<CACLDataItem> iter(iPreHardwareBuffer);
+
+	FOREVER
+		{
+		item = iter++;
+
+		if ( item == NULL ) // ended the iterator
+			{
+			break;
+			}
+
+		if ((*(item->Frame())).ConnectionHandle() == aConnH)
+			{
+			break;
+			}
+		}
+	LOG1(_L("CAclDataQ::FirstItemByConnectionHandle item = 0x%08x"), item);
+	return item;
+	}
+
+/**
+ Returns the first item on the outbound queue and sets aConnH to its 
+ connection handle.
+ */
+CACLDataItem* CAclDataQ::FirstItem(const CHCIFacade& /*aHCIFacade*/,
+								   THCIConnHandle& aConnH)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iLevel>0,Panic(ELinkMgrFIFOLevelZeroOrBelowZero));
+
+	CACLDataItem* item = iPreHardwareBuffer.First();
+	aConnH = (*(item->Frame())).ConnectionHandle();
+
+	LOG2(_L("CAclDataQ::FirstItem aConnH = %d, item = 0x%08x"), aConnH, item);
+	return item;
+	}
+
+/**
+	Resets data items onto spare Q and sets the fill level to zero.
+	Hence it acts like the buffer is empty, thus we can utilise it again in 
+	full.
+	This call must be made from the Data Controller ONLY when a Reset occurs.
+	
+	Note: It does not zero the contents of the buffers.
+*/
+void CAclDataQ::InvalidateAll()
+	{
+	LOG_FUNC
+
+	CACLDataItem* item = 0;
+	// Check both the pending and pre-hardware queues for frames
+	// on the connection handle.  Inform the fragment sender that
+	// the element has been sent-  this will ensure that all
+	// resources are cleaned up, and no re-sends are attempted.
+	TSglQueIter<CACLDataItem> pendingDataIter(iPendingData);
+	while(pendingDataIter)
+		{
+		item = pendingDataIter++;
+		iPendingData.Remove(*item);
+		TDataPlaneElementHandle* elementHandle = item->ElementHandle();
+		elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
+		iSpareDataPool.AddLast(*item);
+		}			
+
+	TSglQueIter<CACLDataItem> preHardwareIter(iPreHardwareBuffer);
+	while(preHardwareIter)
+		{
+		item = preHardwareIter++;
+		iPreHardwareBuffer.Remove(*item);
+		TDataPlaneElementHandle* elementHandle = item->ElementHandle();
+		elementHandle->DataPlaneElement().DataElementSent(elementHandle->ElementID());
+		iSpareDataPool.AddLast(*item);
+		}
+	iLevel=0;
+
+	iLevel = 0;
+	}
+
+//
+// End of file