;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        PAGE    60,132
        TITLE   CGABUFUP.ASM -- CGA Buffer Update Routine

;/*****************************************************************************
;*
;* SOURCE FILE NAME = CGABUFUP.ASM
;*
;* DESCRIPTIVE NAME = CGA Buffer Update Routine 
;*
;*
;* VERSION      V2.0
;*
;* DATE         
;*
;* DESCRIPTION  Video Device Handler BufferUpdate routine 
;*
;* FUNCTIONS    BUFFERUPDATE, SetupPhysBuf
;*
;* LINKAGE:   Far Call from Base Video Subsystem (BVSCALLS.DLL) 
;*                                                    
;* INPUT:       STACK FRAME on entry                 
;*                                                    
;* SS:SP  --->  bvsip                            dw BVS IP offset   
;*              bvscs                            dw BVS CS selector   
;*              parmn                            dw Function number (256)  
;*              parmnm1                          dw Parameter block offset  
;*              parmnm2                          dw Parameter block selector 
;*              parmnm3                          dw Environment buffer offset 
;*              parmnm4                          dw Environment buffer selector 
;*                                                    
;*                                                    
;* PARAMETER BLOCK FORMAT:                            
;*                                                    
;*   SIZE   DESCRIPTION                               
;*   ----   -----------                               
;*                                                    
;*   WORD   ParmLength (length of structure - 28 bytes)   
;*   WORD   Flags                                     
;*            Bit 0 = 0, do not update physical display buffer  
;*            Bit 0 = 1, update physical display buffer if possible 
;*            Bit 1 = 0, logical display buffer update not required 
;*            Bit 1 = 1, update logical display buffer   
;*            Bit 2 = 0, use attribute as is        
;*            Bit 2 = 1, convert attribute to or from CGA format 
;*            Bit 3 - 15 are reserved and must be OFF   
;*                                                    
;*          NOTE:  If bit 0 and 1 are both ON then the LVB will  
;*                 be written first before the PVB is updated.  
;*                 This will ensure that video devices with  
;*                 slower VRAM will benefit from this algorithm. 
;*                                                    
;*                 The caller of BufferUpdate routine (BVS) must 
;*                 serialize access to this routine to insure  
;*                 that the LVB and the PVB will not get out of sync. 
;*                                                    
;*   DWORD  AppDataAddr (address of application data)   
;*   DWORD  AppCellAddr (address of character, attribute, or cell) 
;*   WORD   Index (BufferUpdate sub-function to be performed)  
;*            0 = Read cell types                    
;*                  Bit 0 = 0, single cell character   
;*                             (occupies one cell on the screen) 
;*                  Bit 0 = 1, double cell character   
;*                             (occupies two cells on the screen) 
;*                  Bit 1 = 0, leading (or only) cell   
;*                  Bit 1 = 1, trailing cell        
;*                  Bit 2 - 15 are reserved and must be OFF  
;*            1 = Read characters from (Row, Col)   
;*            2 = Read cells from (Row, Col)        
;*            3 = Scroll (Row, Col) through (Row2, Col2) Up  
;*            4 = Scroll (Row, Col) through (Row2, Col2) Down  
;*            5 = Scroll (Row, Col) through (Row2, Col2) Left  
;*            6 = Scroll (Row, Col) through (Row2, Col2) Right  
;*            7 = Write cells to (Row, Col)         
;*            8 = Write characters to (Row, Col)   
;*            9 = Write characters with constant attr to (Row, Col) 
;*           10 = Write repeat character to (Row, Col)   
;*           11 = Write repeat attribute to (Row, Col)   
;*           12 = Write repeat cell to (Row, Col)   
;*   WORD   Row  (Starting row)                      
;*   WORD   Col  (Starting column)                   
;*   WORD   Row2 (Secondary row)                     
;*   WORD   Col2 (Secondary column)                  
;*   WORD   RepeatFactor (# of character cells or rows/columns)  
;*   WORD   LogicalBufSel (logical buffer selector - LVB)  
;*                                                    
;*                                                    
;* ENVIRONMENT BUFFER FORMAT:                         
;*                                                    
;*   SIZE   DESCRIPTION                               
;*   ----   -----------                               
;*   WORD   ModeDataOff (offset to mode data structure)   
;*                                                    
;*                                                    
;* MODEDATA STRUCTURE FORMAT:                         
;*                                                    
;*   SIZE   DESCRIPTION                               
;*   ----   -----------                               
;*   WORD   Length (length of mode data structure - 34 bytes)  
;*   BYTE   ModeType                                  
;*            Bit 0 = 0, monochrome compatible      
;*            Bit 0 = 1, other                        
;*            Bit 1 = 0, text mode                   
;*            Bit 1 = 1, graphics mode               
;*            Bit 2 = 0, enable color burst         
;*            Bit 2 = 1, disable color burst        
;*            Bit 3 = 0, VGA compatible modes (0 - 13h)   
;*            Bit 3 = 1, native mode                 
;*            Bit 4 - 15 are reserved                
;*   BYTE   Color (number of colors as a power of 2)   
;*   WORD   TextCols (number of text columns in current mode) 
;*   WORD   TextRows (number of text rows in current mode) 
;*   WORD   HorizRes (horizontal pel resolution)  
;*   WORD   VertRes (vertical pel resolution)      
;*   BYTE   AttrFormat (attribute format)           
;*   BYTE   NAttributes (number of attributes in a character cell) 
;*  DWORD   BufferAddr (32-bit physical address of PVB)   
;*  DWORD   BufferLength (length of PVB in current mode)  
;*  DWORD   FullBufSize (size of buffer required for screen save) 
;*  DWORD   PartBufSize (size of buffer for popup save)   
;*  DWORD   ExtDataAddr (extended mode data structure address)  
;*                                                    
;* EXIT-NORMAL: AX = 0                                
;*                                                    
;* EXIT-ERROR:  AX = error code, ERROR_VIO_COL      
;*                                                ERROR_VIO_INVALID_LENGTH  
;*                                                ERROR_VIO_INVALID_PARMS  
;*                                                ERRPR_VIO_MODE    
;*                                                ERROR_VIO_ROW    
;*                                                ERROR_VIO_INTERNAL_RESOURCE  
;*                                                    
;* EFFECTS:     All other registers are preserved   
;*                                                    
;* INTERNAL REFERENCES: None                          
;*                                                    
;* EXTERNAL REFERENCES: ReadCellTypes             in CGAREAD.ASM  
;*                      ReadCharStr               in CGAREAD.ASM  
;*                      ReadCellStr               in CGAREAD.ASM  
;*                      ScrollUp                  in CGASCROL.ASM  
;*                      ScrollDown                in CGASCROL.ASM  
;*                      ScrollLeft                in CGASCROL.ASM  
;*                      ScrollRight               in CGASCROL.ASM  
;*                      WriteCellStr              in CGAWRITE.ASM  
;*                      WriteCharStr              in CGAWRITE.ASM  
;*                      WriteCharStrAttr         in CGAWRITE.ASM  
;*                      WriteNChar                in CGAWRITE.ASM  
;*                      WriteNAttr                in CGAWRITE.ASM  
;*                      WriteNCell                in CGAWRITE.ASM  
;*                                                    
;* NOTES        Ring 2 conforming code, executable in either 
;*              privilege level 2 or 3 in protect mode.      
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES  NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVIY =
;*   DATE      FLAG       APAR    CHANGE DESCRIPTION
;*   --------  ---------- -----   --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx xxxxx   xxxxxxx
;****************************************************************************/


        .286p                                     ; 286 protect mode instructions

        .xlist
        INCLUDE struc.inc                         ; Structure macro
        INCLUDE error2.inc                        ; Subsystem error equates
        INCLUDE vdhstruc.inc                      ; Buffer update data structures
        INCLUDE vdhequ.inc                        ; Buffer update equates
        .list

INSTSEG SEGMENT PARA PUBLIC 'DATA'

;/*
;**   Per process instance data
;*/

        PVBPhysAddrLo   dw                       0 ; Physical address of PVB
        PVBPhysAddrHi   dw                       0 ; 
        PVBSizeLo       dw                       0 ; PVB buffer size
        PVBSizeHi       dw                       0 ; 
        PVBOffset       dw                       0 ; PVB Offset
        PVBSelector     dw                       0 ; PVB Selector

INSTSEG ENDS

        PUBLIC  PVBPhysAddrLo
        PUBLIC  PVBPhysAddrHi
        PUBLIC  PVBSizeLo
        PUBLIC  PVBSizeHi
        PUBLIC  PVBSelector

        EXTRN   ReadCellTypes                     : NEAR ; 
        EXTRN   ReadCharStr                       : NEAR ; VioReadCharStr
        EXTRN   ReadCellStr                       : NEAR ; VioReadCellStr
        EXTRN   ScrollUp                          : NEAR ; VioScrollUp
        EXTRN   ScrollDown                        : NEAR ; VioScrollDn
        EXTRN   ScrollLeft                        : NEAR ; VioScrollLt
        EXTRN   ScrollRight                       : NEAR ; VioScrollRt
        EXTRN   WriteCellStr                      : NEAR ; VioWriteCellStr
        EXTRN   WriteCharStr                      : NEAR ; VioWriteCharStr
        EXTRN   WriteCharStrAttr : NEAR ; VioWriteCharStrAttr
        EXTRN   WriteNChar                        : NEAR ; VioWriteNChar
        EXTRN   WriteNAttr                        : NEAR ; VioWriteNAttr
        EXTRN   WriteNCell                        : NEAR ; VioWriteNCell

        EXTRN   _PhysToUVirt                      : FAR ; Allocate PVB selector
        EXTRN   _FreePhysToUVirt : FAR            ; Deallocate PVB selector

        PUBLIC  BUFFERUPDATE
        PUBLIC  DispTbl

R2CSEG  SEGMENT WORD    PUBLIC 'CODE'
        ASSUME  CS:R2CSEG,DS:NOTHING,ES:NOTHING

DispTbl DW      OFFSET R2CSEG:ReadCellTypes      ; 
        DW      OFFSET R2CSEG:ReadCharStr        ; Read characters
        DW      OFFSET R2CSEG:ReadCellStr        ; Read character/attribute 's
        DW      OFFSET R2CSEG:ScrollUp           ; Scroll window up
        DW      OFFSET R2CSEG:ScrollDown         ; Scroll window down
        DW      OFFSET R2CSEG:ScrollLeft         ; Scroll window left
        DW      OFFSET R2CSEG:ScrollRight        ; Scroll window right
        DW      OFFSET R2CSEG:WriteCellStr       ; Write character/attribute 's
        DW      OFFSET R2CSEG:WriteCharStr       ; Write characters
        DW      OFFSET R2CSEG:WriteCharStrAttr   ; Write characters with attr
        DW      OFFSET R2CSEG:WriteNChar         ; Write character N times
        DW      OFFSET R2CSEG:WriteNAttr         ; Write attribute N times
        DW      OFFSET R2CSEG:WriteNCell         ; Write cell N times

;/****************************************************************************
;*
;* FUNCTION NAME = BUFFERUPDATE
;*
;* DESCRIPTION   = This mainline routine checks all high level errors before  
;*                 control is transfer to the worker routine.
;*                 On entry to each worker routine, the following registers
;*                 are setup:
;*
;* INPUT         = DS:SI -> Parameter block buffer
;*                 ES:DI -> Mode data structure in the environment buffer
;*                 SS:BP -> Parameter stack frame
;*
;*                 All registers are preserved
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* PSEUDOCODE    =
;*
;*    Begin BufferUpdate
;*        Preset return code to ERROR_VIO_MODE
;*
;*               Preset return code to ERROR_VIO_INVALID_LENGTH
;*               If correct parameter length
;*                   Preset return code to ERROR_VIO_INVALID_PARMS
;*                   If valid reserved flags              AND
;*                   If valid video buffer flags AND
;*                   If valid function number             AND
;*                   If valid index number
;*                       Call Read/Write/Scroll routines
;*                   Endif
;*               Endif
;*           Endif
;*       End BufferUpdate
;*
;****************************************************************************/

BUFFERUPDATE    PROC    FAR

        push    0                                 ; Allocate storage for: PVB_Sel
        push    0                                 ;   Sel_Type
        sub     sp, Retrace-TopRow                ;   Scroll parms
        push    bp                                ; Save caller's BP
        mov     bp, sp                            ; Establish parameter addressability
        pusha                                     ; Save all registers
        push    ds                                ; 
        push    es                                ; 
        les     di, [bp].EnvBufParm               ; ES:DI -> environment buffer
        add     di, es:[di].ModeDataOff           ; ES:DI -> mode data structure
        mov     ax, ERROR_VIO_MODE                ; Preset invalid mode error
        test    es:[di].ModeType, GRAPHICS_MODE
        .if     <z>                               ; Text mode?
            lds     si, [bp].ParmBuf              ; DS:SI -> parameter buffer
            mov     ax, ERROR_VIO_INVALID_LENGTH  ; Preset error code
            .if     <[si].ParmLength e <size VDHPARM>> ; Invalid parm length?
                mov     ax, ERROR_VIO_INVALID_PARMS ; Preset error code
                test    [si].Flags, RESERVED_FLAGS ; 
                .if     <z>                            AND ; Valid reserved flags?
                test    [si].Flags, PVB_SEL_BIT + LVB_SEL_BIT
                .if     <nz>                           AND ; Either bit is ON?
                .if     <[bp].FuncNumHi e 0>         AND ; Correct function #?
                .if     <[bp].FuncNumLo e FUNC_NUM> AND ; 
                .if     <[si].FuncIndex be MAX_INDEX> ; Invalid index?
                    sub     ax, ax                 ; Clear return code
                    test    [si].Flags, PVB_SEL_BIT ; 
                    .if     <nz>                   ; Asked for PVB update?
                        call                     SetupPhysBuf  ; Go get PVB as needed
                    .endif                          ; 
                    .if     <zero ax>              ; No error?
                        cld                         ; 
                        mov                      bx, [si].FuncIndex ; 
                        shl                      bx, 1   ; Word align jump table
                        call                     cs:DispTbl[bx]  ; Dispatch to handler
                    .endif                          ; 
                .endif                              ; 
            .endif                                  ; 
        .endif                                      ; 
        mov     [bp-2], ax                          ; 
        pop     es                                  ; 
        pop     ds                                  ; 
        popa                                        ; 
        pop     bp                                  ; 
        add     sp, PVB_Sel                         ; Deallocate local storage
        ret     12                                  ; 

BUFFERUPDATE    ENDP

;/****************************************************************************
;*
;* FUNCTION NAME = SetupPhysBuf
;*
;* DESCRIPTION   = 
;*
;* INPUT         = AX = 0                                    
;*                 DS:SI -> parameter block
;*                 ES:DI -> environment buffer (mode data)
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 0                            
;* RETURN-ERROR  = AX = ERROR_VIO_INTERNAL_RESOURCE  
;* EFFECTS       = AX, BX, CX, DX
;*
;****************************************************************************/

        PUBLIC  SetupPhysBuf
SetupPhysBuf    PROC    NEAR

        mov     bx, INSTSEG                       ; 
        mov     ds, bx                            ; Setup per process data area

;/*
;**   If PVBSelector in NULL, indicating that the current process does 
;**   not have a PVB selector allocated then _PhysToUVirt is called 
;**   to allocate one.  If there is a PVB selector then the current 
;**   PVB size along with its physical address will be checked against 
;**   those contained in the environment buffer to see if anything has 
;**   changed due to a prior set mode.  If any of these fields changed 
;**   then the current PVB selector will be deallocated and a new one 
;**   will be allocated based on it new size and/or physical address. 
;*/

        mov     bx, es:[di].BufferaddrLo           ; Get the physical address and
        mov     dx, es:[di].BufferAddrHi           ;   PVB size of the current
        mov     si, es:[di].BufferLenLo            ; 
        mov     cx, ds:PVBSelector                 ; 
        verw    cx                                 ; 
        .if     <nz>                     OR        ; Write access?
        .if     <ds:PVBPhysAddrLo ne bx> OR        ; Anything different due
        .if     <ds:PVBPhysAddrHi ne dx> OR        ;   to mode change?
        .if     <ds:PVBSizeLo ne si>               ; 
            mov     ds:PVBPhysAddrLo, bx           ; Keep them up to date
            mov     ds:PVBPhysAddrHi, dx           ; 
            mov     ds:PVBSizeLo, si               ; 
            push    si                             ; Setup paramters for
            push    ds                             ;   PhysToUVirt call
            push    OFFSET PVBOffset               ;   ('C' routine)
            push    dx                             ; 
            push    bx                             ; 
            .if     <ncxz>                         ; PVB selector already exists?
                push    cx                         ; Deallocate it 1st
                call    _FreePhysToUVirt           ; 
                add     sp, 2                      ; Balance stack
            .endif                                 ; 
            call    _PhysToUVirt                   ; Allocate new PVB selector
            add     sp, 10                         ; Balance
            les     di, [bp].EnvBufParm            ; Re-setup mode data address
            add     di, es:[di].ModeDataOff        ;   from the environment block
            mov     cx, ds:PVBSelector             ; Setup PVB selector
        .endif                                     ; 
        .if     <zero ax>                          ; No error encountered?
            mov     [bp].PVB_Sel, cx               ; Put PVB selector on stack
            lds     si, [bp].ParmBuf               ; Re-setup parameter block addr
        .else                                      ; Error encountered!
            mov     ds:PVBSizelo, 0                ; Clear the necessary per
            mov     ds:PVBSelector, 0              ;   process fields
            mov     ax, ERROR_VIO_INTERNAL_RESOURCE
        .endif                                     ; 
        ret

SetupPhysBuf    ENDP

R2CSEG  ENDS
        END
