;*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 = PALETTE.ASM
;*
;* DESCRIPTIVE NAME = This file contains the DDI-level functions for 
;*                    managing palettes.
;*
;*
;* VERSION      V2.0
;*
;* DATE         08/14/89
;*
;* DESCRIPTION  This file contains most of the new DDI functions to support the
;*              OS/2 palette manager, including functions to create, delete,    
;*              modify, and query palettes and palette data.                    
;*
;* FUNCTIONS    DeviceCreatePalette
;*              DeviceDeletePalette
;*              DeviceSetPaletteEntries
;*              DeviceAnimatePalette
;*              DeviceResizePalette
;*              UpdateColors
;*              QueryHWPaletteInfo
;*              QueryPaletteRealization
;*              validate_hdevpal
;*              validate_pal_params
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/12/87                     Author:  Bob Grudem [bobgru] 
;*   11/09/87                     Bob Grudem [bobgru] Internal color bitmaps
;*                                always use interleaved (i.e. huge)
;*                                scanline format.
;*****************************************************************************/

        .286p
        .xlist

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

        CPUMode 386
        ??_out  palette

        errcode <INV_IN_PATH,INV_IN_AREA,INSUFFICIENT_MEMORY>

        externFP        CreateLogColorTable      ;colortbl.asm
        externFP        far_enter_driver         ;enter.asm
        externFP        far_leave_driver         ;enter.asm
        externFP        DosReallocSeg

NRECTS  equ     NUM_CLIP_RECTS+1                 ;Must be bigger than NUM_CLIP_RECTS
                                                  ;  so enum loop will terminate

sBegin  Data
        externB devpalDefault                     ;Full default palette
        externW npdevpalFore                      ;Foreground palette
        externD phwpal
        externW cPals
        externB fbPalMap
        externW devpalSrc
        externW devpalDst
        externD pfnDefGetVisRects

sEnd    Data

sBegin  PalSeg
        assumes cs,PalSeg

        externW PalSegData

        externNP        get_devpal                ;palmem.asm
        externNP        release_devpal            ;palmem.asm
        externNP        SetHWPalette              ;critsec.asm
        externNP        OEMUpdateColors         ;palsup.asm

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceCreatePalette
;*
;* DESCRIPTION   = Create the necessary data structures for subsequent                  
;*                 realization of a palette.  Until the palette has been                
;*                 realized, the colors that result from using it are                   
;*                 undefined.                                                           
;*
;*                 Registers Preserved:    
;*                       SI,DI,DS,BP          
;*                 Registers Destroyed:       
;*                       AX,BX,CX,DX,ES,FLAGS 
;*
;* INPUT         = npbm:DWORD 
;*                 pBuf:DWORD 
;*                 iStart:DWORD
;*                 pbmi:DWORD   
;*                 cyScans:DWORD,
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = Handle to palette 
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged 
;**************************************************************************/

        check   DeviceCreatePalette,<hdc,ppalinfo,hdevpal,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   DeviceCreatePalette,<PUBLIC,FAR,NODATA>,<di,si>

        parmD   hdc
        parmD   ppalinfo
        parmD   hdevpal
        parmD   hddc
        parmD   FunN

        localW  npdevpal
        localW  cclr
        localW  cbPalSeg
cBegin

;/*
;** Do the usual stuff to get into the driver.
;*/

        cld
        fw_zero <es,ds>
        ddc?    hddc

        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        mov     ax,0
        cwd
        njc     dcp_exit_no_lock                 ;error logged

ifdef FIREWALLS         ;pmgre checks this
        no_path_area    dcp_error_cwd,both
endif

;/*
;** If hdevpal != 0, then just validate it and select it into the hddc.
;*/

        mov     ax,hdevpal.lo
        mov     dx,hdevpal.hi
        or      dx,ax
        jz      dcp_new_palette

        mov     npdevpal,ax                       ;save handle
        devpal? hdevpal
        jmp     dcp_select_pal_into_ddc

;/*
;** hdevpal == 0, which means we need to create a new one and copy
;** the palinfo into it.  Compute the size of the necessary palette
;** segment and create the devpal.  If an error occurs it's because the
;** driver can't make a palseg big enough to hold the largest index
;** requested.  The index itself is valid, but as an implementation
;** restriction we pass back PMERR_INSUFFICIENT_MEMORY.
;*/

dcp_new_palette:
        palinfo? ppalinfo
        assumes ds,Data

        les     si,ppalinfo
        assumes es,nothing
        mov     ax,es:[si].palinfo_cclr.lo
        test    ax,0E000h                         ;these bits will be shifted out
        jnz     dcp_size_bad
        .errnz  (size PALCLR)-8
        mov     cclr,ax
        palOff  ax
        add     ax,size PALSEG
        jnc     dcp_size_ok
dcp_size_bad:
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        save_error_code
        njmp    dcp_error

dcp_size_ok:
        mov     cbPalSeg,ax
        cCall   get_devpal,<ax>
        or      ax,ax
        njz     dcp_error_cwd                     ;error logged, AX == 0
        mov     npdevpal,ax                       ;save handle

;/*
;** Initialize the palseg.
;*/

        xchg    ax,si
        les     di,[si].devpal_pPalSeg            ;ES:DI --> palseg
        assumes es,nothing

;/*
;** Clear the entire apalclr to 0's.
;*/

        mov     ax,cclr
        dec     ax
        mov     cx,cbPalSeg

        mov     es:[di].palseg_fs,PR_REREALIZE
        mov     es:[di].palseg_usMax,ax
        mov     es:[di].palseg_cb,cx

        xor     eax,eax
        sub     cx,size PALSEG
        push    cx
ifdef FIREWALLS
; The rest of the palseg is an array of dwords.
        test    cx,3
        jz      dcp_count_ok
        rip     text,<DCP: invalid CX>
dcp_count_ok:
endif
        shr     cx,2
        add     di,size PALSEG
        rep     stosd
        pop     cx

        mov     di,[si].devpal_pPalSeg.lo        ;reload base of palseg

;/*
;** Call DeviceSetPaletteEntries to copy the palette info across.
;**
;** The arguments have "arg_" prepended because, at the cBegin statement
;** for DeviceSetPaletteEntries, masm complained about the main part of
;** the argument names as being "already different type".
;**
;** ES:DI --> palseg
;*/

        farPtr  arg_hdevpal,PAL_TYPE,npdevpal
        farPtr  arg_ulFormat,ax,[si].palinfo_ulFormat.lo
        farPtr  arg_ulStart,ax,ax
        farPtr  arg_cclr,[si].palinfo_cclr.hi,[si].palinfo_cclr.lo
        farPtr  arg_pclr,ds,bx
        farPtr  arg_ulFunN,FunN.hi,off_DeviceSetPaletteEntries

        arg     hdc
        arg     arg_hdevpal
        arg     arg_ulFormat
        arg     arg_ulStart
        arg     arg_cclr
        arg     arg_pclr
        arg     hddc
        arg     arg_ulFunN

        lds     si,ppalinfo
        assumes ds,nothing

;/*
;** Are default colors to be overwritten if needed?
;*/

        mov     cx,[si].palinfo_flCmd.lo
        and     cx,LCOL_OVERRIDE_DEFAULT_COLORS or LCOL_PURECOLOR
        or      es:[di].palseg_fs,cx
        .errnz  LCOL_OVERRIDE_DEFAULT_COLORS and 0FFFF0000h
        .errnz  LCOL_PURECOLOR and 0FFFF0000h
        .errnz  PR_PURECOLOR - LCOL_PURECOLOR
        .errnz  PR_OVERRIDE_DEFAULTS - LCOL_OVERRIDE_DEFAULT_COLORS

;/*
;** Set in the colors.
;*/

dcp_set_in_colors:
        xor     ax,ax
        lea     bx,[si].palinfo_argb

        cCall   <far ptr DeviceSetPaletteEntries>

        mov     ds,PalSegData
        assumes ds,Data

        inc     cPals                            ; we just added a pal

dcp_select_pal_into_ddc:

;/*
;** Call CreateLogColorTable to reset the ddc to default color table mode.
;** This keeps the ddc in a consistent state when a palette is selected, and
;** also takes care of whatever lazy color management is needed.
;** This call must be made BEFORE setting the DDC_PALETTE bit, otherwise
;** it will return an error (PMERR_PALETTE_SELECTED).
;*/

        farPtr  myflCmd,ax,LCOL_RESET
        farPtr  myulFormat,ax,LCOLF_CONSECRGB
        farPtr  myulStart,ax,ax
        farPtr  mycclr,ax,ax
        farPtr  mypclr,ax,ax
        farPtr  myulFunN,<FunN.hi>,off_CreateLogColorTable

        arg     hdc
        arg     myflCmd
        arg     myulFormat
        arg     myulStart
        arg     mycclr
        arg     mypclr
        arg     hddc
        arg     myulFunN

        xor     ax,ax
        cCall   CreateLogColorTable
        assert  ax,E,1

        mov     si,hddc.lo
        mov     bx,npdevpal
        mov     [si].ddc_npdevpal,bx
        or      [si].ddc_fbBelow,DDC_PALETTE
        inc     [bx].devpal_cUsage
        xchg    ax,bx
        mov     dx,PAL_TYPE
        jmp     short dcp_exit

dcp_error:
        xor     ax,ax
dcp_error_cwd:
        cwd
dcp_exit:
        cCall   far_leave_driver
dcp_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceDeletePalette
;*
;* DESCRIPTION   = Deselect a palette from a ddc, freeing up resources if the  
;*                 palette is unused.                                          
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;**************************************************************************/
 
        check   DeviceDeletePalette,<hdc,hdevpal,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   DeviceDeletePalette,<PUBLIC,FAR,NODATA>,<di,si>

        parmD   hdc
        parmD   hdevpal
        parmD   hddc
        parmD   FunN

cBegin
        fw_zero <es,ds>
        ddc?    hddc
        devpal? hdevpal

        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        mov     ax,0                              ;load return code for error, but
                                                  ;  don't disturb carry flag
        njc     ddp_exit_no_lock                 ;error logged

ifdef FIREWALLS         ;pmgre checks this
        no_path_area    ddp_exit_error,both
endif

;/*
;** Select devpal out of ddc by selecting in the default.
;*/

        mov     si,hddc.lo
        mov     di,hdevpal.lo
        assert  [si].ddc_npdevpal,E,di

        mov     bx,DataOFFSET devpalDefault
        mov     [si].ddc_npdevpal,bx
        and     [si].ddc_fbBelow,not DDC_PALETTE

;/*
;** Call CreateLogColorTable to reset the ddc to default color table mode.
;** This ensures the ddc is in a consistent state when a palette is deselected,
;** and also takes care of whatever lazy color management is needed.
;** This call must be made AFTER clearing the DDC_PALETTE bit, otherwise
;** it will return an error.
;*/

        farPtr  myflCmd,ax,LCOL_RESET
        farPtr  myulFormat,ax,LCOLF_CONSECRGB
        farPtr  myulStart,ax,ax
        farPtr  mycclr,ax,ax
        farPtr  mypclr,ax,ax
        farPtr  myulFunN,<FunN.hi>,off_CreateLogColorTable

        arg     hdc
        arg     myflCmd
        arg     myulFormat
        arg     myulStart
        arg     mycclr
        arg     mypclr
        arg     hddc
        arg     myulFunN

        xor     ax,ax
        cCall   CreateLogColorTable              ;DI,DS preserved
        assert  ax,E,1

;/*
;** Decrement usage count and handle any necessary cleanup.
;*/

        assert  [di].devpal_cUsage,A,0
        dec     [di].devpal_cUsage
        jnz     ddp_exit_ok

        dec     cPals
        cCall   release_devpal,<di>

;/*
;** If this palette was involved in the cached palette mapping,
;** invalidate the cache.
;*/

        cmp     di,devpalSrc
        je      ddp_invalidate_cache
        cmp     di,devpalDst
        jne     ddp_cache_ok
ddp_invalidate_cache:
        or      fbPalMap,MPMV_INVALID
ddp_cache_ok:

;/*
;** If we just released the foregound palette, set the default palette in
;** as the new foreground.
;*/

        cmp     npdevpalFore,di
        jne     ddp_exit_ok
        mov     npdevpalFore,DataOFFSET devpalDefault

ddp_exit_ok:
        mov     ax,1
ddp_exit_error:
        cCall   far_leave_driver
ddp_exit_no_lock:
        cwd
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceSetPaletteEntries
;*
;* DESCRIPTION   = Modify the colors in a palette.  The changes will be 
;*                 reflected the next time the palette is realized.
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;**************************************************************************/

        check   DeviceSetPaletteEntries,<hdc,hdevpal,ulFormat,ulStart,cclr,pclr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   DeviceSetPaletteEntries,<PUBLIC,FAR,NODATA>,<di,si,ds>

        parmD   hdc
        parmD   hdevpal
        parmD   ulFormat
        parmD   ulStart
        parmD   cclr
        parmD   pclr
        parmD   hddc
        parmD   FunN

cBegin
        fw_zero <es,ds>
        ddc?    hddc
        devpal? hdevpal
        palprm? ulFormat,ulStart,cclr,pclr

        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        jnc     dspe_in_driver
        xor     ax,ax
        jmp     short dspe_exit_no_lock

dspe_in_driver:
ifdef FIREWALLS         ;pmgre checks this
        no_path_area    dspe_exit_leave_driver,both
endif

        mov     bx,hdevpal.lo
        les     di,[bx].devpal_pPalSeg           ;ES:DI --> palseg
        mov     dx,di                             ;save copy
        assumes es,nothing

        mov     bx,ulStart.lo
        palOff  bx
        add     di,bx
        add     di,palseg_apalclr.palclr_rgb     ;ES:DI --> first dest rgb
        mov     cx,cclr.lo
        jcxz    dspe_exit_ok                     ;stop right now if no data to copy

;/*
;** Setup the source and destination pointers, and copy the data.
;**
;** CX     =  # entries to copy
;** DX     =  offset to start of palseg
;** ES:DI --> destination of first rgb
;*/

        lds     si,pclr
        assumes ds,nothing

dspe_copy_consecrgb_data:
        movsw
        lodsw
        or      ah,PC_NEW
        stosw
        add     di,(size PALCLR)-(size RGB2)
        loop    dspe_copy_consecrgb_data

        .errnz  rgb2_bBlue
        .errnz  rgb2_bGreen - rgb2_bBlue  - 1
        .errnz  rgb2_bRed   - rgb2_bGreen - 1
        .errnz  rgb2_fcOptions - rgb2_bRed   - 1
        .errnz  (SIZE RGB2) - 4

;/*
;** Mark the palette as needing rerealization.  If this palette is
;** involved in the currently cached palette mapping, invalidate the
;** cache.  Return success.
;**
;** ES:DX --> pPalSeg
;*/

        mov     di,dx
        or      es:[di].palseg_fs,PR_REREALIZE

        mov     ds,PalSegData
        assumes ds,Data

        mov     ax,hdevpal.lo
        cmp     ax,devpalSrc
        je      dspe_invalidate_cache
        cmp     ax,devpalDst
        jne     dspe_exit_ok
dspe_invalidate_cache:
        or      fbPalMap,MPMV_INVALID
        jmp     short dspe_exit_ok

dspe_exit:
        mov     ds,PalSegData
        assumes ds,Data
dspe_exit_ok:
        mov     ax,1
dspe_exit_leave_driver:
        cCall   far_leave_driver
dspe_exit_no_lock:
        cwd
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceAnimatePalette
;*
;* DESCRIPTION   = 
;*                 
;*        Modify the colors in a palette.  The changes will be reflected
;*        immediately for each animated index which has a hardware slot.
;*
;*        The only logical colors that can possibly be affected by this call
;*        are those already marked as PC_RESERVED in the logical palette, by
;*        either DeviceCreatePalette or DeviceSetPaletteEntries.
;*
;*        The only physical colors that can be affected are those that have
;*        been assigned hardware slots by RealizePalette.
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;**************************************************************************/

        check   DeviceAnimatePalette,<hdc,hdevpal,ulFormat,ulStart,cclr,pclr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   DeviceAnimatePalette,<PUBLIC,FAR,NODATA>,<di,si>

        parmD   hdc
        parmD   hdevpal
        parmD   ulFormat
        parmD   ulStart
        parmD   cclr
        parmD   pclr
        parmD   hddc
        parmD   FunN

        localW  cChanged
        localW  usHWIndex

        localD  phwpalMine
cBegin

        fw_zero <es,ds>
        ddc?    hddc
        devpal? hdevpal
        palprm? ulFormat,ulStart,cclr,pclr

        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        mov     eax,PAL_ERROR
        njc     dap_exit_no_lock                 ;error logged

ifdef FIREWALLS         ;pmgre checks this
        no_path_area    dap_exit_error,both,error
endif

;/*
;**  Copy phwpal into the local frame so we can get at it when both DS
;**  and ES are busy.
;*/

        mov     eax,phwpal
        mov     phwpalMine,eax

        mov     cChanged,0                        ;initalize return value

        mov     bx,hdevpal.lo
        les     di,[bx].devpal_pPalSeg
        assumes es,nothing
        lds     si,pclr
        assumes ds,nothing
        mov     cx,cclr.lo
        njcxz   dap_hw_pal_ok

;/*
;** ulFormat == LCOLF_CONSECRGB
;**
;** CX     =  cclr.lo
;** DS:SI --> pclr
;** ES:DI --> palseg
;*/

        mov     ax,ulStart.lo
        palOff  ax
        add     di,ax
        add     di,palseg_apalclr.palclr_rgb
        jmp     short dap_get_next_consecrgb_entry

dap_skip_entry:
        add     si,SIZE RGB2
dap_skip_entry_adjust_di:
        add     di,SIZE PALCLR
        dec     cx
        jz      dap_end_of_consecrgb_loop

;/*
;** CX     =  number of color entries left to process
;** DS:SI --> next source color
;** ES:DI --> next palseg_apalclr.palclr_rgb slot
;*/

dap_get_next_consecrgb_entry:

;/*
;** Skip this entry if either new or old color is not marked PC_RESERVED,
;** or if the new color is marked PC_EXPLICIT.
;*/

        test    [si].rgb2_fcOptions,PC_EXPLICIT
        jnz     dap_skip_entry
        test    [si].rgb2_fcOptions,PC_RESERVED
        jz      dap_skip_entry
        test    es:[di].rgb2_fcOptions,PC_RESERVED
        jz      dap_skip_entry

;/*
;** Read in the new color and save in the palseg.
;*/

        lodsd
        stosd
        add     di,(SIZE PALCLR) - (SIZE RGB2)

;/*
;** if (hardware slot marked as PC_RESERVED and not PC_DEFAULT)
;** {
;**     save new color data in hwpal
;**     set new color into physical palette, mark as PC_FOREGROUND
;** }
;**
;** DS:SI --> next source rgb
;** ES:DI --> next destination rgb
;** EAX    =  current color data
;** CX     =  loop count
;*/

        push    es

        mov     bl,es:[di-(SIZE PALCLR)].palclr_bCur
        xor     bh,bh
        mov     usHWIndex,bx
        rgbOff  bx
        add     bx,phwpalMine.lo
        mov     es,phwpalMine.hi
        assumes es,nothing

        test    es:[bx].rgb2_fcOptions,PC_DEFAULT
        jnz     dap_hw_check_done
        test    es:[bx].rgb2_fcOptions,PC_RESERVED
        jz      dap_hw_check_done

        or      eax,PC_FOREGROUND shl 24
        mov     dword ptr es:[bx].rgb2_bBlue,eax
        inc     cChanged

dap_hw_check_done:
        pop     es
        assumes es,nothing
        loop    dap_get_next_consecrgb_entry

dap_end_of_consecrgb_loop:

;/*
;** Return the number of hardware colors that changed.
;**
;** If this palette is involved in the cached palette mapping, and there
;** was a change, then invalidate the cache.
;*/

dap_exit:
        mov     ds,PalSegData
        assumes ds,Data
        cmp     cChanged,0
        je      dap_hw_pal_ok

        cCall   SetHWPalette,<0,SIZE_HW_PAL,phwpal,0>

dap_hw_pal_ok:
        mov     ax,cChanged
        cwd
        or      ax,ax
        jz      dap_exit_leave_driver

        mov     bx,hdevpal.lo
        cmp     bx,devpalSrc
        jne     dap_exit_leave_driver
dap_invalidate_cache:
        or      fbPalMap,MPMV_INVALID
        jmp     short dap_exit_leave_driver

dap_exit_error:
        mov     ax,PAL_ERROR
        cwd
dap_exit_leave_driver:
        cCall   far_leave_driver
dap_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceResizePalette                                                   
;*                                                                                       
;* DESCRIPTION   = Resize the existing palseg to accommodate the given number             
;*                 of colors.  If the new size is bigger than the old size,
;*                 initialize the new space at the end to zeroes.
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       DosReallocSeg
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc DeviceResizePalette,<FAR,PUBLIC,NODATA>,<si,di,ds>
        parmD   hdc
        parmD   hdevpal
        parmD   cclr
        parmD   hddc
        parmD   FunN
cBegin
        fw_zero <es,ds>
        ddc?    hddc
        devpal? hdevpal
        assert  <cclr.hi>,E,0

        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        mov     ax,0
        cwd
        jc      drp_exit_no_lock                 ;error logged

ifdef FIREWALLS         ;pmgre checks this
        no_path_area    drp_exit_error,both,error
endif

;/*
;** compute new size
;*/
        imul    cx,cclr.lo,size PALCLR
        add     cx,size PALSEG

        mov     di,hdevpal.lo
        mov     ax,[di].devpal_pPalSeg.hi
        push    cx
        cCall   DosReallocSeg,<cx,ax>
        pop     cx
        or      ax,ax
        jz      drp_save_new_size
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        save_error_code
        jmp     short drp_exit_error

drp_save_new_size:
        les     di,[di].devpal_pPalSeg
        assumes es,nothing
        mov     ax,es:[di].palseg_cb              ;get old size
        mov     es:[di].palseg_cb,cx              ;save new size
        sub     cx,ax                              ;compute difference
        jc      drp_exit                           ;if truncated, we're done

ifdef FIREWALLS
        test    cx,3
        jz      drp_count_ok
        rip     text,<DRP: invalid CX>
drp_count_ok:
endif
        add     di,ax
        xor     eax,eax
        shr     cx,2
        rep     stosd

drp_exit:
        mov     ax,1
drp_exit_error:
        cwd
        cCall   far_leave_driver
drp_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = UpdateColors                                                          
;*                                                                                       
;* DESCRIPTION   = Updates the colors from the previous to the current 
;*                 palettes in the visible regions of the DC.
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       GetVisRects
;*                       OEMUpdateColors
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;**************************************************************************/

        check   UpdateColors,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   UpdateColors,<PUBLIC,FAR,NODATA>,<di,ds>

        parmD   hdc
        parmD   hddc
        parmD   FunN

        localW  crcsClip
        localV  arclBuf,%(NRECTS * size RECTL)
        localV  Control,%(size RGNRECT)
        localV  asMappingVector,%(SIZE_HW_PAL)

cBegin
        fw_zero <es,ds>
        ddc?    hddc
        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        njc     uc_error_no_lock

        no_path_area    uc_exit_leave_driver,both

;/*
;** UpdateColors has no effect on a memory DDC.
;*/

        mov     bx,hddc.lo
        test    [bx].ddc_fb,DDC_DEVICE
        njz     uc_exit_ok

;/*
;** Initialize an identity mapping vector.
;*/

IDENTITY_INIT_VALUE     equ     (3 shl 24)+(2 shl 16)+(1 shl 8)+0
IDENTITY_INIT_INC       equ     (4 shl 24)+(4 shl 16)+(4 shl 8)+4

        mov     eax,IDENTITY_INIT_VALUE
        push    ss
        pop     es
        assumes es,nothing
        lea     di,asMappingVector      ;ES:DI --> mapping vector
        mov     si,di                   ;ES:SI --> mapping vector also
        mov     cx,SIZE_HW_PAL/4
        .errnz  SIZE_HW_PAL and 3

uc_identity_loop:
        stosd                           ;initialize 4 entries at once
        add     eax,IDENTITY_INIT_INC   ;next 4 entries
        loop    uc_identity_loop

;/*
;** Get the device palette from the DDC.
;** BX = hddc.lo
;*/

uc_get_pal:
        mov     bx,[bx].ddc_npdevpal    ;get the device palette
        les     di,[bx].devpal_pPalSeg           ;ES:DI --> palseg
        assumes es,nothing
        test    es:[di].palseg_fs,PR_BPREV_VALID
        njz     uc_exit_ok                              ;do nothing if realized just once
        palSize cx,es,di                          ;CX = number of palette entries

;/*
;** Create a mapping vector between the previous and the current palettes
;*/

uc_get_mapping_loop:
        xor     bx,bx                   ;clear the high byte
        mov     bl,es:[di].palseg_apalclr.palclr_bPrev ;previous indices
        mov     al,es:[di].palseg_apalclr.palclr_bCur  ;current indices
        mov     ss:[si+bx],al
        add     di,SIZE PALCLR          ;next palette entry
        loop    uc_get_mapping_loop

;/*
;** Call back to engine to get a set of visible rectangles whose contents
;** must be updated.
;*/

uc_get_vis_rect:
        mov     Control.rgnrc_ircStart,1
        mov     Control.rgnrc_crc,NRECTS
        mov     Control.rgnrc_usDirection,RECTDIR_LFRT_BOTTOP

uc_get_next_vis:
        xor     dx,dx                   ;handy zero
        lea     bx,Control              ;SS:BX --> control params
        lea     ax,arclBuf              ;SS:AX --> list of visible rects
        check   GetVisRects,<hdc,prclBounds,prgnrc,prclVis,hddc,ulFunN>
        farPtr  prclNull,dx,dx
        farPtr  prgnrect,ss,bx
        farPtr  parclVis,ss,ax
        cCall   pfnDefGetVisRects,<hdc,prclNull,prgnrect,parclVis,hddc,GreGetVisRects>
ifdef FIREWALLS
        or      ax,ax
        jnz     @F
        rip     text,<GetVisRects returns error>
@@:
endif

;/*
;** Call low-level update-color routine for each rectangle in the buffer
;*/

uc_call_routine:
        mov     cx,Control.rgnrc_crcReturned
        jcxz    uc_exit
        mov     crcsClip,cx
        add     Control.rgnrc_ircStart,cx
        lea     bx,arclBuf                        ;SS:BX --> first RECTL

uc_call_loop:

ifdef FIREWALLS
        mov     cx,ss:[bx].rcl_yTop.lo
        cmp     cx,ss:[bx].rcl_yBottom.lo
        jg      @F
        rip     text,<UpdateColors - a null rectangle in Y>
@@:
        mov     cx,ss:[bx].rcl_xRight.lo
        cmp     cx,ss:[bx].rcl_xLeft.lo
        jg      @F
        rip     text,<UpdateColors - a null rectangle in X>
@@:
endif

        lea     di,asMappingVector      ;SS:DI --> palette mapping vector
        farPtr  lpVisRects,ss,bx
        farPtr  lpMappingVect,ss,di
        save    <bx>                    ;SS:BX --> this rectangle
        cCall   OEMUpdateColors,<lpVisRects,lpMappingVect>
        add     bx,size RECTL           ;SS:BX --> next rectangle
        dec     crcsClip
        jnz     uc_call_loop
        cmp     Control.rgnrc_crcReturned,NRECTS
        je      uc_get_next_vis

uc_exit:
        mov     ds,PalSegData
        assumes ds,Data
uc_exit_ok:
        mov     ax,1                    ;return success
uc_exit_leave_driver:
        cCall   far_leave_driver        ;unlock the driver
uc_exit_no_lock:
        cwd

cEnd

uc_error_no_lock:
        xor     ax,ax                   ;return failure
        jmp     uc_exit_no_lock


;/***************************************************************************
;*
;* FUNCTION NAME = QueryHWPaletteInfo                                                    
;*
;* DESCRIPTION   = Return the RGB values that are actually in the hardware           
;*                 palette.  The order of the returned colors is the same as in      
;*                 the hardware, so that programs such as the RTG (Random            
;*                 Testcase Generator) can predict the results of color mixing,      
;*                 which happens between palette indices.                            
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       GetVisRects
;*                       OEMUpdateColors
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = number of colors returned 
;* RETURN-ERROR  = DX:AX = PAL_ERROR                 
;*                 error logged
;**************************************************************************/

        check   QueryHWPaletteInfo,<hdc,ulStart,cclr,pclr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryHWPaletteInfo,<PUBLIC,FAR,NODATA>,<di,si>

        parmD   hdc
        parmD   ulStart
        parmD   cclr
        parmD   pclr
        parmD   hddc
        parmD   ulFunN

cBegin

;/*
;** Do the usual stuff to get into the driver.
;*/

        cld
        fw_zero <es,ds>
        ddc?    hddc

        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        mov     ax,PAL_ERROR
        cwd
        jc      qhwpal_exit_no_lock    ;error logged

;/*
;** If cclr is zero return the size of the hardware palette
;*/

        mov     cx,cclr.lo
        or      cx,cx
        jnz     @F
        mov     ax,SIZE_HW_PAL                    ;return # RGBs
        cwd
        jmp     short qhwpal_exit

;/*
;** Validate parameters
;*/

@@:     xor     ax,ax                             ;default return value
        xor     dx,dx

        mov     bx,cx
        add     bx,ulStart.lo
        cmp     bx,SIZE_HW_PAL
        ja      qhwpal_exit
        mov     ax,cx                             ;final return value

;/*
;** Get the hardware palette into the array
;*/

        lds     si,phwpal                         ;source
        assumes ds,nothing
        mov     bx,ulStart.lo
        rgbOff  bx
        add     si,bx

        les     di,pclr                           ;destination
        assumes es,nothing
        cld
        push    di
        push    cx
        rep     movsd
        pop     cx
        pop     di

;/*
;** Clean off any internal PC_* flags
;*/
@@:
        and     es:[di].rgb2_fcOptions,PC_RESERVED
        add     di,size RGB2
        loop    @B

qhwpal_exit:
        mov     ds,PalSegData
        assumes ds,Data
        cCall   far_leave_driver
qhwpal_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = QueryPaletteRealization                                               
;*
;* DESCRIPTION   = Return the mapping from the logical palette in the DC to   
;*                 the hardware palette, as an array of ULONGs.  This function      
;*                 gives the RTG the ability to predict the outcome of color  
;*                 mixing operations.                                               
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       GetVisRects
;*                       OEMUpdateColors
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = number of array elements  returned
;* RETURN-ERROR  = DX:AX = PAL_ERROR                 
;*                 error logged
;**************************************************************************/

        check   QueryPaletteRealization,<hdc,ulStart,cclr,pulTable,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryPaletteRealization,<PUBLIC,FAR,NODATA>,<di,si,ds>

        parmD   hdc
        parmD   ulStart
        parmD   cclr
        parmD   pulTable
        parmD   hddc
        parmD   ulFunN

        localW  cclrRet
cBegin

;/*
;** Do the usual stuff to get into the driver.
;*/

        cld
        fw_zero <es,ds>
        ddc?    hddc

        mov     ds,PalSegData
        assumes ds,Data

        mov     dx,hddc.lo
        cCall   far_enter_driver
        mov     ax,PAL_ERROR
        cwd
        jc      qpr_exit_no_lock    ;error logged

;/*
;** If cclr is zero return the size of the palette mapping vector
;** beyond ulStart.
;*/

        mov     cx,cclr.lo
        or      cx,cx
        jnz     qpr_return_array

        mov     bx,hddc.lo
        mov     bx,[bx].ddc_npdevpal
        lds     si,[bx].devpal_pPalSeg
        assumes ds,nothing
        palSize ax,ds,si                          ;CX = max colors returnable
        sub     ax,ulStart.lo                     ;colors left beyond ulStart
        cwd
        jmp     short qpr_exit

;/*
;** Get the realization table into the array.
;*/

qpr_return_array:
        mov     bx,hddc.lo
        mov     bx,[bx].ddc_npdevpal
        lds     si,[bx].devpal_pPalSeg
        assumes ds,nothing
        palSize cx,ds,si                          ;CX = max colors returnable
        mov     bx,ulStart.lo
        sub     cx,bx                             ;colors left beyond ulStart
        cmp     cx,cclr.lo                        ;CX = min(CX,cclr.lo)
        jae     @F
        mov     cx,cclr.lo
@@:
        mov     cclrRet,cx
        palOff  bx
        add     si,bx

        les     di,pulTable                       ;destination
        assumes es,nothing
        cld

;/*
;** DS:SI --> palseg_apalclr.palclr_bCur
;** ES:DI --> pulTable
;** CX = count of colors in palette
;*/

        xor     eax,eax
@@:     lodsb
        stosd
        add     si,size PALCLR - 1
        loop    @B

        mov     ax,cclrRet
        cwd
qpr_exit:
        mov     ds,PalSegData
        assumes ds,Data
        cCall   far_leave_driver
qpr_exit_no_lock:
cEnd

ifdef   FIREWALLS
;/***************************************************************************
;*
;* FUNCTION NAME = validate_hdevpal
;*
;* DESCRIPTION   = Validate data structures associated with hdevpal. 
;*
;*                 Registers Preserved:    
;*                       AX,BX,CX,DX,SI,DI,DS,ES,BP
;*                 Registers Destroyed:    
;*                       FLAGS
;*                 Calls:
;*                       GetVisRects
;*                       OEMUpdateColors
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = Handle to palette 
;* RETURN-ERROR  = DX:AX = PAL_ERROR                 
;*                 error logged
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc validate_hdevpal,<PUBLIC,NEAR,NODATA>,<ax,bx,ds>
        parmD   hdevpal
cBegin
        cmp     hdevpal.lo,DataOFFSET devpalDefault
        je      valid_hdevpal

        cmp     hdevpal.hi,PAL_TYPE              ;correct handle type?
        jne     invalid_hdevpal

        mov     bx,hdevpal.lo                     ;correct handle identifier?
        mov     ds,PalSegData
        assumes ds,Data
        cmp     [bx].devpal_ident,PAL_IDENTIFIER
        jne     invalid_hdevpal

        mov     bx,[bx].devpal_pPalSeg.hi ;do we have access?
        lar     ax,bx
        jz      valid_hdevpal

invalid_hdevpal:
        rip     text,<invalid hdevpal>

valid_hdevpal:
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = validate_pal_params
;*
;* DESCRIPTION   = Validate the various parameters passed into the API-level    
;*                 functions.                                                   
;*
;*                 Registers Preserved:    
;*                       AX,BX,CX,DX,SI,DI,DS,ES,BP
;*                 Registers Destroyed:    
;*                       FLAGS
;*                 Calls:
;*                       GetVisRects
;*                       OEMUpdateColors
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = Handle to palette 
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;* PSEUDO-CODE   =
;*
;*           if (usFunction == DeviceCreatePalette)
;*              if (flCmd & ~LCOL_PURECOLOR)
;*                  assert(FALSE, "Invalid options");
;*          
;*           // Check that cclr is a positive 32-bit number.
;*          
;*           if (cclr < 0)
;*               assert(FALSE, "Invalid count of color entries");
;*          
;*           if (ulFormat == LCOLF_CONSECRGB)
;*           {
;*               LONG lMax;
;*               USHORT usCount;
;*          
;*               if (ulStart < 0)
;*                   assert(FALSE, "Invalid starting index");
;*          
;*               // Adjust cclr to fit within [0,255]
;*               // and verify any data within our reach.
;*          
;*               if (ulStart < 256)
;*               {
;*                   lMax = ulStart + cclr;
;*                   if (lMax <= 256)
;*                       usCount = cclr;
;*                   else
;*                       usCount = 256 - ulStart;
;*          
;*                   for (;usCount > 0; --usCount, ++pclr)
;*                       if (*pclr != -1)
;*                           if (*pclr & 0xFF000000 & ~(PC_RESERVED|PC_EXPLICIT))
;*                               assert(FALSE, "Invalid color data");
;*               }
;*           }
;*           else
;*               assert(FALSE, "Invalid format");
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc validate_pal_params,<PUBLIC,NEAR,NODATA>,<ax,cx,dx,si,ds>
        parmW   usFunction
        parmD   flCmd
        parmD   ulFormat
        parmD   ulStart
        parmD   cclr
        parmD   pclr
cBegin

;/*
;** if (usFunction == DeviceCreatePalette)
;**    if (flCmd & ~LCOL_PURECOLOR)
;**        assert(FALSE, "Invalid options");
;*/

        cmp     usFunction,vpp_DeviceCreatePalette
        jne     vpp_options_checked
        cmp     flCmd.hi,0
        jne     vpp_invalid_options
        mov     ax,flCmd.lo
        and     ax,not (LCOL_PURECOLOR OR LCOL_OVERRIDE_DEFAULT_COLORS)
        jz      vpp_options_checked
        .errnz  LCOL_PURECOLOR and 0FFFF0000h
        .errnz  LCOL_OVERRIDE_DEFAULT_COLORS and 0FFFF0000h
vpp_invalid_options:
        rip     text,<Invalid options>
vpp_options_checked:

;/*
;** // Check that cclr is a positive 32-bit number.
;**
;** if (cclr.hi != 0)
;**     assert(FALSE, "Invalid count of color entries");
;*/

        cmp     cclr.hi,0
        je      vpp_count_checked
        rip     text,<Invalid count>
vpp_count_checked:

;/*
;** if (ulFormat != LCOLF_CONSECRGB)
;**     assert(FALSE, "Invalid format");
;*/

        cmp     ulFormat.hi,0
        jne     vpp_invalid_format
        mov     ax,ulFormat.lo
        cmp     ax,LCOLF_CONSECRGB
        je      vpp_format_is_consecrgb
        .errnz   LCOLF_CONSECRGB and 0FFFF0000h
vpp_invalid_format:
        rip     text,<Invalid format>

;/*
;**  if (ulFormat == LCOLF_CONSECRGB)
;**  {
;**      LONG lMax;
;**      USHORT usCount;
;** 
;**      if (ulStart.hi != 0)
;**          assert(FALSE, "Invalid starting index");
;** 
;**      // Adjust cclr to fit within [0,255]
;**      // and verify any data within our reach.
;** 
;**      if (ulStart < 256)
;**      {
;**          lMax = ulStart + cclr;
;**          if (lMax <= 256)
;**              usCount = cclr;
;**          else
;**              usCount = 256 - ulStart;
;** 
;**          for (;usCount > 0; --usCount, ++pclr)
;**              if (*pclr != -1)
;**                  if (*pclr & 0xFF000000 & ~(PC_RESERVED|PC_EXPLICIT))
;**                      assert(FALSE, "Invalid color data");
;**      }
;**  }
;*/

vpp_format_is_consecrgb:

;/*
;** Check that ulStart is a positive 32-bit number.
;*/

        cmp     ulStart.hi,0
        jne     vpp_invalid_start                ; ulStart > 64K
        mov     ax,ulStart.lo
        cmp     ax,0
        jge     vpp_start_checked                ; ulStart >= 0 && ulStart < 64K
vpp_invalid_start:
        rip     text,<Invalid starting index>
vpp_start_checked:

;/*
;** See if ulStart is low enough for us to use any of the data.
;** For now, let USHORT values through.  The memory allocation code
;** will cause unreasonably high indices to be rejected later on.
;*/

        cmp     ulStart.hi,0
        jne     vpp_consecrgb_checked

        cmp     cclr.hi,0
        jne     vpp_consecrgb_checked

        mov     cx,cclr.lo
        jcxz    vpp_consecrgb_checked            ;stop right now if no data to check
        mov     ax,cx
        add     ax,ulStart.lo
        jc      vpp_consecrgb_checked

;/*
;** Check each color entry in pclr for correct flags.
;** The only valid user-specified flags are PC_RESERVED and PC_EXPLICIT.
;*/

        mov     ax,pclr.hi                        ;stop right now if     selector
        or      ax,ax
        jz      vpp_invalid_color_data_selector
        mov     ds,ax
        assumes ds,nothing
        mov     si,pclr.lo
        cld
vpp_check_next_consecrgb:
        lodsw                                    ;anything's ok for lower word
        lodsw
        and     ah,not (PC_RESERVED or PC_EXPLICIT or PC_NOCOLLAPSE)
        jnz     vpp_invalid_color_flags_consecrgb
vpp_check_consecrgb_bottom_of_loop:
        loop    vpp_check_next_consecrgb

        .errnz  rgb2_bBlue
        .errnz  rgb2_bGreen - rgb2_bBlue  - 1
        .errnz  rgb2_bRed   - rgb2_bGreen - 1
        .errnz  rgb2_fcOptions - rgb2_bRed   - 1
        .errnz  (SIZE RGB2) - 4

vpp_consecrgb_checked:
        jmp    short vpp_exit

vpp_invalid_color_data_selector:
        rip     text,<pclr.hi == 0>
        jmp    short vpp_exit

vpp_invalid_color_flags_consecrgb:
        rip     text,<invalid PC_* flags>
vpp_exit:
cEnd
endif

sEnd PalSeg

ifdef FIREWALLS
        public  dcp_new_palette
        public  dcp_size_bad
        public  dcp_size_ok
        public  dcp_count_ok
        public  dcp_set_in_colors
        public  dcp_select_pal_into_ddc
        public  dcp_error
        public  dcp_error_cwd
        public  dcp_exit
        public  dcp_exit_no_lock
        public  ddp_invalidate_cache
        public  ddp_cache_ok
        public  ddp_exit_ok
        public  ddp_exit_error
        public  ddp_exit_no_lock
        public  dspe_in_driver
        public  dspe_copy_consecrgb_data
        public  dspe_invalidate_cache
        public  dspe_exit
        public  dspe_exit_ok
        public  dspe_exit_leave_driver
        public  dspe_exit_no_lock
        public  dap_skip_entry
        public  dap_skip_entry_adjust_di
        public  dap_get_next_consecrgb_entry
        public  dap_hw_check_done
        public  dap_end_of_consecrgb_loop
        public  dap_exit
        public  dap_hw_pal_ok
        public  dap_invalidate_cache
        public  dap_exit_error
        public  dap_exit_leave_driver
        public  dap_exit_no_lock
        public  drp_save_new_size
        public  drp_count_ok
        public  drp_exit
        public  drp_exit_error
        public  drp_exit_no_lock
        public  uc_identity_loop
        public  uc_get_pal
        public  uc_get_mapping_loop
        public  uc_get_vis_rect
        public  uc_get_next_vis
        public  uc_call_routine
        public  uc_call_loop
        public  uc_exit
        public  uc_exit_ok
        public  uc_exit_leave_driver
        public  uc_exit_no_lock
        public  uc_error_no_lock
        public  qhwpal_exit
        public  qhwpal_exit_no_lock
        public  qpr_return_array
        public  qpr_exit
        public  qpr_exit_no_lock
        public  invalid_hdevpal
        public  valid_hdevpal
        public  vpp_invalid_options
        public  vpp_options_checked
        public  vpp_count_checked
        public  vpp_invalid_format
        public  vpp_format_is_consecrgb
        public  vpp_invalid_start
        public  vpp_start_checked
        public  vpp_check_next_consecrgb
        public  vpp_check_consecrgb_bottom_of_loop
        public  vpp_consecrgb_checked
        public  vpp_invalid_color_data_selector
        public  vpp_invalid_color_flags_consecrgb
        public  vpp_exit
endif

end
