;*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.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = ENABLE.ASM
;*
;* DESCRIPTIVE NAME = Contains procedure header for the exported Enable routine.
;*
;*
;* VERSION      V2.0
;*
;* DATE         02/06/87 
;*
;* DESCRIPTION  
;*
;*        The enable routine is called by the Graphics Engine for driver
;*        initialization, DC management, display management, and other
;*        functions.  There are twelve functions that the Enable routine
;*        performs, which can be grouped into three catagories:
;*     
;*            Device Control - Fill LDeviceBlock
;*                             Fill PDeviceBlock
;*                             Fill Information PDeviceBlock
;*                             Disable PDeviceBlock
;*     
;*            DC Control     - Enable Device Context
;*                             Disable Device Context
;*                             Save DC State
;*                             Restore DC State
;*                             Reset DC State
;*     
;*            Simulations    - Install Simulation
;*     
;*     
;*      Fill LDeviceBlock:
;*     
;*        The Engine first makes contact with the driver by invoking the
;*        "Fill LDeviceBlock" entry point.  This entry point is used to
;*        set up the dispatch table which will be used for ALL physical
;*        devices for the driver (one physical device may have many DCs
;*        associated with it).
;*     
;*        At this time the driver also indicates under what conditions
;*        a physical device needs to be created.  A device like the
;*        main display would indicate that only one physical device
;*        is to be created regardless of the logical device name or
;*        output file name passed on the create call.  A device like
;*        an epson printer would indicate that a new physical device
;*        is needed for every DC.
;*     
;*        This function is informed of the Engine version number to allow
;*        a driver to be backwards compatible with earlier versions of the
;*        Engine.
;*     
;*        This entry point will be called once for each task which uses
;*        the driver.  On the very first entry to this routine the driver
;*        should allocate all dynamic segments which will be needed (they
;*        don't have to be allocated to their full size, they could be
;*        grown later).  On each subsequent call to this entry point, the
;*        selectors should be validated, and per task memory allocated.
;*     
;*        This is also the time the driver should tag onto the exit list.
;*     
;*     
;*      Fill PDeviceBlock:
;*     
;*        Fill PDeviceBlock is invoked each time the Engine determines
;*        that a physical instance of the device is to be created, based
;*        on the flags returned by "Fill LDeviceBlock".
;*     
;*        A Physical Device (PD) contains the information necessary for
;*        output operations to occur.  Every Device Context (DC) will be
;*        associated with a PD.  How information is distributed between
;*        the two is up to the driver writer, but generally the PD will
;*        contain information such as the output file name and banding
;*        buffer for printers, and the DC will contain state information
;*        such as fill pattern and font.
;*     
;*        When this call is made, the driver should interpret the passed
;*        parameters to determine the mode of operation, allocate the
;*        space for the PD, and initialize it as appropriate.
;*     
;*     
;*      Fill Information PDeviceBlock:
;*     
;*        Fill Information PDeviceBlock differs from the Fill PDeviceBlock
;*        in only one manner, this being that no output is to be performed
;*        to the physical device.  However, inquires may be made to the
;*        device (e.g. text extent), and bitmap operations may occur.
;*     
;*        The use of this function allows devices which require banding
;*        buffers or other resources to skip their acquisition.  If the
;*        device requires hardware support for a bitmap operation, then
;*        the driver has the option of acquiring the hardware to perform
;*        the operation or returning a failure on the Enable Device
;*        Context call.
;*     
;*     
;*      Disable PDeviceBlock:
;*     
;*        Disable PDeviceBlock is invoked when the last DC (including
;*        memory DCs) for the given PD has been deleted.  All resources
;*        associated with the given PD should be freed, including the
;*        physical device itself.
;*     
;*        The driver should reference count the number of PDeviceBlocks
;*        that have been allocated for it.  When the last PDeviceBlock
;*        has been deleted, the driver should free all other resources
;*        associated with it as it will be unloaded after returning to
;*        the caller.
;*     
;*        For the main display, this call can be a nop since Winthorn
;*        never terminates.
;*     
;*     
;*      Enable Device Context:
;*     
;*        Enable Device Context will be invoked when a new DC is created.
;*        The device driver is expected to allocate any memory it needs
;*        to support the attributes of the DC.  The identifier for this
;*        block of memory is returned to the Engine.  This "magic number"
;*        or DDC (handle to Display Device Context) will be available to
;*        all calls to identify which DDC is being referenced.
;*     
;*        The PDeviceBlock containing the PD with which this DDC is to be
;*        associated with is passed as one of the parameters to this
;*        function.
;*     
;*     
;*      Disable Device Context:
;*     
;*        Disable Device Context will be invoked when a DC is about to be
;*        deleted.  The device driver is expected to free up any memory
;*        it has allocated for the DC.
;*     
;*        Any physical disabling of the device should be delayed until
;*        the Disable PDeviceBlock function is invoked.
;*     
;*     
;*      Save DC State:
;*     
;*        Save DC State saves a copy of the DDC for the given DC.
;*        A DC's state may be saved multiple times, in a LIFO order.
;*        This function will return an error code if there is not enough
;*        memory available to save the state.
;*     
;*     
;*      Restore DC State:
;*     
;*        Restore DC State restores a previously saved DC state. A
;*        parameter to this function is which saved state is to be
;*        restored (a number).
;*     
;*        The saved states work like a stack.  If the number indicating
;*        which state to restore is positive, it indicates the actual
;*        state to be restored.  That is, if the number is one, then
;*        the first saved state is restored, and all others are lost.  If
;*        the number is two, the second saved state will be restored, and
;*        one will remain saved.  If the number is negative, it indicates
;*        which state relative from the current state is to be restored
;*        (e.g. if the current state was 5 and -3 was given, state 2 would
;*        be returned).
;*     
;*        If the number is zero, or a positive or negative number is given
;*        specifying a state that hasn't been saved, an error will be
;*        returned.
;*     
;*     
;*      Reset DC State:
;*     
;*        Reset DC State will reset the information for the given DC
;*        to its original initialized state.
;*
;* FUNCTIONS    Public: perform_rip
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   02/06/87                     Walt Moore [waltm] - Created
;*   01/12/88                     Walt Moore [waltm] - The big rewrite
;*   10/03/91                     David Kerr use VioGetMode to determine
;*                                if color @DAKCOL PTR SM05623
;*   06/07/88                     Paul Klingler [paulk]
;*                                  Changed name of function to OS2_DRV_ENABLE
;*                                  for dcr24000 (linking by names)           
;*   08/14/90                     Viroon Touranachun
;*                                  Removed CS-aliasing the Instance Data
;*                                  segment.
;*   06/07/89                     Bob Grudem [bobgru]
;*                                  Moved the collection of engine function
;*                                  addresses so that it happens only once.
;*   03/31/89                     Lee A. Newberg [leen]
;*                                  Made it not recored the default code page.
;*                                  We can't cache the default code page for it
;*                                  may change.  PTR SM83231
;*   04/26/88                     Charles Whitmer [chuckwh]
;*                                  Made it record the default code page.
;*   10/10/89                     John Colleran [johnc]
;*                                  Made it record the default code page.  Added
;*                                  call to VioGetConfig the first time.  Note  
;*                                  that this must be called AFTER the          
;*                                  physical_enable which sets the mode so we   
;*                                  get the correct display, the one that will  
;*                                  run the PM screen group                     
;*   05/08/89                     Lee A. Newberg [leen]
;*                                  Info DC's are created with 1 clip rectangle  
;*                                  rather than 0. PTR HM377.                    
;*   03/31/89                     Lee A. Newberg [leen]
;*                                  Had it query PMWIN and the engine for the code
;*                                  page information, rather than reading it from 
;*                                  a cache.  PTR SM83231                         
;*   01/12/88                     Walt Moore [waltm] The big rewrite. 
;*   03/05/87                     Hock Lee [hockl] Wrote enable_ddc
;*   05/05/89                     Lee A. Newberg [leen]
;*                                  Preserves User bounds around the restore.  PTR
;*                                  SM83744.
;*   04/03/89                     Lee A. Newberg [leen]
;*                                  Made it not set the default code page for the 
;*                                  process.  PMWIN will do it for us.            
;*   04/17/88                     Charles Whitmer [chuckwh]
;*                                  The small rewrite.  Now we don't call out of  
;*                                  here unless we absolutely need to.  We now    
;*                                  preserve part of the DDC.  We do the RGB bit  
;*                                  ourselves rather than always call             
;*                                  CreateLogColorTable.  This should be much     
;*                                  faster.                                       
;*   10/06/88                     Charles Whitmer [chuckwh] Wrote ring3_VioGetCP.
;*                                  I only use it as a random VIO call.
;*****************************************************************************/

        .xlist
        include cmacros.inc
ifdef PALMGR
INCL_GPIBITMAPS         equ     1
endif
INCL_GPILOGCOLORTABLE   equ     1
INCL_DDICOMFLAGS        equ     1
INCL_GRE_COLORTABLE     equ     1
INCL_GRE_FONTS          equ     1
INCL_DEV                equ     1
INCL_DDIMISC            equ     1
INCL_DOSPROCESS         equ     1
INCL_SUB                equ     1
DINCL_VIO               equ     1
        include pmgre.inc
DINCL_ENABLE            equ     1
        include driver.inc
        include assert.mac
        include njmp.mac
ifdef PALMGR
        include palette.inc
endif ;PALMGR
        .list

        ??_out  enable

        errcode <INSUFFICIENT_MEMORY,BASE_ERROR,INV_DC_TYPE,DEV_FUNC_NOT_INSTALLED>

        externFP SetDriverInfo          ;** Engine Functions we Dynlink to

        externFP DosCallback            ;** OS|2 Functions we need
        externFP DosCreateCSAlias
        externFP DosGetResource2
        externFP DosExitList
        externFP DosCallBack
        externFP DosGetMessage
        externFP FSRSemEnter
        externFP FSRSemLeave
        externFP WinQueryProcessCp
        externFP GreEntry3
        externFP VioGetCP
        externFP VioSetMode
        externFP VioSetCurPos
        externFP VioWrtTTY
        externFP ring3_VioGetConfig
        externFP save_bitmap
        externFP far_alloc_far_mem
        externFP far_free_far_mem

;/*
;**        Our own functions
;*/

        externFP exit_list_proc
        externFP one_time_init
        externFP CreateLogColorTable

        externA DEV_DISPATCH_TBL_SIZE   ;** Size of dispatch table
        externA DEF_DISPATCH_TBL_SIZE   ;** Size of default dispatch table

sBegin  Data

        externB fEnabled                ;**  Logical Virgin flag
        externB fPhysEnabled            ;**  Physical Virgin flag
        externB sdIC                    ;**  Surface definition for an IC
        externB ddcInit                 ;**  Initial ddc
        externB rddcInit                ;**  Initial ddc
        externW cResource               ;**  Number of resources to load
        externD apfnDefDispatch         ;**  Default dispatch table

        externW wAdapter                ;**  Display and Adapter Type
        externW wDisplay
        externB bVGAtype

;/*
;**  The address of the exit list routine which will be invoked when a
;**  process terminates.  This will be passed to DosExitList whenever
;**  fill_log_dev_blk is called.  It is defined in this manner instead
;**  of synthesizing it on the fly so that the linker will determine
;**  the correct segment for it.
;*/


        globalD pfnExit,exit_list_proc

sEnd    Data

sBegin  Ring2Conform


cProc   OS2_PM_DRV_ENABLE,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   u32_param1
        parmD   u32_param2

cBegin  <nogen>

        jmp     far ptr Enable

cEnd    <nogen>

sEnd    Ring2Conform

sBegin  FarCode
        externW FarCodeData

        externNP save_lct

sEnd    FarCode

sBegin  InitSeg

        externW InitSegData


        externD apfnOurDispatch         ;** Our function handlers

sEnd    InitSeg

        externNP alloc_ddc
        externNP free_ddc
        externFP far_physical_enable
        externFP far_deselect_bitmap    ;**  BMSUP.ASM
        externNP deselect_lct           ;**  COLORTBL.ASM

sBegin  Code
        assumes cs,Code

        externW CodeData                ;** Our DS

        externNP enter_driver_sem
        externNP leave_driver

;/*
;** apfnEnable is the dispatch table for the Enable function.  The last
;** three entries are not supported by this driver.  They will be detected
;** with the range check in the dispatcher.
;*/

apfnEnable     equ     this word
        dd      fill_log_dev_blk
        dd      fill_phys_dev_blk
        dd      enable_bad_subfunction  ;** Reserved
        dd      enable_exit_zero        ;** disable_phys_dev_blk
        dd      enable_ddc
        dd      disable_ddc
        dd      save_ddc_state
        dd      restore_ddc_state
        dd      reset_ddc_state
        dd      enable_exit_zero        ;** !!! set DDC_ENABLED at some point
        dd      enable_exit_zero        ;** !!! clear DDC_ENABLED at some point

ENABLE_TABLE_SIZE equ ($ - apfnEnable) / 4
page

;/***************************************************************************
;*
;* FUNCTION NAME = Enable
;*
;* DESCRIPTION   = Enable dispatches control to the given Enable subfunction.
;*                 All subfunctions except Install Simulation are required for
;*                 a display driver.  Returns will be made to the caller for
;*                 all functions.  There cannot be any jumps through the
;*                 default dispatch table.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       FSRSemEnter
;*                       FSRSemLeave
;*
;* INPUT         = None
;* OUTPUT        = None
;*                 
;* RETURN-NORMAL = As per subfunction                                
;* RETURN-ERROR  = As per subfunction                                
;*                 DX:AX = ERROR_BAD_INDEX if subfunction is unknown 
;**************************************************************************/

ENABLE_LOCAL_SIZE       equ  20         ;# of locals allocted by Enable
RPL_RING3               equ   3         ;We want it to look like ring 3
ERROR_ALREADY_EXISTS    equ 183

        assumes ds,Data
        assumes es,nothing

cProc   Enable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   u32_param1
        parmD   u32_param2

        localV  workspace,ENABLE_LOCAL_SIZE

cBegin
        cld
        fw_zero <es,si,di>
        cmp     subfunction.lo,1        ;** look for fill_log_dev_blk
        jnz     do_enable

;/*
;** Hook into the exit list for this process.  This is the step we
;** need to take for per-process initialization.
;*/

        or      pfnExit.sel,RPL_RING3   ;**  RPL stamp the CS with ring 3
        cCall   DosExitList,<EXLST_PRTY_UNLOCK+EXLST_ADD,pfnExit>
        or      ax,ax
        jz      do_enable               ;** Success
        cmp     ax,ERROR_ALREADY_EXISTS ;** It's also OK if we've been here before
        jz      do_enable               ;** Success
        xchg    ax,bx                   ;** Save DOS error code in BX
        mov     ax,PMERR_BASE_ERROR
        save_error_code
        mov     ax,-1                   ;** -1 is Enable's error code
        cwd
        jmp     short enable_final

do_enable:
        call    enter_driver_sem
        cmp     subfunction.hi,0        ;** The segment of the sub function
        jnz     enable_bad_subfunction  ;**   must be zero.
        mov     bx,subfunction.lo       ;** The passed sub function is
        dec     bx                      ;**   1 based, need it as 0 based
        cmp     bx,ENABLE_TABLE_SIZE    ;** If subfunction is out of range,
        jae     enable_bad_subfunction  ;**   return the ERROR_BAD_OPTION code
        add     bx,bx                   ;** The sub function is valid,
        add     bx,bx
        jmp     dword ptr apfnEnable[bx] ;**   so invoke the processor for it

;/*
;**  An enable function handler JMPs back to enable_handle_exit to
;**  handle exiting from Enable.  BX contains the offset of the exit
;**  handler routine.
;*/
public  enable_handle_exit
enable_handle_exit:
        jmp     bx                      ;**  dispatch to exit handler

enable_no_memory:
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        jmp     short enable_log_error

enable_no_cs_alias:
enable_dos_error:
        xchg    ax,bx                   ;** Save DOS error code in BX
        mov     ax,PMERR_BASE_ERROR
        jmp     short enable_log_error

enable_bad_subfunction:
        mov     ax,PMERR_DEV_FUNC_NOT_INSTALLED
        errn$   enable_log_error

enable_log_error:
        save_error_code
enable_dont_log_error:
        mov     ax,-1                   ;** -1 is Enable's error code
        cwd
        jmp     short enable_exit

enable_exit_zero:
        xor     ax,ax
        cwd
        errn$   enable_exit

;/*
;**  enable_exit is the entry point for all subfunctions with their
;**  own return code already set in DX:AX.
;*/

enable_exit:
        mov     ds,CodeData
        assumes ds,Data
        call    leave_driver
enable_final:
        fw_zero <es,cx>
cEnd

sEnd    Code

page

;/***************************************************************************
;*
;* FUNCTION NAME = fill_log_dev_blk 
;*
;* DESCRIPTION   = For the first entry:                                             
;*                   call one_time_init                                             
;*                                                                                  
;*                 For all entries:                                                 
;*                   The exit list will be hooked for the process                   
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 
;* INPUT         = frame set up by Enable dispatch function  
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 0 if successful  
;* RETURN-ERROR  = AX = -1 if error   
;*                 error logged     
;**************************************************************************/

sBegin  InitSeg
        assumes cs,InitSeg

        assumes ds,Data
        assumes es,nothing

staticD ring3_GetConfig,ring3_VioGetConfig

cProc   fill_log_dev_blk,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   pFun1Parm
        parmD   pFun1Ret

cBegin  <nogen>
        xor     cx,cx
        xchg    cl,fEnabled
        jcxz    alloc_per_task_data     ;** Have been here before

;/*
;** This is the very first time that the driver is being called.  Perform
;*/  all the one-time initialization.

        cCall   one_time_init
        or      ax,ax
        mov     bx,CodeOFFSET enable_log_error
        jnz     fill_log_exit_relay     ;** Error occured, AX = error code

        les     si,pFun1Ret
        assumes es,nothing

;/*
;** The default of any entry will be saved if we need to dispatch
;**  to it if we cannot perform a function or the function must be passed to
;**  the default handler after we finish with it.
;*/

        les     si,es:[si].fun1_papfn   ;** ES:SI = default table
        assumes es,nothing

        mov     di,DataOFFSET apfnDefDispatch   ;** DS:DI =

        mov     cx,DEF_DISPATCH_TBL_SIZE
;/*
;**  apfnDefDispatch is initialized with the offset into the default table
;**  of the function whose address we want.  Fetch the function address,
;**  and store it in the default table.
;*/

save_default_loop:
        mov     bx,[di]                 ;**  Get default table index
        mov     ax,es:[si+bx].off       ;**  get default function address
        mov     dx,es:[si+bx].sel
        mov     [di].off,ax             ;**  and stick it in apfnDefDispatch
        mov     [di].sel,dx
        add     di,4                    ;**  advance to next
        loop    save_default_loop

alloc_per_task_data:

;/*
;**  Make sure the font resource selectors are valid (OS/2 Base DCR 132)
;*/
        cld
        mov     si,DataOFFSET cResource
        lodsw                           ;** Get count of resources to load
        xchg    ax,cx
        jcxz    resources_loaded
resource_load_loop:
        les     bx,[si].fr_pp
        assumes es,nothing
        farPtr  pselTemp,<es>,<bx>
        arg     ([si].fr_hModule)
        arg     ([si].fr_usType)
        arg     ([si].fr_usId)
        arg     pselTemp
        cCall   DosGetResource2
ifdef   FIREWALLS
        les     bx,[si].fr_pp
        assert  [bx].fr_pp.lo,E,0       ;**  Currently fonts must be seg aligned
endif   ;** FIREWALLS
        or      ax,ax
        mov     bx,CodeOFFSET enable_log_error
        jnz     fill_log_exit_relay     ;** Error occured, AX = error code
        add     si,size FONT_RES
        loop    resource_load_loop
        jmp     short resources_loaded

fill_log_exit_relay:
        jmp     fill_log_exit

resources_loaded:

;/*
;**  All instance data has been set up.  Now fill in the dispatch table
;**  if needed.
;**
;**  One of the parameters to this function is the number of entries in the
;**  dispatch table.  The number of entries which we will fill in will be
;**  the minimum of this number and the number of entries we know about.
;**  This value is fetched now to reduce the number of segment loads.
;*/

        lds     di,pFun1Parm
        assumes ds,nothing
        mov     cx,[di].fun1_cpfn.lo
        jcxz    edit_dispatch_done      ;** Have done it before
        cmp     cx,DEV_DISPATCH_TBL_SIZE
        jb      enable_have_minimum
        mov     cx,DEV_DISPATCH_TBL_SIZE
enable_have_minimum:

;**  Inform the graphics engine that we only want one physical device, and
;**  that all DCs are to share it.

        lds     si,pFun1Ret
        assumes ds,nothing
        les     di,[si].fun1_pfb
        assumes es,nothing

        and     byte ptr es:[di],not (MUSTHAVEPDEV + LDEVSINGLEDC)
        or      byte ptr es:[di],LDEVIGNORENAMES
        .errnz  high (LDEVIGNORENAMES or MUSTHAVEPDEV or LDEVSINGLEDC)

;/*
;**  Fill in the passed dispatch table with those routines we plan to process.
;**  Our dispatch table will contain nulls wherever the default is to be used.
;*/

save_default_dispatch:
        lds     si,[si].fun1_papfn      ;** DS:SI = default table
        assumes ds,nothing

        mov     cx,DEV_DISPATCH_TBL_SIZE
        mov     di,InitSegOFFSET apfnOurDispatch

        mov     bx,SIZE_DWORD           ;** Size of a segmented address

edit_dispatch_table:
        mov     ax,cs:[di].off          ;** Get our handler
        mov     dx,cs:[di].sel
        or      dx,dx                   ;** If the segment of our handler
        jz      edit_dispatch_next      ;**   is 0, use the default
        mov     ds:[si].off,ax          ;** Inform engine of our handler
        mov     ds:[si].sel,dx
edit_dispatch_next:
        add     si,bx                   ;** --> next destination and
        add     di,bx                   ;**   and source
        loop    edit_dispatch_table
edit_dispatch_done:

        mov     bx,CodeOFFSET enable_exit_zero  ;**  no error
fill_log_exit:
        jmp     far ptr enable_handle_exit

cEnd    <nogen>

page

;/***************************************************************************
;*
;* FUNCTION NAME = fill_phys_dev_blk  
;*
;* DESCRIPTION   = The display will be enabled for output operations.  Since the      
;*                 driver told the Engine to only call this routine once, there is    
;*                 no need to allocate and maintain multiple physical devices.  No    
;*                 value needs to be saved in the PDeviceBlock for association when   
;*                 Enable Device Context is called.                                   
;*                                                                                    
;*                 The input parameters for logical device name, output device,       
;*                 etc., will be ignored.                                             
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       physical_enable
;*                 
;* INPUT         = frame set up by Enable dispatch function  
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = PDEV_MAGIC_COOKIE 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   fill_phys_dev_blk,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   u32_param1
        parmD   u32_param2

cBegin  <nogen>

;/*
;**  See if we've done this before.
;*/

        xor     cx,cx
        xchg    cl,fPhysEnabled
        cmp     cl,0
        jnz     @F
        jmp     fill_phys_ok
@@:

;/*
;**  Initialize the VIO for this screen group.  We need to make any random
;**  call to VIO.  When they see this, they'll clear the screen in ASCII
;**  mode.  If we don't do this, we get the "prison bars" displayed on the
;**  screen during intialization.
;*/

        save    <ds>
        farPtr  pfn,<Ring3CodeBASE>,<Ring3CodeOFFSET ring3_VioGetCP>
        cCall   DosCallBack,<pfn>

;/*
;**  Enable the device.
;*/

        farPtr  Null,0,0
        cCall   far_physical_enable,<INIT_VRAM,Null>
        or      ax,ax                   ;** Did enable succeed?
        jz      fill_phys_enabled       ;**   Yes, can continue
                                        ;**   No, report error if FW
        rip     text,<The driver failed to initialize itself>
        jmp     far ptr enable_dos_error    ;**     and return Vio error code

        public  fill_phys_enabled
fill_phys_enabled:
        save    <ds>                    ;**  trashed by upward ring transition
        cCall   DosCallback,<ring3_GetConfig>
        assert  ax,E,0
        mov     wAdapter,bx
        mov     wDisplay,cx

ifdef VGA
;/*
;** determine if the VGA adapter is an ExpressWay card
;*/
        mov     dx,3C3h
        mov     al,0
        out     dx,al

        mov     dx,3C2h
        in      al,dx
        mov     bVGAtype,al

        mov     dx,3C3h
        mov     al,1
        out     dx,al
endif ;** VGA

fill_phys_ok:
        mov     ax,PDEV_MAGIC_COOKIE and 0FFFFh
        mov     dx,PDEV_MAGIC_COOKIE shr 16


        jmp     far ptr enable_exit



cEnd    <nogen>

sEnd    InitSeg

page

;/***************************************************************************
;*
;* FUNCTION NAME = enable_ddc 
;*
;* DESCRIPTION   
;*
;* Enable Device Context will be invoked when a new DC is created.  The
;* device driver allocates a DDC block for each DC created to support the
;* attributes of the DC.  The handle to this DDC will be returned to the
;* graphics engine.  This "magic number" or hddc (handle to device DC)
;* will be available to all calls to identify which device DC (ddc) is
;* being referenced.
;*
;* Since DCs to both memory bitmaps and to the physical display are
;* supported, the type of DC being enabled is stored in the allocated
;* DDC.  The type of the DC being created must be one of those supported
;* by this driver.  If it isn't, an error will be returned.
;* We support:
;*
;*       OD_MEMORY
;*       OD_DIRECT
;*       OD_INFO
;*
;* The exact initialization of the DDC will be based on the calls the
;* Engine will make for initialization of the DC (e.g. clip region,
;* font, etc.), and on whether the DC is a memory DC or a screen DC.
;*
;* The device also initializes default attributes in its own ddc.
;*
;* Registers Preserved:
;*       SI,DI,DS,BP
;* Registers Destroyed:
;*       AX,BX,CX,DX,ES,FLAGS
;*
;* Calls:
;*       heap manager
;*
;* INPUT         = frame set up by Enable dispatch function  
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = hDDC
;* RETURN-ERROR  = AX = -1         
;*                 error logged  
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

sBegin  Code
        assumes cs,Code

cProc   enable_ddc,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   pFun5Parm
        parmD   u32_param2              ;** Ignored for this function
        localW  ddcType
        localD  prddc
cBegin  <nogen>

        .errnz  ??? ge ENABLE_LOCAL_SIZE ;** too many local variables?

        cld

        CPUMode 386
        mov     prddc,0
        CPUMode 286
ifdef FIREWALLS
        les     bx,pFun5Parm
        assumes es,nothing
        cmp     es:[bx].fun5_hState.lo,PDEV_MAGIC_COOKIE and 0FFFFh
        jne     enable_ddc_bad_pdev
        cmp     es:[bx].fun5_hState.hi,PDEV_MAGIC_COOKIE shr 16
        je      enable_ddc_good_pdev
enable_ddc_bad_pdev:
        rip     text,<EnableDDC - Unknown physical device>
enable_ddc_good_pdev:
        fw_zero <es>
endif

        les     di,pFun5Parm            ;** --> parameters to this function
        assumes es,nothing

;/*
;**  Validate the DC type to see if it is one of those which we can deal
;**  with.  If the type isn't OD_MEMORY, OD_DIRECT, or OD_INFO we cannot
;** deal with it.
;*/

        mov     bx,PMERR_INV_DC_TYPE
        mov     ax,es:[di].fun5_type.hi
        or      ax,ax
        jnz     enable_ddc_error_relay
        mov     cx,es:[di].fun5_type.lo
        cmp     cx,15                   ;** Our test doesn't handle CX > 15
        .erre   OD_MEMORY LE 15
        .erre   OD_DIRECT LE 15
        .erre   OD_INFO   LE 15
        ja      enable_ddc_error_relay
        inc     ax                      ;** AX = 1
        shl     ax,cl                   ;** Shift 1, giving a bitmask
        test    ax,(1 shl OD_MEMORY) or (1 shl OD_DIRECT) or (1 shl OD_INFO)
        jnz     @f
enable_ddc_error_relay:
        jmp     enable_ddc_error
        .erre   (1 shl OD_MEMORY) and 0FFFFh
        .erre   (1 shl OD_DIRECT) and 0FFFFh
        .erre   (1 shl OD_INFO)   and 0FFFFh
@@:

;/*
;**  The type of the DDC seems to be valid.  While we have the pointer to
;**  the parameters, save away the engine's hdc which will be stored in the
;**  ddc once it's allocated.
;*/

        CPUMode 386
        push    es:[di].fun5_hdc
        mov     ddcType,cx              ;** Save DC type

;/*
;**  Allocate RDDC
;*/

        xor     dx,dx
        mov     ax,size RDDC
        cCall   far_alloc_far_mem               ;**  DX:AX = prddc
        mov     bx,PMERR_INSUFFICIENT_MEMORY
        njcxz   enable_ddc_error_pop2

        mov     prddc.sel,dx
        mov     prddc.off,ax

;/*
;**  Allocate DDC
;*/

        cCall   alloc_ddc
        mov     bx,PMERR_INSUFFICIENT_MEMORY    ;**  just in case
        njcxz   enable_ddc_error_pop2           ;** Allocation failed

;/*
;** Fill RDDC with defaults
;*/

        les     di,prddc
        assumes es,nothing
        mov     si,DataOFFSET rddcInit
        mov     cx,(size RDDC)/4
        .errnz  (size RDDC) and 3
        rep     movsd
        mov     es:[di-(SIZE RDDC)].rddc_npddc,ax
        sub     di,size RDDC

;/*
;**  Allocation was successful.  Initialize the DDC to its initial state.
;*/

        mov     di,ax
        mov     es,CodeData             ;**  ES:DI = pDDC
        assumes es,nothing
        mov     si,DataOFFSET ddcInit
        mov     cx,(size DDC)/2
        .errnz  (size DDC) and 1
        rep     movsw
        sub     di,size DDC             ;** --> back to the start of the ddc
        pop     [di].ddc_hdc            ;** Set Engine's handle

        mov     eax,prddc
        mov     [di].ddc_prddc,eax                  ;**  link in the RDDC
        CPUMode 286

;/*
;**  set the default code page for this process
;*/

        cCall   WinQueryProcessCp                   ;**  Returns AX
        mov     [di].ddc_ca.ca_idCodePage,ax
        cmp     ax,DEFAULTVIOCODEPAGE and 0FFFFh
        jz      no_map_needed
        or      [di].ddc_ca.ca_fs,CA_MUST_MAP
        check   QueryCodePageVector,<idCP,hddc,ulFunN>
        farPtr  CodePage,0,ax
        farPtr  hddcNull,ax,ax
        cCall   GreEntry3,<CodePage,hddcNull,GreQueryCodePageVector>
        or      dx,dx
        jnz     @F
        jmp     far ptr enable_dont_log_error
@@:
        mov     [di].ddc_ca.ca_paus.lo,ax
        mov     [di].ddc_ca.ca_paus.hi,dx
no_map_needed:
        mov     ax,ddcType              ;**  ddc type

;/*
;**  modify the defaults depending on the TYPE
;*/

        cmp     al,OD_INFO              ;** What type of ddc?
        jb      enable_finished         ;**   OD_DIRECT
        mov     dx,word ptr [di].ddc_fb
        .errnz  ddc_fbAbove-ddc_fb-1
        and     dl,not DDC_VISIBLE
        or      dh,DDC_INFO_DC
        mov     bx,DataOFFSET sdIC
        cmp     al,OD_INFO              ;** What type of ddc?
        je      enable_its_an_IC        ;**   OD_INFO
        .errnz  OD_DIRECT-5             ;**   OD_MEMORY
        .errnz  OD_INFO-6
        .errnz  OD_MEMORY-8
        mov     [di].ddc_crcsClip,0
        and     dx,not ((DDC_INFO_DC shl 8) or DDC_PRESENT or DDC_DEVICE)
        mov     bx,INVALID_ADDRESS      ;** Want ddc_npsd to be really bogus
enable_its_an_IC:
        mov     [di].ddc_npsd,bx        ;** Set pointer to the surface
        mov     word ptr [di].ddc_fb,dx
        .errnz  ddc_fbAbove-ddc_fb-1

;*/
;**  The DC has been successfully created.  Return its handle to
;**  the caller.  Tag it with the correct identifier for firewalls
;*/

enable_finished:
        mov     dx,HDDC_IDENT           ;** Return DX:AX = hddc
        xchg    ax,di
        ddc?    ax                      ;** Let's make sure it's correct
        jmp     far ptr enable_exit


;/*
;**  An error occured.  We will want to log the error and return -1
;**  to the caller.  BX = error code
;*/

enable_ddc_error_pop2:
        add     sp,2*SIZE_WORD          ;** Clean 2 words from stack
enable_ddc_error:
        cmp     prddc.sel,0
        jz      @F
        mov     ax,prddc.off
        mov     dx,prddc.sel
        save    <bx>
        cCall   far_free_far_mem

@@:
        mov     ax,bx
        jmp     far ptr enable_log_error

cEnd    <nogen>
page

;/***************************************************************************
;*
;* FUNCTION NAME = disable_ddc 
;*
;* DESCRIPTION   = Disable Device Context will be invoked when a DC is about 
;*                 to be deleted.  The device driver frees up the DDC block 
;*                 it has allocated for the DC.                                                            
;*                                                                                        
;*                 The "magic number" field of the DC will be invalidated.                
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;*                 Calls:
;*                       heap manager
;*
;* INPUT         =  frame set up by Enable dispatch function 
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  DX:AX = 0  
;* RETURN-ERROR  =  NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   disable_ddc,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   hddc
        parmD   u32_param2              ;** Ignored for this subfunction

cBegin  <nogen>

ifdef FIREWALLS
        ddc?    hddc,<SURFACE,LEVELS>
;/*
;**  The engine should have freed any bitmap before calling us to delete
;**  the ddc.  Let's keep them honest.  They also should have restored us
;**  to level 1.
;*/

        mov     bx,hddc.lo
        cmp     [bx].ddc_cLevel,1       ;** Guaranteed by the Engine!
        je      @F
        rip     text,DisableNotLevel1,<DisableDDC - ddc has saved levels>
@@:
        test    [bx].ddc_fb,DDC_DEVICE
        jnz     @F
        cmp     [bx].ddc_npsd,INVALID_ADDRESS
        je      @F
        rip     text,<DiableDDC - Bitmap selected into the ddc>
@@:
        fw_zero <es,si>
endif

        mov     si,hddc.lo
        call    deselect_lct            ;** Free any logical color table

;/*
;** Make magic cookie in the Engine be INVALID_ADDRESS so that we might
;**  generate a GP fault if we ever try to do an IDENT on it.
;*/

        farPtr  hdcTemp,<[si].ddc_hdc.hi>,<[si].ddc_hdc.lo>
        mov     ax,INVALID_ADDRESS
        farPtr  u32_data,ax,ax
        farPtr  lTemp,ax,DI_HDC
        cCall   SetDriverInfo,<u32_data,hdcTemp,lTemp,hdcTemp>
        mov     ax,[si].ddc_prddc.off
        mov     dx,[si].ddc_prddc.sel
        cCall   far_free_far_mem
        call    free_ddc
        jmp     far ptr enable_exit_zero

cEnd    <nogen>

page

;/***************************************************************************
;*
;* FUNCTION NAME = save_ddc_state 
;*
;* DESCRIPTION   = A copy of the DDC will be made, and added to a linked list of 
;*                 saved states for the DC (LIFO ordering).  An error is returned 
;*                 if there is insufficient memory.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;*                 Calls:
;*                       alloc_ddc
;*
;* INPUT         = frame set up by Enable dispatch function 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 0   
;* RETURN-ERROR  = PMERR_INSUFFICIENT_MEMORY 
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   save_ddc_state,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   hddc
        parmD   u32_param2              ;** Ignored for this subfunction

cBegin  <nogen>

        ddc?    hddc,<SURFACE,LEVELS>

;/*
;**  Allocate enough memory to make a copy of the ddc and copy it there.
;*/

        call    alloc_ddc               ;** Allocate ddc memory
        mov     bx,PMERR_INSUFFICIENT_MEMORY    ;** Error code if allocation failed
        njcxz   save_ddc_error
        xchg    di,ax                   ;** DI = saved ddc handle
        mov     si,hddc.lo              ;** SI = ddc to save
        mov     ax,ds
        mov     es,ax                   ;** Copy ddc to allocated memory
        assumes es,nothing

        mov     cx,(size DDC)/2
        .errnz  (size DDC) and 1
        cld
        rep     movsw
        sub     si,size DDC             ;** si -> this ddc
        sub     di,size DDC             ;** di -> saved level

        xor     dx,dx
        mov     ax,size RDDC
        cCall   far_alloc_far_mem               ;**  DX:AX = new RDDC
        jcxz    save_ddc_error_free_ddc_in_di   ;**  also set error code

        mov     bx,di                   ;** save newly alloced saved DDC ptr
        lds     si,[si].ddc_prddc       ;** DS:SI is source RDDC
        assumes ds,nothing
        mov     di,ax
        mov     es,dx                   ;** ES:DI is dest RDDC
        assumes es,nothing
        mov     cx,(size RDDC)/4
        .errnz  (size RDDC) and 3
        CPUMode 386
        rep     movsd
        CPUMode 286
        sub     di,size RDDC

        rddc?   es,di
        mov     es:[di].rddc_npddc,bx   ;**  tighty up the references
        mov     ds,CodeData
        assumes ds,Data
        mov     [bx].ddc_prddc.sel,es
        mov     [bx].ddc_prddc.off,di
        mov     di,bx                   ;**  DS:DI saved DDC
        mov     si,hddc.lo

;/*
;**  The ddc has been copied.  Now update all the correct fields as necessary.
;**
;**  Currently this consists of:
;**
;**     1) Marking the saved ddc as saved
;**     2) Incrementing the save level in ddc
;**     3) Updating the pointer to the previous ddc
;**     4) Incrementing the bitmap select count if a memory DC and a
;**        bitmap is selected into it
;**     5) Incrementing the logical color table count if a user-defined
;**        logical color table is in use
;*/

        mov     [di].ddc_usId,SAVED_DDC_IDENT
        .erre   DDC_IDENT-SAVED_DDC_IDENT
        inc     [si].ddc_cLevel
        mov     [si].ddc_npddcPrev,di
        mov     al,[si].ddc_fb
        and     al,DDC_DEVICE or DDC_PRESENT
        cmp     al,DDC_PRESENT
        jne     save_ddc_bm_incremented
        mov     bx,[si].ddc_npsd
        call    save_bitmap
save_ddc_bm_incremented:

ifdef PALMGR
        mov     bx,[si].ddc_npdevpal
        inc     [bx].devpal_cUsage
endif ;** PALMGR

        cCall   save_lct
        ddc?    si,<SURFACE,LEVELS>         ;** Let's check up on ourselves
        jmp     far ptr enable_exit_zero    ;** Indicate success

save_ddc_error_free_ddc_in_di:
        mov     si,di
        cCall   free_ddc                    ;**  frees DS:SI DDC
        mov     bx,PMERR_INSUFFICIENT_MEMORY

save_ddc_error:
        mov     ax,bx
        jmp     far ptr enable_log_error

cEnd    <nogen>
page

;/***************************************************************************
;*
;* FUNCTION NAME = restore_ddc_state  
;*
;* DESCRIPTION   = A previously saved DDC is restored.  All memory associated with      
;*                 any discarded DDCs will be freed.  A request to restore an 
;*                 invalid save level (including a request to restore to level 0), 
;*                 will return an error.                                                     
;*                                                                                      
;*                 The save state blocks are a linked list, with the hddc pointing 
;*                 to the current level (head of the list).  To prevent excess 
;*                 copying, hddc will be altered to point to the correct level 
;*                 and then the ddcs will be freed.                                                       
;*                                                                                      
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         =  Frame set up by Enable dispatch function 
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  0 
;* RETURN-ERROR  =  -1 
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   restore_ddc_state,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   subfunction
        parmD   hddc
        parmD   cLevel

        localW  cLevelReq
        localV  ptsOldOrg,%(size POINTS)
        localV  rcsUserBound,<SIZE rddc_rcsUsrBound>

cBegin  <nogen>

        .errnz  ??? ge ENABLE_LOCAL_SIZE ;** too many local variables?

ifdef FIREWALLS

        ddc?    hddc,<SURFACE,LEVELS>

;/*
;**  Make sure that the level to restore is valid.  This is within a
;**  FIREWALL since the Engine will ensure that the level is valid
;**  (we're only checking up on the Engine).!!!
;*/

        mov     bx,hddc.lo
        mov     ax,cLevel.lo            ;** Make sure that the number is
        cwd                             ;**   properly sign extended
        cmp     dx,cLevel.hi
        jne     restore_fw_bad_level
        or      ax,ax                   ;** If level is negative, it is relative
        jg      restore_level_positive  ;**   to the current level of the DDC
        add     ax,[bx].ddc_cLevel
restore_level_positive:
        cmp     ax,[bx].ddc_cLevel      ;** Within range?
        jae     restore_fw_bad_level    ;**   No, error
        or      ax,ax                   ;** A level of zero could get through the
        jnz     restore_good_level      ;**   above checks.
restore_fw_bad_level:
        rip     text,<RestoreDDC - Restore to an invalid level>
restore_good_level:
        fw_zero <es,bx>
endif

;*/
;**  Compute which level we're to restore to and do it.  For each level
;**  we restore to, we'll have to free any user-defined logical color
;**  table and decrement the count on any bitmap selected into the ddc.
;**  Might as well free the memory also.
;**
;**  Anything stored in the ddc in SCREEN coordinates must be adjusted by
;**  the deltas of the old and new dc origin.
;*/

        mov     si,hddc.lo              ;** --> ddc
        mov     ax,cLevel.lo            ;** Map requested level to an ABS number
        cwd
        and     dx,[si].ddc_cLevel      ;** 0 if level +, ddc_save_level if neg
        add     ax,dx                   ;** AX = desired level
        cmp     ax,[si].ddc_cLevel
        jb      level_is_ok
        jmp     restore_all_done        ;** Restoring to current level
level_is_ok:

        mov     cLevelReq,ax            ;** Save desired restore level

        CPUMode 386
        lgs     si,[si].ddc_prddc       ;**  GS:SI = RDDC
        assumes gs,nothing
        rddc?   gs,si

        mov     eax,dword ptr gs:[si].rddc_ptsOrg
        mov     ptsOldOrg,eax

;/*
;**  Save the current user bounds to stack
;*/
        add     si,rddc_rcsUsrBound     ;**  GS:SI = rcsUsrBound
        mov     ax,ss
        mov     es,ax
        assumes es,nothing
        lea     di,rcsUserBound
        mov     cx,(SIZE rddc_rcsUsrBound) / 4
        .errnz  (SIZE rddc_rcsUsrBound) and 3
        assert  ND
        rep     movs dword ptr es:[di],dword ptr gs:[si]
        mov     si,hddc.lo              ;** SI = DDC being restored
        CPUMode 286
        ddc?    si

;/*
;**  Find the right ddc to restore and free the rest on the way.
;*/

        public  free_next_level
free_next_level:

        mov     di,[si].ddc_npddcPrev   ;** DI--> previous ddc
        call    deselect_lct            ;** Free any logical color table
        test    [di].ddc_fb,DDC_DEVICE
        jnz     @F
        call    far_deselect_bitmap     ;** Free any bitmap
        cmp     si,hddc.lo              ;** Don't free orig ddc
        je      @F
        mov     ax,[si].ddc_prddc.off
        mov     dx,[si].ddc_prddc.sel
        cCall   far_free_far_mem        ;** Free rddc
        call    free_ddc                ;** Free ddc at DS:SI
@@:
        mov     si,di                   ;** SI = previous ddc

ifdef FIREWALLS
        .erre   DDC_IDENT-SAVED_DDC_IDENT
        cmp     [si].ddc_usId,SAVED_DDC_IDENT
        je      @F
        rip     text,<RestoreDDC - Previous level not a saved DDC>
@@:
endif
        mov     [si].ddc_usId,DDC_IDENT ;** Mark as valid DC
        mov     ax,cLevelReq
        cmp     ax,[si].ddc_cLevel
        jb      free_next_level

        mov     di,hddc.lo              ;** DI = DDC being restored
        CPUMode 386

;/*
;**  Now SI is the ddc state we want, so copy it to the orig RDDC block
;**  Also the saved DDC pointer is transferred to the current DDC below
;*/

        push    [di].ddc_prddc          ;** save RDDC being restored
        push    si                      ;** save DDC to free
        les     di,[di].ddc_prddc       ;** ES:DI = RDDC to restore
        assumes es,nothing
        lgs     si,[si].ddc_prddc       ;** GS:SI = RDDC source info
        assumes gs,nothing
        mov     ax,si
        mov     dx,gs                   ;** DX:AX = RDDC to free after copy
        mov     cx,(size RDDC)/4
        .errnz  size RDDC and 3
        rep     movs dword ptr es:[di],dword ptr gs:[si]

ifdef FIREWALLS
        mov     gs,dx                   ;** double check we're deleting a RDDC
        mov     si,ax
        assumes gs,nothing
        rddc?   gs,si
        mov     gs:[si].rddc_usId,-1
endif
        cCall   far_free_far_mem        ;** Frees memory at DX:AX

;/*
;**  Now copy DDC info
;*/
        mov     di,hddc.lo              ;** DI = DDC being restored
        pop     si                      ;** SI = DDC source info
        mov     cx,(size DDC)/2
        .errnz  (size DDC) and 1
        mov     ax,ds
        mov     es,ax
        assumes es,nothing
        rep     movsw
        sub     si,(size DDC)           ;** SI--> saved ddc info

;/*
;**  Now free the last ddc space, mark ddc as display so ddc_validate
;**  won't object when we free the ddc struc that is merely a copy
;*/

ifdef FIREWALLS
        mov     [si].ddc_npsd,INVALID_ADDRESS
        mov     [si].ddc_fb,0
endif
        call    free_ddc                ;** Free ddc at DS:SI

;/*
;**  Update origin and current position in restored ddc
;*/

        mov     si,hddc.lo              ;** DS:SI = DDC (restored)
        ddc?    si
        pop     [si].ddc_prddc          ;** restore RDDC pointer
        les     di,[si].ddc_prddc       ;** ES:DI = RDDC (restored)
        assumes es,nothing
        rddc?   es,di
        mov     es:[di].rddc_npddc,si
        mov     ax,ptsOldOrg.pts_x
        xchg    ax,es:[di].rddc_ptsOrg.pts_x
        sub     ax,es:[di].rddc_ptsOrg.pts_x
        jz      @F
        sub     es:[di].rddc_ptsCurPos.pts_x,ax     
        sub     [si].ddc_pa.pa_ptsOrg.pts_x,ax
        or      [si].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
@@:
        mov     ax,ptsOldOrg.pts_y
        xchg    ax,es:[di].rddc_ptsOrg.pts_y
        sub     ax,es:[di].rddc_ptsOrg.pts_y
        jz      @F
        sub     es:[di].rddc_ptsCurPos.pts_y,ax     
        sub     [si].ddc_pa.pa_ptsOrg.pts_y,ax
        or      [si].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
@@:
        CPUMode 286

;/*
;**  Put the user bounds in this level.
;*/

        mov     bx,si                           ;**  save DDC ptr
        ddc?    si
        rddc?   es,di
        lea     di,[di].rddc_rcsUsrBound
        lea     si,rcsUserBound
        mov     cx,(SIZE rddc_rcsUsrBound) / 4
        .errnz  (SIZE rddc_rcsUsrBound) and 3
        assert  ND
        CPUMode 386
        rep     movs dword ptr es:[di], dword ptr ss:[si]
        CPUMode 286
        mov     si,bx                           ;**  restore DDC ptr

restore_all_done:
        ddc?    si,<SURFACE,LEVELS>
        jmp     far ptr enable_exit_zero        ;** Indicate success

cEnd    <nogen>
page

;/***************************************************************************
;*
;* FUNCTION NAME = reset_ddc_state 
;*
;* DESCRIPTION   = The given DDC will be initialized to nearly the same state 
;*                 as when it was created.  The difference is mainly that the 
;*                 DC Origin and Clip region data will be maitained.  This is 
;*                 because Apps reset their DCs, it shouldn't change the window 
;*                 position!                               
;*                                                                                        
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*                
;* INPUT         = frame set up by Enable dispatch function 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   reset_ddc_state,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
        parmD   subfunction
        parmD   hddc                    ;**  Our DDC cookie
        parmD   flColorMode             ;**  Color reset flag
cBegin  <nogen>

ifdef FIREWALLS
        ddc?    hddc,<SURFACE,LEVELS>

;/*
;**  There should only be one bit set on the flColorMode parameter
;*/

        cmp     flColorMode.hi,0
        jnz     reset_bad_option
        test    flColorMode.lo,not (RDC_RGBMODE + RDC_SETOWNERTOSHELL)
        jz      @F
reset_bad_option:
        rip     text,<ResetDDC - Unknown option flags>
@@:

;/*
;**  The engine should have freed any bitmap before calling us to reset
;**  the ddc.  Let's keep them honest.  They should have also restore us
;**  to level 1.
;*/

        mov     bx,hddc.lo
        cmp     [bx].ddc_cLevel,1       ;**  Guaranteed by the Engine!
        je      @F
        rip     text,<ResetDDC - ddc has saved levels>
@@:
        mov     al,[bx].ddc_fb
        and     al,DDC_DEVICE or DDC_PRESENT
        cmp     al,DDC_PRESENT
        jne     @F
        rip     text,<ResetDDC - Bitmap selected into the ddc>
@@:
        fw_zero <es>
endif

;/*
;**  free any Logical Color Table
;*/

        mov     si,hddc.lo              ;**  Get handle to the DDC
        test    [si].ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jz      deselect_lct_done
        call    deselect_lct            ;**  Free any logical color table
deselect_lct_done:

;/*
;**  copy in the default state, but only copy bundles if they are dirty.
;**  If a system color changed and the change hasn't been reflected in
;**  the ddc, the treat the bundles as if they were dirty.
;*/

        mov     ax,ds
        mov     es,ax
        assumes es,nothing
        cld
        mov     bx,RESET_DDC_BUNDLES
        mov     ax,ddcInit.ddc_iSysClr
        cmp     ax,[si].ddc_iSysClr
        jne     bundles_are_dirty
        test    [si].ddc_fbBelow,DDC_DIRTY_ATTRS
        jnz     bundles_are_dirty
        mov     bx,RESET_DDC_POST_BUNDLES
bundles_are_dirty:
        CPUMode 386
        lea     di,[si][bx]
        lea     si,ddcInit[bx]
        mov     cx,size DDC
        sub     cx,bx
        shr     cx,1
        assert  NC
        .errnz  (size DDC - RESET_DDC_BUNDLES) and 1
        .errnz  (size DDC - RESET_DDC_POST_BUNDLES) and 1
        rep     movsw
        sub     di,size DDC             ;**  DI = DDC

        les     di,[di].ddc_prddc       ;**  ES:DI = RDDC
        assumes es,nothing
        rddc?   es,di
        mov     si,DataOFFSET rddcInit
        add     si,RESET_RDDC_START
        add     di,RESET_RDDC_START
        mov     cx,(size RDDC - RESET_RDDC_START)/4
        .errnz  (size RDDC - RESET_RDDC_START) and 3
        rep     movsd
        CPUMode 286                     ;**  restore prddc
        mov     di,hddc.lo              ;**  DI = DDC

;/*
;**  the Current Position is kept in SCREEN coordinates
;**    => set it to be (0,0) relative to the DC Origin
;*/

        mov     si,[di].ddc_prddc.off
        rddc?   es,si
        mov     ax,es:[si].rddc_ptsOrg.pts_x
        mov     bx,es:[si].rddc_ptsOrg.pts_y
        mov     es:[si].rddc_ptsCurPos.pts_x,ax
        mov     es:[si].rddc_ptsCurPos.pts_y,bx

;/*
;**  our brush rotation has been reset => set it too.  The pattern stored
;**  in ddcInit is always rotated for an origin of 0,0.  Y rotation is
;**  performed at output time.  X rotation is performed at realization
;**  time.
;*/

        mov     [di].ddc_pa.pa_ptsOrg.pts_x,ax
        mov     [di].ddc_pa.pa_ptsOrg.pts_y,bx
        or      ax,ax
        jz      @F
        or      [di].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
@@:

;/*
;**  reset the flags
;*/

        and     [di].ddc_fb,DDC_PRESENT+DDC_DEVICE+DDC_CLIP_NOTIFY+DDC_VISIBLE
        or      [di].ddc_fb,DDC_UNIT_XFORM+DDC_FIRST_PEL    

;/*
;**  We don't need to set the default code page for this process since
;**  PMWIN will set it!
;*/

;/*
;**  set RGB mode if requested
;*/

        test    flColorMode.lo,RDC_RGBMODE
        jz      dont_set_RGB_mode
        or      [di].ddc_fbClrTbl,DDC_RGB_MODE
        or      [di].ddc_ca.ca_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [di].ddc_pa.pa_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [di].ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [di].ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [di].ddc_ma.ma_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
dont_set_RGB_mode:

        ddc?    di,<SURFACE,LEVELS>
        jmp     enable_exit_zero
cEnd    <nogen>

sEnd    Code

sBegin  Ring3Code
        assumes cs,Ring3Code

errmsgfile      db "OSO001.MSG",0               ;** system error message file

;/*
;**  The following parameters are the parameters passed to VioSetMode
;**  to enter back into text mode.  For fatal exit message.
;*/

vio_mode_data_text      label   byte

        dw      6                               ;** 6 bytes of data (1+1+2+2)
        .errnz  viomi_cb

        db      VGMT_OTHER                      ;** color monitor
        .errnz  viomi_fbType-viomi_cb-2

        db      4                               ;** 16 color
        .errnz  viomi_color-viomi_fbType-1

        dw      80
        .errnz  viomi_col-viomi_color-1

        dw      24
        .errnz  viomi_row-viomi_col-2


;/***************************************************************************
;*
;* FUNCTION NAME = ring3_CriticalError
;*
;* DESCRIPTION   =  Called when the driver cannot recover and needs to display a 
;*                  message to the user convey some information.
;*
;* INPUT         =  AX = Message number to display 
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  Does not return!
;* RETURN-ERROR  =  Does not return! 
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   ring3_CriticalError,<PUBLIC,FAR,NODATA,NONWIN>
        localV  szMsg,512
        localD  cbMsg
cBegin


        farPtr  MyNull,0,<0>
        lea     di,szMsg
        farPtr  MypszMsg,ss,di
        farPtr  Myperrmsgfile,cs,<Ring3CodeOFFSET errmsgfile>
        lea     si,cbMsg
        farPtr  MypcbMsg,ss,si
        cCall   DosGetMessage,<MyNull,0,MypszMsg,512,ax,Myperrmsgfile,MypcbMsg>

        farPtr  pviomt,cs,<Ring3CodeOFFSET vio_mode_data_text>
        cCall   VioSetMode,<pviomt,0>

        cCall   VioSetCurPos,<5,0,0>

        farPtr  pszMsg,ss,di
        cCall   VioWrtTTY,<pszMsg,word ptr cbMsg,0>

        jmp     $                       ;** hang the system

cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = ring3_VioGetCP
;*
;* DESCRIPTION   = Gets a Code Page
;*                 Registers Destroyed:
;*                       DS,ES
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = CodePage 
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   ring3_VioGetCP,<PUBLIC,FAR,NODATA,NONWIN>
        localW  idCodePage
cBegin
        lea     ax,idCodePage
        farPtr  pidCodePage,ss,ax
        cCall   VioGetCP,<0,pidCodePage,0>
        mov     ax,idCodePage
cEnd


sEnd    Ring3Code

        end
