;*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    XGAWRITE.ASM -- Common Buffer Write Routines for EGA, VGA, BGA
;/*****************************************************************************
;*
;* SOURCE FILE NAME = XGAWRITE.ASM
;*
;* DESCRIPTIVE NAME = Common Buffer Write Routines for EGA, VGA, BGA
;*
;*
;* VERSION      V2.0
;*
;* DATE
;*
;* DESCRIPTION  This module contains routines that run at ring 2:
;*              Common Buffer Write Routines for EGA, VGA, BGA
;*
;* FUNCTIONS    WriteCellStr, WriteCharStr, WriteCharStrAttr,
;*              WriteNChar, WriteNAttr, WriteNCell
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES   LocateBuffAddr  (in XGAREAD.ASM)
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVIY =
;*   DATE      FLAG        APAR    CHANGE DESCRIPTION
;*   --------  ----------  -----   --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx   xxxxxxx
;*   03/25/89  @P1         D132    TPL, DCR 132 changes
;*   01/29/91  MS00                TPL, Convert IFDEF to IF
;*   01/29/91  MS01                TPL, Rollover MS's runtime check
;*   01/29/91  MS01                for CGA speedup
;*   04/11/91              D1348   NAKADA, Enable DBCS support in Vio-Window
;*   09/14/94  @95837              WKB, pmwinp.inc -> pmwinx.inc
;****************************************************************************/


        .286c                           ; 286 protect mode instructions

        .xlist
        INCLUDE struc.inc               ; Structure macro
        INCLUDE error2.inc              ; Subsystem error equates
IFDEF D1348 ;needs viops_* for common format
        INCLUDE pmwinx.inc              ; @95837
        INCLUDE pmaviop.inc
ENDIF ;D1348
        INCLUDE vdhstruc.inc            ; Buffer update data structures
        INCLUDE vdhctl.inc              ; Conditional Assembly Control  ;MS01
        INCLUDE vdhequ.inc              ; Buffer update equates
        INCLUDE xgamac.inc                                              ;@P1
        .list

        EXTRN   SetBuffAddr:NEAR        ; Determine target/source buffer;@P1

IFDEF D1348 ;BufferUpdate with dbcs bits handling
        extrn   WriteCellStrWrld:near
        extrn   WriteCharStrWrld:near
        extrn   WriteCharStrAttrWrld:near
        extrn   WriteNCharWrld:near
        extrn   WriteNAttrWrld:near
        extrn   WriteNCellWrld:near
ENDIF ;D1348

IF VDHCGA AND (1 - CGA_ALWAYS_FAST)     ; IF VDHCGA AND NOT CGA_ALWAYS_FAST ;MS00


;/*
;** If CGA video memory accesses may need to wait for retrace,
;** these routines are necessary. (See MAKEFILE)
;*/

        extrn   CGA_REP_MOVSW:far                                       ;@P1
        extrn   CGA_REP_STOSW:far                                       ;@P1
        extrn   CGA_REP_MOVSB_INCSI_LOOP:far                            ;@P1
        extrn   CGA_REP_MOVSW_STOSW_LOOP:far                            ;@P1
        extrn   CGA_REP_INCDI_STOSB_LOOP:far                            ;@P1
        extrn   CGA_REP_STOSB_INCDI_LOOP:far                            ;@P1
        extrn   CGA_REP_LODSB_STOSW_LOOP:far                            ;@P1
        extrn   CGA_REP_MOVSB_INCDI_LOOP:far                            ;@P1
        extrn   CGA_REP_MOVSW_ADDSI2_LOOP:far                           ;@P1
ENDIF   ;VDHCGA                                                         ;MS00

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

;/****************************************************************************
;*
;* SUBROUTINE NAME:     WriteCellStr
;*
;* DESCRIPTIVE NAME:    Video device handler write cells
;*
;* FUNCTION:    Process write cells sub-function.
;*              The cells are written to the LVB and/or PVB
;*              starting at the specified row, column location.
;*              Line wrap occurs if the end of a line is reached.
;*              Write function is terminated if the end of PVB or
;*              LVB is reached.  The number of the char/attr cells
;*              written is returned in the RepeatFactor field of
;*              the paramter block.
;*
;* ENTRY POINT: WriteCellStr
;*   LINKAGE:   Near Call from BUFFERUPDATE routine
;*
;* INPUT:
;*
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)
;*
;* PARAMETER BLOCK FORMAT:
;*
;*   SIZE   DESCRIPTION
;*   ----   -----------
;*
;*   WORD   Parameter length
;*   WORD   Flags                     (target data buffer - LVB, PVB)
;*   DWORD  Application data address  (source data buffer)
;*   DWORD  Application data2 address (not used in this call)
;*   WORD   Index (7)
;*   WORD   Starting row              (target row)
;*   WORD   Starting column           (target column)
;*   WORD   Secondary row             (not used in this call)
;*   WORD   Secondary column          (not used in this call)
;*   WORD   RepeatFactor              (input and output length)
;*   WORD   LogicalBufSel
;*
;* OUTPUT:      LVB and/or PVB = new attributes
;*              RepeatFactor = sum of char/attr pairs written
;*
;* EXIT-NORMAL: AX = 0
;*
;* EXIT-ERROR:  AX = Error from LocateBuffAddr
;*
;* EFFECTS:     All
;*
;* INTERNAL REFERENCES: None
;*
;* EXTERNAL REFERENCES: LocateBuffAddr   (in VDHREAD.ASM)
;*
;****************************************************************************/

        PUBLIC  WriteCellStr
WriteCellStr    PROC    NEAR

        mov     bx, 1                       ; Move by buffer byte count
        call    SetBuffAddr                 ; On exit: BX = sel, AX = off;@P1
        .if     <nc>    near                ; Continue?
            lds     si, [si].AppDataAddr    ; Setup source address
            .if     <nonzero bx>            ; write to LVB requested    ;@P1
                mov     di,ax                                           ;@P1
IFDEF D1348 ;check if DBCS && common lvb.
                .if    <bit <[bp].flgDBCS> and anyDBCS> and
                .if    <[bp].j_funcindx eq WorldFmtIndx>
                    mov     es, bx          ; Setup destination selector
                    call    WriteCellStrWrld
                .else
ENDIF ;D1348
                    push    si                                          ;@P1
                    push    cx                                          ;@P1
                    shr     cx,1            ; convert bytes to words    ;@P1
                    mov     es, bx          ; Setup destination selector;@P1
                    rep     movsw           ; Fill destination buffer   ;@P1
                    pop     cx                                          ;@P1
                    pop     si                                          ;@P1
IFDEF D1348
                .endif
ENDIF ;D1348
            .endif                                                      ;@P1
            mov     bx, [bp].PVB_Sel        ; (bx) = PVB selector       ;@P1
            .if     <nonzero bx>            ; write to PVB requested    ;@P1
                mov     es,bx               ; Setup destination selector;@P1
                mov     di,[bp].PVBOff      ; (di) = PVB offset from LVB off
                mov     bx,[bp].RowLength                               ;@P1
                mov     dx,cx                                           ;@P1
                mov     cx,[bp].FirstRow                                ;@P1

                .if     <[bp].cellsize e WorldCellSize>                 ;@P1
                    cmp     cx,dx                                       ;@P1
                    jbe     wces20                                      ;@P1

                    mov     cx,dx                                       ;@P1
                    jmp     short wces20                                ;@P1

wces10:             add     di,[bp].PVBSkip                             ;@P1
                    mov     cx,dx                                       ;@P1
                    cmp     cx,bx                                       ;@P1
                    jbe     wces20                                      ;@P1

                    mov     cx,bx                                       ;@P1
wces20:             sub     dx,cx                                       ;@P1
                    shr     cx,2            ; bytes to cells (dword cells)
                    REP_MOVSW_ADDSI2_LOOP   ; Use this macro so CGA can share
                                            ; the same set of sources
                                            ; BUGBUG this may need to deal
                                            ; with the final attribute word
                    or      dx,dx                                       ;@P1
                    jnz     wces10                                      ;@P1
                .else                                                   ;@P1
                    cmp     cx,dx                                       ;@P1
                    jbe     wces40                                      ;@P1

                    mov     cx,dx                                       ;@P1
                    jmp     short wces40                                ;@P1

wces30:             add     di,[bp].PVBSkip                             ;@P1
                    mov     cx,dx                                       ;@P1
                    cmp     cx,bx                                       ;@P1
                    jbe     wces40                                      ;@P1

                    mov     cx,bx                                       ;@P1
wces40:             sub     dx,cx                                       ;@P1
                    shr     cx,1            ; bytes to cells (word cells)
                    REP_MOVSW               ; Use this macro so CGA can share
                                            ; the same set of sources
                    or      dx,dx                                       ;@P1
                    jnz     wces30                                      ;@P1
                .endif                                                  ;@P1
            .endif                                                      ;@P1
            sub     ax, ax                  ; Clear return code
        .endif                              ; 
        ret                                 ; 

WriteCellStr    ENDP

;/****************************************************************************
;*
;* SUBROUTINE NAME:     WriteCharStr
;*
;* DESCRIPTIVE NAME:    Video device handler write characters
;*
;* FUNCTION:    Process write characters sub-function.
;*              The characters are read from a user supplied
;*              buffer which to be placed starting a the
;*              specified row, column location within the PVB
;*              and/or LVB.  Line wrap occurs if the end of a
;*              line is reached.  Write function is terminated
;*              if the end of PVB or LVB is reached.  The number
;*              of characters written is returned in the
;*              RepeatFacter field of the parameter block.
;*
;* ENTRY POINT: WriteCharStr
;*   LINKAGE:   Near Call from BUFFERUPDATE routine
;*
;* INPUT:
;*
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)
;*
;* PARAMETER BLOCK FORMAT:
;*
;*   SIZE   DESCRIPTION
;*   ----   -----------
;*
;*   WORD   Parameter length
;*   WORD   Flags                     (target data buffer - LVB, PVB)
;*   DWORD  Application data address  (source data buffer)
;*   DWORD  Application data2 address (not used in this call)
;*   WORD   Index (8)
;*   WORD   Starting row              (target row)
;*   WORD   Starting column           (target column)
;*   WORD   Secondary row             (not used in this call)
;*   WORD   Secondary column          (not used in this call)
;*   WORD   RepeatFactor              (input and output length)
;*   WORD   LogicalBufSel
;*
;* OUTPUT:      PVB and/or LVB = new characters
;*              RepeatFactor = number of characters written
;*
;* EXIT-NORMAL: AX = 0
;*
;* EXIT-ERROR:  AX = Error from LocateBuffAddr
;*
;* EFFECTS:     AX, BX, DI, SI, DS, ES
;*
;* INTERNAL REFERENCES: None
;*
;* EXTERNAL REFERENCES: LocateBuffAddr  (in XGAREAD.ASM)
;*
;****************************************************************************/

        PUBLIC  WriteCharStr
WriteCharStr    PROC    NEAR

        sub     bx, bx                      ; Move done in terms of cells
        call    SetBuffAddr                 ; On exit: BX = sel, AX = off;@P1
        .if     <nc>                        ; Continue?
            lds     si, [si].AppDataAddr    ; Setup source address       ;@P1
            .if     <nonzero bx>            ; Write through request?     ;@P1
                mov     di, ax              ; Setup destination offset   ;@P1
                mov     es, bx              ; Setup destination selector ;@P1
IFDEF D1348 ;check if DBCS && common lvb.
                .if    <bit <[bp].flgDBCS> and anyDBCS> and
                .if    <[bp].j_funcindx eq WorldFmtIndx>
                    call    WriteCharStrWrld
                .else
ENDIF ;D1348
                    mov     bx,[bp].cellsize                             ;@P1
                    dec     bx                                           ;@P1
                    push    cx              ; Save repeat factor, source ;@P1
                    push    si              ;   and destination offset   ;@P1
                    push    di              ;                            ;@P1
                    .repeat                 ;                            ;@P1
                        movsb               ; Fill destination buffer    ;@P1
                        add     di,bx       ; Skip pass attribute        ;@P1
                    .loop                   ;                            ;@P1
                    pop     di              ; ES:DI -> LVB write start   ;@P1
                    pop     si              ; DS:SI -> AppDataAddr       ;@P1
                    pop     cx              ;                            ;@P1
IFDEF D1348
                .endif
ENDIF ;D1348
            .endif                          ;                            ;@P1
            mov     bx, [bp].PVB_Sel        ; (bx) = PVB selector        ;@P1
            .if     <nonzero bx>            ; write to PVB requested     ;@P1
                mov     es, bx              ; Setup destination selector ;@P1
                mov     di, [bp].PVBOff     ; (di) = PVB offset from LVB off
                mov     bx, [bp].RowLength  ; (bx) = line width in cells ;@P1
                mov     dx,cx                                            ;@P1
                mov     cx,[bp].FirstRow                                 ;@P1
                mov     ax,[bp].PVBSkip                                  ;@P1
                cmp     cx,dx                                            ;@P1
                jbe     wchs20                                           ;@P1

                mov     cx,dx                                            ;@P1
                jmp     short wchs20                                     ;@P1

wchs10:         add     di,ax                                            ;@P1
                mov     cx,dx                                            ;@P1
                cmp     cx,bx                                            ;@P1
                jbe     wchs20                                           ;@P1

                mov     cx,bx                                            ;@P1
wchs20:         sub     dx,cx                                            ;@P1
                REP_MOVSB_INCDI_LOOP        ; Use this macro so CGA can share
                                            ; the same set of sources    ;@P1
                                            ; BUGBUG this may need to deal
                                            ; with the final attribute word
                or      dx,dx                                            ;@P1
                jnz     wchs10                                           ;@P1
            .endif                                                       ;@P1
            xor     ax, ax                  ; Clear return code
        .endif                              ; 
        ret                                 ; 

WriteCharStr    ENDP

;/****************************************************************************
;*
;* SUBROUTINE NAME:     WriteCharStrAttr
;*
;* DESCRIPTIVE NAME:    Video device handler write characters
;*                      with a constant attribute
;*
;* FUNCTION:    Process write characters, attribute sub-function.
;*              The characters and attribute are read from user
;*              supplied buffers which will be placed starting
;*              at the specified row, column location within the
;*              PVB and/or LVB.  Line wrap occurs if the end of
;*              a line is reached.  Write function is terminated
;*              if the end of PVB or LVB is reached.  The number
;*              of char/attr pairs written is returned in the
;*              RepeatFacter field of the parameter block.
;*
;* ENTRY POINT: WriteCharStrAttr
;*   LINKAGE:   Near Call from BUFFERUPDATE routine
;*
;* INPUT:
;*
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)
;*
;* PARAMETER BLOCK FORMAT:
;*
;*   SIZE   DESCRIPTION
;*   ----   -----------
;*
;*   WORD   Parameter length
;*   WORD   Flags                     (target data buffer - LVB, PVB)
;*   DWORD  Application data address  (source data buffer)
;*   DWORD  Application data2 address (source attribue buffer)
;*   WORD   Index (9)
;*   WORD   Starting row              (target row)
;*   WORD   Starting column           (target column)
;*   WORD   Secondary row             (not used in this call)
;*   WORD   Secondary column          (not used in this call)
;*   WORD   RepeatFactor              (input and output length)
;*   WORD   LogicalBufSel
;*
;* OUTPUT:      PVB and/or LVB = new characters
;*              RepeatFactor = sum of char/attr pairs written
;*
;* EXIT-NORMAL: AX = 0
;*
;* EXIT-ERROR:  AX = Error from LocateBuffAddr
;*
;* EFFECTS:     AX, BX, DI, SI, DS, ES
;*
;* INTERNAL REFERENCES: None
;*
;* EXTERNAL REFERENCES: LocateBuffAddr  (in XGAREAD.ASM)
;*
;****************************************************************************/

        PUBLIC  WriteCharStrAttr
WriteCharStrAttr        PROC    NEAR

        sub     bx, bx                          ; Operation in terms of cells
        call    SetBuffAddr                     ; On exit: BX = sel, AX = off
        .if     <nc>    near                    ; Continue?
            mov     di, ax                      ; Setup destination offset
            lds     si, [si].AppCellAddr        ; Setup address to attribute
            lodsb                               ; Get attribute
            xchg    al, ah                      ; AH = attribute
            .if     <nonzero bx>                ; Write through request?
                mov     es, bx                  ; Setup destination selector
IFDEF D1348 ;check if DBCS && common lvb.
                .if    <bit <[bp].flgDBCS> and anyDBCS> and
                .if    <[bp].j_funcindx eq WorldFmtIndx>
                    xchg    ax,dx               ; dh = first attr byte
                    lodsw                       ; al = attr #2
                                                ; ah = attr #3(sys byte)
                    xchg    ax, dx              ; ah = attr #1
                                                ; dl = attr #2
                                                ; dh = attr #3(sys byte)
                    lds     si,[bp].ParmBuf     ; Setup parameter buffer addr
                    lds     si,[si].AppDataAddr ; Setup source address
                    call    WriteCharStrAttrWrld
                .else
ENDIF ;D1348
                    push    cx                      ; Save repeat factor and
                    .if     <[bp].cellsize e WorldCellSize>
                        xchg    ax, bx              ; bh = first attr byte
                        lodsw                       ; ax = last attr word
                        xchg    ax, bx              ; ah = first attr byte
                        lds     si, [bp].ParmBuf    ; Setup parameter buffer addr
                        lds     si, [si].AppDataAddr; Setup source address
                        .repeat                     ; 
                            lodsb                   ; AL = character
                            stosw                   ; Transfer first word of cell
                            xchg    ax, bx          ; ax = last attr word
                            stosw                   ; store the last attr word
                            xchg    ax, bx          ; ah = first attr byte
                        .loop                       ; 
                    .else
                        lds     si, [bp].ParmBuf    ; Setup parameter buffer addr
                        lds     si, [si].AppDataAddr; Setup source address
                        .repeat                     ; 
                            lodsb                   ; AL = character
                            stosw                   ; Transfer first word of cell
                        .loop                       ; 
                    .endif
                    pop     cx                      ; 
IFDEF D1348
                .endif
ENDIF ;D1348
            .endif                              ; 

            mov     bx, [bp].PVB_Sel            ; Get PVB selector from stack
            .if     <nonzero bx>                ; write to PVB requested
                mov     es,bx                   ; Setup destination selector
                mov     di,[bp].PVBOff          ; (di) = PVB offset from LVB off
                lds     si,[bp].ParmBuf         ; Setup parameter buffer addr
                lds     si,[si].AppDataAddr     ; Setup source address
                mov     bx,[bp].RowLength
                mov     dx,cx
                mov     cx,[bp].FirstRow
                cmp     cx,dx
                jbe     wcsa20

                mov     cx,dx
                jmp     short wcsa20

wcsa10:         add     di,[bp].PVBSkip
                mov     cx,dx
                cmp     cx,bx
                jbe     wcsa20

                mov     cx,bx
wcsa20:         sub     dx,cx
                REP_LODSB_STOSW_LOOP        ; Use this macro so CGA can share
                                            ; the same set of sources
                                            ; (al) = char , (ah) = attribute
                                            ; write the cell
                or      dx,dx
                jnz     wcsa10
            .endif
            sub     ax, ax                      ; Clear return code
        .endif                                  ; 
        ret                                     ; 

WriteCharStrAttr    ENDP

;/****************************************************************************
;*
;* SUBROUTINE NAME:     WriteNChar
;*
;* DESCRIPTIVE NAME:    Video device handler repeat characters
;*
;* FUNCTION:    Process write character sub-function.
;*              The characters are written to either PVB or LVB
;*              starting at the specified row, column location.
;*              Line wrap ocurrs if the end of a line is reached.
;*              Write function is terminated if the end of PVB or
;*              LVB is reached.  The number of characters written
;*              is returned in the RepeatFacter field of the
;*              parameter block.
;*
;* ENTRY POINT: WriteNChar
;*   LINKAGE:   Near Call from BUFFERUPDATE routine
;*
;* INPUT:
;*
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)
;*
;* PARAMETER BLOCK FORMAT:
;*
;*   SIZE   DESCRIPTION
;*   ----   -----------
;*
;*   WORD   Parameter length
;*   WORD   Flags                     (target data buffer - LVB, PVB)
;*   DWORD  Application data address  (source character buffer)
;*   DWORD  Application data2 address (not used in this call)
;*   WORD   Index (10)
;*   WORD   Starting row              (target row)
;*   WORD   Starting column           (target column)
;*   WORD   Secondary row             (not used in this call)
;*   WORD   Secondary column          (not used in this call)
;*   WORD   RepeatFactor              (input and output length)
;*   WORD   LogicalBufSel
;*
;* OUTPUT:      PVB or LVB = new characters
;*              RepeatFactor = number of characters written
;*
;* EXIT-NORMAL: AX = 0
;*
;* EXIT-ERROR:  None
;*
;* EFFECTS:     AX, BX, DI, SI, DS, ES
;*
;* INTERNAL REFERENCES: None
;*
;* EXTERNAL REFERENCES: LocateBuffAddr  (in XGAREAD.ASM)
;*
;********************** END OF SPECIFICATIONS ***************************

        PUBLIC  WriteNChar
WriteNChar      PROC    NEAR

IFDEF D1348 ;BufferUpdate with dbcs bits handling
        push    ds                              ; save parameter block pointer
        push    si
        lds     si,[si].AppDataAddr             ; load character
        lodsb
        .if    <bit <[bp].flgDBCS> and anyDBCS> and
        .if    <[bp].j_funcindx eq WorldFmtIndx>
            push    ds
            push    si
            push    ax
            lds     si,[bp].lpNLSExt
            xor     ah,ah                       ; ignore lcid
            CheckLeadByte                       ; is it DBCS character ?
            pop     ax
            pop     si
            pop     ds
            .if     <c>                         ; if DBCS character
                xchg    al,ah                   ; save leading char
                lodsb                           ; load trailing char
                xchg    al,ah                   ; AL = lead, AH = trail char
            .endif
        .else
            clc
        .endif
        pop     si                              ; rest parameter block pointer
        pop     ds
        .if     <c>                             ; if DBCS character
            shl     ds:[si].RepeatFactor,1      ; cell number *= 2
        .endif
        push    ax                              ; save character
ENDIF ;D1348

        sub     bx, bx                          ; Operation in terms of cells
        call    SetBuffAddr                     ; On exit: BX = sel, AX = off

IFDEF D1348
        pop     dx                              ; restore character
ENDIF ;D1348
        .if     <nc>                            ; Continue?
            mov     di, ax                      ; Setup destination offset
IFDEF D1348
            mov     ax,dx                       ; set character to AX reg.
ELSE  ;D1348
            lds     si, [si].AppDataAddr        ; Setup source address
            lodsb                               ; Get source character
ENDIF ;D1348
            mov     si, [bp].cellsize           ; 
            dec     si                          ; (si) = # attribute bytes
            .if     <nonzero bx>                ; Write through request?
                mov     es, bx                  ; Setup destination selector

IFDEF D1348 ;check if DBCS && common lvb.
                .if    <bit <[bp].flgDBCS> and anyDBCS> and
                .if    <[bp].j_funcindx eq WorldFmtIndx>
                    call    WriteNCharWrld
                .else
ENDIF ;D1348
                    push    cx                  ; Save repeat factor and
                    .repeat                     ; 
                        stosb                   ; Fill destination buffer
                        add     di,si           ; 
                    .loop                       ; 
                    pop     cx                  ; 
IFDEF D1348
                .endif
ENDIF ;D1348
            .endif                              ; 

            mov     bx, [bp].PVB_Sel            ; Get PVB selector from stack
            .if     <nonzero bx>                ; write to PVB requested
                mov     es,bx                   ; Setup destination selector
                mov     di,[bp].PVBOff          ; (di) = PVB offset from LVB off
                mov     dx,cx
                mov     bx,[bp].RowLength       ; (bx) = line width in cells
                mov     si,[bp].PVBSkip
                mov     dx,cx
                mov     cx,[bp].FirstRow
                cmp     cx,dx
                jbe     wnch20

                mov     cx,dx
                jmp     short wnch20

wnch10:         add     di,si
                mov     cx,dx
                cmp     cx,bx
                jbe     wnch20

                mov     cx,bx
wnch20:         sub     dx,cx
                REP_STOSB_INCDI_LOOP        ; Use this macro so CGA can share
                                            ; the same set of sources
                or      dx,dx
                jnz     wnch10
            .endif
            sub     ax, ax                      ; Clear return code
        .endif                                  ; 
        ret                                     ; 

WriteNChar      ENDP

;/****************************************************************************
;*
;* SUBROUTINE NAME:     WriteNAttr
;*
;* DESCRIPTIVE NAME:    Video device handler repeat attributes
;*
;* FUNCTION:    Process repeat write attributes sub-function.
;*              The attributes are written to either PVB or LVB
;*              starting at the specified row, column location.
;*              Line wrap occurs if the end of a line is reached.
;*              Write function is terminated if the end of PVB or
;*              LVB is reached.  The number of the attributes
;*              written is returned in the RepeatFactor field
;*              of the paramter block.
;*
;* ENTRY POINT: WriteNAttr
;*   LINKAGE:   Near Call from BUFFERUPDATE routine
;*
;* INPUT:
;*
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)
;*
;* PARAMETER BLOCK FORMAT:
;*
;*   SIZE   DESCRIPTION
;*   ----   -----------
;*
;*   WORD   Parameter length
;*   WORD   Flags                     (target data buffer - LVB, PVB)
;*   DWORD  Application data address  (source attribute buffer)
;*   DWORD  Application data2 address (not used in this call)
;*   WORD   Index (11)
;*   WORD   Starting row              (target row)
;*   WORD   Starting column           (target column)
;*   WORD   Secondary row             (not used in this call)
;*   WORD   Secondary column          (not used in this call)
;*   WORD   RepeatFactor              (input and output length)
;*   WORD   LogicalBufSel
;*
;* OUTPUT:      LVB and/or PVB = new attributes
;*              RepeatFactor = number of attributes written
;*
;* EXIT-NORMAL: AX = 0
;*
;* EXIT-ERROR:  AX = Error from LocateBuffAddr
;*
;* EFFECTS:     All
;*
;* INTERNAL REFERENCES: None
;*
;* EXTERNAL REFERENCES: LocateBuffAddr   (in XGAREAD.ASM)
;*
;********************** END OF SPECIFICATIONS ***************************

        PUBLIC  WriteNAttr
WriteNAttr      PROC    NEAR

        sub     bx, bx                          ; Operation in terms of cells
        call    SetBuffAddr                     ; On exit: BX = sel, AX = off
        .if     <nc>                            ; Continue?
            mov     di, ax                      ; Setup destination offset
            lds     si, [si].AppDataAddr        ; Setup address to attribute
            lodsb                               ; Get attribute
            .if     <nonzero bx>                ; Write through request?
                mov     es, bx                  ; Setup destination selector
IFDEF D1348 ;check if DBCS && common lvb.
                .if    <bit <[bp].flgDBCS> and anyDBCS> and
                .if    <[bp].j_funcindx eq WorldFmtIndx>
                    call    WriteNAttrWrld
                .else
ENDIF ;D1348
                    push    cx                  ; Save repeat factor and
                    .if     <[bp].cellsize e WorldCellSize>
                        xchg    ax, bx          ; bh = first attr byte
                        lodsw                   ; ax = last attr word
                        xchg    ax, bx          ; al = first attr byte
                        .repeat                 ; 
                            inc     di          ; skip the character
                            stosb               ; save the first attribute byte
                            xchg    ax, bx      ; ax = last attr word
                            stosw               ; store the last attr word
                            xchg    ax, bx      ; al = first attr byte
                        .loop                   ; 
                    .else
                        .repeat                 ; 
                            inc     di          ; skip the character
                            stosb               ; save the attribute byte
                        .loop                   ; 
                    .endif
                    pop     cx                  ; 
IFDEF D1348
                .endif
ENDIF ;D1348
            .endif                              ; 

            mov     bx, [bp].PVB_Sel            ; Get PVB selector from stack
            .if     <nonzero bx>                ; write to PVB requested
                mov     es,bx                   ; Setup destination selector
                mov     di,[bp].PVBOff          ; (di) = PVB offset from LVB off
                mov     bx,[bp].RowLength
                mov     si,[bp].PVBSkip
                mov     dx,cx
                mov     cx,[bp].FirstRow
                cmp     cx,dx
                jbe     wnat20

                mov     cx,dx
                jmp     short wnat20

wnat10:         add     di,si
                mov     cx,dx
                cmp     cx,bx
                jbe     wnat20

                mov     cx,bx
wnat20:         sub     dx,cx
                REP_INCDI_STOSB_LOOP        ; Use this macro so CGA can share
                                            ; the same set of sources
                                            ; skip the character
                                            ; save the attribute
                or      dx,dx
                jnz     wnat10
            .endif
            sub     ax, ax                      ; Clear return code
        .endif                                  ; 
        ret                                     ; 

WriteNAttr      ENDP

;/****************************************************************************
;*
;* SUBROUTINE NAME:     WriteNCell
;*
;* DESCRIPTIVE NAME:    Video device handler repeat cells
;*
;* FUNCTION:    Process write cells sub-function.
;*              The cells are written to either PVB or LVB
;*              starting at the specified row, column location.
;*              Line wrap ocurrs if the end of a line is reached.
;*              Write function is terminated if the end of PVB
;*              or LVB is reached.  The number of cells written
;*              is returned in the RepeatFacter field of the
;*              parameter block.
;*
;* ENTRY POINT: WriteNCell
;*   LINKAGE:   Near Call from BUFFERUPDATE routine
;*
;* INPUT:
;*
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)
;*
;* PARAMETER BLOCK FORMAT:
;*
;*   SIZE   DESCRIPTION
;*   ----   -----------
;*
;*   WORD   Parameter length
;*   WORD   Flags                     (target data buffer - LVB, PVB)
;*   DWORD  Application data address  (source cell buffer)
;*   DWORD  Application data2 address (not used in this call)
;*   WORD   Index (12)
;*   WORD   Starting row              (target row)
;*   WORD   Starting column           (target column)
;*   WORD   Secondary row             (not used in this call)
;*   WORD   Secondary column          (not used in this call)
;*   WORD   RepeatFactor              (input and output length)
;*   WORD   LogicalBufSel
;*
;* OUTPUT:      PVB or LVB = new characters
;*              RepeatFactor = sum of char/attr pairs written
;*
;* EXIT-NORMAL: AX = 0
;*
;* EXIT-ERROR:  AX = Error from LocateBuffAddr
;*
;* EFFECTS:     AX, BX, DI, SI, DS, ES
;*
;* INTERNAL REFERENCES: None
;*
;* EXTERNAL REFERENCES: LocateBuffAddr  (in XGAREAD.ASM)
;*
;****************************************************************************/

        PUBLIC  WriteNCell
WriteNCell      PROC    NEAR

IFDEF D1348 ;BufferUpdate with dbcs bits handling
        .if    <bit <[bp].flgDBCS> and anyDBCS> and
        .if    <[bp].j_funcindx eq WorldFmtIndx>
            push    ds                          ; save parameter block pointer
            push    si
            lds     si,[si].AppDataAddr         ; load character
            lodsb
            mov     ah,byte ptr ds:[si+1]       ; get attr#2
            CheckLeadByte                       ; is it DBCS character ?
            pop     si                          ; rest parameter block pointer
            pop     ds
            .if     <c>                         ; if DBCS character
                shl     ds:[si].RepeatFactor,1  ; cell number *= 2
            .endif
        .endif
ENDIF ;D1348

        sub     bx, bx                          ; Operation in terms of cells
        call    SetBuffAddr                     ; On exit: BX = sel, AX = off
        .if     <nc>                            ; Continue?
            mov     di, ax                      ; Setup destination offset
            lds     si, [si].AppDataAddr        ; Setup address to attribute
            lodsw                               ; Get attribute
            .if     <nonzero bx>                ; Write through request?
                mov     es, bx                  ; Setup destination selector

IFDEF D1348 ;check if DBCS && common lvb.
                .if    <bit <[bp].flgDBCS> and anyDBCS> and
                .if    <[bp].j_funcindx eq WorldFmtIndx>
                    call    WriteNCellWrld
                .else
ENDIF ;D1348
                    push    cx                  ; Save repeat factor and
                    .if     <[bp].cellsize e WorldCellSize>
                        xchg    ax, bx          ; bh = first cell word
                        lodsw                   ; ax = last cell word
                        xchg    ax, bx          ; ax = first cell word
                        .repeat                 ; 
                            stosw               ; save the first attribute byte
                            xchg    ax, bx      ; ax = last attr word
                            stosw               ; store the last attr word
                            xchg    ax, bx      ; al = first attr byte
                        .loop                   ; 
                    .else
                        rep stosw               ; 
                    .endif
                    pop     cx                  ; 
IFDEF D1348
                .endif
ENDIF ;D1348
            .endif                              ; 

            mov     bx, [bp].PVB_Sel            ; Get PVB selector from stack
            .if     <nonzero bx>                ; write to PVB requested
                mov     es, bx                  ; Setup destination selector
                mov     di, [bp].PVBOff         ; (di) = PVB offset from LVB off
                mov     dx, cx
                mov     bx, [bp].RowLength      ; this is in cells
                mov     dx,cx
                mov     cx,[bp].FirstRow
                cmp     cx,dx
                jbe     wnce20

                mov     cx,dx
                jmp     short wnce20

wnce10:         add     di,[bp].PVBSkip
                mov     cx,dx
                cmp     cx,bx
                jbe     wnce20

                mov     cx,bx
wnce20:         sub     dx,cx
                REP_STOSW                   ; Use this macro so CGA can share
                                            ; the same set of sources
                or      dx,dx
                jnz     wnce10
            .endif
            sub     ax, ax                      ; Clear return code
        .endif                                  ; 
        ret                                     ; 

WriteNCell      ENDP

R2CSEG  ENDS
        END

;@P1  = 03/25/89  PL, DCR 132 changes
;MS00 = 01/29/91 TPL, Convert IFDEF to IF
;MS01 = 01/29/91 TPL, Rollover MS's runtime check for CGA speedup
;D1348 = 04/11/91 NAKADA, Enable DBCS support in Vio-Window, DCR 1348
