;       SCCSID = @(#)mdintrf.asm        6.3 91/07/23


        page 66, 132
        title  Monitor Dispatcher DvHlp Functions - DevHlp interface
        subttl IBM Confidential
; ***************************************************************************
; *
; *                       IBM Confidential
; *
; *                 Copyright (c) IBM Corporation  1987, 1990
; *                           All Rights Reserved
; *
; ***************************************************************************

;/********************** START OF SPECIFICATIONS **************************
;/*
;/*  Source File Name: MONINTRF.ASM
;/*
;/*  Descriptive Name: Monitor Dispatcher DevHlp routines - Part 2
;/*
;/*  Function:  Character Device Monitors provide a mechanism for
;/*     applications or subsystems to monitor all characters passing
;/*     through a device driver.  This mechanism allows any reg-
;/*     istered process to remove, insert or modify the information
;/*     passing through the device.
;/*
;/*     The Monitor Dispatcher DevHlp routines provide the services
;/*     for device drivers to support character stream monitoring.
;/*
;/*  Notes: These modules make up the Monitor Dispatcher DevHlps:
;/*
;/*     MDINIT.ASM  - Initialization routine
;/*     MDINTRF.ASM - Stub entries for devhlps in low mem
;/*     MDSUBA.ASM  - Common subroutines that must be assembler
;/*     MDLOCK.C    - dhw_Write and subroutines (interrupt-time routines)
;/*     MDSWAP1.C   - MD32IMONREAD, MD32IMONWRITE, and subroutines
;/*     MDSWAP2.C   - dhw_Create, dhw_Register, dhw_Deregister, and subroutines
;/*
;/*  Procedures Defined in this module:
;/*     dh_MonitorCreate (FAR) - create/delete a monitor chain for device
;/*     dh_Register (FAR) - register a monitor into a monitor chain
;/*     dh_DeRegister (FAR) - remove a monitor from a monitor chain
;/*     dh_MonWrite (FAR) - send a data request packet into monitor chain
;/*     dh_MonFlush (FAR) - send a flush request packet into monitor chain
;/*     dh32_MonitorCreate (far) - worker for dh_MonitorCreate
;/*     dh32_Register (far) - worker for dh_Register
;/*     dh32_DeRegister (far) - worker for dh_DeRegister
;/*     dh32_MonFlush (far) - worker for dh_MonFlush
;/*
;/*  External References (other kernel components):
;/*     FuWordNF
;/*
;/*************************************************************************


        .xlist
        INCLUDE mddvhlp.inc

        .list


 ; declare external INTRA-COMPONENT entry points called by this module

        EXTRN32  _dhw_MonitorCreate
        EXTRN32  _dhw_Register
        EXTRN32  _dhw_Deregister
        EXTRN32  _dhw_MonWrite
        EXTRN16  FuWordNF

        ReferGlobal InterruptLevel, BYTE


    DATA SEGMENT WORD
        flush_record            DW 0004H  ;Should be in 16bit segment!
    DATA ENDS
;/***************************************************************************
;/***************************************************************************
;/***************************************************************************
;-----------------------------------------------------------------------------
; The following procedures should be in 32 bit swapable segment
;-----------------------------------------------------------------------------

        FARCODE HIGH32
.386p
MON32SWAP_TEXT    segment

;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME: dh32_MonFlush
;/*
;/* DESCRIPTIVE NAME:  Removes all data from the monitor stream.
;/*
;/* FUNCTION: MonFlush creates a FLUSH data record and places
;/*           it in the monitor chain data stream.  As the data
;/*           record passes thru all monitors in the chain,  the
;/*           monitors recognize the FLUSH flags in this record
;/*           and reset their buffers.
;/*
;/*
;/* ENTRY POINT:  dh32_MonFlush
;/*    LINKAGE:   CALL32 from dh_MonFlush
;/*
;/* INPUT:  see dh_MonFlush
;/*
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = 0
;/*
;/* EXIT-ERROR:   'C' (carry flag) set
;/*               AX <> 0; = error code
;/*                          ERROR_MON_INVALID_HANDLE
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES: mon_write
;/*
;/* EXTERNAL REFERENCES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh32_MonFlush, far32

        SaveReg <FS,GS>
        mon_savemost_regs

        NullContext <FS,GS>,DX          ; zero FS and GS in case we block

        DosContext ds                  ; load up our own private DS
        LEA     SI, flush_record       ; setup parameters for
        push   si
        mov    si,ds                   ;
        shl    esi,16                  ;put DS:SI into ESI to pass as parm
        pop    si                      ;

        movzx  eax, ax                 ;clear unneeded portions of registers
        mov    ecx, 02
        mov    edx, WF_CALLED_FROM_DHFLUSH
        xor    ebx, ebx
        FlatContext <DS,ES>            ; set up DS and ES for C routine
        CCall  _dhw_MonWrite, <esi,ecx,eax,edx,ebx>
        .386p


        mon_restoremost_regs
        RestoreReg <GS,FS>

        CMP AX, 0                ; re-set carry flag, appropriately before
        JA dhf32_Error             ; returning to the device driver
        CLC
        JMP short dhf32_Done

dhf32_Error:
        stc

dhf32_Done:
        ret

EndProc dh32_MonFlush

;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME:  dh32_MonitorCreate
;/*
;/* DESCRIPTIVE NAME: Create/Remove a monitor chain for a device.
;/*
;/*
;/* ENTRY POINT:  dh32_MonitorCreate
;/*    LINKAGE:   CALL32 from dh_MonitorCreate
;/*
;/* INPUT:  see dh_MonitorCreate
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = monitor chain handle if input handle was
;/*                    = 0; otherwise = 0.
;/*                          ERROR_MON_INVALID_PARAMETER
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES:  MonitorCreate
;/*
;/* EXTERNAL REFERENCES:
;/*    ROUTINES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh32_MonitorCreate,far32
        LocalVar TempHandle,WORD           ; TCB pointer
        EnterProc

        CLC
        MOV    [TempHandle],0          ; Initialize to 0 (saves code later)

        SaveReg <fs,gs>
        NullContext <fs,gs>            ; zero FS and GS in case we block
        mon_savemost_regs

        push   si
        mov    si,es                   ;
        and    si,0fff8h               ;MAF assure ring 0/GDT selector
        shl    esi,16                  ;put ES:SI into ESI to pass as parm
        pop    si                      ;

        push   di
        mov    di,ds                   ;
        and    di,0fff8h               ;MAF assure ring 0/GDT selector
        shl    edi,16                  ;put DS:DI into EDI to pass as parm
        pop    di                      ;

        lea    bx, TempHandle
        push   bx
        mov    bx,ss
        shl    ebx, 16
        pop    bx
        mov    [TempHandle],ax

        FlatContext <DS,ES>            ; set up DS and ES for C routine
        CCall  _dhw_MonitorCreate, <esi,edi,ebx>
        .386p

        mon_restoremost_regs
        RestoreReg <gs,fs>

        CMP    AX, 0             ; re-set carry flag, appropriately before
        JA dhc32_Error           ; returning to the device driver
        MOV    AX,[TempHandle]   ; Put handle into AX (0 if handle was removed)
        CLC
        JMP short dhc32_Done

dhc32_Error:
        STC

dhc32_Done:
        LeaveProc
        RET

EndProc dh32_MonitorCreate



;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME: dh32_Register
;/*
;/* DESCRIPTIVE NAME: Add a Monitor to a Monitor Chain for a
;/*                   device.
;/*
;/*
;/* ENTRY POINT:  dh32_Register
;/*    LINKAGE:   CALL32 from dh_Register
;/*
;/*
;/* INPUT:  see dh_Register
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = 0
;/*
;/* EXIT-ERROR:   'C' (carry flag) set
;/*               AX = error code:
;/*                    ERROR_MON_INVALID_HANDLE
;/*                    ERROR_NOT_ENOUGH_MEMORY
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*           All input parameter registers altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES: mon_Register
;/*
;/* EXTERNAL REFERENCES:
;/*    ROUTINES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh32_Register,far32

        SaveReg <FS,GS>
        NullContext <FS,GS>             ;Zero FS and GS in case we block

        PUSH EBX
        PUSH ECX
        PUSH EDX
        PUSH DS
        PUSH EDI
        PUSH ESI
        PUSH ES

        mov     BX, ES
        movzx   ebx, bx
        movzx   esi, si
        movzx   edi, di
        movzx   ecx, cx
        movzx   eax, ax
        movzx   edx, DH

        FlatContext <DS,ES>            ; set up DS and ES for C routine
        CCall  _dhw_Register, <EBX,ESI,EDI,ECX,EAX, EDX>
        .386p


        POP EBX       ;get ES value
        POP ESI       ;get ESI value
        PUSH EAX      ; save error, if any, returned from mon_Register
        PUSH ESI      ;save ESI value again
        PUSH EBX      ;save ES value again
 ;
 ;  We have to be careful not to TRAP while popping a user selector
 ;  into a segment register in the kernel.  We must guarantee access
 ;  to the user segment via FuWordNF
 ;
        CALL16 FuWordNF
        JNC dhr32_SegOK
        POP EBX       ; can't access this segment without taking a fault
        JMP short dhr32_BypassPOP
dhr32_SegOK:
        POP ES
dhr32_BypassPOP:
        POP ESI
        POP EAX
        POP EDI
        POP DS
        POP EDX
        POP ECX
        POP EBX


        RestoreReg <GS,FS>

        CMP AX, 0                ; re-set carry flag, appropriately before
        JA dhr32_Error             ; returning to the device driver
        CLC
        JMP short dhr32_Done

dhr32_Error:
        stc

dhr32_Done: RET

EndProc dh32_Register



;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME: dh32_DeRegister
;/*
;/* DESCRIPTIVE NAME: Remove a monitor from a monitor chain.
;/*
;/*
;/* ENTRY POINT:  dh32_DeRegister
;/*    LINKAGE:   CALL32 from dh_Deregister
;/*
;/* INPUT:  see dh_DeRegister
;/*
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = # of monitors still registered with chain
;/*
;/* EXIT-ERROR:   'C' (carry flag) set
;/*               AX = error code:
;/*                    ERROR_MON_INVALID_HANDLE
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*           All input parameter registers altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES: mon_DeRegister
;/*
;/* EXTERNAL REFERENCES:
;/*    ROUTINES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh32_DeRegister,far32
        LocalVar MonLeft, WORD

        EnterProc
        SaveReg <FS,GS>
        NullContext <FS,GS>             ; Zero FS and GS in case we block
        mon_savemost_regs

        movzx   ebx, bx
        movzx   eax, ax

        lea    si, MonLeft
        push   si
        mov    si,ss
        shl    esi, 16
        pop    si


        FlatContext <DS,ES>            ; set up DS and ES for C routine
        CCall  _dhw_Deregister, <ebx, eax, esi>
        .386p

        mon_restoremost_regs
        RestoreReg <GS,FS>

        CMP AX, 0                ; re-set carry flag, appropriately before
        JA dhd32_Error           ; returning to the device driver
        MOV    AX,[MonLeft]      ; Put # monitors left in AX
        CLC
        JMP short dhd32_Done

dhd32_Error:
        STC

dhd32_Done: LeaveProc
            RET

EndProc dh32_DeRegister


MON32SWAP_TEXT    ENDS

;/***************************************************************************
;/***************************************************************************
;/***************************************************************************
;-----------------------------------------------------------------------------
; The following procedures should be in 16 bit fixed segment
;-----------------------------------------------------------------------------


.386P
FARCODE LOW
CODE    SEGMENT

        ASSUME  DS:nothing,ES:nothing,SS:nothing

;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME: dh_MonWrite
;/*
;/* DESCRIPTIVE NAME: Give Data to Monitors.
;/*
;/* NOTES: This is a Device Helper Service;  this function may
;/*        may be called either at task time or at interrupt
;/*        time.
;/*
;/*        DS MUST point to the device driver's header segment .
;/*
;/* ENTRY POINT:  dh_MonWrite
;/*    LINKAGE:   FAR CALL TO Device_Help with function code 26
;/*               (MonWrite) in DL register.
;/*
;/* INPUT:  from registers with the following calling sequence
;/*
;/*         LDS SI, data_record
;/*         MOV CX, count
;/*         MOV AX, monitor_handle
;/*         MOV DH, wait_flag
;/*         MOV DI, timeout_high      ;if wait_flag=2
;/*         MOV BX, timeout_low       ;if wait_flag=2
;/*
;/*      where
;/*
;/*      DS:SI = address of data record
;/*      count = byte count of data record
;/*      monitor_handle = handle for monitor chain returned on
;/*                       previous MonitorCreate call.
;/*      waitflag = 0 = wait, infinite timeout (task time)
;/*                 1 = nowait                 (interrupt time)
;/*                 2 = wait, timeout in DI,BX (task time)
;/*      timeout_high = top word of timeout (in milliseconds)
;/*      timeout_low = low word of timeout (in milliseconds)
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = 0
;/*
;/* EXIT-ERROR:   'C' (carry flag) set
;/*               AX <> 0; = error code:
;/*                          ERROR_MON_INVALID_HANDLE
;/*                          ERROR_NOT_ENOUGH_MEMORY
;/*                          ERROR_INTERRUPT
;/*                          ERROR_SEM_TIMEOUT
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES: mon_write
;/*
;/* EXTERNAL REFERENCES: none
;/******************* END OF SPECIFICATIONS *********************
.386p

Procedure dh_MonWrite

        SaveReg <FS,GS>
        mon_savemost_regs

        NullContext <FS,GS>             ; zero FS and GS in case we block

        push   si
        mov    si,ds                   ;
        shl    esi,16                  ;put DS:SI into ESI to pass as parm
        pop    si                      ;

        movzx  ecx, cx                 ;
        movzx  eax, ax                 ;clear unneeded portions of registers
        movzx  edx, dh                 ;

        push   bx
        mov    bx,di
        shl    ebx, 16                 ;put timeout into EBX
        pop    bx
        FlatContext <DS,ES>            ; set up DS and ES for C routine
        CCALL32  _dhw_MonWrite,<esi,ecx,eax,edx,ebx>
        .386p
        mon_restoremost_regs
        RestoreReg <GS,FS>

        CMP AX, 0                ; re-set carry flag, appropriately before
        JA dhw_Error             ; returning to the device driver
        CLC
        JMP short dhw_Done
dhw_Error:
        STC
dhw_Done:

        RET

EndProc dh_MonWrite


;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME: dh_MonFlush
;/*
;/* DESCRIPTIVE NAME:  Removes all data from the monitor stream.
;/*
;/* FUNCTION: MonFlush creates a FLUSH data record and places
;/*           it in the monitor chain data stream.  As the data
;/*           record passes thru all monitors in the chain,  the
;/*           monitors recognize the FLUSH flags in this record
;/*           and reset their buffers.
;/*
;/* NOTES: This is a Device Helper Service;  this function may
;/*        be called only at task time.
;/*
;/*        The Monitor Dispatcher will not place data into the
;/*        monitor chain until the flush record has passed thru
;/*        all monitors in the chain and been returned to the
;/*        device driver's monitor chain buffer.
;/*
;/* ENTRY POINT:  dh_MonFlush
;/*    LINKAGE:   FAR CALL TO Device_Help with function code 27
;/*               (MonFlush) in DL register.
;/*
;/* INPUT:  from registers with the following calling sequence
;/*
;/*         MOV AX, monitor_handle
;/*
;/*      where
;/*
;/*      monitor_handle = handle for monitor chain returned on
;/*                       previous MonitorCreate call.
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = 0
;/*
;/* EXIT-ERROR:   'C' (carry flag) set
;/*               AX <> 0; = error code
;/*                          ERROR_MON_INVALID_HANDLE
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*
;/*           All monitors in the chain recognize the special
;/*           data record with a FLUSH indicator*  that
;/*           causes them to reset all internal buffers, remove
;/*           all data from the input buffer, reset their
;/*           internal state, and pass the FLUSH flag record
;/*           into their output buffer.
;/*
;/*           The FLUSH record consists of a flag WORD only,
;/*           with bit 3 of the high byte set.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES: mon_write
;/*
;/* EXTERNAL REFERENCES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh_MonFlush

        whattime                        ; check if called at INT time
        JNE      dhf_IntTime

        CALL32 dh32_MonFlush
        JMP short dhf_Done

dhf_IntTime:                     ; we're being called at wrong time -
        mov     ax, ERROR_MON_INVALID_PARMS
        stc

dhf_Done: ret

EndProc dh_MonFlush

;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME:  dh_MonitorCreate
;/*
;/* DESCRIPTIVE NAME: Create/Remove a monitor chain for a device.
;/*
;/* NOTES: This is a Device Helper Service;  this function may
;/*        may only be called at task time.
;/*
;/* ENTRY POINT:  dh_MonitorCreate
;/*    LINKAGE:   FAR CALL TO Device_Help with function code 23
;/*               (MonitorCreate) in DL register.
;/*
;/* INPUT:  from registers with the following calling sequence
;/*
;/*         MOV ES, final_buffer_seg
;/*         MOV SI, final_buffer_offset
;/*         MOV DS, notify_seg
;/*         MOV DI, notify_offset
;/*         MOV AX, == 0; to create a new monitor chain;
;/*                 != 0; = handle returned from previous Monitor
;/*                          Create call, indicating that this chain
;/*                          is to be removed.
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = monitor chain handle if input handle was
;/*                    = 0; otherwise = 0.
;/*                          ERROR_MON_INVALID_PARAMETER
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES:  MonitorCreate
;/*
;/* EXTERNAL REFERENCES:
;/*    ROUTINES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh_MonitorCreate

        whattime                        ; check if called at INT time
        JNE      dhc_IntTime

        CALL32 dh32_MonitorCreate
        JMP short dhc_Done

dhc_IntTime:                     ; we're being called at wrong time
        mov     ax, ERROR_MON_INVALID_PARMS
        STC

dhc_Done:
        RET

EndProc dh_MonitorCreate



;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME: dh_Register
;/*
;/* DESCRIPTIVE NAME: Add a Monitor to a Monitor Chain for a
;/*                   device.
;/*
;/* NOTES: This is a Device Helper Service;  this function may
;/*        may only be called at task time.
;/*
;/* ENTRY POINT:  dh_Register
;/*    LINKAGE:   FAR CALL TO Device_Help with function code 24
;/*               (Register) in DL register.
;/*
;/*
;/* INPUT:  from registers with the following calling sequence
;/*
;/*         MOV BX, monitor_buffer_sel
;/*         MOV ES, BX
;/*         MOV SI, input_buffer
;/*         MOV DI, output_buffer
;/*         MOV CX, monitor_PID
;/*         MOV AX, monitor_handle
;/*         MOV DH, placement_flag
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = 0
;/*
;/* EXIT-ERROR:   'C' (carry flag) set
;/*               AX = error code:
;/*                    ERROR_MON_INVALID_HANDLE
;/*                    ERROR_NOT_ENOUGH_MEMORY
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*           All input parameter registers altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES: mon_Register
;/*
;/* EXTERNAL REFERENCES:
;/*    ROUTINES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh_Register

        whattime                        ; check if called at INT time
        JNE      dhr_IntTime

        CALL32 dh32_Register
        JMP short dhr_Done

dhr_IntTime:                     ; we're being called at wrong time -
        mov     ax, ERROR_MON_INVALID_PARMS
        stc

dhr_Done: RET

EndProc dh_Register



;/******************* START OF SPECIFICATIONS *******************
;/*
;/* SUBROUTINE NAME: dh_DeRegister
;/*
;/* DESCRIPTIVE NAME: Remove a monitor from a monitor chain.
;/*
;/* NOTES: This is a Device Helper Service;  this function may
;/*        may only be called at task time.
;/*
;/*        Dh_DeRegister may not return if the device driver
;/*        blocks a monitor's kernal thread on the notification
;/*        call.
;/*
;/*
;/* ENTRY POINT:  dh_DeRegister
;/*    LINKAGE:   FAR CALL TO Device_Help with function code 25
;/*               (DeRegister) in DL register.
;/*
;/* INPUT:  from registers with the following calling sequence:
;/*
;/*         MOV BX, monitor_PID
;/*         MOV AX, monitor_handle
;/*
;/*
;/* EXIT-NORMAL:  'C' (carry flag) clear
;/*               AX = # of monitors still registered with chain
;/*
;/* EXIT-ERROR:   'C' (carry flag) set
;/*               AX = error code:
;/*                    ERROR_MON_INVALID_HANDLE
;/*
;/* EFFECTS:  'C' (carry flag) and AX register altered.
;/*           All input parameter registers altered.
;/*
;/*           FS and GS must be preserved (DevHelp requirement)
;/*
;/* INTERNAL REFERENCES:
;/*    ROUTINES: mon_DeRegister
;/*
;/* EXTERNAL REFERENCES:
;/*    ROUTINES: none
;/******************* END OF SPECIFICATIONS *********************

Procedure dh_DeRegister


        whattime                        ; check if called at INT time
        JNE      dhd_IntTime

        CALL32 dh32_DeRegister
        JMP short dhd_Done

dhd_IntTime:                    ; we're being called at wrong time -
        mov     ax, ERROR_MON_INVALID_PARMS
        STC

dhd_Done: RET

EndProc dh_DeRegister

CODE    ENDS


        END
