home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c070 / 4.ddi / TOOLS.4 / TCTSRC1.EXE / IVCTRL.ASM < prev    next >
Encoding:
Assembly Source File  |  1989-03-31  |  22.3 KB  |  815 lines

  1.     page    60,126
  2.  
  3. ; Name        ivctrl -- Return address of intervention control block.
  4. ;
  5. ; Synopsis    pblock = ivctrl();
  6. ;
  7. ;        IV_CTRL far *pblock
  8. ;                  Address of intervention control block.
  9. ;
  10. ; Description    This function returns the address of the intervention
  11. ;        control block (IV_CTRL structure).  This module also
  12. ;        defines the structure and the intervention filters.
  13. ;
  14. ;        Any program using intervention code contains a unique
  15. ;        intervention control block to control the intervention
  16. ;        filters that give control to the installed intervention
  17. ;        function at the proper time.  The block is located in
  18. ;        the code segment of the filters, so in general it must
  19. ;        be referenced via a far pointer.
  20. ;
  21. ;        It is seldom necessary to access the intervention
  22. ;        control block directly.  IVINSTAL performs all
  23. ;        operations necessary to install the intervention filter.
  24. ;        However, if the intervention mechanism should fail, it
  25. ;        may be useful to examine the following fields in the
  26. ;        structure:
  27. ;
  28. ;            key_event
  29. ;            wait
  30. ;            req
  31. ;            awake
  32. ;            timer_busy
  33. ;            kb_busy
  34. ;            com2_busy
  35. ;            com1_busy
  36. ;            disk_busy
  37. ;            idle_busy
  38. ;            idle_safe
  39. ;            cbreak
  40. ;
  41. ; Returns    *pblock       Address of intervention control block.
  42. ;
  43. ; Version    6.00 (C)Copyright Blaise Computing Inc.  1987-1989
  44. ;
  45.  
  46.     include    beginasm.mac
  47.     beginMod   ivctrl
  48.  
  49.     ;*********************************************************
  50.     ;
  51.     ;    Define symbols and macros
  52.  
  53.                 ; Hot key action codes:
  54. IV_KY_NONE    equ    0   ;  No hot key or action.
  55. IV_KY_WAKE    equ    3   ;  Invoke intervention function and
  56.                 ;    awaken it if asleep.
  57.  
  58. BEGIN_IV_FILTER macro                ;; BEGIN_IV_FILTER:  Macro
  59.         local    begin_label        ;;     to build pointer to
  60.                         ;;     the IV_CTRL structure
  61.         jmp    short begin_label   ;;     at the beginning of each
  62.                         ;;     filter.
  63.         dw    offset begin_block
  64. begin_label:
  65.         endm
  66.  
  67. IV_VECTORS    struc        ; IV_VECTORS:  set of interrupt vectors
  68.                 ;  used by intervention code.
  69.                 ; (Must match version in BINTERV.H exactly!)
  70.  
  71.     ptimer    dd    0   ; INT 08h:    Timer tick.
  72.     pkeybd    dd    0   ; INT 09h:    Keystroke.
  73.     pdisk    dd    0   ; INT 13h:    BIOS disk services.
  74.     pdos    dd    0   ; INT 21h:    DOS functions.
  75.     pidle    dd    0   ; INT 28h:    DOS idle.
  76.                 ;
  77.     pcom1    dd    0   ; INT 0ch:    First asynchronous communication
  78.                 ;        port.
  79.     pcom2    dd    0   ; INT 0bh:    Second asynchronous communication
  80.                 ;        port.
  81. IV_VECTORS    ends
  82.  
  83.     ;*********************************************************
  84.     ;
  85.     ;    Allocate and initialize the IV_CTRL structure.
  86.  
  87.     beginCseg  ivctrl
  88.  
  89.     ;Note:  the following sequence of thirty variables must exactly
  90.     ;        match the IV_CTRL structure as defined in BINTERV.H.
  91.  
  92. begin_block     equ $
  93.  
  94. signature     dw  0        ; Signature identifying this structure.
  95. sign2         dw  0        ; One's complement of "signature".
  96. ident         db  16 dup (0) ; Identifying name.
  97. psp         dw  0        ; PSP of this program.
  98. enabled      dw  0        ; Nonzero if enabled (this prevents the
  99.                 ;  filters from being installed twice).
  100. pgate         dd  0        ; Gateway for invoking this program
  101.                 ;  from outside.
  102. prev_vec     IV_VECTORS <>    ; Previous values of interrupt vectors.
  103.                 ;
  104. dos_need     db  0        ; Nonzero if intervention function
  105.                 ;  uses DOS services.
  106. dkey_need     db  0        ; Nonzero if intervention function
  107.                 ;  uses DOS functions 1-12.
  108.                 ;
  109. pkeytab      dd  0        ; Table of hot keys.
  110. ktsize         dw  0        ; Size of hot key table.
  111.                 ;
  112. keyfound     dw  0        ; Found key, if any.
  113. keyaction     dw  IV_KY_NONE ;
  114.                 ;
  115.                 ; Internal state of filters:
  116.                 ;
  117. iv_wait      db  0        ; Nonzero if INT 21h or INT 28h filter
  118.                 ;  is cycling, waiting for the
  119.                 ;  intervention function to be invoked.
  120. req         db  0        ; Nonzero if intervention function
  121.                 ;  needs invocation.
  122. awake         db  0        ; Zero if intervention function is
  123.                 ;  asleep.
  124.                 ;
  125.                 ; Busy flags:
  126. timer_busy     db  0        ;  INT 08h filter.
  127. kb_busy      db  0        ;  INT 09h filter.
  128. com2_busy     db  0        ;  INT 0bh filter.
  129. com1_busy     db  0        ;  INT 0ch filter.
  130. disk_busy     db  0        ;  INT 13h filter.
  131. idle_busy     db  0        ;  INT 28h filter.
  132.                 ;
  133. idle_safe     db  0        ; Nonzero if INT 28h is in progress
  134.                 ;  and DOS functions are available
  135.                 ;  (but not functions 1-12).
  136.                 ;
  137. pschedblk     dd  0        ; Entry point into scheduler's ISR
  138.                 ;  control block.
  139.                 ;
  140. pdos_crit     dd  0        ; Address of DOS critical section flag
  141.                 ;  (busy flag).
  142.                 ;
  143. prev_16h_vec     dd  0        ; Address of previous INT 16h handler
  144.                 ;  (if replaced).
  145. cbreak         db  0        ; Nonzero if Ctrl-C or Ctrl-Break
  146.                 ;  detected during this invocation of
  147.                 ;  the intervention function.
  148. no_call      db  0        ; Nonzero if user wants to prevent
  149.                 ;  invocation of intervention function.
  150. filter_mask     dw  0        ; Map of installed filters.
  151.  
  152. kb_ext         db  0        ; Nonzero if extended BIOS keyboard
  153.                 ;  services to be used.
  154.                 ;
  155. _res0         db  0        ; Reserved for future use.
  156.                 ;
  157. _reserved     db  8 dup (0)    ; Reserved for future use.
  158.  
  159.     ; End of IV_CTRL structure.
  160.  
  161.  
  162.     ;*********************************************************
  163.     ;
  164.     ;    Internal variables
  165.  
  166. timer_caller_offset dw    ?    ; Return address for INT 08h.
  167. timer_caller_seg    dw    ?
  168.  
  169. kb_caller_offset    dw    ?    ; Return address for INT 09h.
  170. kb_caller_seg        dw    ?
  171.  
  172. com2_caller_offset  dw    ?    ; Return address for INT 0bh.
  173. com2_caller_seg     dw    ?
  174.  
  175. com1_caller_offset  dw    ?    ; Return address for INT 0ch.
  176. com1_caller_seg     dw    ?
  177.  
  178. disk_caller_offset  dw    ?    ; Return address for INT 13h.
  179. disk_caller_seg     dw    ?
  180.  
  181. key_caller_offset   dw    ?    ; Return address for INT 16h.
  182. key_caller_seg        dw    ?
  183. key_caller_flags    dw    ?    ; Flags pushed by caller on stack.
  184. key_entry_flags     dw    ?    ; Flags on entry to IVBIOSKY.
  185. key_func_number     db    ?    ; AH value on entry to INT 16h.
  186. key_busy        db    0    ; Busy flag for INT 16h filter.
  187.  
  188. dos_caller_offset   dw    ?    ; Return address for INT 21h.
  189. dos_caller_seg        dw    ?
  190. dos_save_flags        dw    ?    ; Flags pushed by INT 21h caller.
  191.  
  192. idle_caller_offset  dw    ?    ; Return address for INT 28h.
  193. idle_caller_seg     dw    ?
  194.  
  195.  
  196.     ;*********************************************************
  197.     ;
  198.     ;    Begin code for IVCTRL function.
  199.  
  200.     beginProc   ivctrl
  201.     assume        ds:nothing, es:nothing, ss:nothing
  202.  
  203.     mov        dx,cs            ; Load address of intervention
  204.     mov        ax,offset begin_block   ;  control block into DX:AX.
  205.     ret
  206.  
  207.     endProc     ivctrl
  208.  
  209.  
  210.     ;*********************************************************
  211.     ;
  212.     ;    IVTIMER -- INT 8 filter
  213.     ;
  214.     ;    This function calls the scheduler on every clock tick,
  215.     ;    except that it never does so in a nested fashion,
  216.     ;    so it is reentrant.
  217.  
  218.     beginProc   ivtimer        ; (IVTIMER will perform a far return.)
  219.  
  220.     assume        ds:nothing, es:nothing, ss:nothing
  221.     BEGIN_IV_FILTER
  222.  
  223.     pushf
  224.     cli                ; Disable interrupts until we can
  225.                     ;  set the busy flag.
  226.     cmp        timer_busy,0    ; If this filter is already active,
  227.  
  228.     jne        timer_jmp_prev    ; If timer busy, jump to previous
  229.                     ;  handler.
  230.  
  231.     cmp        no_call,0        ; If no calls wanted, jump to
  232.     jne        timer_jmp_prev    ;  previous handler.
  233.  
  234.     cmp        com1_busy,0     ; If COM1 busy,
  235.     jne        timer_jmp_prev    ;  jump to previous handler.
  236.  
  237.     cmp        com2_busy,0     ; If COM2 busy,
  238.     jne        timer_jmp_prev    ;  jump to previous handler.
  239.  
  240.     cmp        dos_need,0        ; If DOS is not needed
  241.     je        timer_enter
  242.     cmp        disk_busy,0     ;  or disk is idle,
  243.     je        timer_enter     ;  go call scheduler.
  244.                     ; Else jump to previous handler.
  245. timer_jmp_prev:
  246.  
  247.     popff
  248.     jmp        prev_vec.ptimer    ; Jump to previous handler.
  249.                     ;  The previous handler will return
  250.                     ;  directly to the original caller.
  251.  
  252. timer_enter:
  253.     mov        timer_busy,1    ; Prevent nesting.
  254.     popff
  255.     pop        timer_caller_offset ; Save caller's address.
  256.     pop        timer_caller_seg
  257.  
  258.     call        prev_vec.ptimer    ; Call previous handler, which will
  259.                     ;  pop the flags from the top of
  260.                     ;  the stack, send the EOI to the
  261.                     ;  interrupt controller, and
  262.                     ;  reenable interrupts.
  263.  
  264.     pushf                ; Call scheduler.
  265.     call        pschedblk
  266.  
  267.     push        timer_caller_seg
  268.     push        timer_caller_offset
  269.     mov        timer_busy,0    ; No longer any need to protect
  270.                     ;  stored copy of caller's address.
  271.  
  272.     db        0cbh        ; Far return.
  273.  
  274.     endProc     ivtimer
  275.  
  276.     ;*********************************************************
  277.     ;
  278.     ;    IVKEYBD -- INT 9 filter
  279.     ;
  280.     ;    This filter checks the most recent keystroke to see if it
  281.     ;    is a hot key.  If so, it records the keystroke and
  282.     ;    removes it from the type-ahead buffer.
  283.  
  284.     beginProc   ivkeybd
  285.     assume        ds:nothing, es:nothing, ss:nothing
  286.     BEGIN_IV_FILTER
  287.  
  288.     pushf
  289.     cli                ; Disable interrupts until we can
  290.                     ;  set the busy flag.
  291.     cmp        kb_busy,0        ; If this filter is already active,
  292.     je        kb_enter
  293.     popff
  294.     jmp        prev_vec.pkeybd    ;  jump to previous handler.
  295.                     ;  The previous handler will return
  296.                     ;  directly to the original caller.
  297.  
  298. kb_enter:
  299.     mov        kb_busy,1        ; Prevent nesting.
  300.     popff
  301.     pop        kb_caller_offset    ; Save caller's address.
  302.     pop        kb_caller_seg
  303.     call        prev_vec.pkeybd    ; Call previous handler, which will
  304.                     ;  pop the flags from the top of
  305.                     ;  the stack, send the EOI to the
  306.                     ;  interrupt controller, and
  307.                     ;  reenable interrupts.
  308.     pushf
  309.     push        ax
  310.     push        bx
  311.     push        cx
  312.     push        dx
  313.     push        bp
  314.     push        si
  315.     push        di
  316.     push        ds
  317.     push        es
  318.  
  319.     cmp        keyaction,IV_KY_NONE
  320.     jne        kb_exit        ; Quit if any hot key has already
  321.                     ;  been detected.
  322.  
  323.                     ; Scan table of hot keys:
  324.     mov        cx,ktsize        ;
  325.     jcxz        kb_exit        ;    Quit if table is empty.
  326.  
  327.     cmp        kb_ext,0        ; Prepare to call BIOS:
  328.     mov        dh,10h        ;  DH = 10h if extended services,
  329.     jne        kb_chosen
  330.     mov        dh,0        ;  DH = 0 if normal BIOS services.
  331. kb_chosen:
  332.  
  333.     mov        ah,1        ; Examine most recent keystroke.
  334.     add        ah,dh
  335.     int        16h
  336.     jz        kb_exit        ; Quit if none recorded.
  337.  
  338.                     ; AX contains char & key code.
  339.     les        di,pkeytab
  340.     cld
  341.  
  342. kb_loop:
  343.     scasw                ; Check one hot key listing.
  344.     je        kb_found
  345.     inc        di            ; Step over its action code.
  346.     inc        di
  347.     loop        kb_loop
  348.  
  349.     mov        keyfound,0        ; Most recent keystroke is not
  350.                     ;  a hot key.
  351.     mov        keyaction,IV_KY_NONE
  352.     jmp        short kb_exit
  353.  
  354. kb_found:                ; Found a hot key.
  355.     mov        bx,es:[di]        ; Get key action for found key.
  356.  
  357.     cmp        awake,0
  358.     jne        kb_awake        ; If intervention function is asleep
  359.     cmp        bx,IV_KY_WAKE   ;  and this is not the wakeup key,
  360.     jnz        kb_exit        ;  then quit.
  361.  
  362. kb_awake:
  363.     mov        keyfound,ax     ; Record hot key for access by the
  364.     mov        keyaction,bx    ;  scheduler.
  365.     mov        ah,0        ; Drop the keystroke from the
  366.     add        ah,dh
  367.     int        16h         ;  type-ahead buffer.
  368.  
  369. kb_exit:
  370.     pop        es
  371.     pop        ds
  372.     pop        di
  373.     pop        si
  374.     pop        bp
  375.     pop        dx
  376.     pop        cx
  377.     pop        bx
  378.     pop        ax
  379.                     ; Top of stack contains flags returned
  380.                     ;  by previous INT 9 handler.
  381.  
  382.     push        kb_caller_seg
  383.     push        kb_caller_offset
  384.     mov        kb_busy,0
  385.  
  386.     iret
  387.  
  388.     endProc     ivkeybd
  389.  
  390.     ;*********************************************************
  391.     ;
  392.     ;    IVCOM2 -- INT 0bh filter (hardware events on communications port 2)
  393.     ;
  394.     ;    The sole purpose for this filter is to maintain the com2_busy
  395.     ;    flag telling the scheduler when comm port 2 interrupts are in
  396.     ;    progress.
  397.  
  398.     beginProc   ivcom2        ; (IVCOM2 will perform a far return.)
  399.  
  400.     assume        ds:nothing, es:nothing, ss:nothing
  401.     BEGIN_IV_FILTER
  402.  
  403.     pushf
  404.     cli                ; Disable interrupts until we can
  405.                     ;  set the busy flag.
  406.     cmp        com2_busy,0     ; If this filter is already active,
  407.     je        com2_enter
  408.     popff
  409.     jmp        prev_vec.pcom2    ;  jump to previous handler.
  410.                     ;  The previous handler will return
  411.                     ;  directly to the original caller.
  412.  
  413.  
  414. com2_enter:
  415.     mov        com2_busy,1     ; Prevent nesting.
  416.     popff
  417.     pop        com2_caller_offset    ; Save caller's address.
  418.     pop        com2_caller_seg
  419.  
  420.     call        prev_vec.pcom2    ; Call previous handler, which will
  421.                     ;  pop the flags from the top of
  422.                     ;  the stack.
  423.  
  424.     push        com2_caller_seg
  425.     push        com2_caller_offset
  426.     mov        com2_busy,0
  427.  
  428.     db        0cbh        ; Far return.
  429.  
  430.     endProc     ivcom2
  431.  
  432.     ;*********************************************************
  433.     ;
  434.     ;    IVCOM1 -- INT 0ch filter (hardware events on communications port 1)
  435.     ;
  436.     ;    The sole purpose for this filter is to maintain the com1_busy
  437.     ;    flag telling the scheduler when comm port 1 interrupts are in
  438.     ;    progress.
  439.  
  440.     beginProc   ivcom1        ; (IVCOM1 will perform a far return.)
  441.  
  442.     assume        ds:nothing, es:nothing, ss:nothing
  443.     BEGIN_IV_FILTER
  444.  
  445.     pushf
  446.     cli                ; Disable interrupts until we can
  447.                     ;  set the busy flag.
  448.     cmp        com1_busy,0     ; If this filter is already active,
  449.     je        com1_enter
  450.     popff
  451.     jmp        prev_vec.pcom1    ;  jump to previous handler.
  452.                     ;  The previous handler will return
  453.                     ;  directly to the original caller.
  454.  
  455.  
  456. com1_enter:
  457.     mov        com1_busy,1     ; Prevent nesting.
  458.     popff
  459.     pop        com1_caller_offset    ; Save caller's address.
  460.     pop        com1_caller_seg
  461.  
  462.     call        prev_vec.pcom1    ; Call previous handler, which will
  463.                     ;  pop the flags from the top of
  464.                     ;  the stack.
  465.  
  466.     push        com1_caller_seg
  467.     push        com1_caller_offset
  468.     mov        com1_busy,0
  469.  
  470.     db        0cbh        ; Far return.
  471.  
  472.     endProc     ivcom1
  473.  
  474.     ;*********************************************************
  475.     ;
  476.     ;    IVDISK -- INT 13h filter (BIOS disk services)
  477.     ;
  478.     ;    The sole purpose for this filter is to maintain the disk_busy
  479.     ;    flag telling the scheduler when BIOS disk operations are in
  480.     ;    progress.
  481.  
  482.     beginProc   ivdisk        ; (IVDISK will perform a far return.)
  483.  
  484.     assume        ds:nothing, es:nothing, ss:nothing
  485.     BEGIN_IV_FILTER
  486.  
  487.     pushf
  488.     cli                ; Disable interrupts until we can
  489.                     ;  set the busy flag.
  490.     cmp        disk_busy,0     ; If this filter is already active,
  491.     je        disk_enter
  492.     popff
  493.     jmp        prev_vec.pdisk    ;  jump to previous handler.
  494.                     ;  The previous handler will return
  495.                     ;  directly to the original caller.
  496.  
  497.  
  498. disk_enter:
  499.     mov        disk_busy,1     ; Prevent nesting.
  500.     popff
  501.     pop        disk_caller_offset    ; Save caller's address.
  502.     pop        disk_caller_seg
  503.  
  504.     call        prev_vec.pdisk    ; Call previous handler, which will
  505.                     ;  pop the flags from the top of
  506.                     ;  the stack.
  507.  
  508.     push        disk_caller_seg
  509.     push        disk_caller_offset
  510.     mov        disk_busy,0
  511.  
  512.     db        0cbh        ; Far return.
  513.  
  514.     endProc     ivdisk
  515.  
  516.     ;*********************************************************
  517.     ;
  518.     ;    IVBIOSKY -- INT 16h filter (BIOS keyboard services)
  519.     ;
  520.     ;    This filter prevents DOS from encountering a Ctrl-C
  521.     ;    from the keyboard.  It works by filtering all calls to
  522.     ;    keyboard functions 0 (wait for keystroke) and 1 (test for
  523.     ;    keystroke).  If a Ctrl-C is encountered, the keystroke
  524.     ;    is discarded and the operation is repeated.
  525.  
  526.     beginProc   ivbiosky
  527.  
  528.     assume        ds:nothing, es:nothing, ss:nothing
  529.  
  530.     pushf
  531.     cli                ; Disable interrupts until we can
  532.                     ;  set the busy flag.
  533.     cmp        ah,2        ; Filter only if function number
  534.     jae        key_jmp_prev    ;  is 0 or 1.
  535.  
  536.     cmp        key_busy,0        ; If this filter is already active,
  537.     je        key_enter        ;  jump to previous handler.
  538.  
  539. key_jmp_prev:
  540.     popff
  541.     jmp        prev_16h_vec
  542.                     ; The previous handler will return
  543.                     ;  directly to the original caller.
  544.  
  545. key_enter:
  546.     mov        key_busy,1        ; Prevent nesting.
  547.  
  548.     mov        key_func_number,ah    ; Save function number.
  549.  
  550.     popff
  551.     pushf
  552.     pop        key_entry_flags
  553.  
  554.     pop        key_caller_offset    ; Save caller's address and flags
  555.     pop        key_caller_seg
  556.     pop        key_caller_flags
  557.     push        key_caller_flags    ;  but keep caller's flags on
  558.                     ;  top of stack.
  559.  
  560. key_try:
  561.     call        prev_16h_vec    ; Call previous handler, which will
  562.                     ;  pop the flags from the top of
  563.                     ;  the stack.
  564.  
  565.     pushf                ; Save flags as modified by
  566.                     ;  previous handler.
  567.  
  568.     cmp        key_func_number,0
  569.     jne        key_ready
  570.  
  571.                     ; This is function 0:  await
  572.                     ;  keystroke.
  573.     cmp        al,3
  574.     jne        key_exit
  575.     mov        cbreak,1        ; Found a Ctrl-C.
  576.     pop        ax            ; Discard flags from top of stack.
  577.  
  578. key_retry:
  579.                     ; At this point, stack is empty
  580.                     ;  of things that concern us.
  581.     push        key_entry_flags    ; Reestablish the flags that were
  582.     popff                ;  in effect at the beginning.
  583.     push        key_caller_flags
  584.     mov        ah,key_func_number
  585.     jmp        key_try
  586.  
  587. key_ready:
  588.                     ; This is function 1:  test for
  589.                     ;  keystroke.
  590.  
  591.                     ; Check ZF to see if char was found.
  592.     popff
  593.     pushf
  594.     jz        key_exit        ; Exit if no character found.
  595.  
  596.     cmp        al,3
  597.     jnz        key_exit        ; Exit if character found is not
  598.                     ;  a Ctrl-C.
  599.  
  600.     mov        cbreak,1        ; Found a Ctrl-C.
  601.  
  602.     pop        ax            ; Discard flags from top of stack.
  603.     push        key_entry_flags    ; Reestablish the flags that were
  604.     popff                ;  in effect at the beginning.
  605.     push        key_caller_flags
  606.     mov        ah,0        ; Consume the Ctrl-C.
  607.     call        prev_16h_vec
  608.     jmp        key_retry
  609.  
  610. key_exit:
  611.                     ; Top of stack has flags returned
  612.                     ;  by previous handler.
  613.     push        key_caller_seg
  614.     push        key_caller_offset
  615.     mov        key_busy,0
  616.  
  617.     iret
  618.  
  619.     endProc     ivbiosky
  620.  
  621.     ;*********************************************************
  622.     ;
  623.     ;    IVCBREAK -- INT 1Bh handler
  624.     ;
  625.     ;    This filter prevents DOS from encountering a Ctrl-Break.
  626.  
  627.     beginProc   ivcbreak
  628.  
  629.     assume        ds:nothing, es:nothing, ss:nothing
  630.  
  631.     mov        cbreak,1
  632.     iret
  633.  
  634.     endProc     ivcbreak
  635.  
  636.     ;*********************************************************
  637.     ;
  638.     ;    IVDOS -- INT 21h filter
  639.     ;
  640.     ;    The purpose of this filter is to delay the return from
  641.     ;    DOS calls if the intervention function needs DOS and is
  642.     ;    waiting for service.  After invoking DOS, this filter may
  643.     ;    enter a wait loop that will soon be released by the
  644.     ;    scheduler (which is invoked by a clock tick).
  645.  
  646.     beginProc   ivdos        ; (IVDOS will perform a far return.)
  647.  
  648.     assume        ds:nothing, es:nothing, ss:nothing
  649.     BEGIN_IV_FILTER
  650.  
  651.     push        bx
  652.     xchg        ax,bx        ; Save AX in BX.
  653.     lahf                ; Save flags in AH.
  654.  
  655.     cmp        dos_need,0        ; If intervention function doesn't
  656.     je        dos_jmp_prev    ;  need DOS, just invoke DOS directly.
  657.  
  658.     cmp        timer_busy,0    ; If timer tick is busy,
  659.     jne        dos_jmp_prev    ;  just invoke DOS directly.
  660.  
  661.                     ; Certain DOS functions examine their
  662.                     ;  return address or do not return to
  663.                     ;  their caller.  We must invoke them
  664.                     ;  directly:
  665.                     ;
  666.                     ; (Remember that we saved the function
  667.                     ;  number in BH.)
  668.                     ;
  669.     cmp        bh,26h        ; Function 26h:  Make PSP
  670.     je        dos_jmp_prev    ;  (examines caller's address)
  671.                     ;
  672.     cmp        bh,4Bh        ; Function 4Bh:  Exec
  673.     je        dos_jmp_prev    ;  (can destroy registers on return)
  674.                     ;
  675.     cmp        bh,00h        ; Function 00h:  Terminate
  676.     je        dos_jmp_prev    ;  (does not return)
  677.                     ;
  678.     cmp        bh,31h        ; Function 31h:  Keep process
  679.     je        dos_jmp_prev    ;  (does not return)
  680.                     ;
  681.     cmp        bh,4ch        ; Function 4ch:  Terminate
  682.     jne        dos_enter        ;  (does not return)
  683.  
  684.  
  685. dos_jmp_prev:
  686.     sahf                ; Restore the flags.
  687.     xchg        ax,bx
  688.     pop        bx
  689.     jmp        prev_vec.pdos   ; Jump to previous handler.
  690.                     ;  The previous handler will return
  691.                     ;  directly to the original caller.
  692.  
  693. dos_enter:                ; This is a normal DOS function call.
  694.  
  695.     sahf                ; Restore the flags.
  696.     xchg        ax,bx
  697.     pop        bx
  698.  
  699.     cli                ; Rearrange the top items on the
  700.     pop        dos_caller_offset    ; stack to bring the flags to
  701.     pop        dos_caller_seg    ; the top.
  702.     pop        dos_save_flags
  703.     push        dos_caller_seg
  704.     push        dos_caller_offset
  705.     push        dos_save_flags
  706.  
  707.     call        prev_vec.pdos   ; On return, DOS pops the flags from
  708.                     ;  the top of the stack.
  709.  
  710.     pushf
  711.     cli
  712.  
  713.     cmp        req,0        ; Skip the wait loop if the intervention
  714.     je        dos_exit        ;  function doesn't require service
  715.                     ;  at this time.
  716.  
  717.     push        es            ; Check the DOS critical section flag:
  718.     push        di
  719.     les        di,pdos_crit
  720.     cmp        es:byte ptr [di],0
  721.     pop        di
  722.     pop        es
  723.     jne        dos_exit        ;  if DOS is busy, skip the wait loop
  724.                     ;  so DOS can complete its business.
  725.  
  726.     mov        iv_wait,1
  727.     sti
  728. dos_wait:                ; Wait until somebody sets iv_wait
  729.     cmp        iv_wait,0        ;  to zero.
  730.     jne        dos_wait
  731.  
  732. dos_exit:
  733.                     ; Top of stack has flags returned by
  734.                     ;  previous INT 21h handler.
  735.     popff
  736.     db        0cbh        ; Far return.
  737.  
  738.     endProc     ivdos
  739.  
  740.  
  741.     ;*********************************************************
  742.     ;
  743.     ;    IVIDLE -- INT 28h filter
  744.     ;
  745.     ;    The purpose of this filter (similar to the INT 21h filter above)
  746.     ;    is to delay the return from INT 28h calls if the intervention
  747.     ;    function is waiting for service.  After invoking the previous
  748.     ;    handler, this filter may enter a wait loop that will soon be
  749.     ;    released by the scheduler (which is invoked by a clock tick).
  750.  
  751.     beginProc   ividle
  752.     assume        ds:nothing, es:nothing, ss:nothing
  753.     BEGIN_IV_FILTER
  754.  
  755.     pushf
  756.     cli                ; Disable interrupts until we can
  757.                     ;  set the busy flag.
  758.     cmp        idle_busy,0     ; If this filter is already active
  759.     jne        idle_jmp_prev
  760.     cmp        dos_need,0        ;  or if DOS is not needed
  761.     je        idle_jmp_prev
  762.     cmp        dkey_need,0     ;  or if DOS functions 1-12 are needed
  763.     je        idle_enter
  764. idle_jmp_prev:
  765.     popff
  766.     jmp        prev_vec.pidle  ;  jump to previous handler.
  767.                     ;  The previous handler will return
  768.                     ;  directly to the original caller.
  769.  
  770.  
  771. idle_enter:
  772.     mov        idle_busy,1     ; Prevent nesting.
  773.     popff
  774.     pop        idle_caller_offset    ; Save caller's address.
  775.     pop        idle_caller_seg
  776.  
  777.     call        prev_vec.pidle  ; Call previous handler.  On return,
  778.                     ;  it pops the flags from the top
  779.                     ;  of the stack.
  780.  
  781.     mov        idle_safe,1     ; Now we're in the nice INT 28h
  782.                     ;  environment:  all DOS functions are
  783.                     ;  allowable except functions 1-12.
  784.  
  785.     pushf
  786.  
  787.     cli
  788.     cmp        req,0        ; Skip the wait loop if the intervention
  789.     je        idle_exit        ;  function doesn't require service
  790.                     ;  at this time.
  791.  
  792.     sti
  793.     mov        iv_wait,1
  794. idle_wait:
  795.     cmp        iv_wait,0        ; Wait until somebody sets iv_wait
  796.     jne        idle_wait        ;  to zero.
  797.  
  798. idle_exit:
  799.                     ; Top of stack contains flags returned
  800.                     ;  by previous INT 28h handler.
  801.     push        idle_caller_seg
  802.     push        idle_caller_offset
  803.  
  804.     mov        idle_safe,0
  805.     mov        idle_busy,0
  806.  
  807.     iret
  808.  
  809.     endProc     ividle
  810.  
  811.     endCseg     ivctrl
  812.     endMod        ivctrl
  813.  
  814.     end
  815.