;*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.;
;*****************************************************************************/
;/*****************************************************************************
;*
;* SOURCE FILE NAME = ENABLE.ASM
;*
;* DESCRIPTIVE NAME = Device Context Enabling Functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         09/01/90
;*
;* 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   OS2_PM_DRV_ENABLE
;*             fill_log_dev_blk
;*             fill_phys_dev_blk
;*             enable_ddc
;*             disable_ddc
;*             save_ddc_state
;*             restore_ddc_state
;*             reset_ddc_state
;*             ring3_CriticalError
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   01/12/88                     Walt Moore [waltm] The big rewrite.
;*   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.
;*   09/01/90                     Rewrite for 32 bit OS/2 -
;*                                ScottL @ Micrografx
;*   10/10/89                     John Colleran [johnc] 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/05/89              83744  Lee A. Newberg [leen] Preserves User bounds
;*                                around the restore.  PTR SM83744.
;*
;*****************************************************************************/

.386
        OPTION  OLDSTRUCTS
.MODEL FLAT
ASSUME  SS:FLAT, DS:FLAT, CS:FLAT, ES:FLAT

        .xlist
INCL_GRE_FONTS          equ     1
INCL_DEV                equ     1
INCL_DDIMISC            equ     1
INCL_DOSRESOURCES       equ     1
INCL_DOSFILEMGR         equ     1
INCL_DOSMISC            equ     1
INCL_DOSPROCESS         equ     1
INCL_DOSSEMAPHORES      equ     1
INCL_DOSNLS             equ     1
INCL_SUB                equ     1
        include pmgre.inc
DINCL_VIO               equ     1
DINCL_BITMAP            equ     1
DINCL_ENABLE            equ     1
        include driver.inc
        include protos.inc
        include extern.inc
        include assert.mac
        .list

;/*
;** Equates
;*/

        hddcNull        equ     0
;/*
;** Global Data
;*/

.DATA
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.
;*/

ALIGN 4
vio_mode_data_text      label   byte

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

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

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

        dw      80
        .errnz  VIOMODEINFO.viomi_col-VIOMODEINFO.viomi_color-1

        dw      24
        .errnz  VIOMODEINFO.viomi_row-VIOMODEINFO.viomi_col-2

;/*
;** 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.
;*/

ALIGN 4
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        
        dd      enable_exit_zero        
        dd      enable_bad_subfunction  ;Install_simulation

ENABLE_TABLE_SIZE equ ($ - apfnEnable) / 4

;/*
;** CODE
;*/

.CODE

;_TUNE segment USE32 PUBLIC 'CODE'
page

;/***************************************************************************
;*
;* FUNCTION NAME = OS2_PM_DRV_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
;*
;* 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  40         ;# of locals allocted by Enable
RPL_RING3               equ   3         ;We want it to look like ring 3
ERROR_ALREADY_EXISTS    equ 183

;/*
;** NOTE - This procedure gets called from and runs at ring 3
;*/

ALIGN 4
OS2_PM_DRV_ENABLE       PROC SYSCALL USES EBX ESI EDI,
                        subfunction:DWORD,    ; 
                        u32_param1:DWORD,     ; 
                        u32_param2:DWORD      ; 

        LOCAL   workspace[ENABLE_LOCAL_SIZE]:BYTE

        DebugMsg <OS2_PM_DRV_ENABLE>


        cld

do_enable:
        INVOKE  enter_driver_sem
        mov     ebx,subfunction         ;The passed sub function is
        dec     ebx                     ;  1 based, need it as 0 based
        cmp     ebx,ENABLE_TABLE_SIZE   ;If subfunction is out of range,
        jae     enable_bad_subfunction  ;  return the ERROR_BAD_OPTION code

;/*
;** The sub function is valid,
;*/

        jmp     dword ptr apfnEnable[4*ebx] ;  so invoke the processor for it
ALIGN 4

;/*
;** An enable function handler JMPs back to enable_handle_exit to
;** handle exiting from Enable.  EBX contains the offset of the exit
;** handler routine.
;*/

public  enable_handle_exit
enable_handle_exit::
        jmp     ebx                     ; dispatch to exit handler
ALIGN 4

enable_no_memory:
        mov     eax,PMERR_INSUFFICIENT_MEMORY
        jmp     enable_log_error
ALIGN 4

enable_no_cs_alias:
public enable_dos_error
enable_dos_error::
        xchg    eax,ebx                 ;Save DOS error code in EBX
        mov     eax,PMERR_BASE_ERROR
        jmp     enable_log_error
ALIGN 4

public enable_bad_subfunction
enable_bad_subfunction::
        DebugMsg <enable_bad_subfunction>

        mov     eax,PMERR_DEV_FUNC_NOT_INSTALLED
        .errnz $-enable_log_error

        public  enable_log_error
enable_log_error::
        save_error_code
public enable_dont_log_error
enable_dont_log_error::
        mov     eax,-1                  ;-1 is Enable's error code
        jmp     enable_exit
ALIGN 4

public enable_exit_zero
enable_exit_zero::
        xor     eax,eax
        .errnz OFFSET $ - enable_exit

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

public enable_exit
enable_exit::
        INVOKE  leave_driver
enable_final:
        fw_zero <ecx>   ; macro: Firewalled, sets ecx=0
        ret
OS2_PM_DRV_ENABLE ENDP
;_TUNE ENDS

;_TUNE3 segment PARA FLAT PUBLIC '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
;**************************************************************************/

;/*
;**                  Pseudo-Code
;**
;** fill_log_dev_blk()
;** {
;**   if(first time here ever (not per process but EVER))
;**   {
;**       1. one_time_init()
;**             one_time_init does:
;**               1. Get screen pointer into selDeathToUse, and selScreenPtr
;**               2. Gets the codepage
;**               3. Inits the heap
;**               4. Sets up padBitmapFormats, and adDevCapsData
;**               5. Loads the font resources (sets ddc_ca.ca_fs)
;**               6. Sets up the default pick window.
;**               7. Tries to setup drqVideo with the VDD (sets fbOffScreen)
;**       2. Save a copy of the original passed in dispatch table into
;**          apfnDefDispatch.
;**   }
;**  Load the font resources for each process.
;**   Inform the graphics engine that we only want one physical device, and
;**       that all DCs are to share it.
;**   Fill in the dispatch table (if non-Null).
;** }
;*/

OPTION PROLOGUE:None
OPTION EPILOGUE:None

ALIGN 4
fill_log_dev_blk PROC SYSCALL,
        subfunction:DWORD,
        pFun1Parm:DWORD,
        pFun1Ret:DWORD

        DebugMsg <fill_log_dev_blk>
        xor     ecx,ecx
        xchg    cl,fEnabled
        jecxz   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.
;**
;** one_time_init does:
;** 1. Get screen pointer into selDeathToUse, and selScreenPtr
;** 2. Gets the codepage
;** 3. Inits the heap
;** 4. Sets up padBitmapFormats, and adDevCapsData
;** 5. Loads the font resources (sets ddc_ca.ca_fs)
;** 6. Sets up the default pick window.
;** 7. Tries to setup drqVideo with the VDD (sets fbOffScreen)
;*/
        INVOKE  one_time_init
        or      eax,eax
        lea     ebx,enable_log_error
        jnz     fill_log_exit_relay     ;Error occured, EAX = error code


;/*
;** Here we are saving a copy of the original passed in dispatch table into
;** apfnDefDispatch. 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.
;** [esi].fun1_papfn is pDispatchTable in the doc
;*/

        mov     esi,pFun1Ret

;/*
;** ESI = engine passed dispatch table
;*/

        mov     esi,[esi].fun1_ret.fun1_papfn

;/*
;** EDI = where to put our saved copy of passed in dispatch
;*/

        lea     edi,apfnDefDispatch
        mov     ecx,DEF_DISPATCH_TBL_SIZE

;/*
;** apfnDefDispatch is initialized with the offset into the default table
;** of the functions whose addresses we want.  Fetch the function address
;** from the passed in dispatch table and store it in our default table.
;*/

save_default_loop:
        mov     ebx,[edi]               ; Get default table index
        mov     eax,[esi+ebx]           ; get default function address
        mov     [edi],eax               ; and stick it in apfnDefDispatch
        add     edi,4                   ; advance to next
        loop    save_default_loop

;/*
;** Allow the device specific DLL to aquire a copy of the original passed
;** in dispatch table into apfnDevDefDispatch.
;*/

        lea     edi,apfnDevDefDispatch

        mov     ecx,[edi]               ;Size is first DWORD
        jecxz   DevLoopDone             ;none to do
        add     edi,SIZEOF DWORD
SaveDevLoop:
        mov     ebx,[edi]               ; Get default table index
        mov     eax,[esi+ebx]           ; get default function address
        mov     [edi],eax               ; and stick it in apfnDevDefDispatch
        add     edi,SIZEOF DWORD        ; advance to next
        loop    SaveDevLoop
DevLoopDone:

alloc_per_task_data:
        cld
        lea     esi,cResource

        lodsd                           ;Get count of resources to load
        xchg    eax,ecx
        jecxz   resources_loaded
resource_load_loop:
        ASSUME  esi:PFONT_RES

;/*
;** DosGetResource loads the resource and returns a pointer
;** to it in fr_pp
;*/

        INVOKE  DosGetResource2,
                [esi].fr_hModule,
                [esi].fr_usType,
                [esi].fr_usId,
                [esi].fr_pp        ;pselTemp

        ASSUME  esi:NOTHING
        or      eax,eax
        lea     ebx,enable_log_error
        jnz     fill_log_exit_relay     ;Error occured, EAX = error code
        add     esi,sizeof FONT_RES
        loop    resource_load_loop

        jmp     resources_loaded
ALIGN 4
fill_log_exit_relay:
        jmp     fill_log_exit
ALIGN 4



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.
;*/

        mov     edi,pFun1Parm
        mov     ecx,[edi].fun1_parm.fun1_cpfn
        jecxz   edit_dispatch_done      ;Have done it before
        cmp     ecx,DEV_DISPATCH_TBL_SIZE
        jb      enable_have_minimum
        mov     ecx,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.
;*/

        mov     esi,pFun1Ret
        mov     edi,[esi].fun1_ret.fun1_pfb

        and     byte ptr [edi],not (MUSTHAVEPDEV + LDEVSINGLEDC)
        or      byte ptr [edi],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:
        mov     esi,[esi].fun1_ret.fun1_papfn   ;DS:SI = default table
        or      esi,esi
        jz      edit_dispatch_done      ;NULL pointer means not to fill it in
        mov     ebx,esi                 ;Save Pointer to GRE Table
        mov     ecx,DEV_DISPATCH_TBL_SIZE
        lea     edi,apfnOurDispatch
edit_dispatch_table:
        mov     eax,[edi]               ;Get our handler
        or      eax,eax                 ;If the segment of our handler
        jz      edit_dispatch_next      ;  is 0, use the default
        mov     [esi],eax               ;Inform engine of our handler
edit_dispatch_next:
        add     esi,SIZEOF DWORD        ;--> next destination and
        add     edi,SIZEOF DWORD        ;  and source
        loop    edit_dispatch_table

        mov     edi,ebx                 ;EDI -> GRE Table
        lea     esi,tblDevHooks

        mov     ecx,[esi]               ;First DWORD is count
        jecxz   DevEditDispatchEnd
        add     esi,SIZEOF DWORD
DevEditDispatchTable:
        MOV     EBX,[ESI]               ;Get Table Index
        MOV     EAX,[ESI+4]             ;Get pfn
        add     ESI,2*(SIZEOF DWORD)
        mov     [edi+ebx],EAX
DevEditDispatchNext:
        loop    DevEditDispatchTable
DevEditDispatchEnd:

edit_dispatch_done:
        lea     ebx,enable_exit_zero    ; no error
fill_log_exit:
        jmp     enable_handle_exit
ALIGN 4
fill_log_dev_blk ENDP
;_TUNE3 ENDS

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
;*
;* INPUT         = frame set up by Enable dispatch function
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = PDEV_MAGIC_COOKIE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
fill_phys_dev_blk PROC SYSCALL,
        subfunction:DWORD,
        u32_param1:DWORD,
        u32_param2:DWORD

        DebugMsg <fill_phys_dev_blk>
;/*
;** See if we've done this before.
;*/

        xor     ecx,ecx
        xchg    cl,fPhysEnabled
        cmp     ecx,0
        je      fill_phys_ok            ; Have been here before

;/*
;** 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.
;*/

        INVOKE  Vga32CallBack,               ; since all we need is any vio call.
                OFFSET ring3_VioGetConfig


;/*
;** Enable the device.
;** in \pmdisp\egafam\egavga\egainit.asm
;*/

        INVOKE  physical_enable,INIT_VRAM,0
        or      eax,eax                 ;Did enable succeed?
        jz      fill_phys_enabled       ;  Yes, can continue
                                        ;  No, report error if FW
        rip     text,<The driver failed to initialize itself>
        jmp     enable_dos_error    ;    and return Vio error code
ALIGN 4

        public  fill_phys_enabled
fill_phys_enabled::

;/*
;** 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

fill_phys_ok:
        mov     eax,PDEV_MAGIC_COOKIE


        jmp     enable_exit
ALIGN 4


fill_phys_dev_blk ENDP

page

;_TUNE segment PARA FLAT PUBLIC 'CODE'
;/***************************************************************************
;*
;* 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
;*
;* INPUT         = frame set up by Enable dispatch function
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = hDDC
;* RETURN-ERROR  = AX = -1
;*                 error logged
;**************************************************************************/

ALIGN 4
enable_ddc PROC SYSCALL USES EBX,
        subfunction:DWORD,
        pFun5Parm:DWORD,
        u32_param2:DWORD                ;Ignored for this function
LOCAL   ddcType:DWORD
LOCAL   prddc:DWORD
LOCAL   cbCodePageList  :DWORD
        .errnz  (sizeof ddcType + sizeof prddc + sizeof cbCodePageList) ge ENABLE_LOCAL_SIZE ;too many local variables?

        DebugMsg <enable_ddc>
        cld

        mov     prddc,0
ifdef FIREWALLS
        mov     ebx,pFun5Parm
        cmp     [ebx].fun5_parm.fun5_hState,PDEV_MAGIC_COOKIE
        je      enable_ddc_good_pdev
enable_ddc_bad_pdev:
        rip     text,<EnableDDC - Unknown physical device>
enable_ddc_good_pdev:
endif

        mov     edi,pFun5Parm           ;--> parameters to this function

;/*
;** 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     ebx,PMERR_INV_DC_TYPE
        mov     ecx,[edi].fun5_parm.fun5_type
        cmp     ecx,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
        mov     eax,1                   ;AX = 1
        shl     eax,cl                  ;Shift 1, giving a bitmask
        test    eax,(1 shl OD_MEMORY) or (1 shl OD_DIRECT) or (1 shl OD_INFO)
        jnz     @f
enable_ddc_error_relay:
        jmp     enable_ddc_error
ALIGN 4
.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.
;*/

        push    [edi].fun5_parm.fun5_hdc
        mov     ddcType,ecx             ;Save DC type

;/*
;** Allocate RDDC
;*/

        mov     eax,sizeof RDDC
        INVOKE  AllocMem                ; EAX = prddc
        mov     ebx,PMERR_INSUFFICIENT_MEMORY
        or      ecx,ecx
        jz      enable_ddc_error_pop2   ; error
        mov     prddc,eax

;/*
;** Allocate DDC
;*/

        INVOKE  alloc_ddc
        mov     ebx,PMERR_INSUFFICIENT_MEMORY   ; just in case
        or      ecx,ecx
        jz      enable_ddc_error_pop2   ; error

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

        mov     edi,prddc
        lea     esi,rddcInit

        mov     ecx,(sizeof RDDC)/4
        .errnz  (sizeof RDDC) and 3
        rep     movsd
        mov     [edi - sizeof RDDC].RDDC.rddc_npddc,eax

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

        mov     edi,eax                 ; DI = pDDC
        lea     esi,ddcInit

        mov     ecx,(sizeof DDC)/4
        .errnz  (sizeof DDC) and 3
        rep     movsd
        sub     edi,sizeof DDC          ;--> back to the start of the ddc
        pop     [edi].DDC.ddc_hdc       ;Set Engine's handle

        mov     eax,prddc
        mov     [edi].DDC.ddc_prddc,eax    ; link in the RDDC

        INVOKE  alloc_brush
        mov     ebx,PMERR_INSUFFICIENT_MEMORY   ; just in case
        or      eax,eax
        jz      enable_ddc_error   ; error
        mov     [edi].DDC.ddc_pa.pa_abColor,eax

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

        INVOKE  DosQueryCp,                 ; was Win32QueryProcessCp
                sizeof DWORD,
                ADDR [edi].DDC.ddc_ca.ca_idCodePage,
                ADDR cbCodePageList         ; cbCodePageList


        cmp     [edi].DDC.ddc_ca.ca_idCodePage,DEFAULTVIOCODEPAGE
        jz      no_map_needed
        or      [edi].DDC.ddc_ca.ca_fs,CA_MUST_MAP

        DebugMsg <enable_ddc calling NGreQueryCodePageVector>

        INVOKE  Gre32Entry3,
                [edi].DDC.ddc_ca.ca_idCodePage,
                hddcNull,
                NGreQueryCodePageVector

        or      eax,eax
        jnz     @F
        jmp     enable_dont_log_error
ALIGN 4
@@:
        mov     [edi].DDC.ddc_ca.ca_paus,eax
no_map_needed:
        mov     eax,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 [edi].DDC.ddc_fb
        .errnz  DDC.ddc_fbAbove-DDC.ddc_fb-1
        and     dl,not DDC_VISIBLE
        or      dh,DDC_INFO_DC
        lea     ebx,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     [edi].DDC.ddc_crcsClip,0
        and     dx,not ((DDC_INFO_DC shl 8) or DDC_PRESENT or DDC_DEVICE)
        mov     ebx,INVALID_ADDRESS     ;Want ddc_npsd to be really bogus
enable_its_an_IC:
        mov     [edi].DDC.ddc_npsd,ebx  ;Set pointer to the surface
        mov     word ptr [edi].DDC.ddc_fb,dx
        .errnz  DDC.ddc_fbAbove-DDC.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:
;/*
;** edi points to the ddc
;*/


;/*
;** Fake out ResetLogColorTable so that it won't de-allocate
;** a non existing logical color table
;*/

        or      [edi].DDC.ddc_fbClrTbl,DDC_RGB_MODE
        INVOKE  ResetLogColorTable,
                edi

        mov     dx,HDDC_IDENT           ;Return DX:AX = hddc
        xchg    eax,edi
        ddc?    eax                     ;Let's make sure it's correct
        jmp     enable_exit
ALIGN 4

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

enable_ddc_error_pop2:
        add     esp,SIZE_DWORD          ;Clean 2 words from stack
enable_ddc_error:
        cmp     prddc,0     ; was prddc.sel
        jz      @F
        mov     eax,prddc
        push    ebx
        INVOKE  FreeMem
        pop     ebx
@@:
        mov     eax,ebx
        jmp     enable_log_error
ALIGN 4

enable_ddc ENDP
;_TUNE ENDS

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
;*
;* INPUT         =  frame set up by Enable dispatch function
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  DX:AX = 0
;* RETURN-ERROR  =  NONE
;*
;**************************************************************************/

ALIGN 4
disable_ddc PROC SYSCALL USES EBX ESI EDI,
        subfunction:DWORD,
        hddc:DWORD,
        u32_param2:DWORD                ;Ignored for this function

        DebugMsg <disable_ddc>

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     ebx,hddc
        cmp     [ebx].DDC.ddc_cLevel,1  ;Guaranteed by the Engine!
        je      @F
        rip     text,<DisableDDC - Disable Not Level 1!! ddc has saved levels>
@@:
        test    [ebx].DDC.ddc_fb,DDC_DEVICE
        jnz     @F
        cmp     [ebx].DDC.ddc_npsd,INVALID_ADDRESS
        je      @F
        rip     text,<DiableDDC - Bitmap selected into the ddc>
@@:
        fw_zero <esi>
endif

        mov     esi,hddc
        invoke  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.
;*/

        INVOKE  SetDriverInfo,
                INVALID_ADDRESS,
                [esi].DDC.ddc_hdc,
                0FFFF0000h,     ;INVALID_ADDRESS:DI_HDC = 0xffff0000
                [esi].DDC.ddc_hdc

        mov     eax,[esi].DDC.ddc_prddc
        INVOKE  FreeMem

        mov     eax,[esi].DDC.ddc_pa.pa_abColor
        INVOKE  free_brush


; Free DDC
        mov     eax,esi
        INVOKE  FreeMem
        jmp     enable_exit_zero

ALIGN 4
disable_ddc ENDP

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
;*
;* INPUT         = frame set up by Enable dispatch function
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 0
;* RETURN-ERROR  = PMERR_INSUFFICIENT_MEMORY
;*
;**************************************************************************/

ALIGN 4
save_ddc_state PROC SYSCALL USES EBX ESI EDI,
        subfunction:DWORD,
        hddc:DWORD,
        u32_param2:DWORD                ;Ignored for this function

        DebugMsg <save_ddc_state>
        ddc?    hddc,<SURFACE,LEVELS>

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

        INVOKE  alloc_ddc               ;Allocate ddc memory
        mov     ebx,PMERR_INSUFFICIENT_MEMORY   ;Error code if allocation failed
        or      ecx,ecx
        jz      save_ddc_error
        xchg    edi,eax                 ;DI = saved ddc handle
        mov     esi,hddc                ;SI = ddc to save

        mov     ecx,(sizeof DDC)/4
        .errnz  (sizeof DDC) and 3
        cld
        rep     movsd
        sub     esi,sizeof DDC          ;si -> this ddc
        sub     edi,sizeof DDC          ;di -> saved level

        xor     edx,edx
        mov     eax,sizeof RDDC
        INVOKE  AllocMem                ; EAX = new RDDC
        cmp     ecx,0
        jz      save_ddc_error_free_ddc_in_di   ; also set error code

        mov     ebx,edi                 ;save newly alloced saved DDC ptr
        mov     esi,[esi].DDC.ddc_prddc ;DS:SI is source RDDC
        mov     edi,eax
        mov     ecx,(sizeof RDDC)/4
        .errnz  (sizeof RDDC) and 3
        rep     movsd
        sub     edi,sizeof RDDC

        rddc?   edi
        mov     [edi].RDDC.rddc_npddc,ebx ; tighty up the references
        mov     [ebx].DDC.ddc_prddc,edi

        INVOKE  alloc_brush
        or      eax,eax
        jnz     ab_ok
        ;error
        mov     eax,edi
        INVOKE  FreeMem                 ;Free rddc
        mov     edi,ebx
        jmp     save_ddc_error_free_ddc_in_di
ab_ok:
        mov     [ebx].DDC.ddc_pa.pa_abColor,eax
        mov     edi,eax
        mov     esi,hddc
        mov     esi,[esi].DDC.ddc_pa.pa_abColor

        INVOKE  copy_brush

        mov     edi,ebx                 ; EDI new DDC
        mov     esi,hddc

;/*
;** 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     [edi].DDC.ddc_usId,SAVED_DDC_IDENT
        .erre   DDC_IDENT-SAVED_DDC_IDENT
        inc     [esi].DDC.ddc_cLevel
        mov     [esi].DDC.ddc_npddcPrev,edi
        mov     al,[esi].DDC.ddc_fb
        and     al,DDC_DEVICE or DDC_PRESENT
        cmp     al,DDC_PRESENT
        jne     save_ddc_bm_incremented
        mov     ebx,[esi].DDC.ddc_npsd
        INVOKE  save_bitmap
save_ddc_bm_incremented:

        INVOKE  save_lct
        ddc?    esi,<SURFACE,LEVELS>        ;Let's check up on ourselves
        jmp     enable_exit_zero            ;Indicate success
ALIGN 4


save_ddc_error_free_ddc_in_di:
        mov     esi,edi
        INVOKE  free_ddc                    ; frees DS:SI DDC
        mov     ebx,PMERR_INSUFFICIENT_MEMORY

save_ddc_error:
        mov     eax,ebx
        jmp     enable_log_error
ALIGN 4

save_ddc_state ENDP
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
;*
;**************************************************************************/

ALIGN 4
restore_ddc_state PROC SYSCALL USES EBX ESI EDI,
        subfunction:DWORD,
        hddc:DWORD,
        cLevel:DWORD

LOCAL cLevelReq:DWORD
LOCAL ptsOldOrg:POINTL
LOCAL rcsUserBound:RECTS

        .errnz  (sizeof cLevelReq + sizeof ptsOldOrg + sizeof rcsUserBound) ge ENABLE_LOCAL_SIZE ;too many local variables?

        DebugMsg <restore_ddc_state>

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     ebx,hddc
        mov     eax,cLevel               ;Make sure that the number is
        movsx   edx,ax
        cmp     eax,edx
        jne     restore_fw_bad_level
        or      eax,eax                  ;If level is negative, it is relative
        jg      restore_level_positive   ;  to the current level of the DDC
        add     eax,[ebx].DDC.ddc_cLevel
restore_level_positive:
        cmp     eax,[ebx].DDC.ddc_cLevel ;Within range?
        jae     restore_fw_bad_level     ;  No, error
        or      eax,eax                  ;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 <ebx>
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     esi,hddc                ;--> ddc
        mov     eax,cLevel              ;Map requested level to an ABS number
        mov     edx,eax
        or      eax,eax
        jz      enable_dont_log_error
        jg      @F
        neg     eax
        cmp     eax,[esi].DDC.ddc_cLevel
        jge     enable_dont_log_error
        neg     eax
@@:
        and     edx,[esi].DDC.ddc_cLevel        ;0 if level +, ddc_save_level if neg
        add     eax,edx                 ;AX = desired level
        cmp     eax,[esi].DDC.ddc_cLevel
        jb      level_is_ok
        jmp     restore_all_done        ;Restoring to current level
ALIGN 4
level_is_ok:

        mov     cLevelReq,eax           ;Save desired restore level

        mov     esi,[esi].DDC.ddc_prddc ; ESI = RDDC
        rddc?   esi

        mov     eax,[esi].RDDC.rddc_ptsOrg.ptl_y
        mov     ptsOldOrg.ptl_y,eax
        mov     eax,[esi].RDDC.rddc_ptsOrg.ptl_x
        mov     ptsOldOrg.ptl_x,eax

;/*
;** Save the current user bounds to stack
;*/

        add     esi,RDDC.rddc_rcsUsrBound ; SI = rcsUsrBound
        lea     edi,rcsUserBound
        mov     ecx,(sizeof rcsUserBound) / 4
        .errnz  (sizeof rcsUserBound) and 3
        assert  ND
        rep     movsd
        mov     esi,hddc                ;SI = DDC being restored
        ddc?    esi

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

        public  free_next_level
free_next_level::

        mov     edi,[esi].DDC.ddc_npddcPrev     ;DI--> previous ddc
        INVOKE  deselect_lct            ;Free any logical color table
        test    [edi].DDC.ddc_fb,DDC_DEVICE
        jnz     @F
        INVOKE  deselect_bitmap         ;Free any bitmap
        cmp     esi,hddc                ;Don't free orig ddc
        je      @F
        mov     eax,[esi].DDC.ddc_prddc
        INVOKE  FreeMem                 ;Free rddc
        mov     eax,[esi].DDC.ddc_pa.pa_abColor
        INVOKE  free_brush
        INVOKE  free_ddc                ;Free ddc at DS:SI
@@:
        mov     esi,edi                 ;SI = previous ddc

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

        mov     edi,hddc                ;DI = DDC being restored

;/*
;** 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    [edi].DDC.ddc_pa.pa_abColor     ;save brush being restored
        push    [edi].DDC.ddc_prddc     ;save RDDC being restored
        push    esi                     ;save DDC to free
        mov     edi,[edi].DDC.ddc_prddc ;ES:DI = RDDC to restore
        mov     esi,[esi].DDC.ddc_prddc ;ESI = RDDC source info
        mov     eax,esi
        mov     ecx,(sizeof RDDC)/4
        .errnz  sizeof RDDC and 3

        rep     movsd

ifdef FIREWALLS
        mov     esi,eax
        rddc?   esi
        mov     [esi].RDDC.rddc_usId,-1
endif
        INVOKE  FreeMem                 ;Frees memory at DX:AX

        mov     esi,[esp]               ;SI = DDC source info
        mov     esi,[esi].DDC.ddc_pa.pa_abColor
        mov     edi,hddc                ;DI = DDC being restored
        mov     edi,[edi].DDC.ddc_pa.pa_abColor
        INVOKE  copy_brush
        mov     eax,esi
        INVOKE  free_brush

;/*
;** Now copy DDC info
;*/
        mov     edi,hddc                ;DI = DDC being restored
        pop     esi                     ;SI = DDC source info
        mov     ecx,(sizeof DDC)/4
        .errnz  (sizeof DDC) and 3
        rep     movsd
        sub     esi,(sizeof 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     [esi].DDC.ddc_npsd,INVALID_ADDRESS
        mov     [esi].DDC.ddc_fb,0
endif
        INVOKE  free_ddc                ;Free ddc at DS:SI

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

        mov     esi,hddc                ;DS:SI = DDC (restored)
        ddc?    esi
        pop     [esi].DDC.ddc_prddc             ;restore RDDC pointer
        pop     [esi].DDC.ddc_pa.pa_abColor     ;restore brush pointer
        mov     edi,[esi].DDC.ddc_prddc ;ES:DI = RDDC (restored)
        rddc?   edi
        mov     [edi].RDDC.rddc_npddc,esi
        mov     eax,ptsOldOrg.ptl_x
        xchg    eax,[edi].RDDC.rddc_ptsOrg.ptl_x
        sub     eax,[edi].RDDC.rddc_ptsOrg.ptl_x
        jz      @F
        sub     [edi].RDDC.rddc_ptsCurPos.ptl_x,eax     
        sub     [esi].DDC.ddc_pa.pa_ptsOrg.ptl_x,eax
        or      [esi].DDC.ddc_pa.pa_ba.ba_fb,BA_REREALIZE
@@:
        mov     eax,ptsOldOrg.ptl_y
        xchg    eax,[edi].RDDC.rddc_ptsOrg.ptl_y
        sub     eax,[edi].RDDC.rddc_ptsOrg.ptl_y
        jz      @F
        sub     [edi].RDDC.rddc_ptsCurPos.ptl_y,eax     
        sub     [esi].DDC.ddc_pa.pa_ptsOrg.ptl_y,eax
        or      [esi].DDC.ddc_pa.pa_ba.ba_fb,BA_REREALIZE
@@:

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

        mov     ebx,esi                         ; save DDC ptr
        ddc?    esi
        rddc?   edi
        lea     edi,[edi].RDDC.rddc_rcsUsrBound
        lea     esi,rcsUserBound                ; SI = rcsUsrBound
        mov     ecx,(sizeof rcsUserBound) / 4
        .errnz  (sizeof rcsUserBound) and 3
        assert  ND

        rep     movsd

        mov     esi,ebx                         ; restore DDC ptr

restore_all_done:
        ddc?    esi,<SURFACE,LEVELS>
        jmp     enable_exit_zero        ;Indicate success
ALIGN 4

restore_ddc_state ENDP
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
;*
;**************************************************************************/

ALIGN 4
reset_ddc_state PROC SYSCALL USES EBX ESI EDI,
        subfunction:DWORD,
        hddc:DWORD,                     ; Our DDC cookie
        flColorMode:DWORD               ; Color reset flag

        DebugMsg <reset_ddc_state>
ifdef FIREWALLS
        ddc?    hddc,<SURFACE,LEVELS>

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

        cmp     word ptr flColorMode[2],0
        jnz     reset_bad_option
        test    word ptr flColorMode[0],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     ebx,hddc
        cmp     [ebx].DDC.ddc_cLevel,1  ; Guaranteed by the Engine!
        je      @F
        rip     text,<ResetDDC - ddc has saved levels>
@@:
        mov     al,[ebx].DDC.ddc_fb
        and     al,DDC_DEVICE or DDC_PRESENT
        cmp     al,DDC_PRESENT
        jne     @F
        rip     text,<ResetDDC - Bitmap selected into the ddc>
@@:
endif

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

        mov     esi,hddc                ; Get handle to the DDC
        test    [esi].DDC.ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jz      deselect_lct_done
        INVOKE  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.
;*/

        cld
        mov     ebx,RESET_DDC_BUNDLES
        mov     eax,ddcInit.ddc_iSysClr

        cmp     eax,[esi].DDC.ddc_iSysClr
        jne     bundles_are_dirty
        test    [esi].DDC.ddc_fbBelow,DDC_DIRTY_ATTRS
        jnz     bundles_are_dirty
        mov     ebx,RESET_DDC_POST_BUNDLES
bundles_are_dirty:
        push    [esi].DDC.ddc_pa.pa_abColor
        lea     edi,[esi][ebx]          ;edi = esi+ebx
        lea     esi,ddcInit[ebx]        ;esi = (OFFSET ddcInit)+ebx

        mov     ecx,sizeof DDC
        sub     ecx,ebx
        shr     ecx,1
        assert  NC
        .errnz  (sizeof DDC - RESET_DDC_BUNDLES) and 1
        .errnz  (sizeof DDC - RESET_DDC_POST_BUNDLES) and 1
        rep     movsw
        sub     edi,sizeof DDC          ; DI = DDC
        pop     [edi].DDC.ddc_pa.pa_abColor

        mov     edi,[edi].DDC.ddc_prddc ; ES:DI = RDDC
        rddc?   edi
        lea     esi,rddcInit

        add     esi,RESET_RDDC_START
        add     edi,RESET_RDDC_START
        mov     ecx,(sizeof RDDC - RESET_RDDC_START)/4
        .errnz  (sizeof RDDC - RESET_RDDC_START) and 3
        rep     movsd
        mov     edi,hddc                ; DI = DDC

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

        mov     esi,[edi].DDC.ddc_prddc
        rddc?   esi
        mov     eax,[esi].RDDC.rddc_ptsOrg.ptl_x
        mov     ebx,[esi].RDDC.rddc_ptsOrg.ptl_y
        mov     [esi].RDDC.rddc_ptsCurPos.ptl_x,eax
        mov     [esi].RDDC.rddc_ptsCurPos.ptl_y,ebx

;/*
;** 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     [edi].DDC.ddc_pa.pa_ptsOrg.ptl_x,eax
        mov     [edi].DDC.ddc_pa.pa_ptsOrg.ptl_y,ebx
        or      eax,eax
        jz      @F
        or      [edi].DDC.ddc_pa.pa_ba.ba_fb,BA_REREALIZE
@@:

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

        and     [edi].DDC.ddc_fb,DDC_PRESENT+DDC_DEVICE+DDC_CLIP_NOTIFY+DDC_VISIBLE
        or      [edi].DDC.ddc_fb,DDC_UNIT_XFORM+DDC_FIRST_PEL    ; we know this!

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



;/*
;** Fake out ResetLogColorTable so that it won't de-allocate
;** a non existing logical color table
;*/

        or      [edi].DDC.ddc_fbClrTbl,DDC_RGB_MODE
        INVOKE  ResetLogColorTable,
                edi


        test    word ptr flColorMode[0],RDC_RGBMODE
        jz      dont_set_RGB_mode
        or      [edi].DDC.ddc_fbClrTbl,DDC_RGB_MODE
        or      [edi].DDC.ddc_ca.ca_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [edi].DDC.ddc_pa.pa_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [edi].DDC.ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [edi].DDC.ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [edi].DDC.ddc_ma.ma_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE

dont_set_RGB_mode:

        ddc?    edi,<SURFACE,LEVELS>
        jmp     enable_exit_zero

ALIGN 4
reset_ddc_state ENDP


OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF

;/***************************************************************************
;*
;* 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!
;*
;**************************************************************************/

ALIGN 4
ring3_CriticalError PROC SYSCALL USES EBX
        LOCAL szMsg[512]:BYTE
        LOCAL cbMsg:DWORD
        LOCAL msgNum:DWORD

        INT 3       ;INT3
        jmp     $                       ;hang the system
ALIGN 4
ring3_CriticalError ENDP

        end
