/* ========================================================================== */
/*                                                                            */
/*                                                                            */
/*  NAME                                                                      */
/*     videoTranscodeMemMgr.c                                                */
/*                                                                            */
/*  DESCRIPTION                                                               */
/*    This module implements an algorithm memory management "policy" in which */
/*  no memory is shared among algorithm objects.  Memory is, however          */
/*  reclaimed when objects are deleted.                                       */
/*                                                                            */
/*  preemption      sharing             object deletion                       */
/*  ----------      -------             ---------------                       */
/*  yes(*)          none                yes                                   */
/*                                                                            */
/*  Note 1: this module uses run-time support functions malloc() and free()   */
/*  to allocate and free memory.  Since these functions are *not* reentrant,  */
/*  either all object creation and deletion must be performed by a single     */
/*  thread or reentrant versions of these functions must be created.          */
/*                                                                            */
/*                                                                            */
/*   Copyright (c) 2001-2003 Texas Instruments Incorporated.
 *
 *  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 Texas Instruments Incorporated 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "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 THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS 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 <ti/bios/include/std.h> /* Take from Bios*/
#include <ti/xdais/ialg.h>
#include <stdlib.h>     /* malloc/free declarations */
#include <string.h>     /* memset declaration */

#define INTERNAL_DATA_MEM_SIZE    (0x3FD00)
/* list of some parameters macros for worst case memory allocation in external memory */
#define EXTERNAL_DATA_MEM_SIZE    (16*1920*1088)

#pragma DATA_SECTION( ExternalGlobalMemPool, ".testCodecExtMem");
#pragma DATA_SECTION( externalDataMemorySize, ".testCodecExtMem");
#pragma DATA_SECTION( ExternalGlobalMem, ".testCodecExtMem");
#pragma DATA_SECTION( ExternalGlobalMemSecond, ".testCodecExtMemSecond");

#pragma DATA_SECTION( internalDataMemory, ".testCodecIntMem");
#pragma DATA_SECTION( pInternalDataMemory, ".testCodecIntMem");
#pragma DATA_SECTION( internalDataMemorySize, ".testCodecIntMem");

unsigned char  ExternalGlobalMem[EXTERNAL_DATA_MEM_SIZE];
unsigned char  ExternalGlobalMemSecond[EXTERNAL_DATA_MEM_SIZE];
unsigned char  *ExternalGlobalMemPool = ExternalGlobalMem;
unsigned int   externalDataMemorySize = EXTERNAL_DATA_MEM_SIZE;

unsigned int  internalDataMemorySize = INTERNAL_DATA_MEM_SIZE;
unsigned char internalDataMemory[ INTERNAL_DATA_MEM_SIZE];
unsigned char *pInternalDataMemory = internalDataMemory;

Bool _ALG_allocMemory(IALG_MemRec memTab[], Int n, Bool second_inst);
Void _ALG_freeMemory(IALG_MemRec memTab[], Int n, Bool second_inst);

void * memAlignVc(size_t alignment, size_t size)
{
  return malloc( size);
} /* memAlignVc */


int allocateMemTabRequest( IALG_MemRec *memTab)
{
  if( memTab->space == IALG_EXTERNAL ) {
    unsigned int  alignBytes;
    alignBytes = (((unsigned int) ExternalGlobalMemPool + (memTab->alignment - 1)) & (~ (memTab->alignment - 1)));
    alignBytes -= (unsigned int) ExternalGlobalMemPool;
    ExternalGlobalMemPool += alignBytes;
    externalDataMemorySize -= alignBytes;
    if(externalDataMemorySize >= memTab->size) {
      /* allocate memory */
      memTab->base = ExternalGlobalMemPool;
      ExternalGlobalMemPool += memTab->size;
      externalDataMemorySize -= memTab->size;
    } else {
      memTab->base = 0;
    }
  } else {
    /* internal memory request */
    unsigned int  alignBytes;
    alignBytes = (((unsigned int) pInternalDataMemory + (memTab->alignment - 1)) & (~ (memTab->alignment - 1)));
    if(alignBytes!=0)
    {
        alignBytes -= (unsigned int) pInternalDataMemory;
        pInternalDataMemory += alignBytes;
        internalDataMemorySize -= alignBytes;
    }
    if(internalDataMemorySize >= memTab->size)
    {
        /* allocate memory */
        memTab->base = pInternalDataMemory;
        pInternalDataMemory += memTab->size;
        internalDataMemorySize -= memTab->size;
    } else {
        memTab->base = 0;
    }
  }
  return 0;
} /* allocateMemTabRequest */

int freeMemTabRequest( IALG_MemRec  *memTab, Bool second_inst)
{
  if( memTab->space == IALG_EXTERNAL ) {
    memTab->base = 0;
    if(!second_inst)
        ExternalGlobalMemPool = ExternalGlobalMem;
    else
        ExternalGlobalMemPool = ExternalGlobalMemSecond;
    externalDataMemorySize = EXTERNAL_DATA_MEM_SIZE ;
  } else {
    /* internal memory  free request. XXX see the code  below
     * for the dangers of calling them as normal mallocs. Free is faked!!!  */
    memTab->base = 0;
    pInternalDataMemory = internalDataMemory;
    internalDataMemorySize = INTERNAL_DATA_MEM_SIZE;
  }
  return 0;
} /* freeMemTabRequest */


/*
 *  ======== ALG_exit ========
 */
Void ALG_exit(Void)
{
}

/*
 *  ======== ALG_init ========
 */
Void ALG_init(Void)
{
}


/*
 *  ======== _ALG_allocMemory ========
 */
Bool _ALG_allocMemory(IALG_MemRec memTab[], Int n, Bool second_inst)
{
    Int i;
    if(!second_inst)
        ExternalGlobalMemPool = ExternalGlobalMem;
    else
        ExternalGlobalMemPool = ExternalGlobalMemSecond;
    externalDataMemorySize = EXTERNAL_DATA_MEM_SIZE ;

    pInternalDataMemory = internalDataMemory;
    internalDataMemorySize = INTERNAL_DATA_MEM_SIZE;

    for (i = 0; i < n; i++) {
      /* XXX changing the code here, to change the memory allocator for
       * different requirements. */
      allocateMemTabRequest( &memTab[i]);

      if (memTab[i].base == NULL) {
          _ALG_freeMemory(memTab, i, second_inst);
          return (FALSE);
      }
    }

    return (TRUE);
}


/*
 *  ======== _ALG_freeMemory ========
 */
Void _ALG_freeMemory(IALG_MemRec memTab[], Int n, Bool second_inst)
{
    Int i;

    for (i = 0; i < n; i++) {
        if (memTab[i].base != NULL) {
          /* XXX changing code here too. to take care of internal memory
           * allocatiuons */
          freeMemTabRequest( &memTab[i], second_inst);
        }
    }
}

/*
 *  ======== ALG_create ========
 */
#pragma DATA_SECTION( memTabMemory, ".testCodecExtMem");
char memTabMemory[40 * sizeof (IALG_MemRec)];
#include <stdio.h>
#include <stdlib.h>
IALG_Handle ALG_create(IALG_Fxns *fxns, IALG_Handle p, IALG_Params *params, Bool second_inst)
{
    IALG_MemRec *memTab;
    Int i, n;
    IALG_Handle alg;
    IALG_Fxns *fxnsPtr;
    char memTabMemory_local[40 * sizeof (IALG_MemRec)];


    if (fxns != NULL) {
        n = ((fxns->algNumAlloc != NULL) ? fxns->algNumAlloc() : IALG_DEFMEMRECS);
        /* The cores cannot share memtab memory */
        //memTab = (IALG_MemRec *)memTabMemory;
        memTab = (IALG_MemRec *)memTabMemory_local;
        if (memTab!=NULL) {

            n = fxns->algAlloc(params, &fxnsPtr, memTab);
            printf("Num. buffs requested = %d \n", n);
            for (i=0;i<n;i++) {
                printf("algAlloc req. Buffer %d: space = %d, size = %ld \n", i, memTab[i].space, memTab[i].size);
                fflush(stdout);
            }
            if (n <= 0) {
                return (NULL);
            }

            if (_ALG_allocMemory(memTab, n, second_inst)!=FALSE) {
                alg = (IALG_Handle)memTab[0].base;
                alg->fxns = fxns;
                if (fxns->algInit(alg, memTab, p, params) == IALG_EOK) {
                    return (alg);
                }
                fxns->algFree(alg, memTab);
                _ALG_freeMemory(memTab, n, second_inst);
            }
            free(memTab);
        }
    }

    return (NULL);
}

/*
 *  ======== ALG_delete ========
 */
Void ALG_delete(IALG_Handle alg, Bool second_inst)
{
    IALG_MemRec *memTab;
    Int n;
    IALG_Fxns *fxns;

    if ((alg != NULL) && (alg->fxns != NULL)) {
        fxns = alg->fxns;
        n = ((fxns->algNumAlloc != NULL) ? fxns->algNumAlloc() : IALG_DEFMEMRECS);

        memTab = (IALG_MemRec *)malloc(n * sizeof (IALG_MemRec));
        if (memTab!=NULL) {
            memTab[0].base = alg;
            n = fxns->algFree(alg, memTab);
            _ALG_freeMemory(memTab, n, second_inst);

            free(memTab);
        }
    }
}

/*
 *  ======== ALG_control ========
 */
Int ALG_control(IALG_Handle alg, IALG_Cmd cmd, IALG_Status *statusPtr)
{
    if ( (alg) && (alg->fxns->algControl)) {
        return (alg->fxns->algControl(alg, cmd, statusPtr));
    }

    return (IALG_EFAIL);
}



