;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = PALMEM.ASM
;*
;* DESCRIPTIVE NAME = Palette memory management
;*
;*
;* VERSION      V2.0
;*
;* DATE         08/14/89
;*
;* DESCRIPTION  This file contains the memory management functions for palettes.  
;*
;* FUNCTIONS    Public: get_devpal     
;*                      release_devpal 
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   08/14/89                     Author:  Bob Grudem [bobgru]
;*****************************************************************************/

        .286p
        .xlist

        include cmacros.inc
INCL_DDIMISC            equ                      1
INCL_GRE_BITMAPS        equ                      1
INCL_GPIBITMAPS         equ                      1
INCL_GPILOGCOLORTABLE   equ                      1
INCL_DEV                equ                      1
INCL_DDICOMFLAGS        equ                      1
        include pmgre.inc
DINCL_BITMAP            equ                      1
        include driver.inc
        include njmp.mac
        include assert.mac
        include palette.inc
        .list

        errcode <INSUFFICIENT_MEMORY>

        externFP        WinAllocMem
        externFP        SSAllocSeg
        externFP        SSFreeSeg

sBegin  Data

        externD hLocalHeap

globalW nppalFree,0     ;NPDEVPAL nppalFree;
globalW nppalActive,0   ;NPDEVPAL nppalActive;

sEnd    Data


sBegin  PalSeg
        assumes cs,PalSeg

;/***************************************************************************
;*
;* FUNCTION NAME = get_devpal
;*
;* DESCRIPTION   = Return a npdevpal to the caller, creating new handles 
;*                 if necessary.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = DS = Data 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = npdevpal  
;* RETURN-ERROR  = AX = 0         
;*                 error logged 
;* PSEUDO-CODE   =
;*    NPDEVPAL get_devpal(cbPalSeg)
;*    USHORT cbPalSeg;
;*    {
;*        NPDEVPAL npdevpal;
;*    
;*        // get npdevpal; return error if can't
;*        if (nppalFree == 0)
;*            if (!make_some_palette_handles())
;*                return 0;
;*        npdevpal  = nppalFree;
;*        nppalFree = nppalFree->next;
;*        npdevpal->ident = PAL_IDENTIFIER;
;*    
;*        // get pPalSeg.hi; clean up and return if error
;*        if ((npdevpal->pPalSeg.hi = get_selPalSeg(cbPalSeg)) == 0)
;*        {
;*            // link npdevpal back into free list
;*            npdevpal->ident = FREE_HDEVPAL;
;*            assert(npdevpal->next = nppalFree, "get_hdevpal: corrupted link");
;*            nppalFree = npdevpal;
;*            return 0;
;*        }
;*    
;*        // link new handle into active list
;*        npdevpal->next = nppalActive;
;*        nppalActive = npdevpal;
;*    
;*        return npdevpal;
;*    }
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc get_devpal,<PUBLIC,NEAR,PASCAL,NODATA>,<>
        parmW   cbPalSeg
        localW  npdevpal
cBegin
        cmp     nppalFree,0                       ;any free devpals?
        jnz     gdp_got_a_devpal                  ;if yes, use one of them
 
        cCall   make_some_palette_handles  ;try to make more handles
        or      ax,ax                             ;zero if error
        jnz     gdp_got_a_devpal                  ;if ok, nppalFree points to new ones

        xor     ax,ax                             ;if couldn't, exit; error logged
        jmp     short gdp_exit

gdp_got_a_devpal:
        mov     bx,nppalFree                      ;npdevpal = nppalFree
        mov     npdevpal,bx                       ; 
        mov     ax,[bx].devpal_next               ;nppalFree = nppalFree->next
        mov     nppalFree,ax                      ; 
        mov     [bx].devpal_ident,PAL_IDENTIFIER  ;npdevpal->ident = ...

        cCall   <far ptr get_selPalSeg>,<cbPalSeg>;try to get a palseg
        or      ax,ax
        jnz     gdp_got_a_palseg                  ;if ok, link in new devpal and leave

        mov     bx,npdevpal                       ;npdevpal->ident = FREE_HDEVPAL
        mov     [bx].devpal_ident,FREE_HDEVPAL

ifdef   FIREWALLS

;/*
;** npdevpal->next hasn't been changed since it came off the front of the
;** free list, so it should still be pointing there.
;*/
        push    ax
        mov     ax,nppalFree
        assert  [bx].devpal_next,E,ax
        pop     ax
endif
        mov     bx,npdevpal                       ;nppalFree = npdevpal
        mov     nppalFree,bx                      ; 
        assert  ax,E,0                            ;return 0
        jmp     short gdp_exit

gdp_got_a_palseg:
        mov     bx,npdevpal                       ;npdevpal->pPalSeg.hi = ax
        assert  [bx].devpal_pPalSeg.hi,E,0
        mov     [bx].devpal_pPalSeg.hi,ax
        mov     ax,nppalActive                    ;npdevpal->next = nppalActive
        mov     [bx].devpal_next,ax               ; 
        mov     nppalActive,bx                    ;nppalActive = npdevpal
        xor     ax,ax
        mov     [bx].devpal_pPalSeg.lo,ax         ; palseg starts at offset 0
        mov     [bx].devpal_cUsage,ax             ;no one's using it yet
        mov     [bx].devpal_idRealization,ax      ;not realized yet

        xchg    ax,bx                             ;return npdevpal
gdp_exit:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = release_devpal
;*
;* DESCRIPTION   = Return the given npdevpal to the free list of handles.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = DS = Data 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* PSEUDO-CODE   =
;*    VOID release_devpal(npdevpal)
;*    NPDEVPAL npdevpal;
;*    {
;*        // unlink devpal from active list
;*        p = nppalActive;
;*        while ((p != 0) && (p->next != npdevpal))
;*            p = p->next;
;*        assert(p != 0, "release_devpal: prepare for gp fault");
;*        assert(p->next == npdevpal,
;*                       "release_devpal: npdevpal not in active list");
;*        p->next = p->next->next;
;*    
;*        // give up the pPalSeg.hi
;*        release_selPalSeg(npdevpal->pPalSeg.hi);
;*        npdevpal->pPalSeg = 0;
;*    
;*        // put devpal in the free list
;*        npdevpal->ident = FREE_HDEVPAL;
;*        npdevpal->next  = nppalFree;
;*        nppalFree = npdevpal;
;*    }
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc release_devpal,<PUBLIC,NEAR,PASCAL,NODATA>,<si>
        parmW   npdevpal
cBegin


        mov     bx,nppalActive
        mov     si,npdevpal

        cmp     si,bx
        jne     rdp_start_the_search

        mov     ax,[bx].devpal_next
        mov     nppalActive,ax
        jmp     short rdp_release_palseg

rdp_start_the_search:
@@:
ifdef FIREWALLS
        or      bx,bx
        jz      rdp_end_of_search
endif
        cmp     [bx].devpal_next,si
        jz      rdp_end_of_search
        mov     bx,[bx].devpal_next
        jmp     short @B

rdp_end_of_search:
        assert  bx,NE,0
        assert  [bx].devpal_next,E,si
        mov     ax,[si].devpal_next
        mov     [bx].devpal_next,ax


rdp_release_palseg:
        mov     ax,[si].devpal_pPalSeg.hi
        cCall   release_selPalSeg,<ax>
        mov     [si].devpal_pPalSeg.hi,0
        assert  [si].devpal_pPalSeg.lo,E,0


        mov     [si].devpal_ident,FREE_HDEVPAL
        mov     ax,nppalFree
        mov     [si].devpal_next,ax
        mov     nppalFree,si
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = make_some_palette_handles
;*
;* DESCRIPTION   = Allocate and initialize memory for a batch 
;*                 of palette handles. 
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = DS = Data 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = none, nppalFree updated 
;* RETURN-ERROR  = NONE
;*
;* PSEUDO-CODE   =
;*   
;*   #define PAL_ALLOCSIZE sizeof(DEVPAL)*10 // arbitrary number
;*   make_some_palette_handles()
;*   {
;*       NPDEVPAL np;
;*   
;*       // make space in the heap
;*       if (!(nppalFree = WinAllocMem(hLocalHeap, PAL_ALLOCSIZE)))
;*       {
;*           SaveError(PMERR_INSUFFICIENT_MEMORY);
;*           return FALSE;
;*       }
;*   
;*       // break memory up into handles
;*       np = nppalFree + PAL_ALLOCSIZE/sizeof(DEVPAL);
;*       np->next = 0;       // mark end of list
;*       do
;*       {
;*           --np;
;*           np->next       = np+1;
;*           np->ident      = FREE_HDEVPAL;
;*           np->pPalSeg.hi = 0;
;*       } while (np != nppalFree)
;*   
;*       return TRUE;
;*   }
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

PAL_ALLOCSIZE   equ     SIZE DEVPAL * 10

cProc make_some_palette_handles,<PUBLIC,NEAR,NODATA>,<si>
cBegin


        cCall   WinAllocMem,<hLocalHeap,PAL_ALLOCSIZE>
        or      ax,ax
        jnz     msph_got_memory

        mov     ax,PMERR_INSUFFICIENT_MEMORY
        save_error_code
        xor     ax,ax
        jmp     short msph_exit

msph_got_memory:

        mov     nppalFree,bx
        mov     si,bx
        add     bx,(PAL_ALLOCSIZE/(SIZE DEVPAL)-1)*(SIZE DEVPAL)
        xor     cx,cx
        mov     dx,FREE_HDEVPAL
        mov     [bx].devpal_ident,dx
        mov     [bx].devpal_next,cx
        mov     [bx].devpal_pPalSeg.hi,cx
        mov     [bx].devpal_pPalSeg.lo,cx
        mov     [bx].devpal_cUsage,cx
@@:
        mov     ax,bx
        sub     bx,SIZE DEVPAL
        mov     [bx].devpal_ident,dx
        mov     [bx].devpal_next,ax
        mov     [bx].devpal_pPalSeg.hi,cx
        mov     [bx].devpal_pPalSeg.lo,cx
        mov     [bx].devpal_cUsage,cx

        cmp     bx,si
        jne     @B

        mov     ax,1                             ;return TRUE

msph_exit:
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = get_selPalSeg
;*
;* DESCRIPTION   = Get a selector to a palseg of the requested size.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = DS = Data 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = selector       
;* RETURN-ERROR  = AX = 0, error logged
;*
;*    SEL get_selPalSeg(cbPalSeg)
;*    USHORT cbPalSeg;
;*    {
;*        SEL sel;
;*    
;*        if (SSAllocSeg(sizeof(PALSEG), &sel, 0))
;*        {
;*            SaveError(PMERR_INSUFFICIENT_MEMORY);
;*            return 0;
;*        }
;*        return sel;
;*    }
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc get_selPalSeg,<PUBLIC,FAR,NODATA>,<>
        parmW   cbPalSeg
        localW  selPalSeg
cBegin
        farPtr  psel,ss,bx
        lea     bx,selPalSeg
        cCall   SSAllocSeg,<cbPalSeg,psel,0>
        xchg    ax,bx                            ;save return code in BX
        mov     ax,selPalSeg                     ;return sel
        or      bx,bx                            ;check for error
        jz      gsps_exit

        mov     ax,PMERR_INSUFFICIENT_MEMORY
        save_error_code
        xor     ax,ax                            ;return 0

gsps_exit:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = release_selPalSeg
;*
;* DESCRIPTION   = Release a selector to a palseg. 
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = DS = Data 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* PSEUDO-CODE   =
;*
;*   VOID release_selPalSeg(sel)
;*   SEL sel;
;*   {
;*       fErr = SSFreeSeg(sel);
;*       assert(!fErr, "release_selPalSeg: error freeing seg");
;*   }
;***************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc release_selPalSeg,<PUBLIC,NEAR,NODATA>,<>
        parmW   selPalSeg
cBegin
        cCall   SSFreeSeg,<selPalSeg>
        assert  AX,E,0
cEnd

sEnd PalSeg
end
