/******************************************************************************

 � 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc.
 All rights reserved.

 This is proprietary source code of Freescale Semiconductor Inc.,
 and its use is subject to the NetComm Device Drivers EULA.
 The copyright notice above does not evidence any actual or intended
 publication of such source code.

 ALTERNATIVELY, redistribution and use in source and binary forms, with
 or without modification, are permitted provided that the following
 conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
     * Neither the name of Freescale Semiconductor nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *

 **************************************************************************/
#include "error_ext.h"
#include "part_ext.h"
#include "std_ext.h"
#include "string_ext.h"
#include "mem_ext.h"
#include "mem.h"
#include "xx_ext.h"


#if 0
#define PAD_ALIGNMENT(align, x) (((x)%(align)) ? ((align)-((x)%(align))) : 0)

#define ALIGN_BLOCK(p_Block, prefixSize, alignment)                 \
    do {                                                            \
        p_Block += (prefixSize);                                    \
        p_Block += PAD_ALIGNMENT((alignment), (uintptr_t)(p_Block)); \
    } while (0)

#if defined(__GNUC__)
#define GET_CALLER_ADDR \
    __asm__ ("mflr  %0" : "=r" (callerAddr))
#elif defined(__MWERKS__)
/* NOTE: This implementation is only valid for CodeWarrior for PowerPC */
#define GET_CALLER_ADDR \
    __asm__("add  %0, 0, %0" : : "r" (callerAddr))
#endif /* defined(__GNUC__) */


/*****************************************************************************/
static __inline__ void * MemGet(t_MemorySegment *p_Mem)
{
    uint8_t *p_Block;

    /* check if there is an available block */
    if (p_Mem->current == p_Mem->num)
    {
        p_Mem->getFailures++;
        return NULL;
    }

    /* get the block */
    p_Block = p_Mem->p_BlocksStack[p_Mem->current];
#ifdef DEBUG
    p_Mem->p_BlocksStack[p_Mem->current] = NULL;
#endif /* DEBUG */
    /* advance current index */
    p_Mem->current++;

    return (void *)p_Block;
}

/*****************************************************************************/
static __inline__ t_Error MemPut(t_MemorySegment *p_Mem, void *p_Block)
{
    /* check if blocks stack is full */
    if (p_Mem->current > 0)
    {
        /* decrease current index */
        p_Mem->current--;
        /* put the block */
        p_Mem->p_BlocksStack[p_Mem->current] = (uint8_t *)p_Block;
        return E_OK;
    }

    RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
}


#ifdef DEBUG_MEM_LEAKS

/*****************************************************************************/
static t_Error InitMemDebugDatabase(t_MemorySegment *p_Mem)
{
    p_Mem->p_MemDbg = (void *)XX_Malloc(sizeof(t_MemDbg) * p_Mem->num);
    if (!p_Mem->p_MemDbg)
    {
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory debug object"));
    }

    memset(p_Mem->p_MemDbg, ILLEGAL_BASE, sizeof(t_MemDbg) * p_Mem->num);

    return E_OK;
}


/*****************************************************************************/
static t_Error DebugMemGet(t_Handle h_Mem, void *p_Block, uintptr_t ownerAddress)
{
    t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
    t_MemDbg        *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
    uint32_t        blockIndex;

    ASSERT_COND(ownerAddress != ILLEGAL_BASE);

    /* Find block num */
    if (p_Mem->consecutiveMem)
    {
        blockIndex =
            (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
    }
    else
    {
        blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
    }

    ASSERT_COND(blockIndex < p_Mem->num);
    ASSERT_COND(p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE);

    p_MemDbg[blockIndex].ownerAddress = ownerAddress;

    return E_OK;
}

/*****************************************************************************/
static t_Error DebugMemPut(t_Handle h_Mem, void *p_Block)
{
    t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
    t_MemDbg        *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
    uint32_t        blockIndex;
    uint8_t         *p_Temp;

    /* Find block num */
    if (p_Mem->consecutiveMem)
    {
        blockIndex =
            (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);

        if (blockIndex >= p_Mem->num)
        {
            RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
                         ("Freed address (0x%08x) does not belong to this pool", p_Block));
        }
    }
    else
    {
        blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);

        if (blockIndex >= p_Mem->num)
        {
            RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
                         ("Freed address (0x%08x) does not belong to this pool", p_Block));
        }

        /* Verify that the block matches the corresponding base */
        p_Temp = p_Mem->p_Bases[blockIndex];

        ALIGN_BLOCK(p_Temp, p_Mem->prefixSize, p_Mem->alignment);

        if (p_Temp == p_Mem->p_Bases[blockIndex])
            p_Temp += p_Mem->alignment;

        if (p_Temp != p_Block)
        {
            RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
                         ("Freed address (0x%08x) does not belong to this pool", p_Block));
        }
    }

    if (p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE)
    {
        RETURN_ERROR(MAJOR, E_ALREADY_FREE,
                     ("Attempt to free unallocated address (0x%08x)", p_Block));
    }

    p_MemDbg[blockIndex].ownerAddress = (uintptr_t)ILLEGAL_BASE;

    return E_OK;
}

#endif /* DEBUG_MEM_LEAKS */


/*****************************************************************************/
uint32_t MEM_ComputePartitionSize(uint32_t num,
                                  uint16_t dataSize,
                                  uint16_t prefixSize,
                                  uint16_t postfixSize,
                                  uint16_t alignment)
{
    uint32_t  blockSize = 0, pad1 = 0, pad2 = 0;

    /* Make sure that the alignment is at least 4 */
    if (alignment < 4)
    {
        alignment = 4;
    }

    pad1 = (uint32_t)PAD_ALIGNMENT(4, prefixSize);
    /* Block size not including 2nd padding */
    blockSize = pad1 + prefixSize + dataSize + postfixSize;
    pad2 = PAD_ALIGNMENT(alignment, blockSize);
    /* Block size including 2nd padding */
    blockSize += pad2;

    return ((num * blockSize) + alignment);
}

/*****************************************************************************/
t_Error MEM_Init(char       name[],
                 t_Handle   *p_Handle,
                 uint32_t   num,
                 uint16_t   dataSize,
                 uint16_t   prefixSize,
                 uint16_t   postfixSize,
                 uint16_t   alignment)
{
    uint8_t     *p_Memory;
    uint32_t    allocSize;
    t_Error     errCode;

    allocSize = MEM_ComputePartitionSize(num,
                                         dataSize,
                                         prefixSize,
                                         postfixSize,
                                         alignment);

    p_Memory = (uint8_t *)XX_Malloc(allocSize);
    if (!p_Memory)
    {
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment"));
    }

    errCode = MEM_InitByAddress(name,
                                p_Handle,
                                num,
                                dataSize,
                                prefixSize,
                                postfixSize,
                                alignment,
                                p_Memory);
    if (errCode != E_OK)
    {
        RETURN_ERROR(MAJOR, errCode, NO_MSG);
    }

    ((t_MemorySegment *)(*p_Handle))->allocOwner = e_MEM_ALLOC_OWNER_LOCAL;

    return E_OK;
}


/*****************************************************************************/
t_Error MEM_InitByAddress(char      name[],
                          t_Handle  *p_Handle,
                          uint32_t  num,
                          uint16_t  dataSize,
                          uint16_t  prefixSize,
                          uint16_t  postfixSize,
                          uint16_t  alignment,
                          uint8_t   *p_Memory)
{
    t_MemorySegment *p_Mem;
    uint32_t        i, blockSize;
    uint16_t        alignPad, endPad;
    uint8_t         *p_Blocks;

     /* prepare in case of error */
    *p_Handle = NULL;

    if (!p_Memory)
    {
        RETURN_ERROR(MAJOR, E_NULL_POINTER, ("Memory blocks"));
    }

    p_Blocks = p_Memory;

    /* make sure that the alignment is at least 4 and power of 2 */
    if (alignment < 4)
    {
        alignment = 4;
    }
    else if (!POWER_OF_2(alignment))
    {
        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
    }

    /* first allocate the segment descriptor */
    p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
    if (!p_Mem)
    {
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
    }

    /* allocate the blocks stack */
    p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
    if (!p_Mem->p_BlocksStack)
    {
        XX_Free(p_Mem);
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
    }

    /* allocate the blocks bases array */
    p_Mem->p_Bases = (uint8_t **)XX_Malloc(sizeof(uint8_t*));
    if (!p_Mem->p_Bases)
    {
        MEM_Free(p_Mem);
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
    }
    memset(p_Mem->p_Bases, 0, sizeof(uint8_t*));

    /* store info about this segment */
    p_Mem->num = num;
    p_Mem->current = 0;
    p_Mem->dataSize = dataSize;
    p_Mem->p_Bases[0] = p_Blocks;
    p_Mem->getFailures = 0;
    p_Mem->allocOwner = e_MEM_ALLOC_OWNER_EXTERNAL;
    p_Mem->consecutiveMem = TRUE;
    p_Mem->prefixSize = prefixSize;
    p_Mem->postfixSize = postfixSize;
    p_Mem->alignment = alignment;
    /* store name */
    strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);

    p_Mem->h_Spinlock = XX_InitSpinlock();
    if (!p_Mem->h_Spinlock)
    {
        MEM_Free(p_Mem);
        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
    }

    alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
    /* Make sure the entire size is a multiple of alignment */
    endPad = (uint16_t)PAD_ALIGNMENT(alignment, (alignPad + prefixSize + dataSize + postfixSize));

    /* The following manipulation places the data of block[0] in an aligned address,
       since block size is aligned the following block datas will all be aligned */
    ALIGN_BLOCK(p_Blocks, prefixSize, alignment);

    blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);

    /* initialize the blocks */
    for (i=0; i < num; i++)
    {
        p_Mem->p_BlocksStack[i] = p_Blocks;
        p_Blocks += blockSize;
    }

    /* return handle to caller */
    *p_Handle = (t_Handle)p_Mem;

#ifdef DEBUG_MEM_LEAKS
    {
        t_Error errCode = InitMemDebugDatabase(p_Mem);

        if (errCode != E_OK)
            RETURN_ERROR(MAJOR, errCode, NO_MSG);

        p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
        p_Mem->blockSize = blockSize;
    }
#endif /* DEBUG_MEM_LEAKS */

    return E_OK;
}


/*****************************************************************************/
t_Error MEM_InitSmart(char      name[],
                      t_Handle  *p_Handle,
                      uint32_t  num,
                      uint16_t  dataSize,
                      uint16_t  prefixSize,
                      uint16_t  postfixSize,
                      uint16_t  alignment,
                      uint8_t   memPartitionId,
                      bool      consecutiveMem)
{
    t_MemorySegment *p_Mem;
    uint32_t        i, blockSize;
    uint16_t        alignPad, endPad;

    /* prepare in case of error */
    *p_Handle = NULL;

    /* make sure that size is always a multiple of 4 */
    if (dataSize & 3)
    {
        dataSize &= ~3;
        dataSize += 4;
    }

    /* make sure that the alignment is at least 4 and power of 2 */
    if (alignment < 4)
    {
        alignment = 4;
    }
    else if (!POWER_OF_2(alignment))
    {
        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
    }

    /* first allocate the segment descriptor */
    p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
    if (!p_Mem)
    {
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
    }

    /* allocate the blocks stack */
    p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
    if (!p_Mem->p_BlocksStack)
    {
        MEM_Free(p_Mem);
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
    }

    /* allocate the blocks bases array */
    p_Mem->p_Bases = (uint8_t **)XX_Malloc((consecutiveMem ? 1 : num) * sizeof(uint8_t*));
    if (!p_Mem->p_Bases)
    {
        MEM_Free(p_Mem);
        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
    }
    memset(p_Mem->p_Bases, 0, (consecutiveMem ? 1 : num) * sizeof(uint8_t*));

    /* store info about this segment */
    p_Mem->num = num;
    p_Mem->current = 0;
    p_Mem->dataSize = dataSize;
    p_Mem->getFailures = 0;
    p_Mem->allocOwner = e_MEM_ALLOC_OWNER_LOCAL_SMART;
    p_Mem->consecutiveMem = consecutiveMem;
    p_Mem->prefixSize = prefixSize;
    p_Mem->postfixSize = postfixSize;
    p_Mem->alignment = alignment;

    p_Mem->h_Spinlock = XX_InitSpinlock();
    if (!p_Mem->h_Spinlock)
    {
        MEM_Free(p_Mem);
        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
    }

    alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
    /* Make sure the entire size is a multiple of alignment */
    endPad = (uint16_t)PAD_ALIGNMENT(alignment, alignPad + prefixSize + dataSize + postfixSize);

    /* Calculate blockSize */
    blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);

    /* Now allocate the blocks */
    if (p_Mem->consecutiveMem)
    {
        /* |alignment - 1| bytes at most will be discarded in the beginning of the
           received segment for alignment reasons, therefore the allocation is of:
           (alignment + (num * block size)). */
        uint8_t *p_Blocks = (uint8_t *)
            XX_MallocSmart((uint32_t)((num * blockSize) + alignment), memPartitionId, 1);
        if (!p_Blocks)
        {
            MEM_Free(p_Mem);
            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
        }

        /* Store the memory segment address */
        p_Mem->p_Bases[0] = p_Blocks;

        /* The following manipulation places the data of block[0] in an aligned address,
           since block size is aligned the following block datas will all be aligned.*/
        ALIGN_BLOCK(p_Blocks, prefixSize, alignment);

        /* initialize the blocks */
        for (i = 0; i < num; i++)
        {
            p_Mem->p_BlocksStack[i] = p_Blocks;
            p_Blocks += blockSize;
        }

#ifdef DEBUG_MEM_LEAKS
        p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
        p_Mem->blockSize = blockSize;
#endif /* DEBUG_MEM_LEAKS */
    }
    else
    {
        /* |alignment - 1| bytes at most will be discarded in the beginning of the
           received segment for alignment reasons, therefore the allocation is of:
           (alignment + block size). */
        for (i = 0; i < num; i++)
        {
            uint8_t *p_Block = (uint8_t *)
                XX_MallocSmart((uint32_t)(blockSize + alignment), memPartitionId, 1);
            if (!p_Block)
            {
                MEM_Free(p_Mem);
                RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
            }

            /* Store the memory segment address */
            p_Mem->p_Bases[i] = p_Block;

            /* The following places the data of each block in an aligned address */
            ALIGN_BLOCK(p_Block, prefixSize, alignment);

#ifdef DEBUG_MEM_LEAKS
            /* Need 4 bytes before the meaningful bytes to store the block index.
               We know we have them because alignment is at least 4 bytes. */
            if (p_Block == p_Mem->p_Bases[i])
                p_Block += alignment;

            *(uint32_t *)(p_Block - 4) = i;
#endif /* DEBUG_MEM_LEAKS */

            p_Mem->p_BlocksStack[i] = p_Block;
        }
    }

    /* store name */
    strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);

    /* return handle to caller */
    *p_Handle = (t_Handle)p_Mem;

#ifdef DEBUG_MEM_LEAKS
    {
        t_Error errCode = InitMemDebugDatabase(p_Mem);

        if (errCode != E_OK)
            RETURN_ERROR(MAJOR, errCode, NO_MSG);
    }
#endif /* DEBUG_MEM_LEAKS */

    return E_OK;
}


/*****************************************************************************/
void MEM_Free(t_Handle h_Mem)
{
    t_MemorySegment *p_Mem = (t_MemorySegment*)h_Mem;
    uint32_t        num, i;

    /* Check MEM leaks */
    MEM_CheckLeaks(h_Mem);

    if (p_Mem)
    {
        num = p_Mem->consecutiveMem ? 1 : p_Mem->num;

        if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL_SMART)
        {
            for (i=0; i < num; i++)
            {
                if (p_Mem->p_Bases[i])
                {
                    XX_FreeSmart(p_Mem->p_Bases[i]);
                }
            }
        }
        else if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL)
        {
            for (i=0; i < num; i++)
            {
                if (p_Mem->p_Bases[i])
                {
                    XX_Free(p_Mem->p_Bases[i]);
                }
            }
        }

        if (p_Mem->h_Spinlock)
            XX_FreeSpinlock(p_Mem->h_Spinlock);

        if (p_Mem->p_Bases)
            XX_Free(p_Mem->p_Bases);

        if (p_Mem->p_BlocksStack)
            XX_Free(p_Mem->p_BlocksStack);

#ifdef DEBUG_MEM_LEAKS
        if (p_Mem->p_MemDbg)
            XX_Free(p_Mem->p_MemDbg);
#endif /* DEBUG_MEM_LEAKS */

       XX_Free(p_Mem);
    }
}


/*****************************************************************************/
void * MEM_Get(t_Handle h_Mem)
{
    t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
    uint8_t         *p_Block;
    uint32_t        intFlags;
#ifdef DEBUG_MEM_LEAKS
    uintptr_t       callerAddr = 0;

    GET_CALLER_ADDR;
#endif /* DEBUG_MEM_LEAKS */

    ASSERT_COND(h_Mem);

    intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
    /* check if there is an available block */
    if ((p_Block = (uint8_t *)MemGet(p_Mem)) == NULL)
    {
        XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
        return NULL;
    }

#ifdef DEBUG_MEM_LEAKS
    DebugMemGet(p_Mem, p_Block, callerAddr);
#endif /* DEBUG_MEM_LEAKS */
    XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);

    return (void *)p_Block;
}


/*****************************************************************************/
uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[])
{
    t_MemorySegment     *p_Mem = (t_MemorySegment *)h_Mem;
    uint32_t            availableBlocks;
    register uint32_t   i;
    uint32_t            intFlags;
#ifdef DEBUG_MEM_LEAKS
    uintptr_t           callerAddr = 0;

    GET_CALLER_ADDR;
#endif /* DEBUG_MEM_LEAKS */

    ASSERT_COND(h_Mem);

    intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
    /* check how many blocks are available */
    availableBlocks = (uint32_t)(p_Mem->num - p_Mem->current);
    if (num > availableBlocks)
    {
        num = availableBlocks;
    }

    for (i=0; i < num; i++)
    {
        /* get pointer to block */
        if ((array[i] = MemGet(p_Mem)) == NULL)
        {
            break;
        }

#ifdef DEBUG_MEM_LEAKS
        DebugMemGet(p_Mem, array[i], callerAddr);
#endif /* DEBUG_MEM_LEAKS */
    }
    XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);

    return (uint16_t)i;
}


/*****************************************************************************/
t_Error MEM_Put(t_Handle h_Mem, void *p_Block)
{
    t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
    t_Error         rc;
    uint32_t        intFlags;

    ASSERT_COND(h_Mem);

    intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
    /* check if blocks stack is full */
    if ((rc = MemPut(p_Mem, p_Block)) != E_OK)
    {
        XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
        RETURN_ERROR(MAJOR, rc, NO_MSG);
    }

#ifdef DEBUG_MEM_LEAKS
    DebugMemPut(p_Mem, p_Block);
#endif /* DEBUG_MEM_LEAKS */
    XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);

    return E_OK;
}


#ifdef DEBUG_MEM_LEAKS

/*****************************************************************************/
void MEM_CheckLeaks(t_Handle h_Mem)
{
    t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
    t_MemDbg        *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
    uint8_t         *p_Block;
    int             i;

    ASSERT_COND(h_Mem);

    if (p_Mem->consecutiveMem)
    {
        for (i=0; i < p_Mem->num; i++)
        {
            if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
            {
                /* Find the block address */
                p_Block = ((p_Mem->p_Bases[0] + p_Mem->blockOffset) +
                           (i * p_Mem->blockSize));

                XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
                         p_Block, p_MemDbg[i].ownerAddress);
            }
        }
    }
    else
    {
        for (i=0; i < p_Mem->num; i++)
        {
            if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
            {
                /* Find the block address */
                p_Block = p_Mem->p_Bases[i];

                ALIGN_BLOCK(p_Block, p_Mem->prefixSize, p_Mem->alignment);

                if (p_Block == p_Mem->p_Bases[i])
                    p_Block += p_Mem->alignment;

                XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
                         p_Block, p_MemDbg[i].ownerAddress);
            }
        }
    }
}

#endif /* DEBUG_MEM_LEAKS */


#endif