/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/* memman.c                                                           */
/*                                                                    */
/* Memory management functions.                                       */
/**********************************************************************/
#define INCL_DOSPROCESS
#define INCL_DOSMISC
#define INCL_ERRORS
#include <eddinclt.h>
#include <eddbcone.h>

#include <memman.h>

extern PBYTE    pSysCacheStart;
extern PVOID    pPhunkVirt;

ULONG           ulSSAllocated   = 0;
ULONG           ulSSFreed       = 0;
ULONG           ulSSInUse       = 0;


PVOID DRIVERCALL AllocateMemory(ULONG ulSize,
                                ULONG ulTypeID,
                                ULONG ulFlags)
{
    PVOID   pNewMemoryBase;
    ULONG   ulErrorCode;

    /**************************************************************/
    /* Objects requested as SSAlloc'd must be exactly the size    */
    /* asked for - this therefore means we cannot store our       */
    /* memory information for them - and thus they may never be   */
    /* freed (which if they must be SSAlloc'd is a reasonable     */
    /* request).                                                  */
    /*                                                            */
    /* For all other requests we grab a bit more memory than      */
    /* asked for, in order to store our memory object info.       */
    /**************************************************************/
    if (!(ulFlags & MO_SSALLOC))
    {
        /**************************************************************/
        /* Add in the structure we add to the start of the memory     */
        /* block.                                                     */
        /**************************************************************/
        ulSize += sizeof(MEMORYOBJECTINFO);

        /**************************************************************/
        /* Round up to a multiple of 8 bytes.                         */
        /**************************************************************/
        ulSize = (ulSize + 7) & 0xFFFFFFF8;

    }


    /******************************************************************/
    /* Either the object was too big, the allocation on the heap      */
    /* was unsucessful, or we were specifically asked for an SSAlloc'd*/
    /* object. We must create a specific new memory object            */
    /* for the requested memory.                                      */
    /******************************************************************/
    do
    {
        /**************************************************************/
        /* If the object is an external bitmap or a bitmap info       */
        /* structure then it may be accessed else where in the system */
        /* so we must make sure that the object is tiled.  (Otherwise */
        /* 16bit code could not access it).  We use non-tiled memory  */
        /* in all the other cases because this gives better           */
        /* performance. (No selector has to be allocated).            */
        /**************************************************************/
        if ((ulTypeID == MT_EXT_BITMAP) || (ulTypeID == MT_BITMAP_INFO2))
        {
            ulErrorCode = SSAllocMem( &pNewMemoryBase,
                                      ulSize,
                                      OBJ_TILE |
                                         PAG_COMMIT | PAG_READ | PAG_WRITE );
        }
        else
        {
            ulErrorCode = SSAllocMem( &pNewMemoryBase,
                                      ulSize,
                                      PAG_COMMIT | PAG_READ | PAG_WRITE );
        }

    } while ( ulErrorCode == ERROR_INTERRUPT );

    if (ulErrorCode != NO_ERROR)
    {
        LogError(PMERR_MEMORY_ALLOCATION_ERR);
        return(NULL);
    }

    ulSSAllocated += ulSize;
    ulSSInUse     += ulSize;

    /******************************************************************/
    /* We have successfully got a block of memory of the required     */
    /* size. We must now set up the memory object info structure and  */
    /* return the pointer to the block of memory.                     */
    /*                                                                */
    /* Only set up the memory object info structure if we actually    */
    /* got the memory to do so.                                       */
    /******************************************************************/
    if (!(ulFlags & MO_SSALLOC))
    {
        ((PMEMORYOBJECTINFO)pNewMemoryBase)->ulSize      = ulSize;
        ((PMEMORYOBJECTINFO)pNewMemoryBase)->ulAllocType = AT_SSALLOC;
        ((PMEMORYOBJECTINFO)pNewMemoryBase)->objectid    = ulTypeID;

        /**************************************************************/
        /* The user memory block is after the structure info.         */
        /**************************************************************/
        (PBYTE)pNewMemoryBase += sizeof(MEMORYOBJECTINFO);
    }

    /******************************************************************/
    /* Now return the pointer to the start of the requested memory    */
    /* block.                                                         */
    /******************************************************************/
    return (pNewMemoryBase);
}


ULONG DRIVERCALL FreeMemory(PVOID pFreeMemoryBase)
{
    ULONG   ulSize;
    ULONG   ulAT;
    ULONG   ulErrorCode;

    /******************************************************************/
    /* First we must adjust the pointer so that it points at the start*/
    /* of the memory object info that preceeds each allocated block   */
    /* of memory.                                                     */
    /******************************************************************/
    pFreeMemoryBase = ((PBYTE)pFreeMemoryBase) - sizeof(MEMORYOBJECTINFO);

    /******************************************************************/
    /* Get the information we need to free the memory.                */
    /******************************************************************/
    ulSize = ((PMEMORYOBJECTINFO)pFreeMemoryBase)->ulSize;
    ulAT = ((PMEMORYOBJECTINFO)pFreeMemoryBase)->ulAllocType;

    do {
        ulErrorCode = SSFreeMem ( pFreeMemoryBase );
    } while ( ulErrorCode == ERROR_INTERRUPT );

    if (ulErrorCode == NO_ERROR)
    {
        /**************************************************************/
        /* The memory was freed sucessfully.                          */
        /**************************************************************/
        ulSSInUse -= ulSize;
        ulSSFreed += ulSize;
        return(TRUE);
    }
    else
    {
        /**************************************************************/
        /* The memory could not be freed.                             */
        /**************************************************************/
        LogError(PMERR_MEMORY_DEALLOCATION_ERR);
        return(FALSE);
    }
}


