gceSTATUS vgsMEMORYMANAGER_Construct(
    IN gcoOS Os,
	IN gctUINT ItemSize,
	IN gctUINT Granularity,
	OUT vgsMEMORYMANAGER_PTR * Manager
	)
{
	gceSTATUS status;
	vgsMEMORYMANAGER_PTR manager = gcvNULL;

    gcmHEADER_ARG("Os=0x%x ItemSize=0x%x Granularity=0x%x Manager=0x%x",
        Os, ItemSize, Granularity, Manager);

	gcmVERIFY_ARGUMENT(ItemSize > 0);
	gcmVERIFY_ARGUMENT(Granularity > 0);
	gcmVERIFY_ARGUMENT(Manager != gcvNULL);

	do
	{
		gctUINT itemSize;
		gctUINT allocationSize;

		/* Allocate the memory manager structure. */
		gcmERR_BREAK(gcoOS_Allocate(
			Os,
			gcmSIZEOF(vgsMEMORYMANAGER),
			(gctPOINTER *) &manager
			));

		/* Determine the size of the item. */
		itemSize = gcmSIZEOF(vgsMEMORYITEM) + ItemSize;

		/* Determine the allocation size. */
		allocationSize = gcmSIZEOF(vgsMEMORYITEM) + Granularity * itemSize;

		/* Initialize the structure. */
		manager->os             = Os;
		manager->allocationSize = allocationSize;
		manager->itemCount      = Granularity;
		manager->itemSize       = itemSize;
		manager->firstAllocated = gcvNULL;
		manager->firstFree      = gcvNULL;

#if vgvVALIDATE_MEMORY_MANAGER
		manager->allocatedCount       = 0;
		manager->maximumAllocated     = 0;
		manager->allocatedBufferCount = 0;
#endif

		/* Set the result pointer. */
		* Manager = manager;
	}
	while (gcvNULL);

    gcmFOOTER();

	/* Return status. */
	return status;
}
/*******************************************************************************
**
**  gcoDUMP_DumpData
**
**  Dump data the file.
**
**  INPUT:
**
**      gcoDUMP Dump
**          Pointer to a gcoDUMP object.
**
**      gceDUMP_TAG Type
**          Type of data.
**
**      gctUINT32 Address
**          Physical address to be used as a handle for the data.
**
**      gctSIZE_T ByteCount
**          Number of bytes to write.
**
**      gctCONST_POINTER Data
**          Pointer to the data to write.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS
gcoDUMP_DumpData(
    IN gcoDUMP Dump,
    IN gceDUMP_TAG Type,
    IN gctUINT32 Address,
    IN gctSIZE_T ByteCount,
    IN gctCONST_POINTER Data
    )
{
    gceSTATUS status;
    gcsDUMP_DATA header;

    gcmHEADER_ARG("Dump=0x%x Type=%d Address=%x ByteCount=%d Data=0x%x",
                    Dump, Type, Address, ByteCount, Data);

    /* Verify the arguments. */
    gcmVERIFY_OBJECT(Dump, gcvOBJ_DUMP);
    gcmVERIFY_ARGUMENT(ByteCount > 0);
    gcmVERIFY_ARGUMENT(Data != gcvNULL);

    if (Dump->file == gcvNULL)
    {
        /* There is no open dump file. */
        gcmFOOTER_NO();
        return gcvSTATUS_OK;
    }

    do
    {
        /* Write the data record. */
        header.type    = Type;
        header.length  = ByteCount;
        header.address = Address;

        gcmERR_BREAK(
            gcoOS_Write(gcvNULL, Dump->file, sizeof(header), &header));

        /* Write the data. */
        gcmERR_BREAK(gcoOS_Write(gcvNULL, Dump->file, ByteCount, Data));

        /* Update the frame length. */
        Dump->frameLength += sizeof(header) + ByteCount;

        /* Update the file length. */
        Dump->length += sizeof(header) + ByteCount;
    }
    while (gcvFALSE);

    /* Return the status. */
    gcmFOOTER();
    return status;
}
/*******************************************************************************
**
**  gcoDUMP_AddSurface
**
**  Allocate a surface.
**
**  INPUT:
**
**      gcoDUMP Dump
**          Pointer to a gcoDUMP object.
**
**      gctINT32 Width, Height
**          Width and height of the surface.
**
**      gceSURF_FORMAT PixelFormat
**          Pixel format for the surface.
**
**      gctUINT32 Address
**          Physical address to be used as a handle for the surface.
**
**      gctSIZE_T ByteCount
**          Number of bytes inside the surface.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS
gcoDUMP_AddSurface(
    IN gcoDUMP Dump,
    IN gctINT32 Width,
    IN gctINT32 Height,
    IN gceSURF_FORMAT PixelFormat,
    IN gctUINT32 Address,
    IN gctSIZE_T ByteCount
    )
{
    gceSTATUS status;
    gcsDUMP_SURFACE surface;

    gcmHEADER_ARG("Dump=0x%x Width=%d Height=%d PixelFormat=%d Address=%x "
                  "ByteCount=%d",
                  Dump, Width, Height, PixelFormat, Address, ByteCount);

    /* Verify the arguments. */
    gcmVERIFY_OBJECT(Dump, gcvOBJ_DUMP);
    gcmVERIFY_ARGUMENT(ByteCount > 0);

    if (Dump->file == gcvNULL)
    {
        /* There is no open dump file. */
        gcmFOOTER_NO();
        return gcvSTATUS_OK;
    }

    do
    {
        /* Write the data record. */
        surface.type    = gcvTAG_SURFACE;
        surface.address = Address;
        surface.width   = (gctINT16) Width;
        surface.height  = (gctINT16) Height;
        surface.format  = PixelFormat;
        surface.length  = ByteCount;

        gcmERR_BREAK(
            gcoOS_Write(gcvNULL, Dump->file, sizeof(surface), &surface));

        /* Update the frame length. */
        Dump->frameLength += sizeof(surface);

        /* Update the file length. */
        Dump->length += sizeof(surface);
    }
    while (gcvFALSE);

    /* Return the status. */
    gcmFOOTER();
    return status;
}
gceSTATUS vgsMEMORYMANAGER_Destroy(
	IN vgsMEMORYMANAGER_PTR Manager
	)
{
	gceSTATUS status;
	vgsMEMORYITEM_PTR current;
	vgsMEMORYITEM_PTR next;

    gcmHEADER_ARG("Manager=0x%x", Manager);

	/* Verify arguments. */
	gcmVERIFY_ARGUMENT(Manager != gcvNULL);

	/* Assume success. */
	status = gcvSTATUS_OK;

	/* Everything has to be freed. */
#if vgvVALIDATE_MEMORY_MANAGER
	gcmASSERT(Manager->allocatedCount == 0);
#endif

	/* Destroy all allocated buffers. */
	while (Manager->firstAllocated)
	{
		/* Get the current buffer. */
		current = Manager->firstAllocated;

		/* Get the next buffer. */
		next = current->next;

		/* Free the current. */
		gcmERR_BREAK(gcoOS_Free(Manager->os, current));

		/* Advance to the next one. */
		Manager->firstAllocated = next;
	}

	/* Success? */
	if (gcmIS_SUCCESS(status))
	{
		status = gcoOS_Free(Manager->os, Manager);
	}

    gcmFOOTER();
	/* Return status. */
	return status;
}
/*******************************************************************************
**
**  gcoDUMP_IsEnabled
**
**  Test whether dumping is enabeld or not.
**
**  INPUT:
**
**      gcoDUMP Dump
**          Pointer to a gcoDUMP object.
**
**  OUTPUT:
**
**      gctBOOL * Enabled
**          Pointer to a variable receiving the dump status.
*/
gceSTATUS
gcoDUMP_IsEnabled(
    IN gcoDUMP Dump,
    OUT gctBOOL * Enabled
    )
{
    gcmHEADER_ARG("Dump=0x%x Enabled=0x%x", Dump, Enabled);

    /* Verify the arguments. */
    gcmVERIFY_OBJECT(Dump, gcvOBJ_DUMP);
    gcmVERIFY_ARGUMENT(Enabled != gcvNULL);

    /* Return dump status. */
    *Enabled = (Dump->file != gcvNULL);

    /* Success. */
    gcmFOOTER_ARG("*Enabled=%d", *Enabled);
    return gcvSTATUS_OK;
}
/*******************************************************************************
**
**  gcoDUMP_Construct
**
**  Construct a new gcoDUMP object.
**
**  INPUT:
**
**      gcoOS Os
**          Pointer to an gcoOS object.
**
**      gcoOS Hal
**          Pointer to an gcoHAL object.
**
**  OUTPUT:
**
**      gcoDUMP * Dump
**          Pointer to a variable receiving the gcoDUMP object pointer.
*/
gceSTATUS
gcoDUMP_Construct(
    IN gcoOS Os,
    IN gcoHAL Hal,
    OUT gcoDUMP * Dump
    )
{
    gceSTATUS status;
    gcoDUMP dump;
    gctPOINTER pointer = gcvNULL;

    gcmHEADER_ARG("Os=0x%x Dump=0x%x", Os, Dump);

    /* Verify the arguments. */
    gcmVERIFY_ARGUMENT(Dump != gcvNULL);

    do
    {
        /* Allocate the gcoDUMP structure. */
        gcmERR_BREAK(gcoOS_Allocate(Os,
                                    sizeof(struct _gcoDUMP),
                                    &pointer));

        dump = pointer;

        /* Initialize the gcoDUMP object. */
        dump->object.type = gcvOBJ_DUMP;
        dump->file        = gcvNULL;

        /* Return pointer to the object. */
        *Dump = dump;
    }
    while (gcvFALSE);

    /* Return the status. */
    gcmFOOTER_ARG("*Dump=0x%x", *Dump);
    return status;
}
gceSTATUS
gcoQUEUE_Construct(
    IN gcoOS Os,
    OUT gcoQUEUE * Queue
    )
{
    gcoQUEUE queue = gcvNULL;
    gceSTATUS status;
#ifdef __QNXNTO__
    gctSIZE_T allocationSize;
    gctPHYS_ADDR physAddr;
#endif
    gctPOINTER pointer = gcvNULL;

    gcmHEADER();

    /* Verify the arguments. */
    gcmVERIFY_ARGUMENT(Queue != gcvNULL);

    /* Create the queue. */
    gcmONERROR(
        gcoOS_Allocate(gcvNULL,
                       gcmSIZEOF(struct _gcoQUEUE),
                       &pointer));
    queue = pointer;

    /* Initialize the object. */
    queue->object.type = gcvOBJ_QUEUE;

    /* Nothing in the queue yet. */
    queue->head = queue->tail = gcvNULL;

    queue->recordCount = 0;

#ifdef __QNXNTO__
    /* Allocate buffer of records. */
    allocationSize = BUFFER_SIZE;
    physAddr = 0;
    gcmONERROR(
        gcoOS_AllocateNonPagedMemory(gcvNULL,
                                     gcvTRUE,
                                     &allocationSize,
                                     &physAddr,
                                     (gctPOINTER *) &queue->records));
    queue->freeBytes = allocationSize;
    queue->offset = 0;
#else
    queue->freeList = gcvNULL;
#endif

    /* Return gcoQUEUE pointer. */
    *Queue = queue;

    /* Success. */
    gcmFOOTER_ARG("*Queue=0x%x", *Queue);
    return gcvSTATUS_OK;

OnError:
    if (queue != gcvNULL)
    {
        /* Roll back. */
        gcmVERIFY_OK(gcmOS_SAFE_FREE(gcvNULL, queue));
    }

    /* Return the status. */
    gcmFOOTER();
    return status;
}
gceSTATUS
gcoQUEUE_AppendEvent(
    IN gcoQUEUE Queue,
    IN gcsHAL_INTERFACE * Interface
    )
{
    gceSTATUS status;
    gcsQUEUE_PTR record = gcvNULL;
#ifdef __QNXNTO__
    gctSIZE_T allocationSize;
    gctPHYS_ADDR physAddr;
#else
    gctPOINTER pointer = gcvNULL;
#endif

    gcmHEADER_ARG("Queue=0x%x Interface=0x%x", Queue, Interface);

    /* Verify the arguments. */
    gcmVERIFY_OBJECT(Queue, gcvOBJ_QUEUE);
    gcmVERIFY_ARGUMENT(Interface != gcvNULL);

    /* Allocate record. */
#ifdef __QNXNTO__
    allocationSize = gcmSIZEOF(gcsQUEUE);
    if (Queue->freeBytes < allocationSize)
    {
        gctSIZE_T recordsSize = BUFFER_SIZE;
        gcsQUEUE_PTR prevRecords = Queue->records;
        gcsHAL_INTERFACE iface;

        /* Allocate new set of records. */
        gcmONERROR(
            gcoOS_AllocateNonPagedMemory(gcvNULL,
                                         gcvTRUE,
                                         &recordsSize,
                                         &physAddr,
                                         (gctPOINTER *) &Queue->records));
        Queue->freeBytes = recordsSize;
        Queue->offset = 0;

        if ( Queue->freeBytes < allocationSize )
        {
            gcmFOOTER_ARG("status=%d", gcvSTATUS_DATA_TOO_LARGE);
            return gcvSTATUS_DATA_TOO_LARGE;
        }

        /* Schedule to free Queue->records,
         * hence not unmapping currently scheduled events immediately. */
        iface.command = gcvHAL_FREE_NON_PAGED_MEMORY;
        iface.u.FreeNonPagedMemory.bytes = BUFFER_SIZE;
        iface.u.FreeNonPagedMemory.physical = 0;
        iface.u.FreeNonPagedMemory.logical = prevRecords;

        gcmONERROR(
            gcoQUEUE_AppendEvent(Queue, &iface));
    }

    record = (gcsQUEUE_PTR)((gctUINT32)Queue->records + Queue->offset);
    Queue->offset += allocationSize;
    Queue->freeBytes -= allocationSize;
#else
    /* Check if we have records on the free list. */
    if (Queue->freeList != gcvNULL)
    {
        /* Allocate from hte free list. */
        record          = Queue->freeList;
        Queue->freeList = record->next;
    }
    else
    {
        gcmONERROR(gcoOS_Allocate(gcvNULL,
                       gcmSIZEOF(gcsQUEUE),
                                  &pointer));
        record = pointer;
    }
#endif

    /* Initialize record. */
    record->next  = gcvNULL;
    gcoOS_MemCopy(&record->iface, Interface, gcmSIZEOF(record->iface));

    if (Queue->head == gcvNULL)
    {
        /* Initialize queue. */
        Queue->head = record;
    }
    else
    {
        /* Append record to end of queue. */
        Queue->tail->next = record;
    }

    /* Mark end of queue. */
    Queue->tail = record;

    /* update count */
    Queue->recordCount++;

    /* Success. */
    gcmFOOTER_NO();
    return gcvSTATUS_OK;

OnError:
#ifndef __QNXNTO__
    if (pointer != gcvNULL)
    {
        /* Put record on free list. */
        record->next    = Queue->freeList;
        Queue->freeList = record;
    }
#endif

    /* Return the status. */
    gcmFOOTER();
    return status;
}
gceSTATUS vgsMEMORYMANAGER_Allocate(
	IN vgsMEMORYMANAGER_PTR Manager,
	OUT gctPOINTER * Pointer
	)
{
	gceSTATUS status;
	vgsMEMORYITEM_PTR firstFree;

    gcmHEADER_ARG("Manager=0x%x Pointer=0x%x", Manager, Pointer);
	/* Verify arguments. */
	gcmVERIFY_ARGUMENT(Manager != gcvNULL);
	gcmVERIFY_ARGUMENT(Pointer != gcvNULL);

	/* Get the first free. */
	firstFree = Manager->firstFree;

	/* Are there free items? */
	if (firstFree != gcvNULL)
	{
		/* Set the result. */
		* Pointer = firstFree + 1;

		/* Remove from the free list. */
		Manager->firstFree = firstFree->next;

		/* Update allocated items count. */
#if vgvVALIDATE_MEMORY_MANAGER
		Manager->allocatedCount += 1;

		if ((gctUINT) Manager->allocatedCount > Manager->maximumAllocated)
		{
			Manager->maximumAllocated = Manager->allocatedCount;
		}
#endif

		/* Success. */
                gcmFOOTER_ARG("*Pointer=0x%x", *Pointer);
		return gcvSTATUS_OK;
	}

	/* No free items available. */
	do
	{
		vgsMEMORYITEM_PTR newBuffer;
		gctUINT i, itemCount;
		gctUINT itemSize;

		/* Allocate a new buffer. */
		gcmERR_BREAK(gcoOS_Allocate(
			Manager->os,
			Manager->allocationSize,
			(gctPOINTER) &newBuffer
			));

		/* Link in. */
		newBuffer->next = Manager->firstAllocated;
		Manager->firstAllocated = newBuffer;

		/* Set the result. */
		* Pointer = newBuffer + 2;

		/* Update allocated items count. */
#if vgvVALIDATE_MEMORY_MANAGER
		Manager->allocatedCount       += 1;
		Manager->allocatedBufferCount += 1;

		if ((gctUINT) Manager->allocatedCount > Manager->maximumAllocated)
		{
			Manager->maximumAllocated = Manager->allocatedCount;
		}
#endif

		/* Get the number of items per allocation. */
		itemCount = Manager->itemCount;

		/* Get the item size. */
		itemSize = Manager->itemSize;

		/* Determine the first free item. */
		firstFree = (vgsMEMORYITEM_PTR)
		(
			(gctUINT8_PTR) (newBuffer + 1) + itemSize
		);

		/* Populate the new buffer. */
		for (i = 1; i < itemCount; i++)
		{
			/* Add to the free item list. */
			firstFree->next = Manager->firstFree;
			Manager->firstFree = firstFree;

			/* Advance to the next item. */
			firstFree = (vgsMEMORYITEM_PTR)
			(
				(gctUINT8_PTR) firstFree + itemSize
			);
		}
	}
	while (gcvFALSE);

    gcmFOOTER();
	/* Return status. */
	return status;
}