        page ,132
        title  GETSET - GETting and SETting MS-DOS system calls

;********************************************************************** ;BN002;
; 23Jan92 - G.L.Fulk                                                    ;BN002;
; Enable the Swappable DOS data area feature.                           ;BN002;
;********************************************************************** ;BN002;
; 05Feb92 - G.L.Fulk                                                    ;BN003;
; Special function 64h, #5 added (get sft2 flags)                       ;BN003;
;********************************************************************** ;BN003;
; 22May92 - G.L.Fulk                                                    ;BN004;
; DOS fake version needs to come from the PDB.                          ;BN004;
;********************************************************************** ;BN004;
; 26May92 - G.L.Fulk                                                    ;BN005;
; Int 21h, 3001h support added (get DosInRom flag).                     ;BN005;
;********************************************************************** ;BN005;
; 28May92 - G.L.Fulk                                                    ;BD006;
; $SetExtendedError does not belong in this module.  It is a SrvCall    ;BD006;
; sub-function.                                                         ;BD006;
;********************************************************************** ;BD006;
;
; System Calls which get and set various things
;
;   $GET_VERSION
;   $GET_VERIFY_ON_WRITE
;   $SET_VERIFY_ON_WRITE
;   $INTERNATIONAL
;   $GET_DRIVE_FREESPACE
;   $GET_DMA
;   $SET_DMA
;   $GET_DEFAULT_DRIVE
;   $SET_DEFAULT_DRIVE
;   $GET_INTERRUPT_VECTOR
;   $SET_INTERRUPT_VECTOR
;   RECSET
;   $CHAR_OPER
;   $GetExtendedError                  DOS 3.3
;   Get_Global_CdPg                    DOS 4.0
;   $ECS_CALL                          DOS 4.0
;
;   Revision history:
;
;Local
; Tag   D/P     By Whom Date        Comment
;-----  -----   ------- ----------- --------------------------------
;
;               ARR     30-Mar-1983 Created
;A000                      Jan-1988 version 4.0
;A006   D503                        fake version for IBMCACHE
;A008   P4070                       fake version for MS WINDOWS
;               danno   14-Nov-1988 Modified for MVDM
;

.xlist
.xcref
include v86seg.inc
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include demver.inc
include dossymc.inc
include demdbcs.inc
include doscntry.inc
include demmult.inc
include error.inc
include demsvc.inc
include mvdmexp.inc
include dpl.inc
include pdb.inc
include intnat.inc
include mi.inc
include struc30.inc
.cref
.list


V86DATA SEGMENT

COUNTRYBUFFER   DB      SetCountryInfo                  ; MUST BE CONTIGUOUS
SIZE_NLS_BUFFER equ     258
NLSBUFFER       DB      SIZE_NLS_BUFFER DUP(0)          ;

                PUBLIC  NLSBUFFERSEG
NLSBLOCK        DB      0                               ; MUST BE CONTIGUOUS
                DW      OFFSET V86GROUP:NLSBUFFER       ;
NLSBUFFERSEG    DW      0                               ;

V86DATA ENDS

V86CODE    SEGMENT
        ASSUME  CS:V86GROUP

        CpuMode 8086

        ReferV86    VERFLG,BYTE
        ReferV86    CNTCFLAG,BYTE
        ReferV86    DMAADD,DWORD
        ReferV86    CURDRV,BYTE
        ReferV86    chSwitch,BYTE
        ReferV86    CDSCount,BYTE
        ReferV86    EXTERR,WORD
        ReferV86    EXTERR_ACTION,BYTE
        ReferV86    EXTERR_CLASS,BYTE
        ReferV86    EXTERR_LOCUS,BYTE
        ReferV86    EXTERRPT,DWORD
        ReferV86    CurrentPDB,WORD
        ReferV86    InterCon,BYTE               ; !0 if console mode == interim
        ReferV86    Country_CdPg,BYTE

        ReferV86    FILE_UCASE_TAB,BYTE
        ReferV86    UCASE_TAB,BYTE
        ReferV86    DBCS_TAB,BYTE

        EXTRN   GETLET3:NEAR
        EXTRN   TESTKANJ:NEAR
        EXTRN   get_user_stack:NEAR
        EXTRN   FCB_RET_ERR:NEAR
        EXTRN   Sys_Return:NEAR
        EXTRN   MAP_CASE:NEAR
        EXTRN   RMDevCheck:NEAR                                         ;BN003;
        EXTRN   pJFNFromHandle:NEAR                                     ;BN003;
        EXTRN   TXT_MSG_RESPONSE_DATA: byte
        EXTRN   SYS_RET_OK: NEAR
        EXTRN   SYS_RET_ERR: NEAR
        EXTRN   SYS_RET_ERR_AL: NEAR

;------------------------

subttl $Get_Version -- Return DOS version number
page
        procedure   $GET_VERSION,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Function:
;       Return DOS version number
; Inputs:
;       AL= BH flag
; Outputs:
;       Version number as AL.AH in binary
;       User number in BL:CX (24 bits)
;       OEM number in BH
;       NOTE: On pre 1.28 DOSs AL will be zero

        push    ax                                                      ;BN005;
        SVC     SVC_DEMGETVERSION
        ;return: AH,AL=major,minor version number
        ;        BH=OEM serial number
        ;        BL:CX=24-bit user serial number
        pop     dx                                                      ;BN005;
        .if     <DL eq 1>               ;if entry.AL==1 then return BH  ;BN005;
          xor   bh,bh                   ;  with only the DosInRom flag  ;BN005;
        .endif                          ;  (for us it's always false).  ;BN005;
        push    ds                                                      ;BN004;
        mov     ds,[CurrentPDB]                                         ;BN004;
        mov     bl,ds:[PDB_version_count]                               ;BN004;
        mov     dx,ax                                                   ;BN004;
        mov     ax,ds:[PDB_version]                                     ;BN004;
        .if     <NONZERO BL> and                                        ;BN004;
        .if     <BL ne -1>                                              ;BN004;
          dec     bl                                                    ;BN004;
          mov     ds:[PDB_version_count],bl                             ;BN004;
          .if     z                                                     ;BN004;
            mov     ds:[PDB_version],dx                                 ;BN004;
          .endif                                                        ;BN004;
        .endif                                                          ;BN004;
        pop     ds                                                      ;BN004;
        call    get_user_stack
        assume  ds:nothing
        mov     [si].user_BX,bx
        mov     [si].user_CX,cx
;BD004; cmp     [Fake_Count],0FFh
;BD004; jz      short reg
;BD004; .if     <[Fake_Count] ne 0>
;BD004;   dec     [Fake_Count]
;BD004;   reg:
;BD004;   .if     <[Special_version] ne 0>
;BD004;     mov     ax,[Special_version]
;BD004;   .endif
;BD004; .endif
        mov     [SI.user_AX],ax         ; Really only sets AH
        ret
EndProc $GET_VERSION

subttl $Get_Verify_on_Write - return verify-after-write flag
page
        procedure   $GET_VERIFY_ON_WRITE,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       none.
; Function:
;       returns flag
; Returns:
;       AL = value of VERIFY flag

        mov     al,[VERFLG]
        ret
EndProc $GET_VERIFY_ON_WRITE

subttl $Set_Verify_on_Write - Toggle verify-after-write flag
page
        procedure   $SET_VERIFY_ON_WRITE,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       AL = desired value of VERIFY flag
; Function:
;       Sets flag
; Returns:
;       None

        AND     AL,1
        MOV     [VERFLG],AL
        SVC     SVC_DEMSETWRITEVERIFY
        ret
EndProc $SET_VERIFY_ON_WRITE

subttl $International - return country-dependent information
page
;
; Inputs:
;       MOV     AH,International
;       MOV     AL,country      (al = 0 => current country)
;      [MOV     BX,country]
;       LDS     DX,block
;       INT     21
; Function:
;       give users an idea of what country the application is running
; Outputs:
;       IF DX != -1 on input (get country)
;         AL = 0 means return current country table.
;         0<AL<0FFH means return country table for country AL
;         AL = 0FF means return country table for country BX
;         No Carry:
;            Register BX will contain the 16-bit country code.
;            Register AL will contain the low 8 bits of the country code.
;            The block pointed to by DS:DX is filled in with the information
;            for the particular country.
;               BYTE  Size of this table excluding this byte and the next
;               BYTE  Country code represented by this table
;                       A sequence of n bytes, where n is the number specified
;                       by the first byte above and is not > internat_block_max,
;                       in the correct order for being returned by the
;                       INTERNATIONAL call as follows:
;               WORD    Date format 0=mdy, 1=dmy, 2=ymd
;               5 BYTE  Currency symbol null terminated
;               2 BYTE  thousands separator null terminated
;               2 BYTE  Decimal point null terminated
;               2 BYTE  Date separator null terminated
;               2 BYTE  Time separator null terminated
;               1 BYTE  Bit field.  Currency format.
;                       Bit 0.  =0 $ before #  =1 $ after #
;                       Bit 1.  no. of spaces between # and $ (0 or 1)
;               1 BYTE  No. of significant decimal digits in currency
;               1 BYTE  Bit field.  Time format.
;                       Bit 0.  =0 12 hour clock  =1 24 hour
;               DWORD   Call address of case conversion routine
;               2 BYTE  Data list separator null terminated.
;         Carry:
;            Register AX has the error code.
;       IF DX = -1 on input (set current country)
;         AL = 0 is an error
;         0<AL<0FFH means set current country to country AL
;         AL = 0FF means set current country to country BX
;         No Carry:
;           Current country SET
;           Register AL will contain the low 8 bits of the country code.
;         Carry:
;            Register AX has the error code.
;
;       NOTE    Set country information is restricted to setting of the
;               current country code, all others will be treated as
;               invalid.

        procedure   $INTERNATIONAL,NEAR   ; DOS 3.3
        ASSUME  DS:NOTHING,ES:NOTHING
        .if     <AL ne -1>
          MOV     BL,AL                 ; -1 means country code is in BX
          XOR     BH,BH                 ; Put AL country code in BX
        .endif
        PUSH    DS
        POP     ES
        PUSH    DX
        POP     DI                      ; User buffer to ES:DI
        context DS
        CMP     DI,-1
        JZ      short international_set
        .if     <ZERO bx>
          mov     si,offset V86GROUP:COUNTRY_CDPG
          JMP     SHORT international_copy
        .endif
        MOV     BP,0                    ; flag it for GetCntry only
        CALL    international_get
        JC      short errtn
        CMP     BX,0                    ; nlsfunc finished it ?
        JNZ     SHORT international_copy ; no, copy by myself
        MOV     BX,DX                   ; put country back
        JMP     SHORT international_ok3

international_get:
        mov     si,offset V86GROUP:COUNTRY_CDPG
        .if     <BX eq <[SI.ccDosCountry]>>  ; = current country id
          ret
        .endif
        mov     dx,bx
        xor     bx,bx                   ; bx = 0, default code page

        CMP     BP,0                    ; GetCntry ?
        JNZ     short interr            ; return error on set country code
        MOV     AX,ES
        MOV     DS,AX
        MOV     SI,DI                   ; (DS:SI) = user buffer
        MOV     CX,OLD_COUNTRY_SIZE     ; (CX) = size of buffer
        XOR     AL,AL                   ; get $INTERNATIONAL country info
        SVC     SVC_DEMGETCOUNTRYINFO
        MOV     [SI].Map_call.Segmt,cs
        MOV     [SI].Map_call.Offst,offset V86GROUP:MAP_CASE
chkok:
        .if     <AL eq 0>
          ret
        .endif
        stc                             ; set carry
        ret
interr:
        mov     al,-1                   ; flag nlsfunc error
        stc                             ; set carry
        ret

international_copy:
        MOV     BX,[SI.ccDosCountry]    ; = current country id
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG.ccDFormat
        MOV     CX,OLD_COUNTRY_SIZE
        REP     MOVSB                   ; copy country info
international_ok3:
        call    get_user_stack
        ASSUME  DS:NOTHING
        MOV     [SI.user_BX],BX
international_ok:
        mov     ax,bx                   ; return country code in AX too.
        jmp     SYS_RET_OK

international_set:
        ASSUME  DS:V86GROUP
        MOV     BP,1                    ; flag it for SetCodePage only
        CALL    international_get
        JNC     international_ok
errtn:
        CMP     AL,0FFH
        JZ      short errtn2
        jmp     SYS_RET_ERR_AL         ; return what we got from NLSFUNC
errtn2:
        error   error_Invalid_Function  ; NLSFUNC not existent

EndProc $INTERNATIONAL



subttl $GetExtCntry - return extended country-dependent information
page
;
; Inputs:
;       if AL >= 20H
;         AL= 20H    capitalize single char, DL= char
;             21H    capitalize string ,CX= string length
;             22H    capitalize ASCIIZ string
;             23H    YES/NO check, DL=1st char DH= 2nd char (DBCS)
;             80H bit 0 = use normal upper case table
;                     1 = use file upper case table
;          DS:DX points to string
;
;       else
;
;       MOV     AH,GetExtCntry   ; DOS 3.3
;       MOV     AL,INFO_ID      ( info type,-1  selects all)
;       MOV     BX,CODE_PAGE    ( -1 = active code page )
;       MOV     DX,COUNTRY_ID   ( -1 = active country )
;       MOV     CX,SIZE         ( amount of data to return)
;       LES     DI,COUNTRY_INFO ( buffer for returned data )
;       INT     21
; Function:
;       give users extended country dependent information
;       or capitalize chars
; Outputs:
;         No Carry:
;            extended country info is succesfully returned
;         Carry:
;            Register AX has the error code.
;            AX=0, NO    for YES/NO CHECK
;               1, YES


procedure $GetExtCntry,NEAR   ; DOS 3.3
        ASSUME  DS:NOTHING,ES:NOTHING
        .if     <AL b 20h>              ;is it one of the new Cap functions?
          jmp     notcap                ;  no, go to old routines
        .endif

        mov     bx,offset V86GROUP:UCASE_TAB+2 ; get normal upper case
        .if     <BIT AL and 80h>        ; which upper case table to use
          mov     bx,offset V86GROUP:FILE_UCASE_TAB+2 ; get file upper case
        .endif

        .if     <AL eq 20h>             ;cap one char?
          mov     al,dl                 ; set up AL
          call    GETLET3               ; upper case it
          call    get_user_stack        ; get user stack
          mov     byte ptr [SI.user_DX],AL ; user's DL=AL
          jmp     SYS_RET_OK
        .endif

        .if     <AL eq 23h>             ; check YES or NO?
          mov     ax,dx
          call    TESTKANJ              ; DBCS ?
          .if     z                     ;zr=no DBCS
            call    GETLET3             ;convert to uppercase
            mov     ah,' '
          .endif
          xor     dx,dx
          .if     <AX ne <word ptr [TXT_MSG_RESPONSE_DATA+2]>>  ;no
            inc     dx
            .if     <AX ne <word ptr [TXT_MSG_RESPONSE_DATA+0]>>  ;yes
              inc     dx
            .endif
          .endif
          mov     ax,dx
          jmp     SYS_RET_OK
        .endif

        mov     si,dx                   ; si=dx
        .if     <AL eq 21h>
          .if     <ncxz>                ; check count 0
            .repeat
              lodsb                     ; get char
              call    TESTKANJ          ; DBCS ?
              .if     nz                ; yes, DBCS found
                INC     SI              ; skip 2 chars
                DEC     CX              ; bad input, one DBCS char at end?
                .leave  Z               ; yes, bad
              .else                     ;no DBCS:
                call    GETLET3         ; upper case it
                mov     byte ptr [SI-1],AL ; store back
              .endif
            .loop
          .endif
          jmp     SYS_RET_OK
        .endif

        .if     <AL eq 22h>
          .repeat
            LODSB                       ; get char
            .leave  <ZERO AL>           ; end of string ?
            call    TESTKANJ            ; DBCS ?
            .if     nz                  ; yes DBCS:
              .leave  <<byte ptr [si]> eq 0>  ;bad input, one DBCS char at end?
              inc     si                ; skip 2 chars
            .else                       ;no DBCS:
              call    GETLET3           ; upper case it
              mov     byte ptr [SI-1],AL; store back
            .endif
          .until
          jmp     SYS_RET_OK
        .endif
        error   error_Invalid_Function  ; info type not found


notcap:
        .if     <CX b 5>                ; minimum size is 5
          error   error_Invalid_Function
        .endif

        context DS
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG
        .if     <DX eq -1>              ; active country ?
          MOV     DX,[SI.ccDosCountry]  ; get active country id
        .endif
        .if     <BX eq -1>              ; active code page?
          MOV     BX,[SI.ccDosCodePage] ; get active code page id
        .endif
        CMP     DX,[SI.ccDosCountry]    ; same as active country id?
        JNZ     short CHKNLS            ; no
        CMP     BX,[SI.ccDosCodePage]   ; same as active code page id?
        JNZ     short CHKNLS            ; no

        MOV     BX,[SI.ccSysCodePage]   ; bx = sys code page id
        PUSH    CX                      ; save cx
        MOV     CX,[SI.ccNumber_of_entries]
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG.ccSetUcase
        .repeat
          CMP     AL,[SI]               ; compare info type
          JZ      short FOUNDIT
          ADD     SI,5                  ; next entry
        .loop
        POP     CX
capinval:
        error   error_Invalid_Function  ; info type not found

FOUNDIT:
        movsb                           ; move info id byte
        pop     cx                      ; retsore char count
        .if     <AL ne 1> ;=SetCountryInfo  ; select country info type ?
          MOV     CX,4                  ; 4 bytes will be moved
          MOV     AX,5                  ; 5 bytes will be returned in CX
OK_RETN:
          REP     MOVSB                 ; copy info
          MOV     CX,AX                 ; CX = actual length returned
          MOV     AX,BX                 ; return sys code page in ax
GETDONE:
          call    get_user_stack        ; return actual length to user's CX
          mov     [SI.user_CX],cx
          jmp     SYS_RET_OK
        .endif

        SUB     CX,3                    ; size after length field
        .if     <<WORD PTR [SI]> b CX>  ; less than table size
          MOV     CX,WORD PTR [SI]      ; truncate to table size
        .endif
        MOV     ES:[DI],CX              ; copy actual length to user's
        ADD     DI,2                    ; update index
        ADD     SI,2
        MOV     AX,CX
        ADD     AX,3                    ; AX has the actual length
        JMP     OK_RETN                 ; go move it

;%%%%%%%
CHKNLS:
        PUSH    CX                      ; FOUNDIT pops CX off
        MOV     [NLSBLOCK],AL
        MOV     CX,SIZE_NLS_BUFFER
        MOV     SI,OFFSET V86GROUP:NLSBUFFER
        SVC     SVC_DEMGETCOUNTRYINFO
        .if     <ZERO al>               ; success ?
          MOV     AL,[NLSBLOCK]         ; (AL) = nls table type
          MOV     BX,[COUNTRY_CDPG].ccSysCodePage ; (BX) = system code page
          MOV     SI,OFFSET V86GROUP:NLSBLOCK
          .if     <AL eq 1>  ;=SetCountryInfo ; jump if not set country info
            MOV     SI,OFFSET V86GROUP:COUNTRYBUFFER
            .errnz  (NLSBUFFER - COUNTRYBUFFER) - 1
            MOV     [SI].(ccMono_ptr-ccSetCountryInfo).Segmt,cs
            MOV     [SI].(ccMono_ptr-ccSetCountryInfo).Offst,offset V86GROUP:MAP_CASE
          .endif
          JMP     FOUNDIT
        .endif
        POP     CX
        jmp     SYS_RET_ERR_AL         ; return what is got from NLSFUNC
;%%%%%%%
;dos6;  XOR     AH,AH
;dos6;  PUSH    AX                         ; save info type
;dos6;  POP     BP                         ; bp = info type
;dos6;  ;CallInstall NLSInstall,NLSFUNC,0 ; check if NLSFUNC in memory
;dos6;  mov     ax,1400h
;dos6;  int     2Fh
;dos6;  .if     <AL ne -1>
;dos6;    error   error_Invalid_Function
;dos6;  .endif
;dos6;  ;CallInstall GetExtInfo,NLSFUNC,2  ;get extended info
;dos6;  mov     ax,1402h
;dos6;  int     2Fh
;dos6;  .if     <ZERO AL>                  ; success ?
;dos6;    mov     ax,[SI.ccSysCodePage]   ; ax = sys code page id;smr;use ds;BUGBUG;check whether DS is OK after the above calls
;dos6;    jmp     GETDONE
;dos6;  .endif
;dos6;  jmp     SYS_RET_ERR            ; return what is got from NLSFUNC
;%%%%%%%

EndProc $GetExtCntry

subttl $GetSetCdPg - get or set global code page
page
;
; Inputs:
;       MOV     AH,GetSetCdPg   ; DOS 3.3
;       MOV     AL,n            ; n = 1 : get code page, n = 2 : set code page
;       MOV     BX,CODE_PAGE    ( set code page only)
;       INT     21
; Function:
;       get or set the global code page
; Outputs:
;         No Carry:
;            global code page is set    (set global code page)
;            BX = active code page id   (get global code page)
;            DX = system code page id   (get global code page)
;         Carry:
;            Register AX has the error code.


procedure   $GetSetCdPg,NEAR   ; DOS 3.3
        ASSUME  DS:NOTHING,ES:NOTHING
        context DS
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG
        CMP     AL,1                   ; get global code page
        JNZ     short setglpg                ; set global cod epage
        MOV     BX,[SI.ccDosCodePage]  ; get active code page id
        MOV     DX,[SI.ccSysCodePage]  ; get sys code page id
        call    get_user_stack
        ASSUME  DS:NOTHING
        MOV     [SI.user_BX],BX        ; update returned bx
        MOV     [SI.user_DX],DX        ; update returned dx
OK_RETURN:
        jmp     SYS_RET_OK


        ASSUME  DS:V86GROUP
setglpg:
        .if     <AL ne 2>
          error   error_Invalid_Function ; function not defined
        .endif
        MOV     DX,[SI.ccDosCountry]
        SVC     SVC_DEMSETCODEPAGE         ;set the code page
        MOV     [SI].ccMono_ptr.Segmt,cs
        MOV     [SI].ccMono_ptr.Offst,offset V86GROUP:MAP_CASE
        CMP     AL,0                       ; success ?
        JZ      OK_RETURN                  ; yes
        .if     <AL ne 65>
          jmp      SYS_RET_ERR_AL
        .endif
        MOV     AX,65
        MOV     [EXTERR],AX
        MOV     [EXTERR_ACTION],errACT_Ignore
        MOV     [EXTERR_CLASS],errCLASS_HrdFail
        MOV     [EXTERR_LOCUS],errLOC_SerDev
        jmp     SYS_RET_ERR

EndProc $GetSetCdPg



subttl $Get_Drive_Freespace -- Return bytes of free disk space on a drive
page
        procedure   $GET_DRIVE_FREESPACE,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       DL = Drive number
; Function:
;       Return number of free allocation units on drive
; Outputs:
;       BX = Number of free allocation units
;       DX = Total Number of allocation units on disk
;       CX = Sector size
;       AX = Sectors per allocation unit
;          = -1 if bad drive specified
; This call returns the same info in the same registers (except for FAT pointer)
;      as the old FAT pointer calls

        context DS
        SVC     SVC_DEMGETDRIVEFREESPACE
        .if     nc
          mov     ax,si                   ; (AX) = sectors per allocation unit
        .else
          invoke  FCB_RET_ERR
          mov     ax,-1
        .endif
        call    get_user_stack
        ASSUME  DS:NOTHING
        MOV     [SI.user_DX],DX
        MOV     [SI.user_CX],CX
        MOV     [SI.user_BX],BX
        MOV     [SI.user_AX],AX
        ret
EndProc $GET_DRIVE_FREESPACE



subttl  $Get_DMA, $Set_DMA -- Get/Set current DMA address
page

procedure   $GET_DMA,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       None
; Function:
;       Get DISK TRANSFER ADDRESS
; Returns:
;       ES:BX is current transfer address

        mov     bx,word ptr [DMAADD]
        mov     cx,word ptr [DMAADD+2]
        call    get_user_stack
        mov     [SI.user_BX],BX
        mov     [SI.user_ES],CX
        ret
EndProc $GET_DMA

procedure   $SET_DMA,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       DS:DX is desired new disk transfer address
; Function:
;       Set DISK TRANSFER ADDRESS
; Returns:
;       None

        MOV     WORD PTR [DMAADD],DX
        MOV     WORD PTR [DMAADD+2],DS
        push    ax
        SVC     SVC_DEMSETDTA
        pop     ax
        ret
EndProc $SET_DMA

subttl  $Get_Default_Drive, $Set_Default_Drive -- Set/Get default drive
page

procedure $GET_DEFAULT_DRIVE,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       None
; Function:
;       Return current drive number
; Returns:
;       AL = drive number

        mov     al,[CURDRV]
        ret
EndProc $GET_DEFAULT_DRIVE

procedure $SET_DEFAULT_DRIVE,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       DL = Drive number for new default drive
; Function:
;       Set the default drive
; Returns:
;       AL = Number of drives, NO ERROR RETURN IF DRIVE NUMBER BAD

        SVC     SVC_DEMSETDEFAULTDRIVE
        .if     nc
          mov     [CURDRV],DL
        .endif
        mov     al,[CDScount]
        ret
EndProc $SET_DEFAULT_DRIVE


subttl $Get_Interrupt_Vector - Get/Set interrupt vectors
page
        procedure   $GET_INTERRUPT_VECTOR,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       AL = interrupt number
; Function:
;       Get the interrupt vector
; Returns:
;       ES:BX is current interrupt vector

        call    RECSET
        LES     BX,DWORD PTR es:[bx]
        call    get_user_stack
        mov     [SI.user_BX],bx
        mov     [SI.user_ES],es
        ret
EndProc $GET_INTERRUPT_VECTOR

procedure   $SET_INTERRUPT_VECTOR,NEAR
        assume  ds:nothing,es:nothing

; Inputs:
;       AL = interrupt number
;       DS:DX is desired new interrupt vector
; Function:
;       Set the interrupt vector
; Returns:
;       None

        CALL    RECSET
        cli                             ; Watch out!!!!! Folks sometimes use
        mov     es:[bx],dx              ;   this for hardware ints (like timer).
        mov     es:[bx+2],ds
        sti
        ret
EndProc $SET_INTERRUPT_VECTOR


procedure   RECSET,NEAR

        xor     BX,BX
        mov     ES,BX
        mov     bl,al
        shl     bx,1
        shl     bx,1
        ret
EndProc recset

subttl $Char_Oper - hack on paths, switches so that xenix can look like PCDOS
page
;
; input:    AL = function:
;                   0 - read switch char
;                   1 - set switch char (char in DL)
;                   2 - read device availability
;                       Always returns available
;                   3 - set device availability
;                       No longer supported (NOP)
; output:   (get) DL - character/flag
;
procedure $CHAR_OPER,NEAR
        assume  ds:nothing,es:nothing
        context DS
        CMP     AL,1
        JB      short CharGetSw
        JZ      short CharSetSw
        CMP     AL,3
        JB      short CharGetDev
        JZ      short CharSetDev
        mov     al,-1
        ret
CharGetSw:
        mov     dl,chSwitch
        jmp     short CharSet
CharSetSw:
        mov     chSwitch,dl
        ret
CharGetDev:
        MOV     DL,-1
CharSet:
        call    Get_User_Stack
        ASSUME  DS:NOTHING
        mov     [SI.User_DX],dx
CharSetDev:
        ret
EndProc $CHAR_OPER

subttl $GetExtendedError - Return Extended DOS error code
page
;
; input:    None
; output:   AX = Extended error code (0 means no extended error)
;           BL = recommended action
;           BH = class of error
;           CH = locus of error
;           ES:DI = may be pointer
;
procedure $GetExtendedError,NEAR
        assume  ds:nothing,es:nothing
        Context DS
        MOV     AX,[EXTERR]
        LES     DI,[EXTERRPT]
        MOV     BX,WORD PTR [EXTERR_ACTION]     ; BL = Action, BH = Class
        MOV     CH,[EXTERR_LOCUS]
        call    get_user_stack
        assume  ds:nothing
        MOV     [SI.user_DI],DI
        MOV     [SI.user_ES],ES
        MOV     [SI.user_BX],BX
        MOV     [SI.user_CX],CX
        jmp     SYS_RET_OK
EndProc $GetExtendedError


;BD006; Break   <$SetExtendedError - set extended error for later retrieval>
;BD006;
;BD006; ;
;BD006; ; $SetExtendedError takes extended error information and loads it up
;BD006; ; for the next extended error call.  This is used by interrupt-level
;BD006; ; processors to mask their actions.
;BD006; ;
;BD006; ;   Inputs: DS:SI points to DPL which contains all registers
;BD006; ;   Outputs: none
;BD006; ;
;BD006;
;BD006; Procedure $SetExtendedError,near
;BD006;         assume  ds:nothing,es:nothing
;BD006;         mov     ax,[SI].dpl_AX
;BD006;         mov     [EXTERR],ax
;BD006;         MOV     AX,[SI].dpL_di
;BD006;         MOV     WORD PTR ExtErrPt,AX
;BD006;         MOV     AX,[SI].dpL_ES
;BD006;         MOV     WORD PTR ExtErrPt+2,AX
;BD006;         MOV     AX,[SI].dpL_BX
;BD006;         MOV     WORD PTR [EXTERR_ACTION],AX
;BD006;         MOV     AX,[SI].dpL_CX
;BD006;         mov     [EXTERR_LOCUS],ah
;BD006;         ret
;BD006; EndProc     $SetExtendedError

subttl $Get_Global_CdPg  - Return Global Code Page
page
;
; input:    None
; output:   AX = Global Code Page
;
procedure Get_Global_CdPg,NEAR
        assume  ds:nothing,es:nothing
        push    si
        mov     si,OFFSET V86GROUP:COUNTRY_CDPG
        mov     ax,[SI.ccDosCodePage]
        pop     si
        ret
EndProc Get_Global_CdPg


;-------------------------------Start of DBCS 2/13/KK
subttl  ECS_call - Extended Code System support function
page

ASSUME  DS:NOTHING, ES:NOTHING

        procedure   $ECS_call,NEAR

; Inputs:
;       AL = 0  get lead byte table
;               on return DS:SI has the table location
;
;       AL = 1  set / reset interim console flag
;               DL = flag (00H or 01H)
;               no return
;
;       AL = 2  get interim console flag
;               on return DL = current flag value
;
;       AL = OTHER then error, and returns with:
;               AX = error_invalid_function
;
;  NOTE: THIS CALL DOES GUARANTEE THAT REGISTER OTHER THAN
;        SS:SP WILL BE PRESERVED!

 IF  DBCS                                                                       ;AN000;
                                                                                ;AN000;
        or      al, al                  ; AL = 0 (get table)?                   ;AN000;
        je      short get_lbt                                                         ;AN000;
        cmp     al, SetInterimMode      ; AL = 1 (set / reset interim flag)?    ;AN000;
        je      short set_interim                                                     ;AN000;
        cmp     al, GetInterimMode      ; AL = 2 (get interim flag)?            ;AN000;
        je      short get_interim                                                     ;AN000;
        error   error_invalid_function                                          ;AN000;
                                                                                ;AN000;
get_lbt:                                ; get lead byte table                   ;AN000;
        push    ax                                                              ;AN000;
        push    bx                                                              ;AN000;
        push    ds                                                              ;AN000;
        context DS                                                              ;AN000;
        MOV     BX,offset V86GROUP:COUNTRY_CDPG.ccSetDBCS                       ;AN000;
        MOV     AX,[BX+1]               ; set EV address to DS:SI               ;AN000;
        MOV     BX,[BX+3]                                                       ;AN000;
        ADD     AX,2                    ; Skip Lemgth                           ;AN000;
        call    get_user_stack                                                  ;AN000;
        assume  ds:nothing                                                              ;AN000;
        MOV     [SI.user_SI], AX                                                ;AN000;
        MOV     [SI.user_DS], BX                                                ;AN000;
        pop     ds                                                              ;AN000;
        pop     bx                                                              ;AN000;
        pop     ax                                                              ;AN000;
        jmp     SYS_RET_OK

set_interim:                            ; Set interim console flag              ;AN000;
        push    dx                                                              ;AN000;
        and     dl,01                   ; isolate bit 1                         ;AN000;
        mov     [InterCon], dl                                                  ;AN000;
        push    ds                                                              ;AN000;
        mov     ds, [CurrentPDB]                                                ;AN000;
        mov     byte ptr ds:[PDB_InterCon], dl  ; update value in pdb           ;AN000;
        pop     ds                                                              ;AN000;
        pop     dx                                                              ;AN000;
        jmp     SYS_RET_OK

get_interim:                                                                    ;AN000;
        push    dx                                                              ;AN000;
        push    ds                                                              ;AN000;
        mov     dl,[InterCon]                                                   ;AN000;
        call    get_user_stack          ; get interim console flag              ;AN000;
        assume  ds:nothing                                                              ;AN000;
        mov     [SI.user_DX],DX                                                 ;AN000;
        pop     ds                                                              ;AN000;
        pop     dx                                                              ;AN000;
        jmp     SYS_RET_OK
 ELSE                                                                           ;AN000;
        .if     <ZERO AL>            ; AL = 0 (get table)?
          call    get_user_stack
          assume  ds:nothing
          MOV     [SI.user_SI], Offset V86GROUP:DBCS_TAB+2
          MOV     [SI.user_DS], CS
        .endif
        jmp     SYS_RET_OK

 ENDIF

EndProc $ECS_call

V86CODE ENDS

        END
