IPC_SmQ IPC_QCreate(void)
{
	IPC_SmQ Queue = IPC_SmAlloc(sizeof(IPC_QHead_T));

	if (Queue == 0) {
		IPC_TRACE(IPC_Channel_Error, "IPC_QCreate",
			  "IPC_SmAlloc failed", 0, 0, 0, 0);
		return 0;
	}

	return IPC_QInitialise(Queue, Queue);
}
//**************************************************
IPC_BufferPool IPC_CreateBufferPoolWithDescriptor
(
	IPC_EndpointId_T		SourceEndpointId,
	IPC_EndpointId_T		DestinationEndpointId,
	IPC_U32					NumberOfBuffers,
	IPC_U32					BufferSize,
	IPC_U32					FlowStartLimit,
	IPC_U32					FlowStopLimit,
	IPC_U32					LocalDescriptorSize
)
{
	IPC_U32				MaxDataSize		= ALIGN4 (BufferSize);
	IPC_BufferPool		Pool;
	IPC_BufferPool_T *	PoolPtr;
	IPC_Endpoint		DestinationEpPtr;
	IPC_SmPtr			Buffer;
	IPC_U32				Id;
	char *				LocalData;

	IPC_TRACE (IPC_Channel_Pool, "IPC_CreateBufferPool",
				"Source %02X, Destination %02X, Buffer Count %d, Buffer Size %d",
				SourceEndpointId, DestinationEndpointId, NumberOfBuffers, BufferSize);

	// Sanity Checks
	if (NumberOfBuffers == 0)
	{
		IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid NumberOfBuffers %d", NumberOfBuffers, 0, 0, 0);
		return 0;
	}

	if (!IPC_SmEndpointInfo (SourceEndpointId))
	{
		IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid Source Endpoint %d", SourceEndpointId, 0, 0, 0);
		return 0;
	}

	if (0 == (DestinationEpPtr = IPC_SmEndpointInfo (DestinationEndpointId)))
	{
		IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid Destination Endpoint %d", DestinationEndpointId, 0, 0, 0);
		return 0;
	}

	if (FlowStartLimit > NumberOfBuffers)
	{
		IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid FlowStartLimit %d", FlowStartLimit, 0, 0, 0);
		return 0;
	}

	if (FlowStopLimit >= NumberOfBuffers)
	{
		IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid FlowStopLimit %d", FlowStopLimit, 0, 0, 0);
		return 0;
	}

	// Allocate Sm For Pool
	Pool = IPC_SmPoolAlloc (sizeof (IPC_BufferPool_T), DestinationEpPtr->MaxHeaderSize, MaxDataSize, NumberOfBuffers);

	if (!Pool)
	{
		IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "IPC_SmPoolAlloc Failed", 0, 0, 0, 0);
		return 0;
	}

	if (LocalDescriptorSize != 0)
	{
#ifdef UNDER_LINUX
        // Use kmalloc instead of OSHEAP_Alloc in Linux platform
		LocalData = kmalloc ((LocalDescriptorSize * NumberOfBuffers), GFP_KERNEL);
#else
		LocalData = (char *) OSHEAP_Alloc (LocalDescriptorSize * NumberOfBuffers);
#endif  // UNDER_LINUX

		if (!LocalData)
		{
			IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "LocalData OSHEAP_Alloc Failed", 0, 0, 0, 0);
			return 0;
		}
	} else {
		LocalData = 0;
	}

	// Initialise Pool
	PoolPtr	= IPC_PoolPtr(Pool);

	PoolPtr->Cpu					= IPC_SM_CURRENT_CPU;
	PoolPtr->SourceEndpointId		= SourceEndpointId;
	PoolPtr->DestinationEndpointId	= DestinationEndpointId;
	PoolPtr->MaxDataSize			= MaxDataSize;
	PoolPtr->MaxHeaderSize			= DestinationEpPtr->MaxHeaderSize;
	PoolPtr->FlowStartLimit			= FlowStartLimit;
	PoolPtr->FlowStopLimit			= FlowStopLimit;
	PoolPtr->FlowControlState		= IPC_FLOW_START;
	PoolPtr->FlowControlCallPending	= IPC_FALSE;
	PoolPtr->FreeBuffers			= NumberOfBuffers;
	PoolPtr->MaxBuffers				= NumberOfBuffers;
	PoolPtr->LowWaterMark			= NumberOfBuffers;
	PoolPtr->NextPool				= 0;
	PoolPtr->BufferFreeFunction		= NULL;
	PoolPtr->AllocationFailures		= 0;
	PoolPtr->Allocations			= 0;
	PoolPtr->BytesSent				= 0;
	PoolPtr->FlowStopCalls			= 0;
	PoolPtr->FlowStartCalls			= 0;

	PoolPtr->EmptyEvent				= IPC_EVENT_CREATE;

	IPC_QInitialise			(IPC_SmOffset(&PoolPtr->FreeBufferQ), Pool);
	IPC_QInitialise			(IPC_SmOffset(&PoolPtr->AllocatedBufferQ), Pool);



	// Initialise Buffers in pool
	Buffer = Pool + sizeof (IPC_BufferPool_T);

	for (Id = 0; Id < NumberOfBuffers; Id++)
	{
		IPC_BufferToPtr (Buffer)->LocalData = LocalData;

		LocalData += LocalDescriptorSize;

		IPC_QAddBack (Buffer, IPC_POOLFreeQ(Pool));
		Buffer = IPC_BufferInitialise (Pool, Buffer, Id, PoolPtr->MaxHeaderSize, MaxDataSize);

	}

	// For Debug
	{
		IPC_PoolList_T * EpPools = &PoolList [PoolPtr->SourceEndpointId];

		if (EpPools->Count < IPC_POOLLIST_LENGTH)
		{
			EpPools->Pool [EpPools->Count++] = PoolPtr;
		}
	}

	IPC_TRACE (IPC_Channel_Pool, "IPC_CreateBufferPool", "Pool %08X", Pool, 0, 0, 0);

	return Pool;
}