        page    ,132
        title   DemDD - Real Mode Device Driver for MVDM

;***    demdd - Dos Device drivers for MVDM
;
;       Copyright (C) Microsoft Corp. 1982, 1983, 1984, 1985
;
;
;       P R N - PRINTER DEVICE
;       A U X - AUXILLARY DEVICE
;
;
; This file contains the PRN dand AUX device Drivers.
;
; The routines in this file are:
;
;       routine                 function
;       -------                 --------
;       PRN$WRITE               Write to printer device
;       PRN$STATUS              Printer status routine
;       PRN$TilBusy             Print spooler routine
;       Prn$GenIOCTL            Generic IOCTL routine
;
;       AUX$READ                Read characters
;       AUX$RDND                Non-desrucrtive read
;       AUX$FLUSH               Flush AUX
;       AUX$WRITE               Write characters
;       AUX$STATUS              Get status
;
;
; Only PRN device is supported. LPT1-3 are treated as OS/2 devices.
;
;   Modification History
;       sudeepb bharati 10-Sep-1989  Ported for MVDM (DCR 540)
;
;
;  B001    CP20 PTR B722937 - 5/24/91  Jeff Muir
;          Added default block device driver header to data stucture
;          for Brooklyn Bridge DEVICES program
;
;  B002    CP20 PTR B733134 - 02/17/92 George Fulk (fix applied by J Hare)
;          BX register getting trashed sometimes in dd$int causing doskrnl
;          to fail.  Need to restore BX with good value.
;
;  54297   01-20-93  RickGiroux, ChgTeam:  With GLFulk's abundant guidance,
;          fixed printing to DOS real mode device, thus: "copy /b tmp.1 prn",
;          so it would behave as "copy /b tmp.1 lpt1", OS2 protected mode device,
;          while lpt1 is active printer with it's Q held.  Tmp.1 file is now
;          shown on printQ as "system" file, while the same file printed to
;          lpt1 appears as "TMP.1" file as also displayed in job icon view.
;          Unless DOS settings are changed for INT17 timeout, PRN files going
;          to spooler may be placed in one file on Q for all the PRN's, as in
;          the case of using .BAT file with multiple copies to PRN.  This IS
;          as designed.
;***********************************************************************;BN040;
;  29Jul93 - J.M.Hare    defect 71358                                   ;BN040;
; Add propogating of DOSFLAG through files system for exec_only test.   ;BN040;
;***********************************************************************;BN040;
;  13APR94 - ChangeTeam  defect 81250                                   ;81250;
; ChrIn is defined to return AL=00 if an extended key was pressed.      ;81250;
; Codepage 852 has a valid char (o-mulate) with ascii code              ;81250;
; E0 and ChrIn was erroneously skipping the processing of E0 if codepage;81250;
; 852 was in use.  This caused ChrIn to return E0 (not 00) when an      ;81250;
; extended key was pressed under codepage 852. Apps depending on        ;81250;
; the 00 return were interpreting the extended keys as the o-mulate     ;81250;
; char on the Hungarian kbd (cp 852).                                   ;81250;
;***********************************************************************;150931;
;  15APR96 - S.A.Barnes  defect 150931                                  ;150931;
; Merge in SBCS support for CYRILLIC and LATIN2                         ;150931;
;***********************************************************************;150931;

.xlist
include v86seg.inc
.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include devsym.inc
include error.inc
include dossymc.inc
include ioctl.inc
include struc30.inc
include demsvc.inc
include mvdmexp.inc
include demsvc.inc
include doscntry.inc
BUFFERFLAG EQU 0
include sysvar.inc
.cref
.list

.SFCOND
.LALL

;
; EQU for this file:
;
; The following are used to test status on return from ROM-BIOS

; For PRN Device driver

BusyBit         equ     10000000b
OutPaperBit     equ     00100000b
IOErrorBit      equ     00001000b
TimeOutBit      equ     00000001b

; For AUX Device driver

DSetReadyBit    equ     00100000b   ; Data Set Ready Status Bit
DReadyBit       equ     00000001b   ; Data Ready Status Bit
THRegEmptyBit   equ     00100000b   ; Tran Holding Register Empty Status Bit
InputErrorBits  equ     00001110b   ; Framing or Parity or Overrun error


            ReferV86    fHaveK09
            ReferV86    COUNTRY_CDPG


V86DATA     SEGMENT

                public  prg_execdw
prg_execdw      DD      0

                public  agi_execdw
agi_execdw      DD      0

                public  AltAH
ALTAH           DB      0

                PUBLIC  KEYRD_Func, KEYSTS_Func
KEYRD_Func      DB      0
KEYSTS_Func     DB      1
                PUBLIC  OldInt10
OldInt10        dd      0               ;INT 10h vector at time of INIT

                PUBLIC  PTRSAV,TABLE_ADDR
PTRSAV          DD      ?               ; Save Request Header address
WAIT_COUNT      DW      4               ; For IOCTL subfunction 16 of PRN
PORT_NUMBER     DW      ?
TABLE_ADDR      DW      ?
AUXBUF          DB      4 dup (?)       ;> buffer for each AUX port
ActiveOpens     DB      4 dup (0)       ;\ buffer for each PRN port
Retry_Count     DW      4 dup (80)      ;/
com_asciiz      db      "COM0",0
lpt_asciiz      db      "LPT1",0        ;PRN maps to LPT1 only      ;54297;

V86DATA         ENDS

;
; Device Header for device PRN
;

V86CODE    SEGMENT
        ASSUME      CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
;-------------------------------
        PUBLIC  CONDEV
CONDEV  dw      offset V86GROUP:PRNDEV
        dw      -1
        dw      DEV_CIN OR DEV_CHAR_DEV OR DEV_COUT OR DEVLEV_0 OR DEV_SPEC
                        ;0001h DEV_CIN       bit0=1
                        ;0002h DEV_COUT      bit1=1
                        ;0010h DEV_SPEC      bit4=1     (int29h serviced)
                        ;0000h DEV_0         bit7&8=00  ???
                        ;8000h DEV_CHAR_DEV  bit15=1
        dw      OFFSET V86GROUP:Strategy
        dw      OFFSET V86GROUP:ConInt
        db      "CON     "
        PUBLIC  PRNDEV
PRNDEV  DW      offset V86GROUP:AuxDev
        DW      -1
        DW      DEV_CHAR_DEV + OutTilBusy + Dev320
                        ;2000h OutTilBusy
                        ;      Dev320==DEV_GIOCTL
        DW      OFFSET V86GROUP:STRATEGY
        DW      OFFSET V86GROUP:PRNInt
        DB      'PRN     '
        PUBLIC  AUXDEV
AUXDEV  DW      offset V86GROUP:COM1DEV
        DW      -1
        DW      DEV_CHAR_DEV             ; attribute word, character device
        DW      OFFSET V86GROUP:STRATEGY ; device strategy routine
        DW      OFFSET V86GROUP:AUXInt   ; device interrupt routine
        DB      'AUX     '               ; device name
        PUBLIC  COM1DEV
COM1DEV DW      offset V86GROUP:COM2DEV
        DW      -1
        DW      DEV_CHAR_DEV             ; attribute word, character device
        DW      OFFSET V86GROUP:STRATEGY ; device strategy routine
        DW      OFFSET V86GROUP:COM1Int  ; device interrupt routine
        DB      'COM1    '               ; device name
        PUBLIC  COM2DEV
COM2DEV DW      offset V86GROUP:COM3DEV
        DW      -1
        DW      DEV_CHAR_DEV             ; attribute word, character device
        DW      OFFSET V86GROUP:STRATEGY ; device strategy routine
        DW      OFFSET V86GROUP:COM2Int  ; device interrupt routine
        DB      'COM2    '               ; device name
        PUBLIC  COM3DEV
COM3DEV DW      offset V86GROUP:COM4DEV
        DW      -1
        DW      DEV_CHAR_DEV             ; attribute word, character device
        DW      OFFSET V86GROUP:STRATEGY ; device strategy routine
        DW      OFFSET V86GROUP:COM3Int  ; device interrupt routine
        DB      'COM3    '               ; device name
        PUBLIC  COM4DEV
COM4DEV DW      offset V86GROUP:BLKDEV
        DW      -1
        DW      DEV_CHAR_DEV             ; attribute word, character device
        DW      OFFSET V86GROUP:STRATEGY ; device strategy routine
        DW      OFFSET V86GROUP:COM4Int  ; device interrupt routine
        DB      'COM4    '               ; device name
        PUBLIC  BLKDEV                                                  ;B001
BLKDEV  DW      -1                       ; pointer to next device       ;B001
        DW      -1
        DW      0                        ; attribute word, block device ;B001
        DW      OFFSET V86GROUP:STRATEGY ; device strategy routine      ;B001
        DW      OFFSET V86GROUP:BLKint   ; device interrupt routine     ;B001
        PUBLIC  BLKCNT                                                  ;B001
BLKCNT  DB      0                        ; block device count           ;B001
        DB      '       '                ; with space padding           ;B001
;-------------------------------

        PUBLIC  ConJmpTbl
ConJmpTbl   LABEL   WORD
        db      sConJmpTbl
        dw      OFFSET V86GROUP:DD$EXIT      ; 0  Initialization - do nothing
        dw      OFFSET V86GROUP:DD$EXIT      ; 1  Media Check
        dw      OFFSET V86GROUP:DD$EXIT      ; 2  Build BPB
        dw      OFFSET V86GROUP:DD$CMDERR    ; 3  Reserved
        dw      OFFSET V86GROUP:CON$READ     ; 4  Input (Read)
        dw      OFFSET V86GROUP:CON$RDND     ; 5  Non-Destructive read, no wait
        dw      OFFSET V86GROUP:DD$EXIT      ; 6  Input Status
        dw      OFFSET V86GROUP:CON$FLUSHIN  ; 7  Input Flush
        dw      OFFSET V86GROUP:CON$WRITE    ; 8  Output (Write)
        dw      OFFSET V86GROUP:CON$WRITE    ; 9  Output with verify
        dw      OFFSET V86GROUP:DD$EXIT      ; 10 Output Status
sConJmpTbl  EQU ($-ConJmpTbl) / 2
        dw      OFFSET V86GROUP:DD$CMDERR    ;>10 invalid command

        PUBLIC  PrnTbl
PRNTBL  LABEL   WORD
        DB      EndPrn
        DW      OFFSET V86GROUP:DD$EXIT         ;  0  Initialization - do nothing
        DW      OFFSET V86GROUP:DD$EXIT         ;  1  Media Check
        DW      OFFSET V86GROUP:DD$EXIT         ;  2  Build BPB
        DW      OFFSET V86GROUP:DD$CMDERR       ;  3  Reserved
        DW      OFFSET V86GROUP:PRN$READ        ;  4  Input (Read)
        DW      OFFSET V86GROUP:PRN$RDND        ;  5  Non-Destructive read, no wait
        DW      OFFSET V86GROUP:DD$EXIT         ;  6  Input Status
        DW      OFFSET V86GROUP:DD$EXIT         ;  7  Input Flush
        DW      OFFSET V86GROUP:PRN$WRITE       ;  8  Output (Write)
        DW      OFFSET V86GROUP:PRN$WRITE       ;  9  Output with verify
        DW      OFFSET V86GROUP:PRN$STATUSOUT   ; 10  Output Status
        DW      OFFSET V86GROUP:DD$EXIT         ; 11  flush output buffers
        DW      OFFSET V86GROUP:DD$EXIT         ; 12  I/O control write
        DW      OFFSET V86GROUP:PRN$OPEN        ; 13  device open
        DW      OFFSET V86GROUP:PRN$CLOSE       ; 14  device close
        DW      OFFSET V86GROUP:DD$EXIT         ; 15  removalble media
        DW      OFFSET V86GROUP:PRN$TilBusy     ; 16  output until busy
        DW      OFFSET V86GROUP:DD$EXIT         ; 17  reserved
        DW      OFFSET V86GROUP:DD$EXIT         ; 18  reserved
        DW      OFFSET V86GROUP:PRN$GenIOCTL    ; 19  generic IOCTL
        DW      OFFSET V86GROUP:DD$EXIT         ; 20  reserved
        DW      OFFSET V86GROUP:DD$EXIT         ; 21  reserved
        DW      OFFSET V86GROUP:DD$EXIT         ; 22  reserved
        DW      OFFSET V86GROUP:DD$EXIT         ; 23  get logical device
        DW      OFFSET V86GROUP:DD$EXIT         ; 24  set logical device
        DW      OFFSET V86GROUP:PRN$QRYIOCTL    ; 25  query IOCTL
ENDPRN      EQU ($-PRNTBL) / 2
        DW      OFFSET V86GROUP:DD$CMDERR       ;>25

        PUBLIC  AuxTbl
AUXTBL  LABEL   WORD
        DB      EndAux
        DW      OFFSET V86GROUP:DD$EXIT         ; 0
        DW      OFFSET V86GROUP:DD$EXIT         ; 1
        DW      OFFSET V86GROUP:DD$EXIT         ; 2
        DW      OFFSET V86GROUP:DD$CMDERR       ; 3
        DW      OFFSET V86GROUP:AUX$READ        ; 4
        DW      OFFSET V86GROUP:AUX$RDND        ; 5
        DW      OFFSET V86GROUP:DD$EXIT         ; 6
        DW      OFFSET V86GROUP:AUX$FLUSHIN     ; 7
        DW      OFFSET V86GROUP:AUX$WRITE       ; 8
        DW      OFFSET V86GROUP:AUX$WRITE       ; 9
        DW      OFFSET V86GROUP:AUX$STATUSOUT   ; 10
        DW      OFFSET V86GROUP:DD$CMDERR       ; 11
        DW      OFFSET V86GROUP:DD$CMDERR       ; 12
        DW      OFFSET V86GROUP:DD$CMDERR       ; 13
        DW      OFFSET V86GROUP:DD$CMDERR       ; 14
        DW      OFFSET V86GROUP:DD$CMDERR       ; 15
        DW      OFFSET V86GROUP:DD$CMDERR       ; 16
        DW      OFFSET V86GROUP:DD$CMDERR       ; 17
        DW      OFFSET V86GROUP:DD$CMDERR       ; 18
        DW      OFFSET V86GROUP:AUX$GenIOCTL    ; 19
ENDAUX      EQU ($-AUXTBL) / 2
        DW      OFFSET V86GROUP:DD$CMDERR       ;>19


;   COMMOMN Device driver Entry Points

;   Strategy routine

        PUBLIC  STRATEGY
STRATEGY proc   far
        mov     word ptr cs:[PTRSAV],BX
        mov     word ptr cs:[PTRSAV+2],ES
        ret
STRATEGY endp

;---------------------------------------
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        PUBLIC  BlkInt
BlkInt  proc    far
        EXTRN   DemMisc_v86ie_Block_DD: word
        push    cs
        push    cs:[DemMisc_v86ie_Block_DD]
        SVC     SVC_DemInternalError
BlkInt  endp
;---------------------------------------
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        PUBLIC  ConInt
ConInt  PROC    FAR
        mov     cs:[Table_addr],offset V86GROUP:ConJmpTbl
        jmp     short DD$INT
ConInt  ENDP
;---------------------------------------
        public  PRNInt
PRNInt  PROC    FAR
        mov     word ptr cs:[Port_number],0
Prn_int:
        mov     cs:[Table_addr],offset V86GROUP:PrnTbl
        jmp     short DD$INT
PRNInt  ENDP
;---------------------------------------
        PUBLIC  COM2Int
COM2Int:
        mov     word ptr cs:[Port_number],2-1
        jmp     short Aux_int
;-------
        PUBLIC  COM3Int
COM3Int:
        mov     word ptr cs:[Port_number],3-1
        jmp     short Aux_int
;-------
        PUBLIC  COM4Int
COM4Int:
        mov     word ptr cs:[Port_number],4-1
        jmp     short Aux_int
;-------
        PUBLIC  AUXInt,COM1Int
AUXInt  PROC    FAR
COM1Int:
        mov     word ptr cs:[Port_number],1-1
Aux_int:
        mov     cs:[Table_addr],offset V86GROUP:AuxTbl
;       jmp     short DD$INT
AUXInt  ENDP
;---------------------------------------


        public  DD$INT
DD$INT  proc    far

;------ save registers
        cld
        pusha
        push    ds
        push    es

;------ get the Request header and worker address (worker address cs:si)
        LDS     BX,cs:[PTRSAV]
        mov     al,ds:[bx].PktCmd
        mov     si,cs:[Table_addr]
        mov     ah,cs:[si]
        .if     <AL ae AH>
          mov     al,ah
        .endif
        xor     ah,ah
        shl     ax,1
        add     si,ax
        inc     si

;------ setup additional registers
        mov     dx,cs:[port_number]     ;DX = COMx or LPTx port number
;54297  mov     cx,es:[bx].IOcount      ;CX = Count
        mov     cx,ds:[bx].IOcount      ;CX = Count                  ;54297;
        LES     DI,ds:[bx].IOpData      ;ES:DI = address of data

;------ call the worker
; DS:BX = Request header
; ES:DI = transfer address
; CX    = count
; DX    = port#                         ; B002 included this comment
;
        call    word ptr cs:[si]
;
; AX    = status word

;------ Save the device driver status word
        LDS     BX,cs:[PTRSAV]          ; B002 restore ds:bx at this point
        mov     ds:[bx].PktStatus,ax

;------ restore registers
        pop     es
        pop     ds
        popa
        ret
DD$INT  endp




; PRN Device Driver Procedures

;----------------------------------------------------------------
;                                                               :
;               WRITE TO PRINTER DEVICE                         :
;                                                               :
;   CX has count of bytes to be printed                         :
;   ES:DI point to source buffer contains characters            :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$WRITE proc  near
        .if     ncxz
          .repeat
            mov     si,2                ; Initialize retry flag
PRN$out:
            mov     al,es:[di]          ; Get a character into AL
            xor     ah,ah
            call    PRNOP1              ; print character
            .if     nz                  ; if error, try to print again
              dec     si                ; Decrement retry count
              jnz     PRN$out           ; See if done with retrys

              sub     ds:[bx].IOcount,cx  ;# of successful I/O's
              mov     ah,81h            ;=done+error
                                        ; error code was set in PRNOP1
              ret
            .endif
            inc     di                  ; Point to next character
          .loop
        .endif
        mov     ah,1                    ;=done
        ret
PRN$WRITE endp

;----------------------------------------------------------------
;                                                               :
;               PRINTER STATUS ROUTINE                          :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$STATUSOUT proc   near
        mov     ah,2
        call    PRNOP1                  ; get the status
        .if     nz
          sub     ds:[bx].IOcount,cx    ;# of successful I/O's
          mov     ah,81h                ;=error+done
                                        ; Error code set in PRNOP1
          ret
        .endif
        .if     <BIT AH and BusyBit>
          mov     ah,1                  ;=done
        .else
          mov     ah,3                  ;=busy+done
        .endif
        ret
PRN$STATUSOUT endp
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$OPEN PROC  NEAR
        mov     si,dx
        inc     cs:[ActiveOpens+si]
        mov     ah,1                    ;=done
        ret
PRN$OPEN ENDP
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$CLOSE PROC  NEAR
        mov     si,dx
        dec     cs:[ActiveOpens+si]
        .if     z
          mov     ah,1                  ; AH = initialize port function
          int     17h                   ; issue BIOS call to init port
        .endif
        mov     ah,1                    ;=done
        ret
PRN$CLOSE ENDP
;----------------------------------------------------------------
;
;   PRNOP       print a character
;
; PRNOP is a routine which calls on the ROM-BIOS printer routines.
;
;   INPUT       AL=char to print (depending on function)
;               AH=printer function
;
;   OUTPUT      - AL holds error code (as indicated on PG 2-17 of device
;                    driver guide.
;               - AH status byte from printer
;               - flag NZ if error
PRNOP1  proc    near
        int     17h                     ; call ROM-BIOS printer routine
        .if     <BIT AH nand IOErrorBit>
          mov     AL, error_I24_not_ready ; assume timeout error
          test    AH, TimeOutBit          ; test for timeout, set z flag
          ret
        .endif
        mov     AL, error_I24_out_of_paper; assume out of paper error
        .if     <BIT AH nand OutPaperBit>
          mov     AL, error_I24_write_fault       ; no, must be write fault
          test    AH, IOErrorBit          ; clear the zero flag, indicate error
        .endif
        ret
PRNOP1  endp


;----------------------------------------------------------------
;                                                               :
;               Output until Busy                               :
;                                                               :
; Output until busy.  This entry point is used EXCLUSIVELY by   :
; the print spoolers.  Under no curcumstances should the device :
; driver block waiting for the device to become ready.          :
;                                                               :
;   Inputs:     CX has count of bytes to output.                :
;               ES:DI points to source buffer                   :
;   Outputs:    Set the number of bytes transferred             :
;                 appropriately.                                :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$TilBusy proc near

        push    es
        pop     ds
        mov     si,di                   ; everything is set for LODSB
;DS:SI=transfer address

        mov     di,dx
;DI=port #

        .repeat
          push    cx
          mov     cx,cs:[Retry_Count+di]
          .repeat
            mov     ah,2
            call    PrnOp1              ; get status
            .if     nz                  ; if error jump to error routine
              pop     cx                ; recover number of char left
PRN$BErr:
              mov     ah,81h            ;=error+done
              LDS     BX,cs:[PTRSAV]
              sub     ds:[bx].IOcount,cx  ; Determine number of succ. I/O's
              ret
            .endif
            test    ah, BusyBit         ; test busy bit of status
          .loop   z
          pop     cx                    ; get original count
          jz      PRN$BErr              ; still not ready => done
          lodsb
          xor     ah,ah
          call    PrnOp1                ; print the character
          jnz     PRN$BErr              ; error
        .loop
        mov     ah,1                    ;=done
        ret
PRN$TilBusy endp
;---------------------------------------
;
; Prn$GenIOCTL:
;
; Manipulates the value in WAIT_COUNT depending on the value passed in the
; Generic IOCTL packet.
; It either sets or returns the current value for the retry count for the
; device.
;
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
Prn$GenIOCTL proc near
        .if     <<ds:[bx].IOGCMA> ne IOC_PC> NEAR ; Major code
          mov     ds:[BX].IOcount,0     ;# of successful I/O's
          mov     ax,8100h+ERROR_I24_BAD_COMMAND   ;=done+error #3
        .else NEAR
          mov     al,ds:[bx].IOGCMI     ; Minor code
          LES     DI,ds:[bx].IOGCAD
          mov     si,dx
          .select
          .when   <AL eq GET_RETRY_COUNT>
            mov     ax,cs:[Retry_Count+si]      ; obtain current retry count
            mov     es:[di].RC_Count,ax         ; return current retry count
            mov     ah,1
          .when   <AL eq SET_RETRY_COUNT>
            mov     ax,es:[di].RC_Count         ; yes, obtain retry count input
            mov     cs:[Retry_Count+si],ax
            mov     ah,1                        ;=done

;54297;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54297;
          .when   <AL eq SET_PRINTJOB_TITLE>    ;=4Dh
;-------- Open "LPT1"
            xor     ax,ax
            mov     cx,ax                       ;cx=attributes, none
            mov     di,ax
            dec     di                          ;es:di=0:-1 ==no EAs
            mov     es,ax
            mov     bx,0040h                    ;bx=open mode bits
            push    cs
            pop     ds                          ;ds:si=&asciiz
            mov     si,offset V86GROUP:lpt_asciiz  ;LPT1

;------ initialize Not Exec_only flag from the loader                            exec_only BN040
.386
            push    edx                             ; 112811
            xor     edx,edx                         ; only need Edl part                  exec_only BN040
            mov     cs:[prg_execdw],edx             ; zero save area                      exec_only BN040
            and     dh, not EXECOPEN                ; set exec_only bit off               exec_only BN040
            mov     word ptr cs:[prg_execdw+1],dx   ; save dx in hi word                  exec_only BN040
            mov     edx,cs:[prg_execdw]             ; restore edx with edl as DOSFLAG     exec_only BN040
            mov     dx,ax                           ;dx=open flags, none
            inc     dx
.8086
            SVC     SVC_DEMOPEN
           ;return ax=os/2 handle
           ;       bx=dos sft flags
           ;       cx=action taken
.386
            pop     edx                             ; 112811
.8086
            .if     c
              mov     ax,8100h+ERROR_I24_GEN_FAILURE ;=done+error #12
            .else
              LES     bx,cs:[PTRSAV]
           ;------ IOCTL call to protect mode LPT1 device
              mov     ch,es:[bx]+0Dh
              mov     cl,es:[bx]+0Eh
              mov     si,es:[bx]+0Fh
              mov     di,es:[bx]+11h
              LDS     DX,es:[bx]+13h
              mov     bx,ax                     ;=OS/2 handle
              push    bx
              mov     ax,000Ch                  ;IOCTL, generic ioctl function
              SVC     SVC_DEMIOCTL              ; do all work in protect mode
           ;------ close the handle
              pop     bx                        ;=OS/2 handle
              SVC     SVC_DEMCLOSE
              mov     ah,1                      ;=done OK
            .endif
;54297;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54297;

          .otherwise
            mov     ds:[BX].IOcount,0           ;# of successful I/O's
            mov     ax,8100h+ERROR_I24_BAD_COMMAND   ;=done+error #3
          .endselect

        .endif
        ret
Prn$GenIOCTL endp
;---------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$QRYIOCTL  proc near
        .if     <<ds:[bx].IOGCMA> eq IOC_PC>  ; Major code
          mov     al,es:[bx].IOGCMI               ; get minor code
          .if     <AX eq GET_RETRY_COUNT> or
          .if     <AX eq SET_RETRY_COUNT>
            mov     ah,1                  ;=done
            ret
          .endif
        .endif
        mov     ds:[BX].IOcount,0     ;# of successful I/O's
        mov     ax,8100h+ERROR_I24_BAD_COMMAND   ;=done+error #3
        ret
PRN$QRYIOCTL  endp
;---------------------------------------


;  AUX Device driver Procedures

;----------------------------------------------------------------
;                                                               :
;       Read zero or more characters from Auxilary Device       :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
AUX$READ proc   near
        .if     ncxz
          xor     ax,ax
          mov     si,dx
          xchg    al,cs:[AUXBUF+si]
          or      al,al                 ;\ jump if the buffer
          jnz     aux2                  ;/  is not empty
          .repeat
            ;Aux read: AH=2, DX=port#
            mov     ah,2
            int     14h
            ;returns: AL=char read, AH=line status
            .if     <BIT AH and InputErrorBits>
              mov     ax,8100h+ERROR_I24_READ_FAULT    ;=done+error #11
              jmp     short read_ret
            .endif
AUX2:
            stosb                   ; store character
          .loop
        .endif

        mov     ah,1                    ;=done
read_ret:
        sub     ds:[bx].IOcount,cx  ;# of successful I/O's
        ret
AUX$READ endp

;----------------------------------------------------------------
;                                                               :
;       Aux non-destructive read with no waiting                :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
AUX$RDND proc   near
        mov     si,dx
        mov     al,cs:[AUXBUF+si]         ; copy contents of buffer to AL
        .if     <ZERO al>
          ;Aux status: ah=3, dx=port#
          mov     ah,3            ; set command to get status
          int     14h             ; call rom-bios for status
          ;returns: al=modem status ah=line status
          .if     <BIT AH nand DReadyBit> or
          .if     <BIT AL nand DSetReadyBit>
            mov     ah,3                    ;=busy+done
            ret
          .endif
          ;Aux read: AH=2, DX=port#
          mov     ah,2
          int     14h
          ;returns: AL=char read, AH=line status
          .if     <BIT AH and InputErrorBits>
            sub     ds:[bx].IOcount,cx  ;# of successful I/O's
            mov     ax,8100h+ERROR_I24_READ_FAULT    ;=done+error #11
            ret
          .endif
          mov     cs:[AUXBUF+si],al         ; save character in buffer
        .endif
        mov     ds:[bx].IOmedia, AL     ; move character into req. header
        mov     ah,1                    ;=done
        sub     ds:[bx].IOcount,cx
        ret
AUX$RDND endp

;----------------------------------------------------------------
;                                                               :
;               Aux Output Status                               :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
AUX$STATUSOUT proc   near
        ;AUX status: ah=3, dx=port#
        mov     ah,3
        int     14h
        ;returns: al=modem status, ah=line status
        .if     <BIT AH and THRegEmptyBit> and
        .if     <BIT AL and DSetReadyBit>
          mov     ah,1                    ;=done
        .else
          mov     ah,3                    ;=busy+done
        .endif
        ret
AUX$STATUSOUT endp
;----------------------------------------------------------------
;                                                               :
;  Flush AUX Input buffer - set contents of AUXBUF to zero      :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
AUX$FLUSHIN proc  near
        mov     si,dx
        mov     byte ptr cs:[AUXBUF+si],0      ; zero out buffer
        mov     ah,1                    ;=done
        ret
AUX$FLUSHIN endp
;----------------------------------------------------------------
;                                                               :
;               Write to Auxilary Device                        :
;                                                               :
;----------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
AUX$WRITE proc  near
        .if     ncxz
          .repeat
            mov     al,es:[di]      ; get character to be written
            inc     di              ; move DI pointer to next character
            ;Aux write: ah=1, dx=port#, al=char to send
            mov     ah,1            ; set command to send character
            int     14h             ; call rom-bios
            ;returns: ah=line status, al=no change
            .if     <BIT AH and 80h>
              sub     ds:[bx].IOcount,CX        ;# of successful I/O's
              mov     ax,8100h+ERROR_I24_WRITE_FAULT   ;=done+error #10
              ret
            .endif
          .loop
        .endif
        mov     ah,1                    ;=done
        ret
AUX$WRITE endp

;-----------------------------------------------------
; Exit  Points
;-----------------------------------------------------


;---------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$RDND proc   near
        mov     ah,3                    ;=busy+done
        ret
PRN$RDND endp
;---------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
PRN$READ proc   near
        mov     ds:[bx].IOcount,0       ;# of successful I/O's
        mov     ah,1                    ;=done
        ret
PRN$READ endp
;---------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        public  DD$EXIT
DD$EXIT proc    near
        mov     ah,1                    ;=done
        ret
DD$EXIT endp
;---------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        public  DD$CMDERR
DD$CMDERR proc    near
        mov     ds:[bx].IOcount,0       ;# of successful I/O's
        mov     ax,8100h+ERROR_I24_BAD_COMMAND   ;=done+error #3
        ret
DD$CMDERR endp
;---------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        public  AUX$GenIOCTL
AUX$GenIOCTL proc    near

;------ check major code == COMx
        .if     <<byte ptr ds:[bx+0Dh]> ne 1>
          mov     ax,8100h+ERROR_I24_BAD_COMMAND   ;=done+error #3
          ret
        .endif

;------ Open "COMx"
        add     dl,'1'
        mov     cs:[com_asciiz+3],dl
        xor     ax,ax
        mov     cx,ax                   ;cx=attributes
        mov     di,ax
        dec     di                      ;es:di=0:-1 ==no EAs
        mov     es,ax
        mov     bx,0040h                ;bx=open mode bits
        push    cs
        pop     ds                      ;ds:si=&asciiz
        mov     si,offset V86GROUP:com_asciiz

;------ initialize Not Exec_only flag from the loader                                 exec_only BN040
.386
        push    edx                             ; 112811
        xor     edx,edx                         ; only need Edl part                  exec_only BN040
        mov     cs:[agi_execdw],edx             ; zero save area                      exec_only BN040
        and     dh, not EXECOPEN                ; set exec_only bit off               exec_only BN040
        mov     word ptr cs:[agi_execdw+1],dx   ; save dx in hi word                  exec_only BN040
        mov     edx,cs:[agi_execdw]             ; restore edx with edl as DOSFLAG     exec_only BN040
        mov     dx,ax                           ;dx=open flags, none
        inc     dx
.286c

        SVC     SVC_DEMOPEN
        ;return ax=os/2 handle
        ;       bx=dos sft flags
        ;       cx=action taken

.386
        pop     edx                             ; 112811
.286c
        .if     c
          mov     ax,8100h+ERROR_I24_GEN_FAILURE   ;=done+error #12
        .else
          LES     bx,cs:[PTRSAV]

          ;------ IOCTL call to protect mode COMx device
          mov     ch,es:[bx]+0Dh
          mov     cl,es:[bx]+0Eh
          mov     si,es:[bx]+0Fh
          mov     di,es:[bx]+11h
          LDS     DX,es:[bx]+13h

          mov     bx,ax                 ;=OS/2 handle
          push    bx

          mov     ax,000Ch              ;IOCTL, generic ioctl function
          SVC     SVC_DEMIOCTL          ; do all work in protect mode

          ;------ close the handle
          pop     bx                    ;=OS/2 handle
          SVC     SVC_DEMCLOSE

          mov     ah,1                  ;=done
        .endif

        ret
AUX$GenIOCTL endp
;---------------------------------------
;--------------------------------------------------------------------
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        public  CON$READ
CON$READ PROC   near
        .if     ncxz
          .repeat
            call    CHRIN               ;get char in AL
            stosb                       ;store char at ES:DI
          .loop
        .endif
        mov     ah,1                    ;=done
        ret
CON$READ ENDP
;--------------------------------------------------------------------


;---------------------------------------------------------
;
;       INPUT SINGLE CHAR INTO AL
;
;J.K.5/12/87 We are going to issue extended keyboard function, if supported.
;The returning value of the extended key stroke of the extended key board
;function uses 0E0h in AL instead of 00 as in the conventional key board
;function.  This creates a conflict when the user entered real Greek Alpha
;charater (= 0E0h) to  distinguish the extended key stroke and the Greek Alpha.
;This case will be handled in the following manner;
;       AH = 16h
;       INT 16h
;       If AL == 0, then extended code (in AH)
;  else If AL == 0E0h, then
;            IF AH <> 0, then extended code (in AH)
;       else Greek_Alpha character.
;Also, for compatibility reason, if an extended code is detected, then we
;are going to change the value in AL from 0E0h to 00h.

        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        public  CHRIN
CHRIN   PROC    NEAR
        .repeat
          mov     ah,cs:[KEYRD_Func]    ; Set by MSINIT. 0 or 10h
          xor     al,al
          xchg    al,cs:[ALTAH]         ;get character & zero ALTAH

          or      al,al
;if CYRILLIC or LATIN2                                ;150931;
          jz      KEYRETcyr                           ;150931;
          jmp     KEYRET                              ;150931;
KEYRETcyr:                                            ;150931;
;else                                                 ;150931;
;          jnz     KEYRET                             ;150931;
;endif                                                ;150931;

          int     16h
        .until  <NONZERO ax>            ;check for non-key after break

        .if     <ax eq 7200h>           ;check for Ctrl-Prtsc
          mov     al,16   ;ctrl-P
          ret
        .endif

        ;**************************************************************
        ;  IF operation was extended function (i.e. KEYRD_Func != 0) THEN
        ;    IF character read was 0E0h THEN
        ;      IF extended byte was zero (i.e. AH == 0) THEN
        ;        goto keyret
        ;      ELSE
        ;        set AL to zero
        ;        goto ALT_SAVE
        ;      ENDIF
        ;    ENDIF
        ;  ENDIF
        ; BN0001; fix for codepage 852

;**** replaced by codeblock below ************ commented out by  **** ;81250;
;81250        .if     <<cs:[KEYRD_Func]> ne 0> and                        |
;81250        .if     <AL eq 0E0h> and                                    |
;81250        .if     <<cs:[COUNTRY_CDPG].ccSysCodePage> ne 852>          |
;81250          .if     <NONZERO ah>                                      |
;81250            xor     al,al                                           |
;81250            mov     cs:[ALTAH],ah       ;STORE SPECIAL KEY          |
;81250          .endif                                                    |
;81250          ret                                                       |
;81250        .endif                                                      |
;**** replaced by codeblock below *********** commented out by   **** ;81250;

;********************************************************************* ;81250;
; In CodePage 852, E0 is a valid ASCII char => must determine if an       |
; ascii char or an extended key was pressed.  In Scan Code Table, Set     |
; 1, key 13 (o-mulate on Hungarian kbd) has a make code of                |
; 0D.  In Scan Code Table, Sets 2 & 3 its make code is 55.  However,      |
; since sets 2&3 do not use code 0D with extended keys and set 1 does     |
; not use 55 with extended keys, we do not need to determine which        |
; Scan Code Table we are using - just knowing AL=E0 is enough to          |
; allow us to use (AH=0D or AH=55).                                       |
;                                                                         |
; If an extended key was pressed, we need to pass on AL=00.               |
; If the o-mulate char was pressed, we need to pass on AL=E0.             |
;                                                                         |
; The check for <nonzero ah> is to cover the alt-224 case.  Pressing      |
;  Alt-224 retns AX=00E0 and we would not want to change the E0 to        |
;  00 in this case.                                                       |
;********************************************************************* ;81250;

;if CYRILLIC                                                           ;150931;
        .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 866> and            ;150931;
        .if  <<cs:[COUNTRY_CDPG].ccDosCountry> eq 7>                   ;150931;
           .if  <AX eq 2900H>                                          ;150931;
              mov  AX,29F0H                                            ;150931;
              jmp  LabCyr                                              ;150931;
           .endif                                                      ;150931;
           .if  <AX eq 3500H>                                          ;150931;
              mov  AX,35F0H                                            ;150931;
              jmp  LabCyr                                              ;150931;
           .endif                                                      ;150931;
        .endif                                                         ;150931;
;endif                                                                 ;150931;
;if CYRILLIC or LATIN2                                                 ;150931;
        .if     <<cs:[KEYRD_Func]> ne 0> near                          ;81250;;150931;
           .if     <AL eq 0E0h> near                                   ;81250;;150931;
              .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 855>          ;150931;
                .if  <AH eq 1FH>                                       ;150931;
                  jmp  LabCyr                                          ;150931;
                .else near                                             ;150931;
                  jmp  LabHun                                          ;150931;
                .endif                                                 ;150931;
              .else near                                               ;150931;
                .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 866>        ;150931;
                  .if  <AH eq 23H> or                                  ;150931;
                  .if  <AH eq 2CH>                                     ;150931;
                    jmp LabCyr                                         ;150931;
                  .else near                                           ;150931;
                    jmp short LabHun                                   ;150931;
                  .endif                                               ;150931;
                .else                                                  ;150931;
                  .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 915>      ;150931;
                    .if  <AH eq 13H> or                                ;150931;
                    .if  <AH eq 23H> or                                ;150931;
                    .if  <AH eq 33H>                                   ;150931;
                      jmp  short LabCyr                                ;150931;
                    .else                                              ;150931;
                      jmp  short LabHun                                ;150931;
                    .endif                                             ;150931;
                  .else                                                ;150931;
                    .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 852> and ;150931;
                    .if  <<cs:[COUNTRY_CDPG].ccDosCountry> eq 48>      ;150931;
                      .if  <AH eq 18H>                                 ;150931;
                        jmp  short LabCyr                              ;150931;
                      .else                                            ;150931;
                        jmp  short LabHun                              ;150931;
                      .endif                                           ;150931;
                    .else                                              ;150931;
                      .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 921>  ;150931;
                        .if  <AH eq 30H> or                            ;150931;
                        .if  <AH eq 16H> or                            ;150931;
                        .if  <AH eq 52H>                               ;150931;
                          jmp  short LabCyr                            ;150931;
                        .else                                          ;150931;
                          jmp  short LabHun                            ;150931;
                        .endif                                         ;150931;
                      .else                                            ;150931;
                        .if  <<cs:[COUNTRY_CDPG].ccSysCodePage> ne 852> or ;150931;
                        .if   <AH ne 0DH> and                          ;150931;
                        .if   <AH ne 55H>                              ;150931;
LabHun:                                                                ;150931;
                           .if     <NONZERO ah>                        ;150931;
                              xor     al,al                            ;150931;
                              mov     cs:[ALTAH],ah       ;STORE SPECIAL KEY ;150931;
                           .endif                                      ;150931;
                           ret                                         ;150931;
                        .endif                                         ;150931;
                      .endif                                           ;150931;
                    .endif                                             ;150931;
                  .endif                                               ;150931;
                .endif                                                 ;150931;
              .endif                                                   ;150931;
           .endif                                                      ;81250;;150931;
        .endif                                                         ;81250;;150931;
;else
;        .if     <<cs:[KEYRD_Func]> ne 0>                               ;81250;;150931;
;           .if     <AL eq 0E0h>                                        ;81250;;150931;
;              .if  <<cs:[COUNTRY_CDPG].ccSysCodePage> ne 852> or       ;81250;;150931;
;              .if   <AH ne 0DH> and                                    ;81250;;150931;
;              .if   <AH ne 55H>                                        ;81250;;150931;
;                 .if     <NONZERO ah>                                  ;81250;;150931;
;                    xor     al,al                                      ;81250;;150931;
;                    mov     cs:[ALTAH],ah       ;STORE SPECIAL KEY     ;81250;;150931;
;                 .endif                                                ;81250;;150931;
;                 ret                                                   ;81250;;150931;
;              .endif                                                   ;81250;;150931;
;           .endif                                                      ;81250;;150931;
;        .endif                                                         ;81250;;150931;
;endif                                                                 ;150931;

;if CYRILLIC or LATIN2                                                 ;150931;
LabCyr:                                                                ;150931;
;endif                                                                 ;150931;

        .if     <ZERO al>               ;SPECIAL CASE?
          mov     cs:[ALTAH],AH         ;STORE SPECIAL KEY
        .endif
KEYRET:
        ret
CHRIN   ENDP

;--------------------------------------------------------------
;
;       KEYBOARD NON DESTRUCTIVE READ, NO WAIT
;
; PC-CONVERTIBLE-TYPE MACHINE: IF BIT 10 IS SET BY THE DOS IN THE STATUS WORD
; OF THE REQUEST PACKET, AND THERE IS NO CHARACTER IN THE INPUT BUFFER, THE
; DRIVER ISSUES A SYSTEM WAIT REQUEST TO THE ROM. ON RETURN FROM THE ROM, IT
; RETURNS A 'CHAR-NOT-FOUND' TO THE DOS.
;
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        public  CON$RDND
CON$RDND proc   near

        .repeat

          mov     al,cs:[ALTAH]
          or      al,al
;if CYRILLIC or LATIN2                                              ;150931;
          jz      RDEXITc                                           ;150931;
          jmp     RDEXIT                                            ;150931;
RDEXITc:                                                            ;150931;
;else                                                               ;150931;
;          jnz     short RDEXIT                                     ;150931;
;endif                                                              ;150931;

          mov     ah,cs:[KEYSTS_Func]
          int     16h
          .if     z

            .if     <<cs:[FHAVEK09]> eq 0> or
            .if     <BIT <ds:[bx].PktStatus> nand 0400h>  ;SYSTEM WAIT ENABLED?
            .else
              ;********************************
              ; NEED TO WAIT FOR IBM RESPONSE TO REQUEST FOR
              ; CODE ON HOW TO USE THE SYSTEM WAIT CALL.
              ;********************************
              mov     ax,4100h          ; WAIT ON AN EXTERNAL EVENT
              xor     bl,bl             ; M055; wait for any event
              int     15h               ; CALL ROM FOR SYSTEM WAIT
            .endif

            mov     ah,3                ;done+busy
            ret
          .endif

          .leave  <NONZERO ax>          ;CHECK FOR NULL AFTER BREAK

          mov     ah,cs:[KEYRD_Func]
          int     16h

        .until

;if CYRILLIC or LATIN2                                                 ;150931;
        .if     <AX eq 7200h>           ;CHECK FOR CTRL-PRTSC          ;150931;
          mov     al,'P' and 1Fh    ;=16  =ctrl-P                      ;150931;
        .else near                                                     ;150931;
          .if     <<cs:[KEYRD_Func]> ne 0> near                        ;150931;
             .if     <AL eq 0E0h> near                                 ;150931;
                .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 855>        ;150931;
                  .if  <AH eq 1FH>                                     ;150931;
                    jmp  RDEXIT                                        ;150931;
                  .else near                                           ;150931;
                    jmp  LabHun1                                       ;150931;
                  .endif                                               ;150931;
                .else near                                             ;150931;
                  .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 866>      ;150931;
                    .if  <AH eq 23H> or                                ;150931;
                    .if  <AH eq 2CH>                                   ;150931;
                      jmp  short RDEXIT                                ;150931;
                    .else                                              ;150931;
                      jmp  short LabHun1                               ;150931;
                    .endif                                             ;150931;
                  .else                                                ;150931;
                    .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 915>    ;150931;
                      .if  <AH eq 13H> or                              ;150931;
                      .if  <AH eq 23H> or                              ;150931;
                      .if  <AH eq 33H>                                 ;150931;
                        jmp  short RDEXIT                              ;150931;
                      .else                                            ;150931;
                        jmp  short LabHun1                             ;150931;
                      .endif                                           ;150931;
                    .else                                              ;150931;
                      .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 852> and  ;150931;
                      .if  <<cs:[COUNTRY_CDPG].ccDosCountry> eq 48>        ;150931;
                        .if  <AH eq 18H>                                   ;150931;
                          jmp  short RDEXIT                                ;150931;
                        .else                                              ;150931;
                          jmp  short LabHun1                               ;150931;
                        .endif                                             ;150931;
                      .else                                                ;150931;
                        .if  <<cs:[COUNTRY_CDPG].ccDosCodePage> eq 921>    ;150931;
                          .if  <AH eq 30H> or                              ;150931;
                          .if  <AH eq 16H> or                              ;150931;
                          .if  <AH eq 52H>                                 ;150931;
                            jmp  short RDEXIT                              ;150931;
                          .else                                            ;150931;
                            jmp  short LabHun1                             ;150931;
                          .endif                                           ;150931;
                        .else                                              ;150931;
                          .if  <<cs:[COUNTRY_CDPG].ccSysCodePage> ne 852> or      ;150931;
                          .if   <AH ne 0DH> and                                   ;150931;
                          .if   <AH ne 55H>                                       ;150931;
LabHun1:                                                                          ;150931;
                             .if     <AH ne 0>   ; Scan code exist? Yes. Greek Alpha char. ;150931;
                                mov     al, 0    ; No. Extended key stroke. Change it for compatibility ;150931;
                             .endif                                                        ;150931;
                          .endif                                                           ;150931;
                        .endif                                                             ;150931;
                      .endif                                                               ;150931;
                    .endif                                                                 ;150931;
                  .endif                                                                   ;150931;
                .endif                                                                     ;150931;
             .endif                                                                        ;150931;
          .endif                                                                           ;150931;
        .endif                                                                             ;150931;
;else                                                                                      ;150931;
;        .if     <AX eq 7200h>           ;CHECK FOR CTRL-PRTSC                             ;150931;
;          mov     al,'P' and 1Fh    ;=16  =ctrl-P                                         ;150931;
;        .else                                                                             ;150931;
;          .if     <<cs:[KEYRD_Func]> ne 0> and   ; Extended Keyboard function? No. Normal exit. ;150931;
;;81250    .if     <AL eq 0E0h> and        ; Extended key value or Greek Alpha?            ;150931;
;          .if     <AL eq 0E0h>                                          ;81250;           ;150931;
;             .if  <<cs:[COUNTRY_CDPG].ccSysCodePage> ne 852> or         ;81250;           ;150931;
;             .if   <AH ne 0DH> and                                      ;81250;           ;150931;
;             .if   <AH ne 55H>                                          ;81250;           ;150931;
;                .if     <AH ne 0>   ; Scan code exist? Yes. Greek Alpha char.             ;150931;
;                   mov     al, 0    ; No. Extended key stroke. Change it for compatibility;150931;
;                .endif                                                                    ;150931;
;             .endif                                                     ;81250;           ;150931;
;          .endif                                                        ;81250;           ;150931;
;        .endif                                                                            ;150931;
;endif                                                                                     ;150931;
RDEXIT:
        mov     ds:[BX].IOMedia,al
        mov     ah,1                    ;=done
        ret
CON$RDND endp
;--------------------------------------------------------------
;
;       KEYBOARD FLUSH ROUTINE
;
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        PUBLIC  CON$FLUSHIN
CON$FLUSHIN proc near
        mov     cs:[ALTAH],0               ;CLEAR OUT HOLDING BUFFER
        .repeat              ; Is there a char there?
          mov     ah,1       ; command code for check status
          int     16h        ; call rom-bios keyboard routine
          .leave  z
          xor     ah,ah      ; if zf is nof set, get character
          int     16h        ; call rom-bios to get character
        .until
        mov     ah,1                    ;=done
        ret
CON$FLUSHIN endp
;-------------------------------------------------------------
;
;       CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE
;
;       CALLED VIA INT 29h
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        PUBLIC  OUTCHR
OUTCHR  PROC    FAR
        sti
        pusha
        mov     ah,0Eh                  ;set command to write a character
        mov     bx,7                    ;set foreground color
        int     10h                     ;call rom-bios
        popa
        iret
OUTCHR  ENDP
;----------------------------------------------------------
;
;       Break key handling
;
;       CALLED VIA INT 1Bh
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        PUBLIC  CBREAK
CBREAK  proc    far
        mov     cs:[ALTAH],3            ;indicate break key set
        iret
CBREAK  endp
;-----------------------------------------------
;
;       CONSOLE WRITE ROUTINE
;
;input:  DS:BX = Request header
;        ES:DI = transfer address
;        CX    = count
;        DX    = port #
;output: AX    = status word
;
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        public  CON$WRITE
CON$WRITE proc   near
        .if     ncxz
          mov     bx,word ptr cs:[OldInt10]
          mov     dx,word ptr cs:[OldInt10+2] ;DX:BX is original INT 10h vector
          sub     ax,ax
          mov     ds,ax
          .if     <BX eq <ds:[10h*4+0]>> and
          .if     <DX eq <ds:[10h*4+2]>>

            ; Make FAST output call to ROM BIOS (in reality, Video VDD)

            ;Note that it is a private INT 10h call, not a standard WRITESTRING
            ;call, which is why we only issue it as long as the INT 10h remains
            ;unhooked.  None of the standard WRITESTRING services allow us to
            ;use the attributes that are already on the screen, which is why we
            ;have to use something a little special.... -JTP

            mov     bp,di                   ;ES:BP -> string
            mov     ax,13FFh                ;AH = WRITESTRING, AL = subfunction
            int     10h                     ;CX = char count (must be NONZERO)
            or      al,al
            jnz     fast_write_ok
          .endif

          .repeat
            mov     al,es:[di]            ;get char
            inc     di
            int     29h                   ;output char
          .loop                           ;repeat until all through
        .endif

fast_write_ok:
        mov     ah,1                    ;=done
        ret
CON$WRITE endp
;-----------------------------------------------

V86CODE ENDS

        END
