PAGE    ,132
TITLE   VDHSERV - Assembly interfaces of VDH services
NAME    VDHSERV
.386p

SCCSID equ "@(#)vdhserv.asm     6.16 92/01/30"

;***    VDHSERV.ASM
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989, 1992
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
;       Title:
;
;       VDH services and 'C' interfaces to 16:16 code
;
;       Description:
;
;       These interfaces are the bridges between VDH services
;       written in 'C' and kernel routines written in assembly.
;
;       Modification History:
;
;       88/12/20    SB  Created
;
;       01/09/92  MarkF                     Added Seamless Windows support
; 6.15  01/22/92  CP20 B731809 Jeff Muir    Fix for VDHDevIOCtl
;       01/30/92  CP20 AZ09655 Frank Schroeder Added extended error support
;       08/28/92  Felix Miro' added fix due to changed filesystem workers
;                 for Protected File Handles
; 1.4   01/18/93  r206 p059793 J. Muir      VDHRead VDHWrite to use ReadDo
; 1.5   03/20/93  r206 p063248 J. Grimm     Added MMIO perf hooks
;***********************************************************************;BN040;
;  29Jul93 - J.M.Hare    defect 71358                                   ;BN040;
; Add propogating of DOSFLAG through files system for exec_only test.   ;BN040;
;***********************************************************************;BN040;
;       06/24/94  r207 86481   TPL          Added VDHWaitRamSem for VWIN
;
;***********************************************************************;BN040;
;  27Jul94 - J.Luu       defect 87734                                   ;WIN32;
; Add new function VDHViewHandle to support Windows Win32s              :WIN32;
;***********************************************************************
;  19Sep94 - bjn
; Changed segment names for page tuning.
;***********************************************************************

INCL_NONE       equ     1                       ; don't include everything
INCL_TYPES      equ     1                       ; include basic types
INCL_DEF        equ     1                       ; include typedef macros
INCL_VDHALL     equ     1                       ; include VDH services

.xlist
        include fnomvdm.inc
        include dosseg.inc
        include basemaca.inc
        include osmaca.inc
        include osconst.inc
        include mi.inc
        include error.inc
        include error2.inc
        include dossymc.inc
        include sigdef.inc
        include except.inc
        include seldesc.inc
        include pgexport.inc
        include vmexport.inc
        include selxport.inc
        include argframe.inc
        include opncreat.inc
        include filemode.inc
        include infoseg.inc
        include tkexport.inc
        include dirent.inc
        include curdir.inc
        include find.inc
        include harderr.inc
        include devsym.inc
        include screen.inc
        include sft.inc
        include sem.inc
        include tkptda.inc
        include ioctl.inc
        include mvdm.inc
        include mvdmexp.inc
        include sched.inc    ;for class$ constants
        include kmode.inc
        include sysentry.inc
        include doshlp.inc      ;for DosHlpTmrSetRollover
        include mmpha.inc       ;MMIO perf hooks
        include pdb.inc         ;WIN32 VDHViewHandle 87734
.list

        ModName  vdhserv, FNO_VDHSERV_ASM

        CpuMode 386

        ReferGlobal     InterruptLevel,BYTE
        ReferGlobal     DHF,DWORD
        EXTRN16         w_OpenCreate
        EXTRN16         w_QHandType
        EXTRN16         w_16DevIOCtl
        EXTRN16         w_32DevIOCtl
        EXTRN16         w_FSCtl
        EXTRN16         w_PhysicalDisk
        EXTRN16         w_Close
;       EXTRN16         w_Read
;       EXTRN16         w_Write
        EXTRN16         ReadDo
        EXTRN16         w_LSeek
        EXTRN16         HardError
        EXTRN16         w_SetFgnd

        EXTRN16         w_RamSemWake
        EXTRN16         w_RamSemRequest
        EXTRN16         w_SemWait                                       ;86481
        EXTRN16         w_Dup                        ; win32 - see fhandle.asm
        EXTRN16         SFFromSFN
        EXTRN16         SFFromHandle
        EXTRN16         pJFNFromHandle
        EXTRN           FSD_Read:NEAR
        EXTRN           FSD_Write:NEAR

DefData IMPORT, GLOBAL, C
ULONG   fIsInitTime
PVOID   pTCBCur
PVOID   pPTDACur
EndData

DefCode IMPORT, GLOBAL, PASCAL
DefFn   vdmmAdjustError
DefFn   VDHSetError
DefFn   VDHAssertInitOnly
DefFn   VDHAssertTask
DefFn   VDHAssertTaskOnly
DefFn   VDHAssertVDMTaskOnly
DefFn   VDHAssertVDMTask
EndCode

DefCode IMPORT, GLOBAL, C
DefFn   SELLdrDesc
DefFn   SELFreeGDT
EndCode

DefCode IMPORT, GLOBAL
DefFn   ksemCreate
DefFn   ksemDestroy
DefFn   ksemQuery
DefFn   ksemResetEvent
DefFn   ksemPostEvent
DefFn   ksemWaitEvent
DefFn   ksemRequestMutex
DefFn   ksemReleaseMutex
EndCode

DefCode EXPORT, GLOBAL, PASCAL
DefFn   VDHQuerySem
DefFn   VDHResetEventSem
DefFn   VDHPostEventSem
EndCode

DefCode EXPORT, SWAP, PASCAL
DefFn   VDHOpen
DefFn   VDHClose
DefFn   VDHRead
DefFn   VDHWrite
DefFn   VDHSeek
DefFn   VDHDevIOCtl
DefFn   VDHFSCtl
DefFn   VDHPhysicalDisk
DefFn   VDHPopup
DefFn   VDHCreateSem
DefFn   VDHDestroySem
DefFn   VDHWaitEventSem
DefFn   VDHRequestMutexSem
DefFn   VDHReleaseMutexSem
DefFn   VDHSetTimer0
DefFn   VDHSetBoost
DefFn   VDHRequestRamSem        ;Seamless
DefFn   VDHWakeRamSem           ;Seamless
DefFn   VDHWaitRamSem           ;Seamless                               ;86481
DefFn   VDHViewHandle           ;win32                                  ;87734
EndCode

        FARCODE HIGH32
DefCode PRIVATE, SWAP, PASCAL

; Seamless windows support start

;***EP+ VDHWakeRamSem - Wake the waiters for this ramsem
;
;      Request the ram semaphore passed in from the VDM.
;
;      ENTRY
;
;
;
;      EXIT-SUCCESS
;          None.
;
;      EXIT-FAILURE
;          System Halt.
;              Not in VDM task context.
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
;      PCODE
;          Call w_RamSemWake
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHWakeRamSem,NEAR

        ArgVar  pVoid,DWORD
        ArgVar  flOldValue,DWORD

        EnterProc
        push    ebx
        push    esi
        push    edi
        push    ds
        push    es

;       Validate calling context
        ASSERTVDMTASKONLY

        mov     eax,pVoid
        mov     bx,ax
        shr     eax,16
        mov     edx,flOldValue

        push    bp
        CALL16  w_RamSemWake
        pop     bp

        xor     eax,eax
        inc     eax                     ; return TRUE
        pop     es
        pop     ds
        pop     edi
        pop     esi
        pop     ebx
        ExitProc
EndProc    VDHWakeRamSem

;***EP+ VDHRequestRamSem - Request the ram semaphore passed in from the VDM
;
;      Request the ram semaphore passed in from the VDM.
;
;      ENTRY
;
;
;
;      EXIT-SUCCESS
;          None.
;
;      EXIT-FAILURE
;          System Halt.
;              Not in VDM task context.
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
;      PCODE
;          Call w_RamSemRequest
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHRequestRamSem,NEAR

        ArgVar  pVoid,DWORD
        ArgVar  ulTimeOut,DWORD
        ArgVar  flOldValue,DWORD

        EnterProc
        push    ebx
        push    esi
        push    edi
        push    ds
        push    es

;       Validate calling context
        ASSERTVDMTASKONLY

        mov     eax,pVoid
        mov     bx,ax
        shr     eax,16
        mov     edi,ulTimeOut
        mov     cx,di
        shr     edi,16
        mov     edx,flOldValue

        push    bp
        CALL16  w_RamSemRequest
        pop     bp

        xor     eax,eax
        inc     eax                     ; return TRUE
        pop     es
        pop     ds
        pop     edi
        pop     esi
        pop     ebx
        ExitProc
EndProc    VDHRequestRamSem

; Start of 86481
;***EP+ VDHWaitRamSem -
;
;      Request the ram semaphore passed in from the VDM.
;
;      ENTRY
;
;
;
;      EXIT-SUCCESS
;          None.
;
;      EXIT-FAILURE
;          System Halt.
;              Not in VDM task context.
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
;      PCODE
;          Call w_RamSemWake
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHWaitRamSem,NEAR

        ArgVar  pVoid,DWORD
        ArgVar  Timeout,DWORD

        EnterProc
        push    ebx
        push    esi
        push    edi
        push    ds
        push    es

;       Validate calling context
        ASSERTVDMTASKONLY

        mov     eax,pVoid
        mov     bx,ax
        shr     eax,16
        mov     edi,ulTimeOut
        mov     cx,di
        shr     edi,16

        push    bp
        CALL16  w_SemWait
        pop     bp

        xor     eax,eax
        inc     eax                     ; return TRUE
        pop     es
        pop     ds
        pop     edi
        pop     esi
        pop     ebx
        ExitProc
EndProc    VDHWaitRamSem
; End of 86481

; Seamless windows support end
SWAP32_27 segment
;***EP+ VDHSetBoost - Set the boost for a VDM
;
;      Add or remove the boost for a VDM.
;
;      ENTRY
;          flBoost - if TRUE, add boost
;                    if FALSE, remove boost
;
;      EXIT-SUCCESS
;          None.
;
;      EXIT-FAILURE
;          System Halt.
;              Invalid handle or not in VDM task context.
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
;      PCODE
;          Call w_SetFgnd
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHSetBoost,NEAR

        ArgVar  flBoost,DWORD

        EnterProc
        push    ebx
        push    esi
        push    edi
        push    ds
        push    es

;       Validate calling context
        ASSERTVDMTASKONLY

        mov     eax,flBoost
        mov     edx,SCOPE_GIVEMSG
        or      eax,eax
        jnz     short doBoost
        mov     edx,SCOPE_TAKEMSG
doBoost:
        mov     bx,ss:[TKOPTDA.CurrTCB] ; get slot number
        mov     ax,ss:[bx].TCBNumber
        movzx   eax,ax

        CALL16  w_SetFgnd

        xor     eax,eax
        inc     eax                     ; return TRUE
        pop     es
        pop     ds
        pop     edi
        pop     esi
        pop     ebx
        ExitProc
EndProc    VDHSetBoost
SWAP32_27 ends

;***EP+ VDHOpen - Open a file/device
;
;      Open a file/device and return a handle.  This handle can be
;      used with VDHRead, VDHWrite, VDHSeek, VDHClose and VDHDevIOCtl
;
;      VDH front end to the file system worker routine for 32 bit DosOpen.
;      Refer to documentation for 32 bit DosOpen API for complete
;      specification of each parameter.
;
;      ENTRY
;          FileName (PSZ) - Filename is the ASCIIZ path name of the file
;                           or device name to be opened.
;
;          FileHandle (PHFILE) - FileHandle is where the system returns the
;                                file handle.
;
;          ActionTaken (PULONG) - ActionTaken is where the system returns a
;                                 description of the action taken as a result
;                                 of this function call. Possible actions
;                                 actions taken:
;                                                 1 - file existed
;                                                 2 - file created
;                                                 3 - file replaced
;
;          FileSize (ULONG) - FileSize is the new file's logical size (EOD)
;                             in bytes.
;
;          FileAttribute (ULONG) - FileAttribute is the file attribute bits,
;                                  used on file creation.
;
;          OpenFlag (ULONG) - OpenFlag specifies the action to be taken
;                             depending on whether or not the file exists.
;
;          OpenMode (ULONG) - OpenMode describes the mode of the open function.
;
;          EABuf (PEAOP2) - EABuf is the address of an EAOP2 structure or NULL.
;
;
;      EXIT-SUCCESS
;          returns TRUE (non-zero)
;
;      EXIT-FAILURE
;          returns FALSE (zero)
;          VDHGetError may return:
;              ERROR_DISK_FULL
;              ERROR_OPEN_FAILED
;              ERROR_FILE_NOT_FOUND
;              ERROR_INVALID_PARAMETER
;              ERROR_PATH_NOT_FOUND
;              ERROR_ACCESS_DENIED
;              ERROR_DRIVE_LOCKED
;              ERROR_NOT_DOS_DISK
;              ERROR_SHARING_BUFFER_EXCEEDED
;              ERROR_SHARING_VIOLATION
;              ERROR_INVALID_ACCESS
;              ERROR_CANNOT_MAKE
;              ERROR_TOO_MANY_OPEN_FILES
;              ERROR_NOT_ENOUGH_MEMORY
;          System Halt
;              If called other than at VDM task time, or if pszFileName
;              ptr is invalid
;
;      VDM TERMINATION IMPLICATIONS
;          Any handles the VDD opened for the terminating VDM must be
;          closed with VDHClose.
;
;      CONTEXT
;          VDM Task
;
;      NOTE
;          Using VDHOpen does not interfere in any way with the
;          handle space available to the VDM via INT 21h,
;          except that it does count against the system wide limit
;          on the number of open file handles.
;
;          The handles returned from INT 21h $Open and these VDHOpen
;          handles can not be used interchangably.
;
;          If pointers passed on this call are allocated from the stack
;          then you must use the SSToDS macro to make the pointer DS
;          relative.
;
;      PCODE
;

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHOpen,NEAR

        ArgVar    pszFile,DWORD
        ArgVar    pFileHandle,DWORD
        ArgVar    ActionTaken,DWORD
        ArgVar    FileSize,DWORD
        ArgVar    FileAttribute,DWORD
        ArgVar    OpenFlag,DWORD
        ArgVar    OpenMode,DWORD
        ArgVar    EABuf,DWORD

        LocalVar  vdhopen_sel,DWORD
        LocalVar  eabuf_sel,DWORD
        LocalVar  errCode,DWORD
        LocalVar  vdhopen_ArgFrame,<size Open3Struc>
        LocalVar  vdhopen_CurrentPDB,WORD

        EnterProc
        SaveReg <ebx,esi,edi>

;       Validate calling context
;@SEC   ASSERTVDMTASKONLY

;       We must clear the current PDB field so the file handle opened
;       here is not automaticly closed during PDB or VDM process
;       termination.  (see DOS_Abort).

        mov     esi,[pPTDACur]          ; (ESI) = pointer to PTDA
        sub     eax,eax                 ; (AX) = 0 = no PDB for this open
        xchg    ax,[esi].CurrentPDB     ; (AX) = current PDB
        mov     [vdhopen_CurrentPDB],ax ; save old PDB value

;       Get the length of the file name string for creating GDT Alias

        mov     edi,[pszFile]           ; by default, ES must equal DS already
        sub     al,al
        mov     ecx,-1
        repne   scasb
        not     ecx
        cmp     ecx,MAXPATHLEN
        mov     eax,ERROR_OPEN_FAILED
        ja      vdhopen2_error

;       Arrange the argument frame for w_OpenCreate

        mov     eax,FileSize
        mov     [vdhopen_ArgFrame].opn3s_Size,eax
        mov     eax,FileAttribute
        mov     [vdhopen_ArgFrame].opn3s_Attrs,ax
        mov     eax,OpenFlag
        mov     [vdhopen_ArgFrame].opn3s_Flag,ax
        mov     eax,OpenMode
        mov     [vdhopen_ArgFrame].opn3s_Mode,ax      ; Mode is the Low word
        shr     eax,16
        mov     [vdhopen_ArgFrame].opn3s_Mode2,ax     ; Mode2 is the High word

        xor     eax,eax
        mov     [vdhopen_sel],eax
        mov     [eabuf_sel],eax
        mov     [errCode],eax
        mov     [vdhopen_ArgFrame].opn3s_Reserved,eax
        mov     [vdhopen_ArgFrame].opn3s_NamePtr,eax
        mov     [vdhopen_ArgFrame].opn3s_HandlePtr,eax
        mov     [vdhopen_ArgFrame].opn3s_ActionPtr,eax
        mov     [vdhopen_ArgFrame].opn3s_EABufPtr,eax
        mov     [vdhopen_ArgFrame].opn3s_FileHandleLockIDPtr,eax

;   Grow selector for pszFile

        lea     edx,[vdhopen_sel]
        SSToDS  edx
        CCALL32 SELLdrDesc, <[pszFile], ecx, edx>
        or      eax,eax
        jz      short vdhopen_file
        jmp     vdhopen2_error                ; on error exit

vdhopen_file:
        mov     eax,[vdhopen_sel]                         ; move selector to
        shl     eax,16                                    ;  high word
        mov     [vdhopen_ArgFrame].opn3s_NamePtr,eax

;   Grow selector for EABuf

        mov     eax,EABuf                     ; Check for null ptr
        or      eax,eax
        jz      short vdhopen_yeseabufsel ; if null then do not create selector
        lea     edx,[eabuf_sel]
        SSToDS  edx
        CCALL32 SELLdrDesc, <[EABuf], 4, edx>
        or      eax,eax
        jz      short vdhopen_eabuf
        mov     [errCode],eax
        jmp     short freepszfile_sel         ; on error free up selectors

vdhopen_eabuf:
        mov     eax,[eabuf_sel]                             ; move selector to
        shl     eax,16                                      ;  high word
        mov     [vdhopen_ArgFrame].opn3s_EABufPtr,eax

vdhopen_yeseabufsel:
        mov     ah,attr_hidden+attr_system+attr_directory
        mov     al,OPCR_SATTR_INDIRECT
        lea     bx,[vdhopen_ArgFrame]   ; ArgFrame in SS:[bx]
        push    ds                      ; protect ds from w_OpenCreate
        push    es                      ; protect es from w_OpenCreate
        mov     dl,IFaceLevel2          ; DL = Interface Level (DosProtectOpen
                                        ; at level of w_OpenCreate worker)
        xor     dh,dh                   ; exec_only BN040
        and     dh, not EXECOPEN        ; set exec_only bit off exec_only BN040

        CALL16  w_OpenCreate
        pop     es                      ; restore es
        pop     ds                      ; restore ds
        jc      short vdhopenerr1       ; on error save bad return code
        inc     ax                      ; remember: our handles are +1
        mov     ecx,[pFileHandle]       ; dword ptr to word value
        mov     word ptr [ecx],ax       ; save handle
        mov     ecx,[ActionTaken]       ; dword ptr to word value
        mov     word ptr [ecx],bx       ; save action taken
        jmp     short freeeabuf_sel     ; free up selectors
vdhopenerr1:
        movzx   eax,ax
        mov     [errCode],eax

;   Free selector for EABuf

freeeabuf_sel:
        mov     eax,EABuf                     ; Check for null ptr
        or      eax,eax
        jz      short freepszfile_sel        ; if null then no selector to free
        CCALL32 SELFreeGDT, <[eabuf_sel]>

;   Free selector for pszFile

freepszfile_sel:
        CCALL32 SELFreeGDT, <[vdhopen_sel]>

        mov     eax,[errCode]
        or      eax,eax
        jz      short vdhopen2noerror

vdhopen2_error:
        call    vdmmAdjustError         ; retrieve hard error code
        PCall   VDHSetError, <eax>
        xor     eax,eax                 ; return NULL on error
        jmp     short vdhopen2_exit

vdhopen2noerror:
        inc     eax                     ; return non-zero on no error

vdhopen2_exit:
        mov     esi,[pPTDACur]          ; (ESI) = pointer to PTDA
        mov     cx,[vdhopen_CurrentPDB] ; (CX) = old PDB value
        mov     [esi].CurrentPDB,cx     ; restore PDB value
        RestoreReg  <edi,esi,ebx>
        ExitProc
EndProc VDHOpen

;***EP+ VDHClose - Close a file handle
;
;      Close a file opened with VDHOpen.
;
;      ENTRY
;          hfile - file handle
;
;      EXIT-SUCCESS
;          None.
;
;      EXIT-FAILURE
;          System Halt.
;              Invalid handle or not in VDM task context.
;
;      VDM TERMINATION IMPLICATIONS
;          Any handles opened by this VDD for the terminating VDM
;          must be closed.
;
;      CONTEXT
;          VDM Task
;
;      PCODE
;          Call w_Close
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHClose,NEAR

        ArgVar  hfile,WORD

        EnterProc
        push    ebx
        push    esi
        push    edi
        push    ds
        push    es

;       Validate calling context
        ASSERTVDMTASKONLY

        mov     bx,[hfile]
        dec     bx                     ; remember: our handles are +1
        push    ds
        push    es
        xor     cx,cx                   ; fake filehandlelockID lowword
        xor     dx,dx                   ; fake filehandlelockID highword
        CALL16  w_Close
        pop     es
        pop     ds
        jnc     short vdhclose_exit
;       Panic   <"VDHClose: Invalid handle">

vdhclose_exit:
        sub     eax,eax
        inc     eax                     ; return TRUE
        pop     es
        pop     ds
        pop     edi
        pop     esi
        pop     ebx
        ExitProc
EndProc    VDHClose

SWAP32_25 segment
;***EP+ VDHRead - Read bytes from a file/device
;
;      Read bytes from a file previously opened by VDHOpen.
;
;      ENTRY
;          hfile      - file handle
;          paddr      - pointer to buffer to be read
;          cbXfer     - count of bytes to read
;
;      EXIT-SUCCESS
;          returns count of bytes read (which can also be zero)
;
;      EXIT-FAILURE
;          returns 0xffffffff
;          VDHGetError may return:
;              ERROR_READ_FAULT (among others)
;          System Halt.
;              If handle is invalid or not in VDM Task context.
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHRead,NEAR

        ArgVar  hfile,WORD
        ArgVar  paddr,DWORD
        ArgVar  cbXfer,DWORD

       LocalVar sel,DWORD
        LocalVar cbTmp,DWORD
        LocalVar cbTotal,DWORD
        LocalVar errCode,DWORD

        mov     eax,ERROR_READ_FAULT
;
; VDH_IO is a common entry point for VDHRead and VDHWrite
;
VDH_IO:
        EnterProc
        mov     [errCode],eax
        push    ebx
        push    esi
        push    edi

;       Validate calling context
        ASSERTVDMTASKONLY

        sub     eax,eax
        mov     [cbTotal],eax

vdhxfer_more:
        mov     ecx,[cbXfer]
        cmp     ecx,65536               ; too large for one xfer?
        jb      short vdhxfer_countok
        sub     ecx,ecx
        dec     cx                      ; if so, set CX to 65535
vdhxfer_countok:
        mov     [cbTmp],ecx

        mov     [sel],0
        lea     edx,[sel]               ; get a selector for data area
        SSToDS  edx
        push    ecx
        CCALL32 SELLdrDesc, <[paddr], [cbTmp], edx>
        pop     ecx
        or      eax,eax
        mov     eax,[errCode]
        jnz     short vdhxfer_error

        push    ds                      ; save flat stuff
        push    es

        mov     ds,[sel]
        sub     edx,edx                 ; DS:DX points to buffer
        mov     bx,[hfile]
        dec     bx                      ; remember: our handles are +1
        push    ebp
;       xor     si,si                   ; fake filehandlelockID lowword
        xor     di,di                   ; fake filehandlelockID highword
        cmp     [errCode],ERROR_READ_FAULT
        jne     short vdhxfer_write
        mov     si,offset DOSHIGH2CODE:FSD_Read
;       CALL16  w_Read                  ; call worker routine to read
        jmp     short vdhxfer_start
vdhxfer_write:
        mov     si,offset DOSHIGH2CODE:FSD_Write ; INT 21 ver, CX=0 -> truncate
;       CALL16  w_Write                 ; call worker routine to write
vdhxfer_start:
        CALL16  ReadDo
        pop     ebp

        pop     es                      ; restore flat stuff
        pop     ds

        pushfd                          ; free selector
        push    eax
        CCALL32 SELFreeGDT, <[sel]>
        pop     eax
        popfd

        movzx   eax,ax
        jc      short vdhxfer_stop
        mov     ecx,eax
        add     [cbTotal],ecx           ; bump total xfer
        add     [paddr],ecx             ; change pointer into buffer
        sub     [cbXfer],ecx            ; reduce total remaining
        mov     eax,[cbTotal]
        jz      short vdhxfer_stop      ; we've finished the request

        cmp     [cbTmp],ecx             ; did we xfer all of cbTmp?
        je      vdhxfer_more            ; yes
                                        ; no, but carry should remain clear
vdhxfer_stop:

        jnc     short vdhxfer_exit
        cmp     eax,ERROR_INVALID_HANDLE
        jne     short vdhxfer_error
;       Panic   <"VDHRead/VDHWrite: Invalid handle">

vdhxfer_error:
        call    vdmmAdjustError         ; retrieve hard error code
        PCall   VDHSetError, <eax>
        sub     eax,eax
        dec     eax                     ; return 0xffffffff to indicate error

vdhxfer_exit:
        pop     edi
        pop     esi
        pop     ebx
        ExitProc
EndProc   VDHRead
SWAP32_25 ends

SWAP32_28 segment
;***EP+ VDHWrite - Write bytes to a file/device
;
;      Write bytes to a file previously opened by VDHOpen.
;
;      ENTRY
;          hfile      - file handle
;          paddr      - pointer to buffer to write
;          cbXfer     - count of bytes to write
;
;      EXIT-SUCCESS
;          returns count of bytes written (which can also be zero)
;
;      EXIT-FAILURE
;          returns 0xffffffff
;          VDHGetError may return:
;              ERROR_WRITE_FAULT (among others)
;          System Halt.
;              If handle is invalid or not in VDM Task context.
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHWrite,NEAR

        mov     eax,ERROR_WRITE_FAULT
        jmp     VDH_IO

EndProc   VDHWrite
SWAP32_28 ends

SWAP32_25 segment
;***EP+ VDHSeek - Move read/write file pointer for a handle
;
;      Seeks to specified position within file previously
;      opened by VDHOpen.
;
;      ENTRY
;          hfile      - file handle
;          offPos     - offset of new file pointer position
;          ultype     - move type (equates are in vdmm.inc)
;                VDHSK_ABSOLUTE - seek relative to beginning of file
;                VDHSK_CURRENT_POSITION - seek relative to current position
;                VDHSK_END_OF_FILE - seek relative to EOF
;
;      EXIT-SUCCESS
;          returns current (new) absolute position within file
;
;      EXIT-FAILURE
;          returns 0xffffffff
;          VDHGetError returns error code
;
;          System Halt.
;              If handle is invalid or not in VDM Task context.
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHSeek,NEAR

        ArgVar  hfile,WORD
        ArgVar  offPos,DWORD
        ArgVar  ultype,DWORD

        EnterProc
        push    ebx
        push    esi
        push    edi

;       Validate calling context
        ASSERTVDMTASKONLY

        mov     dx,word ptr offPos
        mov     cx,word ptr offPos+2
        mov     bx,[hfile]
        dec     bx                      ; remember: our handles are +1
        mov     eax,[ultype]
        cmp     eax,2
        jbe     short vdhseek_good_type
        mov     ebx,ERROR_INVALID_PARAMETER
        jmp     short vdhseek_error

vdhseek_good_type:
        push    ds
        push    es
        push    ebp
        xor     di,di                   ; fake low word of filehandlelockID
        xor     si,si                   ; fake high word of filehandlelockID
        CALL16  w_LSeek                 ; call worker routine to seek
        pop     ebp
        pop     es
        pop     ds
        movzx   ebx,ax
        pushfd
        rol     eax,16                  ; move AX to high word of EAX
        shrd    eax,edx,16              ; now DX:AX reside in EAX
        popfd
        jnc     short vdhseek_exit
        cmp     ebx,ERROR_INVALID_HANDLE
        jne     short vdhseek_error
;       Panic   <"VDHSeek: Invalid handle">

vdhseek_error:
        mov     eax,ebx
        call    vdmmAdjustError         ; retrieve hard error code
        PCall   VDHSetError, <eax>
        sub     eax,eax
        dec     eax                     ; return 0xffffffff to indicate error
        jmp     short vdhseek_exit

vdhseek_exit:
        pop     edi
        pop     esi
        pop     ebx
        ExitProc
EndProc   VDHSeek
SWAP32_25 ends

;***EP+ VDHDevIOCtl - I/O Control for devices
;
;      VDH front end to the file system worker routine for the 32 bit
;      DosDevIOCtl. Parameters and error return codes are identical to
;      the DosDevIOCtl API. Refer to documentation for 32 bit DosDevIOCtl
;      for complete specification of each parameter.
;
;      ENTRY
;          DevHandle (HFILE) - Device handle returned by VDHOpen.
;
;          Category (ULONG)  - Category of function to be performed.
;
;          Function (ULONG)  - Function within category to be performed.
;
;          ParmList (PVOID)  - Pointer to command-specific parameter area.
;
;          ParmLengthMax (ULONG) - Byte length of the maximum size of the
;                                  application input parameter area.
;                                  ParmLengthInOut may be longer than this
;                                  on input, but not on output.
;
;          ParmLengthInOut (PULONG) - Pointer to the length (in bytes) of the
;                                     parameters passed by the caller in
;                                    ParmList.
;
;          DataArea (PVOID)  - Pointer to a data area.
;
;          DataLengthMax (ULONG) - Byte length of the maximum size of the
;                                  data to be returned in DataArea.
;                                  DataLengthInOut may be longer than this
;                                  on input, but not on output.
;
;          DataLengthInOut (PULONG) - Pointer to the length (in bytes) of the
;                                     data passed by the caller in DataArea.
;
;      EXIT-SUCCESS
;          returns TRUE (non-zero)
;
;      EXIT-FAILURE
;          returns FALSE (zero)
;          VDHGetError may return:
;              ERROR_INVALID_HANDLE
;              ERROR_INVALID_FUNCTION
;              ERROR_INVALID_CATEGORY
;              ERROR_INVALID_DRIVE
;              ERROR_INVALID_PARAMETER
;          System Halt
;              If called other than at VDM task time
;
;      VDM TERMINATION IMPLICATIONS
;          None
;
;      CONTEXT
;          VDM Task Time
;
;      NOTE
;          If pointers passed on this call are allocated from the stack
;          then you must use the SSToDS macro to make the pointer DS
;          relative.
;
;          Addresses (pointers) inside of device specific data/parameter
;          packets are not translated.
;
;      PCODE
;          Set up argument frame
;          Grow selectors arguments
;          Call w_32DevIOCtl
;          Free selectors
;

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHDevIOCtl,NEAR

        ArgVar    DevHandle,WORD
        ArgVar    Category,DWORD
        ArgVar    Function,DWORD
        ArgVar    ParmList,DWORD
        ArgVar    ParmLengthMax,DWORD
        ArgVar    ParmLengthInOut,DWORD
        ArgVar    DataArea,DWORD
        ArgVar    DataLengthMax,DWORD
        ArgVar    DataLengthInOut,DWORD

        LocalVar  vdhdevioctl_ArgFrame,<size DIOCTL_Struc>
        LocalVar  errCode,DWORD

        EnterProc
        SaveReg <ebx,esi,edi>

;   Validate calling context
        ASSERTVDMTASKONLY

;   Arrange the argument frame for w_32DevIOCtl

;   VDHOpen handles are managed as one based even though w_OpenCreate
;   returns zero based handles. VDHPhysicalDisk handles are zero based
;   handles and are left that way. VDHPhysicalDisk handles are the only
;   handles that work with category 9 IOCtls. So, if the category is
;   9 the one-based adjustment is bypassed. There is also new support
;   that allows a handle of -1 to be passed. When the handle is -1
;   it is not decremented.

        mov     eax,Category
        mov     [vdhdevioctl_ArgFrame].DIOC_Category,ax
        mov     bx,ax                ; save category temporarily
        mov     ax,DevHandle
        cmp     ax,-1                ; Is this a -1 handle
        je      short vdhioctl_cat9  ; if yes then bypass decrement
        cmp     bx,IOC_PD            ; Bypass decrement if category 9
        je      short vdhioctl_cat9
        dec     ax                   ; VDHOpen handles are +1, adjust back
vdhioctl_cat9:
        mov     [vdhdevioctl_ArgFrame].DIOC_DevHandle,ax
        mov     eax,Function
        mov     [vdhdevioctl_ArgFrame].DIOC_Function,ax
        mov     eax,ParmLengthMax
        mov     [vdhdevioctl_ArgFrame].DIOC_ParmLenMax,ax
        mov     eax,DataLengthMax
        mov     [vdhdevioctl_ArgFrame].DIOC_DataLenMax,ax

        xor     eax,eax
        mov     [errCode],eax
        mov     [vdhdevioctl_ArgFrame].DIOC_pParm,eax
        mov     [vdhdevioctl_ArgFrame].DIOC_pParmLenInOut,eax
        mov     [vdhdevioctl_ArgFrame].DIOC_pData,eax
        mov     [vdhdevioctl_ArgFrame].DIOC_pDataLenInOut,eax

;   Grow selector for ParmList

        mov     eax,ParmList                  ; Check for null ptr
        or      eax,eax
        jz      short vdhioctl_parmlsel ; if null then do not create selector
        lea     edx,[vdhdevioctl_ArgFrame].DIOC_pParm
        SSToDS  edx
        CCALL32 SELLdrDesc, <[ParmList], [ParmLengthMax], edx>
        or      eax,eax
        jz      short vdhioctl_parm
        jmp     vdhdevioctlerror             ; on error exit

vdhioctl_parm:
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pParm    ; move selector to
        shl     eax,16                                   ;  high word
        mov     [vdhdevioctl_ArgFrame].DIOC_pParm,eax

vdhioctl_parmlsel:

;   Grow selector for ParmLengthInOut

        mov     eax,ParmLengthInOut           ; Check for null ptr
        or      eax,eax
        jz      short vdhioctl_parmliosel ; if null then do not create sel
        lea     edx,[vdhdevioctl_ArgFrame].DIOC_pParmLenInOut
        SSToDS  edx
        CCALL32 SELLdrDesc, <[ParmLengthInOut], 4, edx>
        or      eax,eax
        jz      short vdhioctl_parmlenio
        mov     [errCode],eax
        jmp     freeparmlist_sel             ; on error free up selectors

vdhioctl_parmlenio:
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pParmLenInOut   ; move selector to
        shl     eax,16                                          ;  high word
        mov     [vdhdevioctl_ArgFrame].DIOC_pParmLenInOut,eax

vdhioctl_parmliosel:

;   Grow selector for DataArea

        mov     eax,DataArea                             ; Check for null ptr
        or      eax,eax
        jz      short vdhioctl_datasel       ; if null then do not create sel
        lea     edx,[vdhdevioctl_ArgFrame].DIOC_pData
        SSToDS  edx
        CCALL32 SELLdrDesc, <[DataArea], [DataLengthMax], edx>
        or      eax,eax
        jz      short vdhioctl_data
        mov     [errCode],eax
        jmp     freeparmlengthinout_sel      ; on error free up selectors

vdhioctl_data:
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pData    ; move selector to
        shl     eax,16                                   ;  high word
        mov     [vdhdevioctl_ArgFrame].DIOC_pData,eax

vdhioctl_datasel:

;   Grow selector for DataLengthInOut

        mov     eax,DataLengthInOut                      ; Check for null ptr
        or      eax,eax
        jz      short vdhioctl_dataliosel    ; if null then do not create sel
        lea     edx,[vdhdevioctl_ArgFrame].DIOC_pDataLenInOut
        SSToDS  edx
        CCALL32 SELLdrDesc, <[DataLengthInOut], 4, edx>
        or      eax,eax
        jz      short vdhioctl_datalenio
        mov     [errCode],eax
        jmp     freedataarea_sel             ; on error free up selectors

vdhioctl_datalenio:
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pDataLenInOut ; move selector to
        shl     eax,16                                        ;  high word
        mov     [vdhdevioctl_ArgFrame].DIOC_pDataLenInOut,eax

vdhioctl_dataliosel:

;   Note: w_32DevIOCtl requires ss:bx to point to the parameter packet.
;         If TSDStackSize in ..\dosinc\tkexport.h is ever changed to be
;         greater than 0xFFFF then the high word of ebx will become
;         important.

        lea     ebx,[vdhdevioctl_ArgFrame]
        push    ds                            ; protect ds from w_32DevIOCtl
        push    es                            ; protect es from w_32DevIOCtl
        push    fs                            ; 6.15
        push    gs                            ; 6.15
        CALL16  w_32DevIOCtl
        pop     gs                            ; 6.15
        pop     fs                            ; 6.15
        pop     es
        pop     ds
        jnc     short freedatalengthinout_sel
vdhdevioctlerr1:
        movzx   eax,ax
        mov     [errCode],eax

;   Free selector for DataLengthInOut

freedatalengthinout_sel:
        mov     eax,DataLengthInOut           ; Check for null ptr
        or      eax,eax
        jz      short freedataarea_sel        ; if null then no selector to free
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pDataLenInOut
        shr     eax,16               ; move selector to low word for SELFreeGDT
        CCALL32 SELFreeGDT, <eax>

;   Free selector for DataArea

freedataarea_sel:
        mov     eax,DataArea                  ; Check for null ptr
        or      eax,eax
        jz      short freeparmlengthinout_sel ;if null then no selector to free
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pData
        shr     eax,16               ; move selector to low word for SELFreeGDT
        CCALL32 SELFreeGDT, <eax>

;   Free selector for ParmLengthInOut

freeparmlengthinout_sel:
        mov     eax,ParmLengthInOut          ; Check for null ptr
        or      eax,eax
        jz      short freeparmlist_sel       ; if null then no selector to free
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pParmLenInOut
        shr     eax,16               ; move selector to low word for SELFreeGDT
        CCALL32 SELFreeGDT, <eax>

;   Free selector for ParmList

freeparmlist_sel:
        mov     eax,ParmList                 ; Check for null ptr
        or      eax,eax
        jz      short vdhdevioctl_endfreesel ; if null then no selector to free
        mov     eax,[vdhdevioctl_ArgFrame].DIOC_pParm
        shr     eax,16               ; move selector to low word for SELFreeGDT
        CCALL32 SELFreeGDT, <eax>

vdhdevioctl_endfreesel:
        mov     eax,[errCode]
        or      eax,eax
        jz     short vdhdevioctlnoerror

vdhdevioctlerror:
        call    vdmmAdjustError         ; retrieve hard error code
        PCall   VDHSetError, <eax>
        xor     eax,eax                 ; return NULL on error
        jmp     short vdhdevioctlexit

vdhdevioctlnoerror:
        inc     eax                     ; return non-zero on no error

vdhdevioctlexit:
        RestoreReg  <edi,esi,ebx>
        ExitProc
EndProc VDHDevIOCtl

;***EP+ VDHFSCtl - Extended Standard API For FSD Interface
;
;  DESCRIPTION
;
;      VDH front end to the file system worker routine for the 32 bit
;      DosFSCtl. Parameters and error return codes are identical to
;      the DosFSCtl API. Refer to documentation for 32 bit DosFSCtl
;      for complete specification of each parameter.
;
;
;      ENTRY
;          DataArea (PVOID)         - Address of the data area.
;
;          DataLengthMax (ULONG)    - Byte length of the DataArea.
;                                     DataLengthInOut may be larger than this
;                                     on input, but not on output.
;
;          DataLengthInOut (PULONG) - On input, pointer to length in bytes of
;                                     data passed in DataArea.  On output,
;                                     pointer to length of bytes of data
;                                     returned by the FSD in DataArea.
;
;          ParmList (PVOID)         - Address of the command-specific parameter
;                                     list.
;
;          ParmLengthMax (ULONG)    - Byte length of the ParmList.
;                                     DataLengthInOut may be larger than this
;                                     on input, but not on output.
;
;          ParmLengthInOut (PULONG) - On input, pointer to length in bytes of
;                                     data passed in ParmList.  On output,
;                                     pointer to length of bytes of data
;                                     returned by the FSD in ParmList.
;
;          FunctionCode (ULONG)     - FSD-specific function code.
;                       0000 - 7FFF = OS/2 reserved.
;                       8000 - BFFF = local FSD defined.
;                       C000 - FFFF = server FSD defined.
;
;          RouteName (PSZ)          - Address of the ASCIIZ name of the FSD, or
;                                     the path name of a file or directory that
;                                     the operation applies to.
;
;          FileHandle (HFILE)       - File-specific or device-specific handle.
;
;          RouteMethod (ULONG)      - Selects how the request is routed.
;                 (FSCTL_HANDLE)  1 = called with file handle
;                (FSCTL_PATHNAME) 2 = called with pathname
;                 (FSCTL_FSDNAME) 3 = called with FSD name
;
;      EXIT-SUCCESS
;          returns TRUE (non-zero)
;
;      EXIT-FAILURE
;          returns FALSE (zero)
;          VDHGetError may return:
;              ERROR_INVALID_FUNCTION
;              ERROR_ACCESS_DENIED
;              ERROR_INVALID_HANDLE
;              ERROR_INVALID_PARAMETER
;              ERROR_INTERRUPT
;              ERROR_BUFFER_OVERFLOW
;              ERROR_INVALID_CATEGORY
;              ERROR_INVALID_LEVEL
;              ERROR_INVALID_FSD_NAME
;          System Halt
;              If called other than at VDM task time
;
;      VDM TERMINATION IMPLICATIONS
;          None
;
;      CONTEXT
;          VDM Task Time
;
;      NOTE
;
;          If pointers passed on this call are allocated from the stack
;          then you must use the SSToDS macro to make the pointer DS
;          relative.
;
;          Addresses (pointers) inside of device-specific data area/
;          parameter list are not translated.
;
;      PCODE
;

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHFSCtl,NEAR

        ArgVar    DataArea,DWORD
        ArgVar    DataLengthMax,DWORD
        ArgVar    DataLengthInOut,DWORD
        ArgVar    ParmList,DWORD
        ArgVar    ParmLengthMax,DWORD
        ArgVar    ParmLengthInOut,DWORD
        ArgVar    FunctionCode,DWORD
        ArgVar    RouteName,DWORD
        ArgVar    FileHandle,WORD
        ArgVar    RouteMethod,DWORD

        LocalVar  vdhfsctl_ArgFrame,<size FileSysCtlStruc>
        LocalVar  errCode,DWORD

        EnterProc
        SaveReg <ebx,esi,edi>

;   Validate calling context
        ASSERTVDMTASKONLY

;   Arrange the argument frame for w_FSCtl

        xor     eax,eax
        mov     [errCode],eax
        mov     [vdhfsctl_ArgFrame].FSC_pDataArea,eax
        mov     [vdhfsctl_ArgFrame].FSC_pDataLenOut,eax
        mov     [vdhfsctl_ArgFrame].FSC_pParmList,eax
        mov     [vdhfsctl_ArgFrame].FSC_pParmLenOut,eax
        mov     [vdhfsctl_ArgFrame].FSC_szRouteName,eax

;   Grow selector for DataArea

        mov     eax,DataArea                    ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_datasel          ; if null then do not create sel
        lea     edx,[vdhfsctl_ArgFrame].FSC_pDataArea
        SSToDS  edx
        CCALL32 SELLdrDesc, <[DataArea], [DataLengthMax], edx>
        or      eax,eax
        jz      short vdhfsctl_data
        jmp     vdhfsctlerror                   ; on error, exit

vdhfsctl_data:
        mov     eax,[vdhfsctl_ArgFrame].FSC_pDataArea    ; move selector to
        shl     eax,16                                   ;  high word
        mov     [vdhfsctl_ArgFrame].FSC_pDataArea,eax

vdhfsctl_datasel:

;   Grow selector for DataLengthInOut

        mov     eax,DataLengthInOut             ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_dataliosel       ; if null then do not create sel
        lea     edx,[vdhfsctl_ArgFrame].FSC_pDataLenOut
        SSToDS  edx
        CCALL32 SELLdrDesc, <[DataLengthInOut], 4, edx>
        or      eax,eax
        jz      short vdhfsctl_datalenio
        mov     [errCode],eax
        jmp     vdhfsctl_freedata_sel           ; on error free up selectors

vdhfsctl_datalenio:
        mov     eax,[vdhfsctl_ArgFrame].FSC_pDataLenOut  ; move selector to
        shl     eax,16                                   ;  high word
        mov     [vdhfsctl_ArgFrame].FSC_pDataLenOut,eax

vdhfsctl_dataliosel:

;   Grow selector for ParmList

        mov     eax,ParmList                    ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_parmlsel         ; if null then do not create sel
        lea     edx,[vdhfsctl_ArgFrame].FSC_pParmList
        SSToDS  edx
        CCALL32 SELLdrDesc, <[ParmList], [ParmLengthMax], edx>
        or      eax,eax
        jz      short vdhfsctl_parm
        mov     [errCode],eax
        jmp     vdhfsctl_freedatalen_sel        ; on error free up selectors

vdhfsctl_parm:
        mov     eax,[vdhfsctl_ArgFrame].FSC_pParmList    ; move selector to
        shl     eax,16                                   ;  high word
        mov     [vdhfsctl_ArgFrame].FSC_pParmList,eax

vdhfsctl_parmlsel:

;   Grow selector for ParmLengthInOut

        mov     eax,ParmLengthInOut             ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_parmliosel       ; if null then do not create sel
        lea     edx,[vdhfsctl_ArgFrame].FSC_pParmLenOut
        SSToDS  edx
        CCALL32 SELLdrDesc, <[ParmLengthInOut], 4, edx>
        or      eax,eax
        jz      short vdhfsctl_parmlenio
        mov     [errCode],eax
        jmp     vdhfsctl_freeparm_sel           ; on error free up selectors

vdhfsctl_parmlenio:
        mov     eax,[vdhfsctl_ArgFrame].FSC_pParmLenOut  ; move selector to
        shl     eax,16                                   ;  high word
        mov     [vdhfsctl_ArgFrame].FSC_pParmLenOut,eax

vdhfsctl_parmliosel:

        mov     eax,DataLengthMax
        mov     [vdhfsctl_ArgFrame].FSC_cbDataLength,ax
        mov     eax,ParmLengthMax
        mov     [vdhfsctl_ArgFrame].FSC_cbParmLength,ax
        mov     eax,FunctionCode
        mov     [vdhfsctl_ArgFrame].FSC_iFunction,ax

;   Grow selector for RouteName

        mov     eax,RouteName                   ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_routesel         ; if null then do not create sel
        lea     edx,[vdhfsctl_ArgFrame].FSC_szRouteName
        SSToDS  edx
        CCALL32 SELLdrDesc, <[RouteName], [MAXPATHLEN], edx>
        or      eax,eax
        jz      short vdhfsctl_route
        mov     [errCode],eax
        jmp     vdhfsctl_freeparmlen_sel        ; on error free up selectors

vdhfsctl_route:
        mov     eax,[vdhfsctl_ArgFrame].FSC_szRouteName  ; move selector to
        shl     eax,16                                   ;  high word
        mov     [vdhfsctl_ArgFrame].FSC_szRouteName,eax

vdhfsctl_routesel:

;   VDHOpen handles are managed as one based even though w_OpenCreate
;   returns zero based handles.  Must decrement VDHOpen handles.  There
;   is also new support that allows a handle of -1 to be passed.  When
;   the handle is -1 it is not decremented.

;   Note: w_FSCtl requires ax = routemethod and cx = file handle.

        mov     cx,FileHandle
        cmp     cx,-1                           ; Is this a -1 handle
        je      short vdhfsctl_neg              ; if yes then bypass decrement
        dec     cx                        ; VDHOpen handles are +1, adjust back
vdhfsctl_neg:
        mov     [vdhfsctl_ArgFrame].FSC_iFileHandle,cx
        mov     eax,RouteMethod
        mov     [vdhfsctl_ArgFrame].FSC_iRouteMethod,ax

;   Note: w_FSCtl requires ss:bx to point to the parameter packet.
;         If TSDStackSize in ..\dosinc\tkexport.h is ever changed to be
;         greater than 0xFFFF then the high word of ebx will become
;         important.

        lea     ebx,[vdhfsctl_ArgFrame]
        push    ds                              ; protect ds from w_FSCtl
        push    es                              ; protect es from w_FSCtl
        push    fs
        push    gs
        CALL16  w_FSCtl
        pop     gs
        pop     fs
        pop     es
        pop     ds
        jnc     short vdhfsctl_freeroutename_sel
vdhfsctlerr1:
        movzx   eax,ax
        mov     [errCode],eax

;   Free selector for RouteName

vdhfsctl_freeroutename_sel:
        mov     eax,RouteName                   ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_freeparmlen_sel  ; if null - no selector to free
        mov     eax,[vdhfsctl_ArgFrame].FSC_szRouteName
        shr     eax,16                          ; move sel to low word for
        CCALL32 SELFreeGDT, <eax>               ;  SELFreeGDT

;   Free selector for ParmLengthInOut

vdhfsctl_freeparmlen_sel:
        mov     eax,ParmLengthInOut             ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_freeparm_sel     ; if null - no selector to free
        mov     eax,[vdhfsctl_ArgFrame].FSC_pParmLenOut
        shr     eax,16                          ; move sel to low word for
        CCALL32 SELFreeGDT, <eax>               ;  SELFreeGDT

;   Free selector for ParmList

vdhfsctl_freeparm_sel:
        mov     eax,ParmList                    ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_freedatalen_sel  ; if null - no selector to free
        mov     eax,[vdhfsctl_ArgFrame].FSC_pParmList
        shr     eax,16                          ; move sel to low word for
        CCALL32 SELFreeGDT, <eax>               ;  SELFreeGDT

;   Free selector for DataLengthInOut

vdhfsctl_freedatalen_sel:
        mov     eax,DataLengthInOut             ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_freedata_sel     ; if null - no selector to free
        mov     eax,[vdhfsctl_ArgFrame].FSC_pDataLenOut
        shr     eax,16                          ; move sel to low word for
        CCALL32 SELFreeGDT, <eax>               ;  SELFreeGDT

;   Free selector for DataArea

vdhfsctl_freedata_sel:
        mov     eax,DataArea                    ; Check for null ptr
        or      eax,eax
        jz      short vdhfsctl_endfreesel       ; if null - no selector to free
        mov     eax,[vdhfsctl_ArgFrame].FSC_pDataArea
        shr     eax,16                          ; move sel to low word for
        CCALL32 SELFreeGDT, <eax>               ;  SELFreeGDT

vdhfsctl_endfreesel:
        mov     eax,[errCode]
        or      eax,eax
        jz      short vdhfsctlnoerror

vdhfsctlerror:
        call    vdmmAdjustError         ; retrieve hard error code
        PCall   VDHSetError, <eax>
        xor     eax,eax                 ; return NULL on error
        jmp     short vdhfsctlexit

vdhfsctlnoerror:
        inc     eax                     ; return non-zero on no error

vdhfsctlexit:
        RestoreReg  <edi,esi,ebx>
        ExitProc
EndProc VDHFSCtl

;***EP+ VDHPhysicalDisk - Get Information about Partitionable Disks
;
;      DosPhysicalDisk
;
;      ENTRY
;          Function (ULONG)  - Type of information on the
;                             partitionable disk(s) to obtain:
;                              1 = Obtain the total number of
;                                  partitionable disks
;                              2 = Obtain a handle to use with
;                                  Category 9 IOCtls
;                              3 = Release a handle for a
;                                  partitionable disk
;
;          DataPtr  (PULONG) -  Pointer to the return buffer
;
;          DataLen  (ULONG)  -  Length of the return buffer
;
;          ParmPtr  (PULONG) -  Pointer to the user-supplied info
;
;          ParmLen  (ULONG)  -  Length of user-supplied info
;
;
;      EXIT-SUCCESS
;          returns TRUE (non-zero)
;
;      EXIT-FAILURE
;          returns FALSE (zero)
;          VDHGetError may return:
;              ERROR_INVALID_FUNCTION
;              ERROR_ACCESS_DENIED
;              ERROR_INVALID_HANDLE
;              ERROR_LOCK_VIOLATION
;              ERROR_INVALID_PARAMETER
;
;          System Halt
;              If called other than at VDM task time
;
;      VDM TERMINATION IMPLICATIONS
;          None
;
;      CONTEXT
;          VDM Task Time
;
;      NOTE
;          If pointers passed on this call are allocated from the stack
;          then you must use the SSToDS macro to make the pointer DS
;          relative.
;
;          Addresses (pointers) inside of device specific data/parameter
;          packets are not translated.
;
;      PCODE
;          Set up argument frame
;          Grow selectors arguments
;          Call w_PhysicalDisk
;          Free selectors
;

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHPhysicalDisk,NEAR

        ArgVar    Function,DWORD
        ArgVar    DataPtr,DWORD
        ArgVar    DataLen,DWORD
        ArgVar    ParmPtr,DWORD
        ArgVar    ParmLen,DWORD

        LocalVar  vdhphysdisk_ArgFrame,<size DosPhysDiskStruc>
        LocalVar  errCode,DWORD

        EnterProc
        SaveReg <ebx,esi,edi>

;   Validate calling context
        ASSERTVDMTASKONLY

;   Arrange the argument frame for w_PhysicalDisk

        mov     eax,DataLen
        mov     [vdhphysdisk_ArgFrame].dpd_RetBufLen,ax
        mov     eax,ParmLen
        mov     [vdhphysdisk_ArgFrame].dpd_UsrInfoLen,ax
        mov     eax,Function
        mov     [vdhphysdisk_ArgFrame].dpd_PDRCatg,ax

        xor     eax,eax
        mov     [errCode],eax
        mov     [vdhphysdisk_ArgFrame].dpd_RetBufPtr,eax
        mov     [vdhphysdisk_ArgFrame].dpd_UsrInfoPtr,eax

;   Grow selector for DataPtr

        mov     eax,DataPtr               ; Check for null ptr
        or      eax,eax
        jz      short vdhphys_datasel     ; if null then do not create selector
        lea     edx,[vdhphysdisk_ArgFrame].dpd_RetBufPtr
        SSToDS  edx
        CCALL32 SELLdrDesc, <[DataPtr], [DataLen], edx>
        or      eax,eax
        jz      short vdhphys_data
        jmp     vdhphysicaldiskerror             ; on error exit

vdhphys_data:
        mov     eax,[vdhphysdisk_ArgFrame].dpd_RetBufPtr  ; move selector to
        shl     eax,16                                       ;  high word
        mov     [vdhphysdisk_ArgFrame].dpd_RetBufPtr,eax

vdhphys_datasel:

;   Grow selector for ParmPtr

        mov     eax,ParmPtr              ; Check for null ptr
        or      eax,eax
        jz      short vdhphys_parmsel    ; if null then do not create sel
        lea     edx,[vdhphysdisk_ArgFrame].dpd_UsrInfoPtr
        SSToDS  edx
        CCALL32 SELLdrDesc, <[ParmPtr], [ParmLen], edx>
        or      eax,eax
        jz      short vdhphys_parm
        mov     [errCode],eax
        jmp     freedataPtr_sel             ; on error free up selectors

vdhphys_parm:
        mov     eax,[vdhphysdisk_ArgFrame].dpd_UsrInfoPtr ;move selector
        shl     eax,16                                       ;to high word
        mov     [vdhphysdisk_ArgFrame].dpd_UsrInfoPtr,eax

vdhphys_parmsel:

;   Note: w_PhysicalDisk requires ss:bx to point to the parameter packet.
;         If TSDStackSize in ..\dosinc\tkexport.h is ever changed to be
;         greater than 0xFFFF then the high word of ebx will become
;         important.

        lea     ebx,[vdhphysdisk_ArgFrame]
        mov     eax,Function                  ; type of information requested
        push    ds                            ; protect ds from w_PhysicalDisk
        push    es                            ; protect es from w_PhysicalDisk
        CALL16  w_PhysicalDisk
        pop     es
        pop     ds
        jnc     short freeparmPtr_sel
vdhphysicaldiskerr1:
        movzx   eax,ax
        mov     [errCode],eax

;   Free selector for ParmPtr

freeparmPtr_sel:
        mov     eax,ParmPtr          ; Check for null ptr
        or      eax,eax
        jz      short freedataPtr_sel ; if null then no selector to free
        mov     eax,[vdhphysdisk_ArgFrame].dpd_UsrInfoPtr
        shr     eax,16               ; move selector to low word for SELFreeGDT
        CCALL32 SELFreeGDT, <eax>

;   Free selector for DataPtr

freedataPtr_sel:
        mov     eax,DataPtr           ; Check for null ptr
        or      eax,eax
        jz      short vdhphysicaldisk_endfreesel ; if null then no selector to free
        mov     eax,[vdhphysdisk_ArgFrame].dpd_RetBufPtr
        shr     eax,16               ; move selector to low word for SELFreeGDT
        CCALL32 SELFreeGDT, <eax>

vdhphysicaldisk_endfreesel:
        mov     eax,[errCode]
        or      eax,eax
        jz     short vdhphysicaldisknoerror

vdhphysicaldiskerror:
        call    vdmmAdjustError         ; retrieve hard error code
        PCall   VDHSetError, <eax>
        xor     eax,eax                 ; return NULL on error
        jmp     short vdhphysicaldiskexit

vdhphysicaldisknoerror:
        inc     eax                     ; return non-zero on no error

vdhphysicaldiskexit:
        RestoreReg  <edi,esi,ebx>
        ExitProc
EndProc VDHPhysicalDisk

;***EP+ VDHPopup - Display a message
;
;      Display a message according to the message ID, and get a response
;      from the user.  You can specify which responses are valid, as
;      well as replacable parameters values for the message.
;
;      If this is called during initialization, the message appears on
;      the screen as if you had done a DosWrite to the console.  No
;      prompt is displayed, and pulResponse is filled in with 0.
;
;      This services is intended for VDDs which must inform the user
;      of some extraordinary circumstance.  For example, VCOM would
;      issue this call to inform the user that a COM port is busy,
;      and give the user a choice of how to handle the situation.
;
;      ENTRY
;          pszzParm - Table of substitution strings
;          ulCount  - number of substitution strings
;          iMsg     - Message number
;          pflResp  - pointer to ULONG to receive response, filled in
;                       on exit.
;          flRespAllowed - allowed responses bit field; any combination
;              of these flags may be specified:
;                  VDHP_FAIL
;                  VDHP_RETRY
;                  VDHP_IGNORE
;                  VDHP_TERMINATE_SESSION
;          pszMsgFile - Message file (NULL in v2.0)
;
;      EXIT-SUCCESS
;          return TRUE;
;              pflResp is filled in with actual response selected by
;              user.
;
;      EXIT-FAILURE
;          return FALSE;
;          VDHGetError may return:
;              ERROR_GEN_FAILURE
;                  Calling VDD should treat this as a VDHP_FAIL reply.
;
;      CONTEXT
;          Initialization
;              The message will be displayed as a string on the console,
;              as if a DosWrite to stdout had been made.  No user response
;              will be returned.
;          VDM Task
;
;      VDM TERMINATION IMPLICATIONS
;          A VDM cannot be terminated if is waiting in this call for
;          a user response.
;
;      NOTES
;          1.The input value of pflResp is ignored.
;          2.Retry is the defauly action choosen by hard error. If
;            retry is not allowed then End the Program is choosen
;            as the default.
;
;      PCODE
;           Arrange parameters for HardError and call it
;           Translate the return code to VDHP_* codes
;           If return code does'nt match
;               Place VDHP_TERMINATE_SESSION for caller
;               return FAILURE
;           else place the translated code for caller
;           return SUCCESS
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHPopup,NEAR

ArgVar  pszzParm,DWORD
ArgVar  ulCount,DWORD
ArgVar  iMsg,DWORD
ArgVar  pflResp,DWORD
ArgVar  flRespAllowed,DWORD
ArgVar  pszMsgFile,DWORD

        EnterProc
        SaveReg <ebx,edi,esi,ds,es>

;       Validate Context
        ASSERTVDMTASK

       .ERRNZ  VDHP_FAIL               NE  ALLOWED_FAIL
       .ERRNZ  VDHP_TERMINATE_SESSION  NE  ALLOWED_ABORT
       .ERRNZ  VDHP_RETRY              NE  ALLOWED_RETRY
       .ERRNZ  VDHP_IGNORE             NE  ALLOWED_IGNORE

        mov     eax,flRespAllowed       ; (AX) == allowed actions
        mov     esi,[pTCBCur]
        mov     [esi].TCBAllowed,al
        mov     ecx,ulCount             ; (CX) == number of strings
        mov     ax,HEMessage            ; (ax) = send a message
        mov     edx,iMsg                ; (dx) = message number
        mov     esi,[pszzParm]          ; (ds:esi) = substitution strings
        CALL16  HardError

        cmp     ax,HDERR_ABORT
        jne     short vdhp10

        mov     eax,VDHP_TERMINATE_SESSION
        jmp     short vdhp50

vdhp10: cmp     ax,HDERR_FAIL
        jne     short vdhp20

        mov     eax,VDHP_FAIL
        jmp     short vdhp50

vdhp20: cmp     ax,HDERR_RETRY
        jne     short vdhp30

        mov     eax,VDHP_RETRY
        jmp     short vdhp50

vdhp30: cmp     ax,HDERR_IGNORE
        jne     short vdhp40

        mov     eax,VDHP_IGNORE
        jmp     short vdhp50

vdhp40: PCall   VDHSetError, [ERROR_GEN_FAILURE]
        xor     eax,eax
        jmp     short vdhp60

vdhp50: mov     ebx,[pflResp]
        mov     dword ptr [ebx],eax
        sub     eax,eax
        inc     eax                     ; return TRUE

vdhp60: RestoreReg <es,ds,esi,edi,ebx>
        ExitProc
EndProc   VDHPopup

SWAP32_23 segment
;***EP  VDHCreateSem - Create an Event/Mutex Semaphore
;
;       Create an Event or Mutex Semaphore.
;
;       An event semaphore remains in one of the two states i.e.
;       "reset" or "posted". The initial state of an event semaphore
;       is posted. If a VDHResetEventSem call is made on a semaphore
;       when it was posted all the subsequent wait calls on this
;       semaphore will block. Later a call to VDHPostEventSem for
;       this semaphore will wake up all the threads blocked on this
;       semaphore.
;
;       Similarly mutex semaphores have two states i.e. owned and
;       unowned. A mutex semaphore is created as unowned.
;       VDHRquestMutexSem is called to own the semaophore if it is not
;       owned. If it is owned request call will block. A subsequent
;       call to VDHReleaseMutexSem will unown the semaphore and wokeup
;       a blocked thread. Request and Release calls on mutex semaphores
;       can be nested. In that case a semphore will be unowned when
;       release calls will equal request calls.
;
;
;       ENTRY   phksem     - address to store semaphore handle
;               semtype    - VDH_EVENTSEM       Event Semaphore
;                            VDH_MUTEXSEM       Mutex Semaphore
;
;       EXIT    SUCCESS     returns TRUE
;               FAILURE     returns FALSE; VDHGetError may return
;                           ERROR_NOT_ENOUGH_MEMORY
;                           Invalid semtype will result in a panic.
;
;       CONTEXT
;           Task
;
;       VDM TERMINATION IMPLICATIONS
;           These semaphores are global and not attached to a VDM.
;           But if a VDD maintains semaphores on a per VDM bases then it
;           should destroy them via VDHDestroySem when that VDM dies.
;
;       PCODE
;           call ksemCreate
;           if returns error set error  and return 0
;           else return pointer to VDHSEM

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHCreateSem,near,,,esp

ArgVar  phksem, PVOID
ArgVar  semtype, DWORD

;       .errnz  VDH_EVENTSEM NE KRNL_EVENTSEM
;       .errnz  VDH_MUTEXSEM NE KRNL_MUTEXSEM

        EnterProc
        mov     ecx,[phksem]
        MMPHPreVDHCreateSem     ecx     ; 1.5 Added MMIO hooks
        or      ecx,ecx

        IFNDEF MMIOPH
        jz      short vc15
        ELSE
        jz      vc15
        ENDIF

        mov     edx,[semtype]
        call    ksemCreate
        or      eax,eax                 ; Succeeded?
        jnz     short vc10              ;   NO, go return error
        mov     dword ptr [ecx],edx     ; store sem handle
        inc     eax                     ; return TRUE
        MMPHPostVDHCreateSem    ecx     ; 1.5 Added MMIO hooks
        ExitProc

vc10:   PCall   VDHSetError, <eax>
        xor     eax,eax
        MMPHPostVDHCreateSem    eax     ; 1.5 Added MMIO hooks
        ExitProc

vc15:   Panic   <"VDHCreateSem:Invalid Param">
EndProc   VDHCreateSem
SWAP32_23 ends

SWAP32_27 segment
;***EP  VDHDestroySem - Destroy a semaphore
;
;       Destroy a semaphore previously created via VDHCraeteSem. Semaphore
;       must be posted/unowned before making this call.
;
;       ENTRY   hksem   - handle to the semaphore
;
;       EXIT    SUCCESS - returns nothing
;               FAILURE - Panics if:
;                           - vdhsem is invalid.
;                           - sem is reset or owned.
;
;       CONTEXT
;           Task
;
;       VDM TERMINATION IMPLICATIONS
;           None
;
;       PCODE
;           call ksemDestroySem

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHDestroySem,near,,,esp

ArgVar  hksem, DWORD

        EnterProc
        mov     edx,[hksem]
        MMPHPreVDHDestroySem    edx     ; 1.5 Added MMIO hooks
        call    ksemDestroy
        MMPHPostVDHDestroySem           ; 1.5 Added MMIO hooks
        ExitProc
EndProc   VDHDestroySem
SWAP32_27 ends

SWAP32_12 segment
;***EP   VDHWaitEventSem - Wait on an Event Semaphore
;
;       Wait on an event semaphore. If the semaphore is posted it will
;       return immidiately.
;
;       if ulTimeout is 0 the caller wont block, but ERROR_TIMEOUT will
;       be passed. If ulTimeout is -1 the caller will be blocked untill
;       semaphore is posted. Otherwise the caller will block for the
;       specified time.
;
;
;       ENTRY     hksem     - handle of event semaphore
;                 ulTimeout - timeout in milliseconds
;
;       EXIT      Success - returns 1
;                 Failure - returns 0; VDHGetError may return
;                           ERROR_TIMEOUT
;                           ERROR_INTERRUPT
;                           Panic if:
;                               vdhsem is invalid
;       CONTEXT
;           Task
;
;       VDM TERMINATION IMPLICATIONS
;           None
;
;       PCODE
;           call ksemWaitEventSem

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHWaitEventSem,near,,,esp

ArgVar  hksem, DWORD
ArgVar  ulTimeout, PVOID

        EnterProc
        mov     edx,[hksem]
        mov     ecx,[ulTimeout]
        MMPHPreVDHWaitEventSem  edx,ecx ; 1.5 Added MMIO hooks
        call    ksemWaitEvent
        or      eax,eax
        jnz     short vwe10
        inc     eax                     ; Return SUCCESS
        MMPHPostVDHWaitEventSem eax     ; 1.5 Added MMIO hooks
        ExitProc

vwe10:  PCall   VDHSetError, eax
        xor     eax,eax                 ; Return FAILURE
        MMPHPostVDHWaitEventSem eax     ; 1.5 Added MMIO hooks
        ExitProc
EndProc   VDHWaitEventSem
SWAP32_12 ends

SWAP32_17 segment
;***EP   VDHRequestMutexSem - Request a Mutex Semaphore
;
;       Request the ownership of a mutex semaphore. If the semaphore is
;       owned and the caller is not the owner, the thread will block. If the
;       caller is the owner a request count will be incrimented.
;
;       The request calls may be nested. A maximum of 255 requests are
;       allowed per semaphore at any one time. Crossing this limit will
;       result in panic.
;
;       ENTRY     hksem      - handle of a mutex semaphore
;                 ulTimeout  - timeout in milliseconds
;
;       EXIT      Success - return 1
;                 Failure - return 0; VDHGetError may return
;                           ERROR_TIMEOUT
;                           ERROR_INTERRUPT
;                           Panics if
;                               invalid vdhsem.
;                               request count crossing 255 limit.
;       CONTEXT
;           Task
;
;       VDM TERMINATION IMPLICATIONS
;           None
;
;       PSEUDO CODE
;           return (ksemRequestMutexSem)

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHRequestMutexSem,near,,,esp

ArgVar  hksem, DWORD
ArgVar  ulTimeout, PVOID

        EnterProc
        mov     edx,[hksem]
        mov     ecx,[ulTimeout]
        MMPHPreVDHReqMutexSem   edx,ecx ; 1.5 Added MMIO hooks
        call    ksemRequestMutex
        or      eax, eax
        jnz     short vrm10
        inc     eax                     ; Return SUCCESS
        MMPHPostVDHReqMutexSem  eax     ; 1.5 Added MMIO hooks
        ExitProc

vrm10:  PCall   VDHSetError, eax
        xor     eax,eax                 ; Return FAILURE
        MMPHPostVDHReqMutexSem  eax     ; 1.5 Added MMIO hooks
        ExitProc
EndProc   VDHRequestMutexSem
SWAP32_17 ends

SWAP32_17 segment
;***EP   VDHReleaseMutexSem - Release a Mutex Semaphore
;
;       Release the ownership of a mutex semaphore. If the request count
;       comes to zero then highest priority semaphore will be woken up.
;
;       Releasing an unowned mutex semaphore will cause a panic.
;
;       ENTRY     hksem - handle of a mutex
;
;       EXIT      Success - returns nothing
;                 Failure - Panics if:
;                               vdhsem is invalid
;                               caller is not owner of the semaphore
;
;       CONTEXT
;           Task
;
;       VDM TERMINATION IMPLICATIONS
;           None
;
;       PSEUDO CODE
;           call ksemReleaseMutexSem

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHReleaseMutexSem,near,,,esp

ArgVar  hksem, DWORD

        EnterProc
        mov     edx,[hksem]
        MMPHPreVDHRelMutexSem   edx     ; 1.5 Added MMIO hooks
        call    ksemReleaseMutex
        MMPHPostVDHRelMutexSem  eax     ; 1.5 Added MMIO hooks
        ExitProc
EndProc   VDHReleaseMutexSem
SWAP32_17 ends

SWAP32_23 segment
;***EP   VDHSetTimer0 - Inform Perfview that the timer 0 rate has changed
;
;       This routine is called by vtimer to inform perfview that
;       timer 0 rate has changed.
;
;       ENTRY   ulTimer0Value - new timer 0 value
;
;       EXIT    None
;       CONTEXT
;           VDM Task
;
;       VDM TERMINATION IMPLICATIONS
;           None
;
;       PSEUDO CODE
;           call doshlp to set new rollover count;

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHSetTimer0,near,,,esp

ArgVar  ulTimer0Value,DWORD

        EnterProc

        mov     ecx,[ulTimer0Value]     ;(ecx)=new timer 0 rate
pst8:   CCALL32 DHF.DosHlpTmrSetRollover

        ExitProc

EndProc   VDHSetTimer0
SWAP32_23 ends

EndCode

        FARCODE HIGH32
DefCode PRIVATE, GLOBAL, PASCAL

;***EP   VDHResetEventSem - Reset an Event Semaphore
;
;       VDHResetEventSem resets an event semaphore.
;
;       Resetting an already reset semaphore will result in a panic.
;
;       ENTRY     hksem - handle of event semaphore
;
;       EXIT      Success - returns nothing
;                 Failure - Panics if:
;                               vdhsem is invalid
;                               vdhsem is already reset
;       CONTEXT
;           Task
;           Interrupt
;
;       VDM TERMINATION IMPLICATIONS
;           None
;
;       PCODE
;           call ksemResetEventSem

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHResetEventSem,near,,,esp

ArgVar  hksem, DWORD

        EnterProc
        mov     edx,[hksem]
        MMPHPreVDHResetEventSem edx     ; 1.5 Added MMIO hooks
        call    ksemResetEvent
        MMPHPostVDHResetEventSem edx    ; 1.5 Added MMIO hooks
        ExitProc
EndProc   VDHResetEventSem

;***EP   VDHPostEventSem - Post an Event Semaphore
;
;       VDHPostEventSem posts an event semaphore. All the threads
;       blocked on this semaphore will wakeup.
;
;       Posting an already posted semaphore will result in a Panic.
;
;       ENTRY     hksem - handle of event semaphore
;
;       EXIT      Success - return nothing
;                 Failure - Panics if:
;                               - vdhsem invalid.
;                               - vdhsem is already posted.
;       CONTEXT
;           Task
;           Interrupt
;
;       VDM TERMINATION IMPLICATIONS
;           None
;
;       PCODE
;           call ksemPostEventSem

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHPostEventSem,near,,,esp

ArgVar  hksem, DWORD

        EnterProc
        mov     edx,[hksem]
        MMPHPreVDHPostEventSem  edx     ; 1.5 Added MMIO hooks
        call    ksemPostEvent
        MMPHPostVDHPostEventSem eax     ; 1.5 Added MMIO hooks
        ExitProc
EndProc   VDHPostEventSem

;***EP  VDHQuerySem - Query a Semaphore'state
;
;       Query the state of an event or mutex semaphore.
;
;       ENTRY     hksem       - handle of event to query
;                 pkSemState  - pointer to area to be filled in with current
;                               state of semaphore:
;
;       EXIT      Success - returns nothing; State information in pSemState
;                 Failure - Panics if:
;                               vdhsem is invalid
;       CONTEXT
;           Task
;
;       NOTE    The validity of pVDHSemState is not checked.
;               Caller should make sure to pass valid space.
;
;       PSEUDO CODE
;           call ksemQuerySem
;

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHQuerySem,near,,,esp

ArgVar  hksem, DWORD
ArgVar  pkSemState, PVOID

        EnterProc
        mov     edx,[hksem]
        mov     ecx,[pkSemState]
        MMPHPreVDHQuerySem      edx     ; 1.5 Added MMIO hooks
        call    ksemQuery
        MMPHPostVDHQuerySem             ; 1.5 Added MMIO hooks
        ExitProc
EndProc   VDHQuerySem

;***EP+ VDHViewHandle - Return a new File View Handle
;
;      Duplicate a real handle
;
;      ENTRY
;          hfile      - real file handle
;
;      EXIT-SUCCESS
;          returns TRUE (non-zero) which is the new file handle
;
;      EXIT-FAILURE
;          returns 0xffffffff
;          VDHGetError returns error code
;
;      VDM TERMINATION IMPLICATIONS
;          None.
;
;      CONTEXT
;          VDM Task
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure VDHViewHandle,NEAR                                            ;BEGIN
                                                                        ;WIN32
        ArgVar    hfile,WORD

        EnterProc
        push    ds
        push    es
        push    edi
        push    esi
        push    ebx

;       Validate calling context
        ASSERTVDMTASKONLY

        movzx   ebx,[hfile]

;       pCurrentJFN = PFROMVP((CurrentPDB<<4)->PDB_JFN_Pointer)
        mov     esi,[pPTDACur]          ; (ESI) = pointer to PTDA
        movzx   eax,[esi].CurrentPDB    ; (AX) = current PDB
        shl     eax,4                   ; eax=flat address of old PDB

;       check for valid range
        cmp     bx,[eax].PDB_JFN_Length
        jae     vdhview_error           ; yes, go return error
;
        movzx   edi,[eax].PDB_JFN_Pointer.hiword
        movzx   edx,[eax].PDB_JFN_Pointer.loword
        shl     edi,4
        add     edi,edx
        add     edi,ebx
        cmp     byte ptr [edi],SFN_NULL ; unused handle
        jz      vdhview_error
        movzx   eax,[edi]               ; get SFN

vdhview_create:

        mov     ebx,eax
        CALL16  SFFromHandle
        jc      vdhview_error
        CALL16  w_Dup                   ; BX has the JFN handle
        jc      vdhview_error           ; if Carry set, AX = error code
        inc     eax                     ; VDH Service dec file handle
        jmp     short vdhview_exit

vdhview_error:
        call    vdmmAdjustError         ; retrieve hard error code
        PCall   VDHSetError, <eax>
        sub     eax,eax
        dec     eax                     ; return 0xffffffff to indicate error

vdhview_exit:
        pop     ebx
        pop     esi
        pop     edi
        pop     es
        pop     ds
        ExitProc

EndProc   VDHViewHandle                                                 ;END
                                                                        ;WIN32
EndCode

        END
