home *** CD-ROM | disk | FTP | other *** search
/ Software Collection (I) / TOOLS.iso / b04 / 15.img / COMM / IBMINT.AS_ / IBMINT.AS
Encoding:
Text File  |  1992-01-25  |  32.9 KB  |  1,360 lines

  1. page,132
  2. ;---------------------------Module-Header-------------------------------
  3. ; Module Name: IBMINT.ASM
  4. ;
  5. ; Created: Fri 06-Feb-1987 10:45:12
  6. ; Author:  Walt Moore [waltm]
  7. ;
  8. ; Copyright (c) Microsoft Corporation 1985-1990.  All Rights Reserved
  9. ;
  10. ; General Description:
  11. ;   This file contains the interrupt time routines for the
  12. ;   IBM Windows communications driver.
  13. ;
  14. ;   The interrupt code is preloaded and fixed.
  15. ;
  16. ; History:
  17. ;
  18. ; **********************************************************************
  19. ;    Tue Dec 19 1989 09:35:15    -by-  Amit Chatterjee  [amitc]
  20. ; ----------------------------------------------------------------------
  21. ;    Added a far entry point 'FakeCOMIntFar' so that the routine 'FakeCOMInt'
  22. ; could be called from the 'InitAPort' routine in IBMCOM.ASM
  23. ;
  24. ;   26.Nov.90    richp
  25. ;
  26. ;   Changed interrupt routines to use new VPICD services for bi-modal/multi-
  27. ;   modal interrupt handling.  They now work in straight real mode for real
  28. ;   mode Windows, but can also handle interrupts in real mode or protected
  29. ;   mode for standard mode Windows, and handle interrupts in RING 0 protected
  30. ;   mode for enhanced mode Windows, even when the Windows VM is not currently
  31. ;   executing.
  32. ;
  33. ;-----------------------------------------------------------------------;
  34.  
  35. subttl  Communications Hardware Interrupt Service Routines
  36.  
  37. .xlist
  38. include cmacros.inc
  39. include comdev.inc
  40. include ibmcom.inc
  41. include ins8250.inc
  42. include BIMODINT.INC
  43. .list
  44.  
  45. externFP GetSystemMsecCount
  46.  
  47. externW  COMptrs
  48. externW  activeCOMs
  49.  
  50. externD  lpPostMessage
  51.  
  52. sBegin Data
  53.  
  54. PUBLIC IRQhooks
  55. IRQhooks    label byte
  56. DefineIRQhook MACRO num
  57. IFDEF No_DOSX_Bimodal_Services
  58. IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num,,,, \
  59.                 IntCodeOFFSET DEF_RM_COM_INT_&num>
  60. ELSE
  61. IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num>
  62. ENDIF
  63. ENDM
  64. ??portnum = 1
  65. REPT MAXCOM+1
  66.     DefineIRQhook %??portnum
  67. ??portnum = ??portnum+1
  68. ENDM
  69.  
  70. PURGE DefineIRQhook
  71.  
  72. EXTRN VCD_int_callback:fword
  73.  
  74. sEnd data
  75.  
  76. createSeg _INTERRUPT,IntCode,word,public,CODE
  77. sBegin IntCode
  78. assumes cs,IntCode
  79.  
  80. page
  81.  
  82. IFDEF No_DOSX_Bimodal_Services
  83. public RM_IntDataSeg
  84. RM_IntDataSeg    dw 0
  85.   ; this variable is written into by a routine in inicom
  86.   ; if the 286 DOS extender is present.  This variable
  87.   ; contains the SEGMENT value of the data selector "_DATA"
  88.   ; so that the real mode interrupt handler may use the
  89.   ; data segment, and not it's selector !
  90.  
  91. PUBLIC    RM_CallBack
  92. RM_CallBack    dd  0
  93. ENDIF
  94.  
  95.  
  96. Control proc far
  97.     ret
  98. Control endp
  99.  
  100.  
  101. IFDEF No_DOSX_Bimodal_Services
  102. DEF_RM_Handler proc far
  103.     push    es
  104.     push    di
  105.     push    ax
  106.     mov    es, cs:[RM_IntDataSeg]
  107.     mov    di, es:[di.First_DEB]        ; ES:DI -> ComDEB
  108.     add    di, SIZE ComDEB         ; ES:DI -> BIS
  109.     mov    es:[di.BIS_Mode], 4
  110.     push    cs
  111.     call    NEAR PTR COMHandler
  112.     mov    es:[di.BIS_Mode], 0
  113.     pop    ax
  114.     pop    di                ; ES:DI -> IRQ_Hook_Struc
  115.     jc    short DEF_RM_chain
  116.     pop    es
  117.     pop    di
  118.     add    sp, 4
  119.     iret
  120.  
  121. DEF_RM_chain:
  122.     cli
  123.     push    bp
  124.     mov    bp, sp                ;stack frame:
  125.                         ;    bp+8    -> OldInt CS
  126.                         ;    bp+6    -> OldInt IP
  127.                         ;    bp+4    -> di
  128.                         ;    bp+2    -> es
  129.                         ;    bp+0    -> bp
  130.     les    di, es:[di.RM_OldIntVec]
  131.     mov    [bp+6], di
  132.     mov    [bp+8], es
  133.     pop    bp
  134.     pop    es
  135.     pop    di
  136.     ret                    ; far ret to OldInt handler
  137. DEF_RM_Handler endp
  138. ENDIF    ;No_DOSX_Bimodal_Services
  139.  
  140.  
  141. Define_DEF_COM_INT MACRO num
  142. IFDEF No_DOSX_Bimodal_Services
  143. PUBLIC DEF_RM_COM_INT_&num
  144. DEF_RM_COM_INT_&num proc far
  145.     sub    sp, 4
  146.     push    di
  147.     mov    di, DataOFFSET IRQhook&num
  148.     jmp    short DEF_RM_Handler
  149. DEF_RM_COM_INT_&num endp
  150. ENDIF
  151. PUBLIC DEF_COM_INT_&num
  152. DEF_COM_INT_&num proc far
  153.     sub    sp, 4
  154.     push    di
  155.     mov    di, DataOFFSET IRQhook&num
  156.     jmp    short DEF_Handler
  157. DEF_COM_INT_&num endp
  158. ENDM
  159.  
  160. ??portnum = 2
  161. REPT MAXCOM
  162.     Define_DEF_COM_INT %??portnum
  163. ??portnum = ??portnum+1
  164. ENDM
  165.  
  166. PURGE Define_DEF_COM_INT
  167.  
  168. IFDEF No_DOSX_Bimodal_Services
  169. PUBLIC DEF_RM_COM_INT_1
  170. DEF_RM_COM_INT_1 proc far
  171.     sub    sp, 4
  172.     push    di
  173.     mov    di, DataOFFSET IRQhook1
  174.     jmp    short DEF_RM_Handler
  175. DEF_RM_COM_INT_1 endp
  176. ENDIF
  177.  
  178. PUBLIC DEF_COM_INT_1
  179. DEF_COM_INT_1 proc far
  180.     sub    sp, 4
  181.     push    di
  182.     mov    di, DataOFFSET IRQhook1
  183. IF2
  184. .errnz $ - OFFSET DEF_Handler
  185. ENDIF
  186. DEF_COM_INT_1 endp
  187.  
  188. DEF_Handler proc far
  189.     push    es
  190.     push    di
  191.     push    ax
  192.     mov    ax, _DATA
  193.     mov    es, ax
  194.     mov    di, es:[di.First_DEB]        ; ES:DI -> ComDEB
  195.     add    di, SIZE ComDEB         ; ES:DI -> BIS
  196.     push    cs
  197.     call    NEAR PTR COMHandler
  198.     pop    ax
  199.     pop    di                ; ES:DI -> IRQ_Hook_Struc
  200.     jc    short DEF_chain
  201.     pop    es
  202.     pop    di
  203.     add    sp, 4
  204.     iret
  205.  
  206. DEF_chain:
  207.     cli
  208.     push    bp
  209.     mov    bp, sp                ;stack frame:
  210.                         ;    bp+8    -> OldInt CS
  211.                         ;    bp+6    -> OldInt IP
  212.                         ;    bp+4    -> di
  213.                         ;    bp+2    -> es
  214.                         ;    bp+0    -> bp
  215.     les    di, es:[di.OldIntVec]
  216.     mov    [bp+6], di
  217.     mov    [bp+8], es
  218.     pop    bp
  219.     pop    es
  220.     pop    di
  221.     ret                    ; far ret to OldInt handler
  222. DEF_Handler endp
  223.  
  224. ;------------------------------------------------------------------------------
  225. ;
  226. ;   ENTER:    ES:DI -> BIS
  227. ;
  228. ;   EXIT:    Carry set, if IRQ not handled by any com ports
  229. ;
  230. COMHandler proc far
  231.     push    ds
  232.     push    si
  233.     push    ax
  234.     push    bx
  235.     mov    si, es
  236.     mov    ds, si
  237.     mov    bh, -1
  238. ch_chk_all:
  239.     lea    si, [di-SIZE ComDEB]    ;ds:si -> ComDEB
  240.     mov    si, [si.IRQhook]
  241.     mov    si, [si.First_DEB]
  242.     mov    bl, -1
  243. ch_next_com:
  244.     inc    bl            ; first time bl = 0
  245.     xor    ax, ax
  246.     xchg    ax, [di.BIS_Mode]
  247.     lea    di, [si+SIZE ComDEB]
  248.     mov    [di.BIS_Mode], ax
  249.     call    CommInt
  250.     and    al, 80h
  251.     or    bl, al
  252.  
  253.     mov    si, [si.NextDEB]
  254.     or    si, si
  255.     jnz    ch_next_com
  256.  
  257.     test    bl, 7Fh         ;Q: more than 1 com port?
  258.     jnz    short ch_shared     ;   Y: check if handled
  259.     or    bl, bl            ;Q: int handled by port?
  260.     stc
  261.     jns    ch_exit         ;   N:
  262.  
  263. ch_eoi:
  264.     xor    ax, ax
  265. .errnz BIH_API_EOI
  266.     xor    bx, bx
  267.     xchg    bx, es:[di.BIS_Mode]
  268.     call    es:[bx][di.BIS_User_Mode_API]
  269.     lea    si, [di-SIZE ComDEB]    ; ds:si -> ComDEB
  270.     mov    si, [si.IRQhook]
  271.     mov    al, [si.OldMask]
  272.     shr    al, 1            ; shift bit 0 into Carry (0, if unmasked
  273.     cmc                ;   -1, if originally masked)
  274.  
  275. ch_exit:
  276.     pop    bx
  277.     pop    ax
  278.     pop    si
  279.     pop    ds
  280.     ret
  281.  
  282. ch_shared:
  283.     inc    bh            ; count loop
  284.     or    bl, bl            ;Q: int handled by any port?
  285.     js    ch_chk_all        ;   Y: check all ports again
  286.     or    bh, bh            ;Q: first time thru loop?
  287.     stc
  288.     jz    ch_exit         ;   Y: int wasn't for a COM port, so
  289.                     ;      chain to next IRQ handler
  290.     jmp    ch_eoi
  291.  
  292. COMHandler endp
  293.  
  294.  
  295. IFDEF No_DOSX_Bimodal_Services
  296.  
  297. PUBLIC Entry_From_RM
  298. Entry_From_RM proc far
  299.  
  300. ;
  301. ; Simulate the far ret
  302. ;
  303.     cld
  304.     lodsw
  305.     mov    es:[di.RealMode_IP], ax
  306.     lodsw
  307.     mov    es:[di.RealMode_CS], ax
  308.     add    es:[di.RealMode_SP], 4
  309.  
  310.     push    es
  311.     push    di
  312. .286
  313. ;
  314. ; Push far addr of Ret_To_IRET to cleanup stack and return to DPMI host
  315. ;
  316.     push    cs
  317.     push    IntCodeOFFSET Ret_To_IRET
  318. ;
  319. ; Push far addr of proc to call, so we can do a far ret to it
  320. ;
  321.     push    es:[di.RealMode_CX]    ; segment of callback
  322.     push    es:[di.RealMode_DX]    ; offset of callback
  323.     mov    di, es:[di.RealMode_DI]
  324.     ret                ; far ret to cx:dx
  325.                     ;   called proc will do a far ret
  326. Ret_To_IRET:                ; <- to here
  327.     pop    di
  328.     pop    es
  329.     iret
  330. .8086
  331.  
  332. Entry_From_RM endp
  333.  
  334. PUBLIC RM_APIHandler
  335. RM_APIHandler proc far
  336.     cmp    ax, BIH_API_Call_Back
  337.     jne    APIHandler
  338.     call    cs:[RM_CallBack]
  339.     ret
  340. RM_APIHandler endp
  341.  
  342. ENDIF
  343.  
  344. ;------------------------------------------------------------------------------
  345. ;
  346. ;   ENTER:    ES:DI -> BIS
  347. ;
  348. APIHandler proc far
  349.  
  350.     or    ax, ax
  351.     jnz    short api_not_EOI
  352. .errnz    BIH_API_EOI
  353.     mov    ax, es:[di.BIS_IRQ_Number]
  354.     cmp    al,8            ;Q: slave IRQ?
  355.     mov    al,EOI
  356.     jb    short api_master    ;   N:
  357.     out    0A0h,al         ;   Y: EOI slave
  358. api_master:
  359.     out    INTA0,al        ; EOI master
  360.     ret
  361.  
  362. api_not_EOI:
  363.     cmp    ax, BIH_API_Call_Back
  364.     jae    short api_callme
  365.     push    dx
  366.     push    cx
  367.     mov    dx, INTA1
  368.     mov    cx,  es:[di.BIS_IRQ_Number]
  369.     cmp    cl, 8            ;Q: 2nd PIC?
  370.     jb    @f            ;   N:
  371.     mov    dx, 0A1h        ;   Y: dx = mask port
  372.     sub    cl, 8
  373. @@:
  374.     cmp    al, BIH_API_Get_Mask    ;Q: get IRQ mask?
  375.     jae    api_get_mask        ;   Y:
  376.     mov    ah, al
  377.     mov    ch, 1
  378.     shl    ch, cl            ; ch = mask byte
  379.     pushf
  380.     cli
  381.     in    al, dx            ; get current PIC mask state
  382.     cmp    ah, BIH_API_Mask    ;Q: mask IRQ?
  383.     jne    @f            ;   N:
  384.     or    al, ch            ;   Y: set IRQ's bit
  385.     jmp    short api_mask_exit
  386. @@:
  387.     not    ch            ;   N: clear IRQ's bit to unmask
  388.     and    al, ch
  389. api_mask_exit:
  390.     out    dx, al
  391.     pop    ax
  392.     test    ah, 2            ;Q: ints were enabled?
  393.     jz    @f            ;   N:
  394.     sti
  395. @@:
  396.     pop    cx
  397.     pop    dx
  398.     ret
  399.  
  400. api_get_mask:
  401.     in    al, dx            ; get current PIC mask state
  402.     inc    cl
  403.     shr    al, cl            ; move IRQ's bit into carry
  404.                     ; Carry set, if IRQ masked
  405.     pop    cx
  406.     pop    dx
  407.     ret
  408.  
  409. api_callme:
  410.     push    cx
  411.     push    dx
  412.     ret                ; far ret to call back, which will
  413.                     ; do a far ret to our caller
  414. APIHandler endp
  415.  
  416.  
  417. ;--------------------------Fake a Hardware Interrupt----------------------;
  418. ; FakeCOMInt
  419. ;
  420. ; This routine fakes a hardware interrupt to IRQ3 or IRQ4
  421. ; to clear out characters pending in the buffer
  422. ;
  423. ; Entry:
  424. ;   DS:SI --> DEB
  425. ;   INTERRUPTS DISABLED!
  426. ; Returns:
  427. ;   None
  428. ; Error Returns:
  429. ;   None
  430. ; Registers Preserved:
  431. ;
  432. ; Registers Destroyed:
  433. ;   AX,DX,FLAGS
  434. ; History: glenn steffler 5/17/89
  435. ;-----------------------------------------------------------------------;
  436.  
  437. FakeCOMInt proc near
  438.  
  439.       ; cli                ;Done by caller
  440. ;
  441. ; WARNING: jumping into the middle of CommInt, so the stack must be set
  442. ;       properly.
  443. ;
  444.     push    dx
  445.     push    bx
  446.     push    cx
  447.     push    di
  448.     push    es
  449.     push    EvtWord[si]
  450.     mov    dx,Port[si]        ;Get device I/O address
  451.     add    dl, ACE_IIDR
  452.     push    dx
  453.     jmp    FakeXmitEmpty        ;Process the fake interrupt, DS:SI is
  454.                     ;  already pointing to proper DEB
  455. ;
  456. ; FakeXmitEmpty falls in XmitEmpty which jumps back into CommInt.  When CommInt
  457. ; determines that no interrupt is pending, then it will near return back to
  458. ; FakeCOMIntFar which can far ret back to its caller.
  459. ;
  460. FakeCOMInt endp
  461.  
  462. public    FakeCOMIntFar
  463. FakeCOMIntFar proc far
  464.  
  465.     call    FakeCOMInt
  466.     ret
  467.  
  468. FakeCOMIntFar endp
  469.  
  470. ;--------------------------Interrupt Handler----------------------------
  471. ;
  472. ; CommInt - Interrupt handler for com ports
  473. ;
  474. ; Interrupt handlers for PC com ports.    This is the communications
  475. ; interrupt service routine for RS232 communications.  When an RS232
  476. ; event occurs the interrupt vectors here.  This routine determines
  477. ; who the caller was and services the appropriate interrupt.  The
  478. ; interrupts are prioritized in the following order:
  479. ;
  480. ;     1.  line status interrupt
  481. ;     2.  read data available interrupt
  482. ;     3.  transmit buffer empty interrupt
  483. ;     4.  modem service interrupt
  484. ;
  485. ; This routine continues to service until all interrupts have been
  486. ; satisfied.
  487. ;
  488. ; Entry:
  489. ;   DS:SI --> DEB
  490. ;   INTERRUPTS DISABLED!
  491. ; Returns:
  492. ;   AL = 0, if not handled, -1, if handled
  493. ;
  494. ;-----------------------------------------------------------------------
  495.  
  496. assumes ds,Data
  497. assumes es,nothing
  498.  
  499. ;   Dispatch table for interrupt types
  500.  
  501. SrvTab label word
  502.     dw    OFFSET ModemStatus    ;[0] Modem Status Interrupt
  503.     dw    OFFSET XmitEmpty    ;[2] Tx Holding Reg. Interrupt
  504.     dw    OFFSET DataAvail    ;[4] Rx Data Available Interrupt
  505.                     ;   or [C] if 16550 & 16550A
  506.     dw    OFFSET LineStat     ;[6] Reciever Line Status Interrupt
  507.  
  508.  
  509.     public    CommInt
  510.  
  511. CommInt proc near
  512.  
  513.     xor    al, al
  514.     cmp    word ptr [VCD_int_callback+4], 0
  515.     je    short @F            ; jump if no callback (not 3.1 VCD)
  516.     test    [si.VCDflags], fCOM_ignore_ints ;Q: we still own port?
  517.     jnz    IntLoop40            ;   N: ignore the int
  518. .386
  519.     push    esi
  520.     mov    esi, [si.VCD_data]
  521.     call    [VCD_int_callback]
  522.     pop    esi
  523. .8086
  524. @@:
  525.  
  526.     push    dx
  527.     mov    dx,Port[si]        ;Get comm I/O port
  528.     add    dl,ACE_IIDR        ;--> Interrupt ID Register
  529.     in    al, dx
  530.     test    al, 1            ;Q: interrupt pending?
  531.     jnz    short IntLoop30     ;   N:
  532.  
  533.     push    bx
  534.     push    cx
  535.     push    di
  536.     push    es
  537.     mov    cx, EvtWord[si]
  538.     push    cx
  539.     jmp    short IntLoop10
  540.  
  541. InterruptLoop_ChkTx:
  542.     cmp    QOutCount[si],0     ;Output queue empty?
  543.     je    short InterruptLoop    ;   Y: don't chk tx
  544.     pop    dx
  545.     push    dx
  546.     dec    dx            ; to IER
  547. .errnz ACE_IIDR - ACE_IER - 1
  548.     in    al, dx
  549.     and    al,NOT ACE_ETBEI    ; disable it
  550.     iodelay
  551.     out    dx, al
  552.     or    al, ACE_ETBEI        ; enable it again
  553.     iodelay
  554.     out    dx, al
  555.     iodelay
  556.     out    dx, al
  557.  
  558. InterruptLoop:
  559.     pop    dx            ;Get ID reg I/O address
  560.  
  561.     in    al,dx            ;Get Interrupt Id
  562.     test    al,1            ;Interrupt need servicing?
  563.     jnz    IntLoop20        ;No, all done
  564.  
  565. IntLoop10:
  566.     and    ax, 07h
  567.     mov    di,ax
  568.     push    dx            ;Save Id register
  569.     jmp    SrvTab[di]        ;Service the Interrupt
  570.  
  571. IntLoop20:
  572.     mov    ax,EvtMask[si]        ;Mask the event word to only the
  573.     and    ax, EvtWord[si]     ;  user specified bits
  574.     mov    EvtWord[si], ax
  575.     pop    bx
  576.     test    [si.NotifyFlagsHI], CN_Notify
  577.     jz    short ci_exit
  578.     not    bx
  579.     and    ax, bx            ; bits set in ax are new events
  580.     jnz    short ci_new_events
  581.  
  582. ci_exit:
  583.     pop    es
  584.     assumes es,nothing
  585.  
  586.     pop    di
  587.     pop    cx
  588.     pop    bx
  589.     xor    al, al
  590.  
  591. IntLoop30:
  592.     pop    dx
  593.     and    al, 1
  594.     dec    al            ; 0->-1, 1->0
  595. IntLoop40:
  596.     ret
  597.  
  598. ci_new_events:
  599.     mov    ax, CN_EVENT
  600.     call    notify_owner
  601.     jmp    ci_exit
  602.  
  603. CommInt endp
  604.  
  605. page
  606.  
  607. ;----------------------------Private-Routine----------------------------;
  608. ;
  609. ; LineStat - Line Status Interrupt Handler
  610. ;
  611. ; Break detection is handled and set in the event word if
  612. ; enabled.  Other errors (overrun, parity, framing) are
  613. ; saved for the data available interrupt.
  614. ;
  615. ; This routine used to fall into DataAvail for the bulk of its processing.
  616. ; This is no longer the case...  A very popular internal modem seems to
  617. ; operate differently than a real 8250 when parity errors occur.  Falling
  618. ; into the DataAvail handler on a parity error caused the same character
  619. ; to be received twice.  Having this routine save the LSR status, and
  620. ; return to InterruptLoop fixes the problem, and still works on real COMM
  621. ; ports.  The extra overhead isn't a big deal since this routine is only
  622. ; entered when there is an exception like a parity error.
  623. ;
  624. ; This routine is jumped to, and will perform a jump back into
  625. ; the dispatch loop.
  626. ;
  627. ; Entry:
  628. ;   DS:SI --> DEB
  629. ;   DX     =  Port.IIDR
  630. ; Returns:
  631. ;   None
  632. ; Error Returns:
  633. ;   None
  634. ; Registers Destroyed:
  635. ;   AX,FLAGS
  636. ; History:
  637. ;-----------------------------------------------------------------------;
  638.  
  639.  
  640. ; assumes ds,Data
  641. assumes es,nothing
  642.  
  643. public LineStat             ;Public for debugging
  644. LineStat proc near
  645.  
  646.     or    by EvtWord[si],EV_Err    ;Show line status error
  647.  
  648.     add    dl,ACE_LSR-ACE_IIDR    ;--> Line Status Register
  649.     in    al,dx
  650.     test    al,ACE_PE+ACE_FE+ACE_OR ;Parity, Framing, Overrun error?
  651.     jz    @f
  652.  
  653.     mov    LSRShadow[si],al    ;yes, save status for DataAvail
  654. @@:
  655.     test    al,ACE_BI        ;Break detect?
  656.     jz    InterruptLoop_ChkTx    ;Not break detect interrupt
  657.  
  658.     or    by EvtWord[si],EV_Break ;Show break
  659.  
  660.     jmp    short InterruptLoop_ChkTx
  661.  
  662. LineStat   endp
  663.  
  664. page
  665.  
  666. ;----------------------------Private-Routine----------------------------;
  667. ;
  668. ; DataAvail - Data Available Interrupt Handler
  669. ;
  670. ; The available character is read and stored in the input queue.
  671. ; If the queue has reached the point that a handshake is needed,
  672. ; one is issued (if enabled).  EOF detection, Line Status errors,
  673. ; and lots of other stuff is checked.
  674. ;
  675. ; This routine is jumped to, and will perform a jump back into
  676. ; the dispatch loop.
  677. ;
  678. ; Entry:
  679. ;   DS:SI --> DEB
  680. ;   DX     =  Port.IIDR
  681. ; Returns:
  682. ;   None
  683. ; Error Returns:
  684. ;   None
  685. ; Registers Destroyed:
  686. ;   AX,BX,CX,DI,ES,FLAGS
  687. ; History:
  688. ;-----------------------------------------------------------------------;
  689.  
  690. ; assumes ds,Data
  691. assumes es,nothing
  692.  
  693. public DataAvail                       ;public for debugging
  694. DataAvail   proc   near
  695.  
  696.     sub    dl,ACE_IIDR-ACE_RBR    ;--> receiver buffer register
  697.     in    al,dx            ;Read received character
  698.  
  699.     and    [si.NotifyFlagsHI], NOT CN_Idle ; flag as not idle
  700.  
  701.     mov    ah,LSRShadow[si]    ;what did the last Line Status intrpt
  702.     mov    bh,ah            ;  have to say?
  703.     or    ah,ah
  704.     jz    @f
  705.  
  706.     and    ah,ErrorMask[si]    ;there was an error, record it
  707.     or    by ComErr[si],ah
  708.     mov    LSRShadow[si],0
  709.     .errnz    ACE_OR-CE_OVERRUN    ;Must be the same bits
  710.     .errnz    ACE_PE-CE_RXPARITY
  711.     .errnz    ACE_FE-CE_FRAME
  712.     .errnz    ACE_BI-CE_BREAK
  713. @@:
  714.  
  715. ; Regardless of the character received, flag the event in case
  716. ; the user wants to see it.
  717.  
  718.     or    by EvtWord[si],EV_RxChar ;Show a character received
  719.     .errnz HIGH EV_RxChar
  720.  
  721. ; Check the input queue, and see if there is room for another
  722. ; character.  If not, or if the end of file character has already
  723. ; been received, then go declare overflow.
  724.  
  725. DataAvail00:
  726.  
  727.     mov    cx,QInCount[si]     ;Get queue count (used later too)
  728.     cmp    cx,QInSize[si]        ;Is queue full?
  729.     jge    DataAvail20        ;  Yes, comm overrun
  730.     test    EFlags[si],fEOF     ;Has end of file been received?
  731.     jnz    DataAvail20        ;  Yes - treat as overflow
  732.  
  733. ; Test to see if there was a parity error, and replace
  734. ; the character with the parity character if so
  735.  
  736.     test    bh,ACE_PE        ;Parity error
  737.     jz    DataAvail25        ;  No
  738.     test    [si.DCB_Flags2],fPErrChar   ;Parity error replacement character?
  739.     jz    DataAvail25        ;  No
  740.     mov    al,[si.DCB_PEChar]    ;  Yes, get parity replacement char
  741.  
  742. ; Skip all other processing except event checking and the queing
  743. ; of the parity error replacement character
  744.  
  745.     jmp    short DataAvail80    ;Skip all but event check, queing
  746.  
  747. DataAvail20:
  748.     or    by ComErr[si],CE_RXOVER ;Show queue overrun
  749.     jmp    short DataAvail50
  750.  
  751. ; See if we need to strip null characters, and skip
  752. ; queueing if this is one.  Also remove any parity bits.
  753.  
  754. DataAvail25:
  755.     and    al,RxMask[si]        ;Remove any parity bits
  756.     jnz    DataAvail30        ;Not a Null character
  757.     test    [si.DCB_Flags2],fNullStrip  ;Are we stripping received nulls?
  758.     jnz    DataAvail50        ;  Yes, put char in the bit bucket
  759.  
  760. ; Check to see if we need to check for EOF characters, and if so
  761. ; see if this character is it.
  762.  
  763. DataAvail30:
  764.     test    [si.DCB_Flags],fBinary    ;Is this binary stuff?
  765.     jnz    DataAvail60        ;  Yes, skip EOF check
  766.     cmp    al,[si.DCB_EOFChar]    ;Is this the EOF character?
  767.     jnz    DataAvail60        ;  No, see about queing the charcter
  768.     or    EFlags[si],fEOF     ;Set end of file flag
  769. DataAvail50:
  770.     jmp    DataAvail140        ;Skip the queing process
  771.  
  772. ; If output XOn/XOff is enabled, see if the character just received
  773. ; is either an XOn or XOff character.  If it is, then set or
  774. ; clear the XOffReceived flag as appropriate.
  775.  
  776. DataAvail60:
  777.     test    [si.DCB_Flags2],fOutX    ;Output handshaking?
  778.     jz    DataAvail80        ;  No
  779.     cmp    al,[si.DCB_XoffChar]    ;Is this an X-Off character?
  780.     jnz    DataAvail70        ;  No, see about XOn or Ack
  781.     or    HSFlag[si],XOffReceived ;Show XOff received, ENQ or ETX [rkh]
  782.     test    [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
  783.     jz    DataAvail50        ;  No
  784.     cmp    cx,[si.DCB_XonLim]    ;See if at XOn limit
  785.     ja    DataAvail50        ;  No
  786.     and    HSFlag[si],NOT XOffReceived ;Show ENQ or ETX not received
  787.     and    HSFlag[si], NOT XOnPending+XOffSent
  788.     mov    al, [si.DCB_XonChar]
  789.     call    OutHandshakingChar
  790.     jmp    DataAvail50        ;Done
  791.  
  792. DataAvail70:
  793.     cmp    al,[si.DCB_XonChar]    ;Is this an XOn character?
  794.     jnz    DataAvail80        ;  No, just a normal character
  795.     and    HSFlag[si],NOT XOffReceived
  796.     test    [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
  797.     jz    DataAvail75        ;  No - jump to FakeXmitEmpty to get
  798.                     ;    transmitting going again
  799.     and    HSFlag[si],NOT EnqSent
  800.  
  801. DataAvail75:
  802.     jmp    FakeXmitEmpty        ;Restart transmit
  803.  
  804. ; Now see if this is a character for which we need to set an event as
  805. ; having occured. If it is, then set the appropriate event flag
  806.  
  807.  
  808. DataAvail80:
  809.     cmp    al,[si.DCB_EVTChar]    ;Is it the event generating character?
  810.     jne    DataAvail90        ;  No
  811.     or    by EvtWord[si],EV_RxFlag   ;Show received specific character
  812.  
  813. ; Finally, a valid character that we want to keep, and we have
  814. ; room in the queue. Place the character in the queue.
  815. ; If the discard flag is set, then discard the character
  816.  
  817. DataAvail90:
  818.     test    MiscFlags[si], Discard    ;Discarding characters ?
  819.     jnz    DataAvail50        ;  Yes
  820.  
  821.     lea    bx, [si+SIZE ComDEB]    ; DS:BX -> BIS
  822.     mov    bx, [bx.BIS_Mode]    ; mode will be either 0 or 4
  823.     les    di,QInAddr[si][bx]    ;Get queue base pointer from either
  824.     assumes es,nothing        ;   QInAddr or AltQInAddr
  825.  
  826.     mov    bx,QInPut[si]        ;Get index into queue
  827.     mov    es:[bx][di],al        ;Store the character
  828.     inc    bx            ;Update queue index
  829.     cmp    bx,QInSize[si]        ;See if time for wrap-around
  830.     jc    DataAvail100        ;Not time to wrap
  831.     xor    bx,bx            ;Wrap-around is a new zero pointer
  832.  
  833. DataAvail100:
  834.     mov    QInPut[si],bx        ;Store updated pointer
  835.     inc    cx            ;And update queue population
  836.     mov    QInCount[si],cx
  837.  
  838. ; If flow control has been enabled, see if we are within the
  839. ; limit that requires us to halt the host's transmissions
  840.  
  841.     cmp    cx,XOffPoint[si]    ;Time to see about XOff?
  842.     jc    DataAvail120        ;  Not yet
  843.     test    HSFlag[si],HSSent    ;Handshake already sent?
  844.     jnz    DataAvail120        ;  Yes, don't send it again
  845.  
  846.     mov    ah,HHSLines[si]     ;Should hardware lines be dropped?
  847.     or    ah,ah            ;  (i.e. do we have HW HS enabled?)
  848.     jz    DataAvail110        ;  No
  849.     add    dl,ACE_MCR        ;  Yes
  850.     in    al,dx            ;Clear the necessary bits
  851.     not    ah
  852.     and    al,ah
  853.     or    HSFlag[si],HHSDropped    ;Show lines have been dropped
  854.     out    dx,al            ;  and drop the lines
  855.     sub    dl,ACE_MCR
  856.  
  857. DataAvail110:
  858.     test    [si.DCB_Flags2],fInX    ;Input Xon/XOff handshaking
  859.     jz    DataAvail120        ;  No
  860.     or    HSFlag[si], XOffSent
  861.     mov    al, [si.DCB_XoffChar]
  862.     call    OutHandshakingChar
  863.  
  864. DataAvail120:
  865.     cmp    cx, [si.RecvTrigger]    ;Q: time to call owner's callback?
  866.     jb    short DataAvail130    ;   N:
  867.  
  868.     test    [si.NotifyFlagsHI], CN_RECEIVE
  869.     jnz    short DataAvail140    ; jump if notify already sent and
  870.                     ;   data in buffer hasn't dropped
  871.                     ;   below threshold
  872.     mov    ax, IntCodeOFFSET DataAvail140
  873.     push    ax
  874.     mov    ax, CN_RECEIVE
  875. %OUT probably should just set a flag and notify after EOI
  876.     jmp    notify_owner
  877.  
  878. DataAvail130:
  879.     and    [si.NotifyFlagsHI], NOT CN_RECEIVE
  880.  
  881. DataAvail140:
  882.     pop    dx
  883.     push    dx
  884.     add    dl, ACE_LSR-ACE_IIDR
  885.     in    al, dx
  886.     test    al, ACE_DR        ;Q: more data available?
  887.     jz    @F            ;   N:
  888.     sub    dl, ACE_LSR        ;   Y: go read it
  889.     in    al, dx            ;Read available character
  890.     jmp    DataAvail00
  891. @@:
  892.     jmp    InterruptLoop_ChkTx
  893.  
  894. DataAvail endp
  895.  
  896.  
  897. OutHandshakingChar proc near
  898.  
  899.     add    dl, ACE_LSR
  900.     mov    ah, al
  901. @@:
  902.     in    al, dx
  903.     test    al, ACE_THRE
  904.     jz    @B
  905.     sub    dl, ACE_LSR
  906.     mov    al, ah
  907.     out    dx, al
  908.     ret
  909.  
  910. OutHandshakingChar endp
  911.  
  912.  
  913. page
  914.  
  915. ;----------------------------Private-Routine----------------------------;
  916. ;
  917. ; XmitEmpty - Transmitter Register Empty
  918. ;
  919. ; Entry:
  920. ;   DS:SI --> DEB
  921. ;   DX     =  Port.IIDR
  922. ; Returns:
  923. ;   None
  924. ; Error Returns:
  925. ;   None
  926. ; Registers Destroyed:
  927. ;   AX,BX,CX,DI,ES,FLAGS
  928. ; History:
  929. ;-----------------------------------------------------------------------;
  930.  
  931. ; assumes ds,Data
  932. assumes es,nothing
  933.  
  934. public FakeXmitEmpty
  935. FakeXmitEmpty:
  936.     pop    dx
  937.     push    dx
  938.  
  939. ; "Kick" the transmitter interrupt routine into operation.
  940.  
  941.     dec    dl
  942. .errnz ACE_IIDR - ACE_IER-1
  943.     in    al,dx            ;Get current IER state
  944.     test    al,ACE_ETBEI        ;Interrupt already enabled?
  945.     jnz    @F            ;  Yes, don't reenable it
  946.     or    al,ACE_ETBEI        ;  No, enable it
  947.     out    dx,al
  948.     iodelay             ;8250, 8250-B bug requires
  949.     out    dx,al            ;  writting register twice
  950. @@:
  951.     add    dl,ACE_LSR-ACE_IER    ;--> Line Status Register
  952.     iodelay
  953.     in    al,dx            ;Is xmit really empty?
  954.     sub    dl,ACE_LSR-ACE_THR    ;--> Transmitter Holding Register
  955.     test    al,ACE_THRE
  956.     jnz    short XmitEmpty5    ;   Y: send next char
  957.     jmp    InterruptLoop        ;   N: return to processing loop
  958.  
  959. public XmitEmpty
  960. XmitEmpty proc near
  961.  
  962.     add    dl,ACE_LSR-ACE_IIDR    ;--> Line Status Register
  963.     in    al,dx            ;Is xmit really empty?
  964.     sub    dl,ACE_LSR-ACE_THR    ;--> Transmitter Holding Register
  965.     test    al,ACE_THRE
  966.     jz    Xmit_jumpto90        ;Transmitter not empty, cannot send
  967.  
  968. ; If the hardware handshake lines are down, then XOff/XOn cannot
  969. ; be sent.  If they are up and XOff/XOn has been received, still
  970. ; allow us to transmit an XOff/XOn character.  It will make
  971. ; a dead lock situation less possible (even though there are
  972. ; some which could happen that cannot be handled).
  973.  
  974. XmitEmpty5:
  975.     mov    ah,HSFlag[si]        ;Get handshaking flag
  976.     test    ah,HHSDown+BreakSet    ;Hardware lines down or break set?
  977.     jnz    Xmit_jumpto100        ;  Yes, cannot transmit
  978.  
  979. ; Give priority to any handshake character waiting to be
  980. ; sent.  If there are none, then check to see if there is
  981. ; an "immediate" character to be sent.  If not, try the queue.
  982.  
  983. XmitEmpty10:
  984.     test    [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
  985.     jnz    XmitEmpty40        ;  Yes
  986.  
  987. XmitEmpty15:
  988.     test    ah,HSPending        ;XOff or XOn pending
  989.     jz    XmitEmpty40        ;  No
  990.  
  991. XmitEmpty20:
  992.     and    ah,NOT XOnPending+XOffSent
  993.     mov    al,[si.DCB_XonChar]    ;Get XOn character
  994.  
  995. XmitEmpty30:
  996.     mov    HSFlag[si],ah        ;Save updated handshake flag
  997.     jmp    XmitEmpty110        ;Go output the character
  998.  
  999. Xmit_jumpto90:
  1000.     jmp    XmitEmpty90
  1001.  
  1002. ; If any of the lines which were specified for a timeout are low, then
  1003. ; don't send any characters.  Note that by putting the check here,
  1004. ; XOff and Xon can still be sent even though the lines might be low.
  1005.  
  1006. ; Also test to see if a software handshake was received.  If so,
  1007. ; then transmission cannot continue.  By delaying the software check
  1008. ; to here, XOn/XOff can still be issued even though the host told
  1009. ; us to stop transmission.
  1010.  
  1011. XmitEmpty40:
  1012.     test    ah,CannotXmit        ;Anything preventing transmission?
  1013.     jz    XmitEmpty45        ;  No
  1014. Xmit_jumpto100:
  1015.     jmp    XmitEmpty100        ;  Yes, disarm and exit
  1016.  
  1017. ; If a character has been placed in the single character "transmit
  1018. ; immediately" buffer, clear that flag and pick up that character
  1019. ; without affecting the transmitt queue.
  1020.  
  1021. XmitEmpty45:
  1022.     test    EFlags[si],fTxImmed    ;Character to xmit immediately?
  1023.     jz    XmitEmpty515        ;  No, try the queue
  1024.     and    EFlags[si],NOT fTxImmed ;Clear xmit immediate flag
  1025.     mov    al,ImmedChar[si]    ;Get char to xmit
  1026.     jmp    XmitEmpty110        ;Transmit the character
  1027.  
  1028. XmitEmpty515:
  1029.     mov    cx,QOutCount[si]    ;Output queue empty?
  1030.     jcxz    Xmit_jumpto90        ;  Yes, go set an event
  1031.  
  1032.     test    [si.DCB_Flags],fEtxAck    ;Etx Ack?
  1033.     jz    XmitEmpty55        ;  No
  1034.     mov    cx,QOutMod[si]        ;Get number bytes sent since last ETX
  1035.     cmp    cx,[si.DCB_XonLim]    ;At Etx limit yet?
  1036.     jne    XmitEmpty51        ;  No, inc counter
  1037.     mov    QOutMod[si],0        ;  Yes, zero counter
  1038.     or    HSFlag[si],EtxSent    ;Show ETX sent
  1039.     jmp    short XE_sendXOFF
  1040.  
  1041. XmitEmpty51:
  1042.     inc    cx            ; Update counter
  1043.     mov    QOutMod[si],cx        ; Save counter
  1044.     jmp    short XmitEmpty59    ; Send queue character
  1045.  
  1046. XmitEmpty55:
  1047.     test    [si.DCB_Flags],fEnqAck    ;Enq Ack?
  1048.     jz    XmitEmpty59        ;  No, send queue character
  1049.     mov    cx,QOutMod[si]        ;Get number bytes sent since last ENQ
  1050.     or    cx,cx            ;At the front again?
  1051.     jnz    XmitEmpty56        ;  No, inc counter
  1052.     mov    QOutMod[si],1        ;  Yes, send ENQ
  1053.     or    HSFlag[si],EnqSent    ;Show ENQ sent
  1054. XE_sendXOFF:
  1055.     mov    al,[si.DCB_XoffChar]
  1056.     jmp    short XmitEmpty110    ;Go output the character
  1057.  
  1058. XmitEmpty56:
  1059.     inc    cx            ;Update counter
  1060.     cmp    cx,[si.DCB_XonLim]    ;At end of our out buffer len?
  1061.     jne    XmitEmpty58        ;  No
  1062.     xor    cx,cx            ;Show at front again.
  1063.  
  1064. XmitEmpty58:
  1065.     mov    QOutMod[si],cx        ;Save counter
  1066.  
  1067. XmitEmpty59:
  1068.     lea    bx, [si+SIZE ComDEB]    ; DS:BX -> BIS
  1069.     mov    bx, [bx.BIS_Mode]    ; mode will be either 0 or 4
  1070.     les    di,QOutAddr[si][bx]    ;Get queue base pointer from either
  1071.     assumes es,nothing        ;   QOutAddr or AltQOutAddr
  1072.  
  1073.     mov    bx,QOutGet[si]        ;Get pointer into queue
  1074.     mov    al,es:[bx][di]        ;Get the character
  1075.  
  1076.     inc    bx            ;Update queue pointer
  1077.     cmp    bx,QOutSize[si]     ;See if time for wrap-around
  1078.     jc    XmitEmpty60        ;Not time for wrap
  1079.     xor    bx,bx            ;Wrap by zeroing the index
  1080.  
  1081. XmitEmpty60:
  1082.     mov    QOutGet[si],bx        ;Save queue index
  1083.     mov    cx,QOutCount[si]    ;Output queue empty?
  1084.     dec    cx            ;Dec # of bytes in queue
  1085.     mov    QOutCount[si],cx    ;  and save new population
  1086.  
  1087.     out    dx,al            ;Send char
  1088.  
  1089.     cmp    cx, [si.SendTrigger]    ;Q: time to call owner's callback?
  1090.     jae    short XmitEmpty70    ;   N:
  1091.  
  1092.     test    [si.NotifyFlagsHI], CN_TRANSMIT
  1093.     jnz    short XmitEmpty80    ; jump if notify already sent and
  1094.                     ;   data in buffer hasn't raised
  1095.                     ;   above threshold
  1096.     mov    ax, IntCodeOFFSET XmitEmpty80
  1097.     push    ax
  1098.     mov    ax, CN_TRANSMIT
  1099.     jmp    short notify_owner
  1100.  
  1101. XmitEmpty70:
  1102.     and    [si.NotifyFlagsHI], NOT CN_TRANSMIT
  1103.  
  1104. XmitEmpty80:
  1105. %OUT check fNoFIFO in EFlags[si] to determine if we can queue more output
  1106.     jmp    InterruptLoop
  1107.  
  1108.  
  1109. ; No more characters to transmit.  Flag this as an event.
  1110.  
  1111. XmitEmpty90:
  1112.     or    by EvtWord[si],EV_TxEmpty
  1113.  
  1114. ; Cannot continue transmitting (for any of a number of reasons).
  1115. ; Disable the transmit interrupt.  When it's time resume, the
  1116. ; transmit interrupt will be reenabled, which will generate an
  1117. ; interrupt.
  1118.  
  1119. XmitEmpty100:
  1120.     inc    dx            ;--> Interrupt Enable Register
  1121.     .errnz    ACE_IER-ACE_THR-1
  1122.     in    al,dx            ;I don't know why it has to be read
  1123.     and    al,NOT ACE_ETBEI    ;  first, but it works this way
  1124. XmitEmpty110:
  1125.     out    dx,al
  1126.     jmp    InterruptLoop
  1127.  
  1128. XmitEmpty endp
  1129.  
  1130. page
  1131.  
  1132. ;----------------------------Private-Routine----------------------------;
  1133. ;
  1134. ; ModemStatus - Modem Status Interrupt Handler
  1135. ;
  1136. ; Entry:
  1137. ;   DS:SI --> DEB
  1138. ;   DX     =  Port.IIDR
  1139. ; Returns:
  1140. ;   None
  1141. ; Error Returns:
  1142. ;   None
  1143. ; Registers Destroyed:
  1144. ;   AX,BX,CX,DI,ES,FLAGS
  1145. ; History:
  1146. ;-----------------------------------------------------------------------;
  1147.  
  1148.  
  1149. ; assumes ds,Data
  1150. assumes es,nothing
  1151.  
  1152. public ModemStatus                     ;Public for debugging
  1153. ModemStatus proc near
  1154.  
  1155. ; Get the modem status value and shadow it for MSRWait.
  1156.  
  1157.     add    dl,ACE_MSR-ACE_IIDR    ;--> Modem Status Register
  1158.     in    al,dx
  1159.     mov    MSRShadow[si],al    ;Save MSR data for others
  1160.     mov    ch,al            ;Save a local copy
  1161.  
  1162. ; Create the event mask for the delta signals
  1163.  
  1164.     mov    ah,al            ;Just a lot of shifting
  1165.     shr    ax,1
  1166.     shr    ax,1
  1167.     shr    ah,1
  1168.     mov    cl,3
  1169.     shr    ax,cl
  1170.     and    ax,EV_CTS+EV_DSR+EV_RLSD+EV_Ring
  1171.     or    EvtWord[si],ax
  1172.  
  1173.     mov    ah,ch                       ;[rkh]...
  1174.     shr    ah,1
  1175.     shr    ah,1
  1176.     and    ax,EV_CTSS+EV_DSRS
  1177.     or    EvtWord[si],ax
  1178.  
  1179.     mov    ah,ch
  1180.     mov    cl,3
  1181.     shr    ah,cl
  1182.     and    ax,EV_RLSD
  1183.     or    EvtWord[si],ax
  1184.  
  1185.     mov    ah,ch
  1186.     mov    cl,3
  1187.     shl    ah,cl
  1188.     and    ax,EV_RingTe
  1189.     or    EvtWord[si],ax
  1190.  
  1191.     .errnz       EV_CTS-0000000000001000b
  1192.     .errnz       EV_DSR-0000000000010000b
  1193.     .errnz      EV_RLSD-0000000000100000b
  1194.     .errnz      EV_Ring-0000000100000000b
  1195.  
  1196.     .errnz        EV_CTSS-0000010000000000b        ;[rkh]
  1197.     .errnz        EV_DSRS-0000100000000000b
  1198.     .errnz       EV_RLSDS-0001000000000000b
  1199.     .errnz      EV_RingTe-0010000000000000b
  1200.  
  1201.     .errnz     ACE_DCTS-00000001b
  1202.     .errnz     ACE_DDSR-00000010b
  1203.     .errnz    ACE_DRLSD-00001000b
  1204.     .errnz       ACE_RI-01000000b
  1205.  
  1206.     .errnz     ACE_TERI-00000100b            ;[rkh]
  1207.     .errnz      ACE_CTS-00010000b
  1208.     .errnz      ACE_DSR-00100000b
  1209.     .errnz     ACE_RLSD-10000000b
  1210.  
  1211. ModemStatus10:
  1212.     mov    al,OutHHSLines[si]    ;Get output hardware handshake lines
  1213.     or    al,al            ;Any lines that must be set?
  1214.     jz    ModemStatus40        ;No hardware handshake on output
  1215.     and    ch,al            ;Mask bits of interest
  1216.     cmp    ch,al            ;Lines set for Xmit?
  1217.     je    ModemStatus20        ;  Yes
  1218.     or    HSFlag[si],HHSDown    ;Show hardware lines have dropped
  1219. ModemStatus30:
  1220.     jmp    InterruptLoop
  1221.  
  1222. ModemStatus40:
  1223.     jmp    InterruptLoop_ChkTx
  1224.  
  1225. ; Lines are set for xmit.  Kick an xmit interrupt if needed
  1226.  
  1227. ModemStatus20:
  1228.     and    HSFlag[si],NOT (HHSDown OR HHSAlwaysDown)
  1229.                     ;Show hardware lines back up
  1230.     mov    cx,QOutCount[si]    ;Output queue empty?
  1231.     jcxz    ModemStatus30        ;  Yes, return to InterruptLoop
  1232.     jmp    FakeXmitEmpty        ;Restart transmit
  1233.  
  1234. ModemStatus endp
  1235.  
  1236. page
  1237.  
  1238. ;------------------------------------------------------------------------------
  1239. ;
  1240. ;   ENTER:  AX = message #
  1241. ;        DS:SI -> DEB
  1242. notify_owner proc near
  1243.  
  1244.     or    [si.NotifyFlags], ax
  1245.     lea    di, [si+SIZE ComDEB]
  1246.     mov    ax, ds
  1247.     mov    es, ax
  1248.     mov    ax, BIH_API_Call_Back    ; call immediate, or in protected mode
  1249.     mov    bx, 1            ; force SYS VM, if enhanced mode
  1250.     mov    cx, _INTERRUPT
  1251.     mov    dx, IntCodeOFFSET callback_event
  1252. %OUT use equate
  1253.     push    ds
  1254.     push    si
  1255.     mov    si, 1            ; low priority boost
  1256.     push    bp
  1257.     mov    bp, es:[di.BIS_Mode]
  1258.     call    es:[bp][di.BIS_User_Mode_API]
  1259.     pop    bp
  1260.     pop    si
  1261.     pop    ds
  1262.     ret
  1263.  
  1264. notify_owner endp
  1265.  
  1266. ;------------------------------------------------------------------------------
  1267. ;
  1268. ;   ENTER:  ES:DI -> BIS
  1269. ;
  1270. callback_event proc far
  1271.     lea    si, [di-SIZE ComDEB]
  1272.     mov    ax, es
  1273.     mov    ds, ax
  1274.     mov    ax, [si.NotifyHandle]
  1275.     push    ax            ; push hWnd
  1276.     mov    ax, WM_COMMNOTIFY
  1277.     push    ax            ; push wMsg
  1278.     xor    ax, ax
  1279.     mov    al, [si.DCB_Id]
  1280.     push    ax            ; push wParam = ComID
  1281.     xor    al, al
  1282.     push    ax            ; push high word of lParam
  1283.     xchg    al, [si.NotifyFlagsLO]
  1284.     or    [si.NotifyFlagsHI], al
  1285.     push    ax            ; push low word of lParam = event flags
  1286.     call    [lpPostMessage]
  1287.     ret
  1288. callback_event endp
  1289.  
  1290.  
  1291. PUBLIC TimerProc
  1292. TimerProc proc far
  1293.  
  1294.     push    ds
  1295.     mov    ax, _DATA
  1296.     mov    ds, ax
  1297.     assumes ds,data
  1298.  
  1299.     mov    ax, [activeCOMs]
  1300.     or    ax, ax
  1301.     jz    short tp_nonactive
  1302.     push    si
  1303.     mov    si, DataOFFSET COMptrs
  1304.     mov    cx, MAXCOM+1
  1305. tp_lp:
  1306.     push    si
  1307.     mov    si, [si]        ; si -> ComDEB
  1308.     shr    ax, 1
  1309.     jnc    tp_lpend
  1310.  
  1311.     cmp    [si.RecvTrigger], -1    ;Q: owner wants notification?
  1312.     je    short tp_lpend        ;   N: skip notify
  1313.     cmp    [si.QInCount], 0    ;Q: anything in input queue?
  1314.     je    short tp_lpend        ;   N: skip notify
  1315.     test    [si.NotifyFlagsHI], CN_RECEIVE ;Q: timeout notify already given?
  1316.     jnz    short tp_lpend        ;   N: skip notify
  1317.  
  1318.     xor    [si.NotifyFlagsHI], CN_Idle ;Q: first timer call?
  1319.     js    short tp_lpend        ;   Y: skip notify
  1320.  
  1321.     push    ax
  1322.     push    cx
  1323.     mov    ax, CN_RECEIVE        ;   N: notify owner
  1324.     call    notify_owner
  1325.     pop    cx
  1326.     pop    ax
  1327.  
  1328. tp_lpend:
  1329.     pop    si
  1330.     inc    si            ; inc to ptr to next ComDEB
  1331.     inc    si
  1332.     or    ax, ax
  1333.     loopnz    tp_lp
  1334.     pop    si
  1335.  
  1336. tp_nonactive:
  1337.     pop    ds
  1338.     assumes ds,nothing
  1339.     ret
  1340.  
  1341. TimerProc endp
  1342. page
  1343.  
  1344. ifdef DEBUG
  1345.     public    Control, DEF_Handler, COMHandler, APIHandler
  1346.     public    InterruptLoop, IntLoop10, IntLoop20
  1347.     public    DataAvail25, DataAvail30, DataAvail50
  1348.     public    DataAvail60, DataAvail70, DataAvail80, DataAvail90
  1349.     public    DataAvail100, DataAvail110, DataAvail120
  1350.     public    DataAvail130, DataAvail140, OutHandshakingChar
  1351.     public    XmitEmpty10, XmitEmpty20, XmitEmpty30, XmitEmpty40
  1352.     public    XmitEmpty59, XmitEmpty60
  1353.     public    XmitEmpty90, XmitEmpty100, XmitEmpty110
  1354.     public    ModemStatus10, ModemStatus20, ModemStatus30
  1355.     public    notify_owner, callback_event
  1356. endif
  1357.  
  1358. sEnd   IntCode
  1359. end
  1360.