home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / ATCOM / ATESPISR.ASM < prev    next >
Assembly Source File  |  1995-04-14  |  76KB  |  2,077 lines

  1. ;*DDK*************************************************************************/
  2. ;
  3. ; COPYRIGHT (C) Microsoft Corporation, 1989
  4. ; COPYRIGHT    Copyright (C) 1995 IBM Corporation
  5. ;
  6. ;    The following IBM OS/2 WARP source code is provided to you solely for
  7. ;    the purpose of assisting you in your development of OS/2 WARP device
  8. ;    drivers. You may use this code in accordance with the IBM License
  9. ;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
  10. ;    Copyright statement may not be removed.;
  11. ;*****************************************************************************/
  12. ;       SCCSID = @(#)atespisr.asm       6.3 91/04/22
  13. ; ***************************************************************************
  14. ; *
  15. ; *
  16. ; *
  17. ; ***************************************************************************
  18.  
  19.         PAGE    80,132
  20.         .286p
  21.  
  22.         TITLE   com01.sys - Asynchronous Communication Device Driver
  23.         NAME com01
  24.  
  25. ;***    espisr.asm - Interrupt Handlers
  26. ;
  27. ;       ComInt          - Interrupt entry point
  28. ;       RxInt           - Receive FIFO trigger interrupt
  29. ;       TxInt           - Transmitter FIFO trigger interrupt
  30. ;       EMxInt          - Modem status interrupt
  31. ;
  32. ;       Modification History
  33. ;
  34. ;       ACW     04/16/91        @PVW Added perfview counters/timers
  35. ;       RAC     12/16/93  76699 Make Perfview Optionally compiled
  36. ;       WDM     04/21/94        82548 - pvwxport.inc now included in atcom.inc
  37. ;
  38.  
  39.  
  40. .xlist
  41. ifdef PERFVIEW
  42. ; 82548  include pvwxport.inc            ;@PVW
  43. endif
  44.  
  45. include devhlp.inc
  46. include devsym.inc
  47. include basemaca.inc
  48. include realmac.inc
  49. include osmaca.inc
  50. include error.inc
  51. include protmode.inc
  52. include atcom.inc
  53. include atesp.inc
  54. include devhlpP.inc            ;76711
  55. .list
  56.  
  57.         EXTRNFAR        WriteQueue
  58.         EXTRNFAR        WriteQueueByte
  59.         EXTRNFAR        ReadQueueByte
  60.         EXTRNFAR        ReadQueue
  61.         EXTRNFAR        UnLinkHeadRP
  62.         EXTRNFAR        ProcRun
  63.         EXTRNFAR        GetNextWRP
  64.         EXTRNFAR        ComError
  65.         EXTRNFAR        LinkRP
  66.         extrn           IssueESPCmd:near
  67.         extrn           TriggerTX:near
  68. HSEG SEGMENT
  69.         EXTRN   tcount_ptr:WORD
  70.         EXTRN   read_write_ptr:WORD
  71.         EXTRN   alloc_ptr:WORD
  72.         EXTRN   dealloc_ptr:WORD
  73.         EXTRN   disable_ptr:WORD
  74. HSEG ENDS
  75.  
  76. DSEG SEGMENT
  77.         EXTRN   Com1:WORD
  78.         EXTRN   Com2:WORD
  79.         EXTRN   Com3:WORD
  80.         EXTRN   Com4:WORD
  81.         EXTRN   DevHlp:DWORD
  82.         EXTRN   Flags:BYTE
  83.         EXTRN   Ready:WORD
  84.         EXTRN   Kernel_Type:WORD
  85.         EXTRN   ESP1:WORD
  86.         EXTRN   ESP2:WORD
  87.  
  88. RRMaskTable     DB      00000001b               ; Rx1FIFO int
  89.                 DB      00000010b               ; Tx1FIFO int
  90.                 DB      00010000b               ; Rx2FIFO int
  91.                 DB      00100000b               ; Tx2FIFO int
  92. MAX_RR_INDEX    EQU     $ - RRMaskTable
  93. RRIndex         DB      0
  94.  
  95. RRServiceTable  DW      Rx1Int
  96.                 DW      Tx1Int
  97.                 DW      Rx2Int
  98.                 DW      Tx2Int
  99.  
  100. public sid_buf,sid_buf_index,dma_buf
  101. sid_buf_index   db      0
  102. sid_buf         db      256 dup (0)
  103. dma_buf         db      256 dup (0)
  104.  
  105. DSEG    ENDS
  106.  
  107. E_CSEG  SEGMENT
  108.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  109.  
  110. ;**     ESPInt- Interrupt Handlers for Enhanced Ports
  111. ;
  112. ;       NOTE    interrupt handlers do NOT need to save registers
  113. ;
  114. ;       ENTRY   ds = device driver data segment (set up by kernel)
  115. ;               interrupts disabled
  116. ;
  117. ;       EXIT    none
  118. ;
  119. ;       USES    none
  120.  
  121. Procedure ESPInt,FAR
  122.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  123.         jmp     short eint2
  124.  
  125. eint0:  ComErr  <ComInt: too many nested interrupts>,CALLFAR
  126.  
  127. ;* eint00 - interrupt during first open or init
  128. eint00: sti
  129.         ; New service mask so no more ints from this port
  130.         mov     di,[si].ci_pinfo
  131.         mov     al,[di].pi_svcmask
  132.         cmp     [si].ci_cmd_offset,0
  133.         je      eint01
  134.         CLR     al,ESP_SVC_MASK_PORT1
  135.         jmp     SHORT eint02
  136. eint01: CLR     al,ESP_SVC_MASK_PORT2
  137. eint02: mov     [di].pi_svcmask,al
  138.         SetSvcMask      al
  139.  
  140.         ; Signal EOI. Can't allow interrupts from now on because other
  141.         ; ESP port might interrupt on this same IRQ and cause nesting.
  142.         mov     di,[si].ci_pinfo
  143. ;       mov     al,[di].pi_irq  ; irq                         remove 76711
  144. ;       mov     dl,DevHlp_EOI           ; end of interrupt    remove 76711
  145.         cli
  146. ;       DevHelp                                               remove 76711
  147.         DevEOI    <byte ptr [di].pi_irq>,DevHlp  ;            add    76711
  148.         jmp     eintx
  149.  
  150. ;* eint000 - interrupt during driver shut down
  151. eint000:
  152.         sti
  153.         mov     sp,bp           ; restore stack frame before leaving
  154.         stc                     ; set carry - not my interrupt
  155.         ret                     ; return carry to interrupt manager which
  156.                                 ; will issue EOI for me
  157.  
  158. eint2:
  159.         mov     si,0                    ; (si) -> NULL
  160.         SaveReg         <di>            ; save di (ESPInfo) on stack frame
  161.         mov     bp,sp                   ; (bp)   -> stack frame
  162.                                         ; (bp-2) -> di
  163.         inc     [di].pi_depth           ; inc nested interrupt counter
  164.  ;      jz      eint0        76711       ; too many nested interrupts   76711
  165.         jnz     meg4                    ; too many nested interrupts   76711
  166.         jmp     eint0                   ; too many nested interrupts   76711
  167. meg4:   mov     dx,[di].pi_address
  168.         add     dx,ESP_R_SID
  169.         in      al,dx
  170.         mov     [di].pi_sid,al                  ; (sid) = SID;
  171.  
  172. mov     bl,sid_buf_index
  173. xor     bh,bh
  174. mov     sid_buf[bx],al
  175. inc     sid_buf_index
  176.  
  177.         cmp     al,0
  178.  
  179.         je      eint000                         ; if SID is zero, not my interrupt
  180.  
  181.         ; Was interrupt caused by DMA Timeout condition? Then clear condition
  182.         ; and ignore
  183.         test    [di].pi_sid,ESP_SID_DMATO
  184.         jz      eint5
  185.         mov     dx,[di].pi_address
  186. eint3:  in      al,dx
  187.         test    al,ESP_RDY_CMD1
  188.         jz      eint3
  189.         add     dx,ESP_R_CMD1-ESP_R_RDY
  190.         mov     al,ESP_CMD_CLEARDMAREQ
  191.         out     dx,al
  192.  
  193.         ; Check next for DMA Transfer Finished
  194. eint5:  test    [di].pi_sid,ESP_SID_DMAFIN
  195.         jz      eint6
  196.  
  197.         ;      to get around firmware problem: ESP may generate DMA Transfer
  198.         ; interrupts when in Programmed I/O mode.      fix is this: if no
  199.         ; DMA transfer was started, then clear DMA condition and ignore.
  200.         cmp     [di].pi_DMA_outstanding,0
  201.         jne     eint5a
  202.  
  203.         ; Ignore this DMA Finished condition.
  204.         add     dx,ESP_R_RDY-ESP_R_SID
  205. hack1:  in      al,dx
  206.         test    al,ESP_RDY_CMD1
  207.         jz      hack1
  208.         add     dx,ESP_R_CMD1-ESP_R_RDY
  209.         mov     al,ESP_CMD_CLEARDMAREQ
  210.         out     dx,al
  211.         ; WAIT FOR DMAFIN BIT IN SID TO CLEAR!
  212.         add     dx,ESP_R_SID-ESP_R_CMD1
  213. hack2:   in      al,dx
  214.         test    al,ESP_SID_DMAFIN
  215.         jnz     hack2
  216.         jmp     SHORT eint6
  217.  
  218. eint5a:
  219.         ; One of the ports DID start a DMA transfer, and now it's finished
  220.         mov     si,[di].pi_DMA_outstanding
  221.         ; Was last DMA transfer a WRITE TO memory or a READ FROM memory
  222. eint5b: test    [di].pi_flagx,PIF_DMA_READ
  223.         jnz     eint5c
  224.         call    DMARxInt                        ; DMA_WRITE - Receive finished
  225.         jmp     SHORT eint6
  226.  
  227. eint5c: call    DMATxInt                        ; DMA_READ - Transmit finished
  228.  
  229.         ; Check for error on either port
  230. eint6:  test    [di].pi_sid,ESP_SID_ERROR1 OR ESP_SID_ERROR2
  231.         jz      eint7
  232.         mov     si,[di].pi_port1
  233.         test    [di].pi_sid,ESP_SID_ERROR1
  234.         jnz     eint6a
  235.         mov     si,[di].pi_port2
  236. eint6a:
  237.         call    ErrInt
  238.  
  239.         ; Now process any Rx or Tx ints in round-robin order.
  240. eint7:  mov     cx,MAX_RR_INDEX
  241. eint7a: mov     bl,[di].pi_rrindex
  242.         xor     bh,bh
  243.         mov     al,RRMaskTable[bx]
  244.         test    al,[di].pi_sid
  245.         jz      eint8                           ; this bit not set, test next
  246.  
  247.         ; Service the interrupt corresponding to the RRMaskTable entry.
  248.         ; Use pi_rrindex once again to find address of proper subroutine.
  249.         shl     bl,1                            ; adjust for word pointer
  250.         SaveReg         <cx>
  251.         call    RRServiceTable[bx]
  252.         RestoreReg      <cx>
  253.  
  254.         ; Check flags set by subroutine if it encountered a problem.
  255.         test    [di].pi_flagx,PIF_CI_NULL
  256.         ljnz    eint000                         ; ComInfo ptr null, abandon
  257.  
  258.         test    [di].pi_flagx,PIF_NOT_OPEN
  259.         ljnz    eint00                          ; Port not open, abandon
  260.  
  261.         ; Increment pi_rrindex, wrap to zero when it gets to MAX_RR_INDEX.
  262.         ; pi_rrindex now points to mask used to test pi_sid next time around.
  263. eint8:  inc     [di].pi_rrindex
  264.         cmp     [di].pi_rrindex,MAX_RR_INDEX
  265.         jne     eint9                           ; didn't wrap
  266.         mov     [di].pi_rrindex,0               ; wrapped, reset to zero
  267.  
  268. eint9:
  269.         ; If we haven't looked at all the RRMaskTable entries yet, test
  270.         ; pi_sid again with new mask.
  271.         loop    eint7a
  272.  
  273. eint10:
  274.         CLI
  275.  
  276.         ; done servicing the actual interrupt(s), tell kernel to reset 8259 for me
  277.         mov     di,[si].ci_pinfo
  278.   ;     mov     al,[di].pi_irq          ; irq                     remove 76711
  279.   ;     mov     dl,DevHlp_EOI                 ; end of interrupt  remove 76711
  280.   ;     DevHelp                                                   remove 76711
  281.         DevEOI    <byte ptr [di].pi_irq>,DevHlp  ;                add    76711
  282.  
  283.         cmp     Kernel_Type,ABIOS_COM
  284.         je      eint70
  285.  
  286.         ; Because IRQs on AT-bus are edge-triggered, SID mask must be set to
  287.         ; zero. This will lower the IRQ line, allowing another edge to occur,
  288.         ; should an unserviced IRQ be pending when the "real" SID mask is
  289.         ; programmed. This is unnecessary if a DMA transfer was started
  290.         ; during this ISR, since DMA operations on the ESP always disable the
  291.         ; IRQ for the duration of the transfer.
  292.         test    [di].pi_flagx,PIF_RESET_MASK
  293.         jz      eint70
  294.  
  295.         mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  296. eint90: in      al,dx                            ; wait for cmd1 ready
  297.         test    al,ESP_RDY_CMD1
  298.         jz      eint90
  299.  
  300.         mov     al,ESP_CMD_SETSVCMASK
  301.         add     al,[si].ci_cmd_offset
  302.         add     dx,ESP_R_CMD1-ESP_R_RDY         ; (dx) -> cmd1 reg
  303.         out     dx,al                           ; out cmd1
  304.  
  305.         add     dx,ESP_R_RDY-ESP_R_CMD1         ; (dx) -> ready reg
  306. eint92: in      al,dx
  307.         test    al,ESP_RDY_CMD2                ; wait for cmd2 ready
  308.         jz      eint92
  309.  
  310.         add     dx,ESP_R_CMD2-ESP_R_RDY         ; (dx) -> cmd2 reg
  311.         mov     al,0
  312.         out     dx,al                           ; out next data byte
  313.  
  314.         mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  315. eint95: in      al,dx                            ; wait for cmd1 ready
  316.         test    al,ESP_RDY_CMD1
  317.         jz      eint95
  318.  
  319.         mov     al,ESP_CMD_SETSVCMASK
  320.         add     al,[si].ci_cmd_offset
  321.         add     dx,ESP_R_CMD1-ESP_R_RDY         ; (dx) -> cmd1 reg
  322.         out     dx,al                           ; out cmd1
  323.  
  324.         add     dx,ESP_R_RDY-ESP_R_CMD1         ; (dx) -> ready reg
  325. eint97: in      al,dx
  326.         test    al,ESP_RDY_CMD2                ; wait for cmd2 ready
  327.         jz      eint97
  328.  
  329.         add     dx,ESP_R_CMD2-ESP_R_RDY         ; (dx) -> cmd2 reg
  330.         mov     di,[si].ci_pinfo
  331.         mov     al,[di].pi_svcmask
  332.         out     dx,al                           ; out next data byte
  333.  
  334. eint70:
  335.         ; ProcRun requests on the ready list
  336.         SaveReg         <si>
  337.         mov     si,OFFSET Ready ; (ds:si) -> Ready list
  338.  
  339. eint80: CALLFAR UnLinkHeadRP    ; (es:di) -> runnable request packet
  340.         jc      eint85          ; no more to run
  341.         CALLFAR ProcRun
  342.         jmp     SHORT eint80    ; try to run another
  343.  
  344. eint85: RestoreReg      <si>    ; (ds:si) -> cominfo
  345.         mov     di,[si].ci_pinfo
  346.         ChkComInfoPtr
  347.  
  348. eint99: ; exiting first level interrupt
  349.         and     [si].ci_flagx,NOT FX_DATA_MOVED ; clear data moved flag
  350.  
  351. eintx:  mov     sp,bp           ; restore stack frame
  352.         RestoreReg      <di>    ; (ds:di) -> ESPInfo
  353.         .errnz  D_BAD
  354. eintxx:
  355.         dec     [di].pi_depth
  356.         clc                     ; clear carry to show it was our interrupt
  357.         ret
  358.  
  359. eintnestx:
  360.         or      [di].pi_flagx,PIF_INT_NESTED     ; flag nested int occurred
  361.         jmp     SHORT eintx                     ; done
  362.  
  363. ;* einterr - exit point for internal error at interrupt time
  364. ;
  365. ;       isuue EOI and return
  366. ;       Interrupt level has already been released (UnSetIRQ) and
  367. ;       16450 interrupt disabled in ShutdownPort,
  368. ;       but we still need to issue the EOI for this interrupt.
  369. ;
  370. ;       ENTRY   (ds) -> DD Data Seg
  371.  
  372. Entry   einterr,,,nocheck
  373.  
  374.         mov     sp,bp           ; restore stack frame
  375.         pop     di              ; (ds:si) -> EspInfo
  376.         ChkComInfoPtr
  377.  ;      mov     al,[di].pi_irq                                    remove 76711
  378.  ;      mov     dl,DevHlp_EOI           ; end of interrupt        remove 76711
  379.  ;      DevHelp                                                   remove 76711
  380.         DevEOI    <byte ptr [di].pi_irq>,DevHlp  ;                add    76711
  381.         ; can't get nested ints because 16450 chip interrupts are disabled
  382.         jmp     SHORT eintxx
  383.  
  384. EndProc EspInt
  385.  
  386.  
  387. ;**     EMxInt - Modem Status Interrupt (lowest priority)
  388. ;
  389. ;       ENTRY   (ds:si) -> ComInfo
  390. ;               (al) = modem status register
  391. ;
  392. ;       EXIT    none
  393. ;
  394. ;       USES    ax dx
  395.  
  396. Procedure EMxInt,NEAR
  397.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  398.  
  399.         ChkComInfoPtr
  400.  
  401.  
  402.         SaveReg         <ax>
  403.  
  404.         ; If DSR sensitivity is enabled, look for changes in DSR
  405.         test    [si].ci_dcb_flags1,F1_IN_DSR_SENSE
  406.         jz      mx30
  407.  
  408.         test    al,MS_DSR
  409.         jnz     mx20                            ; DSR went high
  410.  
  411.         ; DSR went low, so clear FX_IN_DSR_OK to let RxInt routine know to
  412.         ; ignore RxFIFO ints. But may be some good data already in ESP's FIFO,
  413.         ; so do GetRxBytes to find out how much and remember in ci_qty_good.
  414.         CLR     [si].ci_flagx,FX_IN_DSR_OK      ; DSR is NOT OK.
  415.         GetRxBytes                              ; (al) = MSB; (ah) = LSB
  416.         xchg    ah,al                           ; (ax) = bytes in ESP's FIFO
  417.         mov     [si].ci_qty_good,ax
  418.         jmp     SHORT mxix
  419.  
  420.         ; DSR went high, so set FX_IN_DSR_OK to let RxInt rountine know data
  421.         ; is good from now on. Flush ESP's FIFO to dump old (bad) data.
  422. mx20:
  423.         FlushRxFIFO                             ; dump old data
  424.         SET     [si].ci_flagx,FX_IN_DSR_OK
  425.  
  426.         ; If DCD ouput handshaking is enabled, look for change in DCD.
  427. mx30:   test    [si].ci_dcb_flags1,F1_OUT_DCD_FLOW
  428.         jz      mxix
  429.  
  430.         test    [si].ci_msrshadow,MS_DCD
  431.         jnz     mx40
  432.  
  433.         ; DCD went low, so XOFF local transmitter
  434.         mov     ah,ESP_CMD_XOFFLOCAL
  435.         jmp     SHORT mx50
  436.  
  437.         ; DCD went low, so XON local transmitter
  438. mx40:   mov     ah,ESP_CMD_XONLOCAL
  439.  
  440. mx50:   mov     dx,[si].ci_esp_address
  441. mx55:   in      al,dx
  442.         test    al,ESP_RDY_CMD1
  443.         jz      mx55
  444.         add     dx,ESP_R_CMD1-ESP_R_RDY     ; (dx) -> cmd1 reg
  445.         mov     al,ah
  446.         add     al,[si].ci_cmd_offset
  447.         out     dx,al
  448.  
  449. mxix:   RestoreReg      <ax>
  450.  
  451.         ; Since ESP won't let us look at delta bits in MSR, must determine
  452.         ; which signals have changed by comparing new MSR to msrshadow.
  453.         mov     ah,[si].ci_msrshadow    ; (ah) = old MSR, (al) = new MSR
  454.         mov     bx,ax                   ; (bh) = old MSR, (al) = new MSR
  455.         xor     ah,al                   ; (ah) = delta MSR, (al) = new MSR
  456.         CLR     ah,MS_DELTAS            ; real deltas are useless
  457.         mov     [si].ci_msrshadow,al    ; shadow contents of new MSR
  458.  
  459.         ; Create the event mask from the modem status deltas
  460.                         ; y = our delta carrier detect
  461.                         ; t = trailing edge ring indicator
  462.                         ; d = our delta data set ready
  463.                         ; c = our clear to send
  464.                         ;      AH                    AL            C
  465.         mov     al,ah   ; y . d c . t . .       y . d c . t . .
  466.         shl     ax,1    ; . d c . t . . y       . d c . t . . .
  467.         shl     al,1    ; . d c . t . . y       d c . t . . . .
  468.         shr     ah,1    ; . . d c . t . .       d c . t . . . .    y
  469.         rcr     al,1    ; . . d c . t . .       y d c . t . . .
  470.         shr     ax,2    ; . . . . d c . t       . . y d c . t .
  471.         ror     ah,1    ; t . . . . d c .       . . y d c . t .
  472.         shr     ah,7    ; . . . . . . . t       . . y d c . t .
  473.         shr     al,2    ; . . . . . . . t       . . . . y d c .
  474.         shl     al,2    ; . . . . . . . t       . . y d c . . .
  475.  
  476.         and     ax,EV_CTS OR EV_DSR OR EV_DCD OR EV_Ring
  477.         or      [si].ci_event,ax
  478.         ret
  479.  
  480. EndProc EMxInt
  481.  
  482. ;**     Rx1Int/Rx2Int - Receive FIFO Interrupt
  483. ;
  484. ;       ENTRY   (ds:di) -> ESPInfo structure
  485. ;
  486. ;       EXIT
  487. ;
  488. ;       USES    ax bx cx dx si
  489.  
  490. Procedure Rx1Int,NEAR
  491.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  492.         mov     si,[di].pi_port1
  493.         jmp     SHORT rf10
  494.  
  495. Entry Rx2Int
  496.         mov     si,[di].pi_port2
  497.  
  498. rf10:   or      si,si
  499.         jnz     rf20
  500.         SET     [di].pi_flagx,PIF_CI_NULL       ; remember ComInfo ptr is null
  501.         jmp     rfix
  502.  
  503. rf20:   cmp     [si].ci_nopens,0
  504.         jne     rf30
  505.         SET     [di].pi_flagx,PIF_NOT_OPEN      ; remember port not open
  506.         jmp     rfix
  507.  
  508. rf30:   test    [si].ci_flagx,FX_LAST_CLOSE
  509.         ljnz    rfix
  510.  
  511.         ; Don't waste any more time if this will be a DMA transfer but
  512.         ; a DMA transfer is already in progress. In this case, ignore this
  513.         ; RxFIFO int, and Esp will give us another one next time.
  514.         mov     di,[si].ci_pinfo
  515.         SET     [di].pi_flagx,PIF_RESET_MASK            ; assume no DMA
  516.         cmp     [si].ci_rx_request,DMA_REQ_DISABLE
  517.         je      rf35
  518.         cmp     [di].pi_DMA_outstanding,0
  519.         ljne    rfix
  520.  
  521.         ; Handling DSR sensitivity is tricky. If this is first RxInt since
  522.         ; DSR was dropped, may still have good data in ESP's FIFO. ci_qty_good
  523.         ; will be non-zero in this case, and exactly that many bytes should be
  524.         ; transferred to in que -- remember to reset ci_qty_good to zero.
  525.         ; If ci_qty_good is zero (good data already processed), and
  526.         ; FX_IN_DSR_OK is NOT SET, then ignore this interrupt.
  527. rf35:
  528.         cmp     [si].ci_qty_good,0
  529.         jne     rf40                            ; transfer data already in FIFO
  530.  
  531.         test    [si].ci_flagx,FX_IN_DSR_OK
  532.         jnz     rf40
  533.  
  534.         ; If we ignore this interrupt, we must reset the service mask before
  535.         ; leaving the isr.
  536.         jmp     rfix
  537.  
  538. ;       calculate length of transfer
  539. ;       there are two cases:
  540. ;       1. in ptr is < out ptr
  541. ;               in this case, we can only put (out - in) - 1 bytes in
  542. ;       2. in ptr >= out ptr
  543. ;               In this case, we can only xfer to end of buffer.
  544. ;               If in == out == base, we must leave last byte
  545. ;               empty.
  546. rf40:   mov     cx,[si].ci_qin.ioq_in
  547.         mov     dx,[si].ci_qin.ioq_out
  548.         sub     cx,dx                   ; (cx) = -(out - in)
  549.         jb      rf50                    ; in < out, can only go to (out - 1)
  550.         add     cx,dx                   ; (cx) = ioq_in
  551.         sub     cx,[si].ci_qin.ioq_end
  552.         cmp     dx,[si].ci_qin.ioq_base
  553.         jne     rf60
  554.  
  555. rf50:   inc     cx                      ; 'subtract' from negated count
  556.  
  557. rf60:   neg     cx                      ; (cx) = transfer count
  558.         jcxz    rf70                    ; no room, return
  559.         jmp     SHORT go
  560.  
  561.         ; No more room in input queue until consumer thread removes some data,
  562.         ; so tell ESP we don't want to hear about receive data
  563. rf70:
  564.         call    TurnOffESP
  565.         CLR     [di].pi_flagx,PIF_RESET_MASK    ; TurnOffESP already reset svc mask
  566.         jmp     rfix
  567.  
  568.         ; (cx) = room left in qin.
  569.         ; Handle ridiculous DSR sensitivity first.
  570. go:     cmp     [si].ci_qty_good,0
  571.         je      rf120
  572.         sub     [si].ci_qty_good,cx
  573.         jg      rf130                     ; not room for all
  574.         mov     cx,[si].ci_qty_good     ; transfer all "good" data
  575.         mov     [si].ci_qty_good,0
  576.         jmp     SHORT rf130
  577.  
  578. rf120:
  579.         ; (cx) = room left in qin.
  580.         SaveReg         <cx>
  581.         GetRxBytes                             ; (ax) = bytes ready in ESP
  582.         RestoreReg      <cx>
  583.         xchg    ah,al                   ; status2 is really MSB
  584.         or      ax,ax                   ; does ESP have any bytes to transfer
  585.         jz      rfix                    ; no, false alram
  586.  
  587.         cmp     cx,ax
  588.         jbe     rf130                   ; not enough room, just fill up queue
  589.         mov     cx,ax                   ; enough room, transfer all ESP has
  590.  
  591. rf130:
  592.         ; (cx) = bytes to transfer
  593.         ; Are we doing DMA or PIO?
  594.         cmp     [si].ci_rx_request,DMA_REQ_DISABLE
  595.         jne     rf135
  596.  
  597.         ; Do that PIO
  598.         call    RxPIO
  599.         jmp     rfix
  600.  
  601. rf135:
  602.         ; Set up DMA controller for WRITE transfer
  603.         mov     [di].pi_xfer_count,cx
  604.         cmp     Kernel_Type,ABIOS_COM
  605.         je      rf140
  606.         mov     al,AT_DMA_MODE_WRITE
  607.         mov     ah,[di].pi_DMA_chan
  608.         call    ATsetupDMA
  609.         jmp     SHORT rf145
  610.  
  611. rf140:  mov     bl,ABIOS_FUNC_WRITEMEM
  612.         call    MCAbeginDMA
  613.  
  614.         ; DMAC ready, tell ESP to start
  615. rf145:  mov     [di].pi_DMA_outstanding,si          ; save ComInfo ptr
  616. mov bl,sid_buf_index
  617. dec bl
  618. xor bh,bh
  619. mov dx,si
  620. mov dma_buf[bx],dl
  621.         mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  622. rf150:  in      al,dx
  623.         test    al,ESP_RDY_CMD1
  624.         jz      rf150
  625.         add     dx,ESP_R_CMD1-ESP_R_RDY
  626.         mov     al,ESP_CMD_DMARX
  627.         add     al,[si].ci_cmd_offset
  628.         out     dx,al
  629.         add     dx,ESP_R_RDY-ESP_R_CMD1
  630. rf160:  in      al,dx
  631.         test    al,ESP_RDY_STATUS1
  632.         jz      rf160
  633.         add     dx,ESP_R_STATUS1-ESP_R_RDY
  634.         in      al,dx
  635.  
  636.         ; Driver got data from the hardware, so reset timeout counter
  637.         mov     cx,[si].ci_r_to_start
  638.         mov     [si].ci_r_to,cx
  639.  
  640.         ; Set flag in my pinfo to let everyone know ESP is busy doing DMA
  641.         SET     [di].pi_flagx,PIF_PECAN_BUSY
  642.         CLR     [di].pi_flagx,PIF_DMA_READ      ; remember DMA was a Write
  643.         CLR     [di].pi_flagx,PIF_RESET_MASK    ; started DMA, no reset needed
  644. rfix:   ret
  645.  
  646. EndProc Rx1Int
  647.  
  648. ;**     Tx1Int/Tx2Int - Transmit FIFO Interrupt
  649. ;
  650. ;       ENTRY   (ds:di) -> ESPInfo
  651. ;
  652. ;       EXIT
  653. ;
  654. ;       USES    ax bx cx dx si
  655.  
  656. Procedure Tx1Int,NEAR
  657.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  658.         mov     si,[di].pi_port1
  659.         jmp     SHORT tx000
  660.  
  661. Entry Tx2Int
  662.         mov     si,[di].pi_port2
  663.  
  664. tx000:  or      si,si
  665.         jnz     tf00
  666.         SET     [di].pi_flagx,PIF_CI_NULL       ; remember ComInfo ptr is null
  667.         jmp     tfix
  668.  
  669. tf00:   cmp     [si].ci_nopens,0
  670.         jne     tf10
  671.         SET     [di].pi_flagx,PIF_NOT_OPEN      ; remember port not open
  672.         jmp     tfix
  673.  
  674. tf10:
  675.         ; Don't waste any more time if this will be a DMA transfer but
  676.         ; a DMA transfer is already in progress. In this case, ignore this
  677.         ; TxFIFO int, and Esp will give us another one next time.
  678.         mov     di,[si].ci_pinfo
  679.         SET     [di].pi_flagx,PIF_RESET_MASK            ; assume no DMA
  680.         cmp     [si].ci_tx_request,DMA_REQ_DISABLE
  681.         je      tf15
  682.         cmp     [di].pi_DMA_outstanding,0
  683.         ljne    tfix
  684.  
  685. tf15:
  686.         test    [si].ci_flagx,FX_WAITING_TX_EMPTY
  687.         ljz      tf20
  688.  
  689.         ; FX_WAITING_EMPTY, which means this is the TxFIFO interrupt
  690.         ; that tells us all data was sent, and it's time to drop RTS
  691.         CLR     [si].ci_flagx,FX_WAITING_TX_EMPTY
  692.         CLR     [si].ci_esp_flow1,ESP_FC1_RX_RTS        ; RTS not used for flow
  693.         CLR     [si].ci_esp_flow1,ESP_FC1_ON_RTS        ; drop RTS
  694.         mov     ah,[si].ci_esp_flow1
  695.         mov     al,[si].ci_esp_flow2
  696.         SetFCType       ah,al
  697.  
  698.         ; Remember to reset TxFIFO trigger level to original value!
  699.         call    ResetTriggerLevel
  700.  
  701.         ; We needed this TxFIFO int to tell us when to drop RTS, but if
  702.         ; there's no more data to send, disable TxFIFO int
  703.         call    TriggerTX
  704.  
  705. tf20:   cmp     [si].ci_w_rp._hi,0              ; really OK to transmit?
  706.         lje     tfix                            ; no, get out
  707.  
  708.         ; check for RTS toggling
  709.         mov     al,[si].ci_dcb_flags2
  710.         and     al,F2_RTS_MASK
  711.         cmp     al,F2_RTS_TOGGLE
  712.         ljne    tf23
  713.  
  714.         test    [si].ci_flagx,FX_WAITING_TX_EMPTY
  715.         ljnz    tf23                    ; took care of this condition above
  716.  
  717.         ; Raise RTS before sending tx data to ESP, and reset TxFIFO trigger
  718.         ; to "FIFO empty", so next TxFIFO int will be when ESP has transmitted
  719.         ; all the data
  720.         SET     [si].ci_flagx,FX_WAITING_TX_EMPTY
  721.         mov     ax,[si].ci_rx_trigger
  722.         SetTriggers     ah,al,HIGH(ESP_TRIGGER_TX_EMPTY),LOW(ESP_TRIGGER_TX_EMPTY)
  723.  
  724.         ; Don't raise RTS if transmitter is flowed off
  725.         test    [si].ci_errshadow2,ESP_ERR2_OFFLOCAL
  726.         jnz     tf23
  727.         CLR     [si].ci_esp_flow1,ESP_FC1_RX_RTS        ; RTS not used for flow
  728.         SET     [si].ci_esp_flow1,ESP_FC1_ON_RTS        ; raise RTS
  729.         mov     ah,[si].ci_esp_flow1
  730.         mov     al,[si].ci_esp_flow2
  731.         SetFCType       ah,al
  732.  
  733. tf23:   mov     ax,[si].ci_qout.ioq_in          ; (ax) = in
  734.         mov     bx,[si].ci_qout.ioq_out         ; (bx) = out
  735.         cmp     ax,bx
  736.         jne     tf25
  737.         jmp     tfc                              ; no data in queue
  738.  
  739. tf25:    jb      tf30
  740. ; in > out
  741.         sub     ax,bx                           ; (ax) = in - out
  742.         jmp     SHORT tf40
  743.  
  744. ; in < out
  745. tf30:    mov     ax,[si].ci_qout.ioq_end         ; (ax) = end
  746.         sub     ax,bx                           ; (ax) = end - out
  747.  
  748.         ; Number of bytes we'd like to transfer is in (ax).
  749.         ; Let's see if ESP has room for all of them.
  750. tf40:   mov     bx,ESP_DEF_TRIGGER_TX
  751.         cmp     ax,bx
  752.         jbe     tf50                             ; plenty of room
  753.         mov     ax,bx                           ; can't transfer all of them
  754.  
  755. tf50:
  756.         ; (ax) = bytes to transfer
  757.         ; Are we doing DMA or PIO?
  758.         cmp     [si].ci_tx_request,DMA_REQ_DISABLE
  759.         jne     tf55
  760.  
  761.         ; Transfer bytes via PIO from out que to ESP's Tx register.
  762.         mov     cx,ax                           ; loop counter
  763.         cmp     [si].ci_cmd_offset,0
  764.         jne     tp10
  765.         mov     bl,ESP_RDY_TX1
  766.         mov     bh,ESP_R_TX1-ESP_R_RDY
  767.         jmp     SHORT tp5
  768. tp10:   mov     bl,ESP_RDY_TX2
  769.         mov     bh,ESP_R_TX2-ESP_R_RDY
  770.  
  771.         ; (bh) = offset of proper tx register; (bl) = ready register mask
  772. tp5:    push    bx                              ; ReadQueueByte uses bx
  773.         CALLFAR ReadQueueByte                   ; (al) = byte to tx
  774.         pop     bx
  775.         jc      tp40
  776. tp20:   mov     ah,al                           ; (ah) = byte to tx
  777.         mov     dx,[si].ci_esp_address
  778. tp30:   in      al,dx
  779.         test    al,bl                           ; is tx register ready?
  780.         jz      tp30
  781.         add     dl,bh                           ; (dx) = tx register
  782.         mov     al,ah                           ; (al) = byte to tx
  783.         out     dx,al
  784.         loop    tp5                             ; finished with all bytes yet?
  785.  
  786.         ; ESP is full or driver's out que is empty
  787. tp40:   cmp     [si].ci_qout.ioq_count,0
  788.         jne     tp45
  789.         SET     [si].ci_event,EV_TX_EMPTY       ; show that txq emptied
  790.  
  791. tp45:   call    FinishWriteReq
  792.         jmp     SHORT tfix
  793.  
  794. tf55:
  795.         ; Set up DMA controller for READ transfer
  796.         mov     [di].pi_xfer_count,ax
  797.         cmp     Kernel_Type,ABIOS_COM
  798.         je      tf60
  799.         mov     al,AT_DMA_MODE_READ
  800.         mov     ah,[di].pi_dma_chan
  801.         call    ATsetupDMA
  802.         jmp     SHORT tf75
  803.  
  804. tf60:   mov     bl,ABIOS_FUNC_READMEM
  805.         call    MCAbeginDMA
  806.  
  807.         ; DMAC ready, tell ESP to start
  808. tf75:   mov     [di].pi_DMA_outstanding,si          ; save ComInfo ptr
  809. mov bl,sid_buf_index
  810. dec bl
  811. xor bh,bh
  812. mov dx,si
  813. mov dma_buf[bx],dl
  814.         mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  815. tf80:   in      al,dx
  816.         test    al,ESP_RDY_CMD1
  817.         jz      tf80
  818.         add     dx,ESP_R_CMD1-ESP_R_RDY         ; (dx) -> cmd1 reg
  819.         mov     al,ESP_CMD_DMATX
  820.         add     al,[si].ci_cmd_offset
  821.         out     dx,al
  822.         add     dx,ESP_R_RDY-ESP_R_CMD1         ; (dx) -> ready reg
  823. tf90:   in      al,dx
  824.         test    al,ESP_RDY_STATUS1
  825.         jz      tf90
  826.         add     dx,ESP_R_CMD1-ESP_R_RDY         ; (dx) -> ready reg
  827.         in      al,dx                           ; read status1
  828.  
  829.         ; Driver gave the data to the hardware, so reset timeout counter
  830.         mov     cx,[si].ci_w_to_start
  831.         mov     [si].ci_w_to,cx
  832.  
  833.         ; Set flag in my pinfo to let everyone know ESP is busy doing DMA
  834.         SET     [di].pi_flagx,PIF_PECAN_BUSY
  835.         SET     [di].pi_flagx,PIF_DMA_READ     ; remember DMA was a Read
  836.         CLR     [di].pi_flagx,PIF_RESET_MASK
  837. tfc:    mov     di,[si].ci_pinfo                ; restore ESPInfo ptr
  838. tfix:   ret
  839.  
  840. EndProc Tx1Int
  841.  
  842. ;**     DMARxInt - DMA Finished Interrupt
  843. ;
  844. ;       ENTRY   (ds:si) -> ComInfo
  845. ;
  846. ;       EXIT
  847. ;
  848. ;       USES    ax bx cx dx si
  849.  
  850. Procedure DMARxInt,NEAR
  851.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  852.  
  853.         ; ESP finished with DMA Receive, so adjust in ptr for inque.
  854.         cmp     Kernel_Type,ABIOS_COM
  855.         jne     drx
  856.         call    MCAendDMA
  857.  
  858. drx:    mov     [di].pi_DMA_outstanding,0
  859.         test    [si].ci_dcb_flags2,F2_NULL_STRIP
  860.         jz      drx0                            ; don't strip nulls
  861.  
  862.         call    StripNulls                      ; will save/restore regs
  863.  
  864. drx0:   mov     bx,[si].ci_qin.ioq_in           ; (bx) -> original in ptr
  865.         mov     ax,[di].pi_xfer_count           ; (ax) -> bytes added to in que
  866.         add     bx,ax                           ; (bx) -> updated in ptr
  867.  
  868.         cmp     bx,[si].ci_qin.ioq_end          ; check for wrap around
  869.         jb      drx1                             ; did not wrap
  870.  
  871.         mov     bx,[si].ci_qin.ioq_base         ; wrap
  872.  
  873.         ; check for overflow condition
  874. drx1:    cmp     bx,[si].ci_qin.ioq_out
  875.         je      drx2                             ; yes, overflow
  876.  
  877.         or      [si].ci_event,EV_RX_CHAR        ; no overflow, mark event
  878.         mov     [si].ci_qin.ioq_in,bx           ; save away updated in ptr
  879.         add     [si].ci_qin.ioq_count,ax        ; update count
  880.         jmp     SHORT drx4
  881.  
  882.  
  883. drx2:   mov     [si].ci_rx_state,RX_STATE_HOLDING
  884.  
  885. drx4:   call    FinishReadReq
  886.  
  887.         ; issue Clear DMA Request command
  888. drx9:   mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  889. drx10:  in      al,dx
  890.         test    al,ESP_RDY_CMD1
  891.         jz      drx10
  892.         add     dx,ESP_R_CMD1-ESP_R_RDY
  893.         mov     al,ESP_CMD_CLEARDMAREQ
  894.         out     dx,al
  895.         ; WAIT FOR DMAFIN BIT IN SID TO CLEAR!
  896.         add     dx,ESP_R_SID-ESP_R_CMD1
  897. drx11:  in      al,dx
  898.         test    al,ESP_SID_DMAFIN
  899.         jnz     drx11
  900.  
  901.         mov     di,[si].ci_pinfo
  902.         CLR     [di].pi_flagx,PIF_PECAN_BUSY    ; tell folks ESP is free
  903.         SET     [di].pi_flagx,PIF_RESET_MASK
  904.  
  905. drix:   ret
  906.  
  907. EndProc DMARxInt
  908.  
  909. Procedure DMATxInt,NEAR
  910.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  911.  
  912.         ; ESP finished with DMA Receive, so adjust out ptr for outque.
  913.         cmp     Kernel_Type,ABIOS_COM
  914.         jne     dt5
  915.         call    MCAendDMA
  916.  
  917. dt5:    mov     ax,[di].pi_xfer_count
  918.         sub     [si].ci_qout.ioq_count,ax       ; adjust que count
  919.         jnz     dt10                            ; didn't take last char
  920.         SET     [si].ci_event,EV_TX_EMPTY       ; show that txq emptied
  921.  
  922. dt10:   add     [si].ci_qout.ioq_out,ax
  923.         mov     ax,[si].ci_qout.ioq_out
  924.         cmp     ax,[si].ci_qout.ioq_end         ; adjust for wrap if necessary
  925.         jne     dt30                            ; did not wrap
  926.         mov     ax,[si].ci_qout.ioq_base        ; wrap
  927.         mov     [si].ci_qout.ioq_out,ax
  928.  
  929. dt30:   mov     [di].pi_DMA_outstanding,0
  930.         call    FinishWriteReq
  931.  
  932.         ; issue Clear DMA Request command
  933. dt7:    mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  934. dt7a:   in      al,dx
  935.         test    al,ESP_RDY_CMD1
  936.         jz      dt7a
  937.         add     dx,ESP_R_CMD1-ESP_R_RDY
  938.         mov     al,ESP_CMD_CLEARDMAREQ
  939.         out     dx,al
  940.         ; WAIT FOR DMAFIN BIT IN SID TO CLEAR!
  941.         add     dx,ESP_R_SID-ESP_R_CMD1
  942. dt8:    in      al,dx
  943.         test    al,ESP_SID_DMAFIN
  944.         jnz     dt8
  945.  
  946.         mov     di,[si].ci_pinfo
  947.         CLR     [di].pi_flagx,PIF_PECAN_BUSY    ; tell folks ESP is free
  948.         SET     [di].pi_flagx,PIF_RESET_MASK
  949.         ret
  950.  
  951. EndProc DMATxInt
  952.  
  953. Procedure ErrInt,NEAR
  954.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  955.  
  956.         SET     [di].pi_flagx,PIF_RESET_MASK
  957.         CLR     [di].pi_flagx,PIF_PECAN_BUSY
  958.  
  959. ; GET ERROR STATUS FROM ESP
  960.         call    GetError                        ; fills in errshadow1 and errshadow2
  961.  
  962. ; TEST FOR BREAK/LINE STATUS FIRST
  963.         test    [si].ci_errshadow1,ESP_ERR1_BRK OR ESP_ERR1_FRAME OR ESP_ERR1_PARITY
  964.         jz      er35
  965.  
  966.         call    LineStatusError
  967. ; TEST FOR RX TIMEOUT NEXT
  968. er35:   test    [si].ci_errshadow1,ESP_ERR1_RXTO
  969.         ljz      er90
  970.  
  971.         ; Don't wait on RxFIFO trigger level, transfer bytes waiting now.
  972.         ; Don't waste any more time if this will be a DMA transfer but
  973.         ; a DMA transfer is already in progress. In this case, ignore this
  974.         ; int, and Esp will give us another one next time.
  975.         cmp     [si].ci_rx_request,DMA_REQ_DISABLE
  976.         je      er36
  977.         cmp     [di].pi_DMA_outstanding,0
  978.         ljne     er90                           ; process next error condition
  979.  
  980.  
  981.         ; Handling DSR sensitivity is tricky. If this is first Rx Timeout since
  982.         ; DSR was dropped, may still have good data in ESP's FIFO. ci_qty_good
  983.         ; will be non-zero in this case, and exactly that many bytes should be
  984.         ; transferred to in que -- remember to reset ci_qty_good to zero.
  985.         ; If ci_qty_good is zero (good data already processed), and
  986.         ; FX_IN_DSR_OK is NOT SET, then ignore this interrupt.
  987. er36:
  988.         cmp     [si].ci_qty_good,0
  989.         jne     er37                            ; transfer data already in FIFO
  990.  
  991.         test    [si].ci_flagx,FX_IN_DSR_OK
  992.         jnz     er37
  993.  
  994.         ; Calculate length of transfer -- there are two cases
  995.         ; 1. in ptr is < out ptr
  996.         ;    in this case, we can only put (out - in) - 1 bytes in
  997.         ; 2. in ptr >= out ptr
  998.         ;    In this case, we can only xfer to end of buffer.
  999.         ; If in == out == base, we must leave last byte empty
  1000. er37:   mov     cx,[si].ci_qin.ioq_in
  1001.         mov     dx,[si].ci_qin.ioq_out
  1002.         sub     cx,dx                   ; (cx) = -(out - in)
  1003.         jb      er40                    ; in < out, can only go to (out - 1)
  1004.         add     cx,dx                   ; (cx) = ioq_in
  1005.         sub     cx,[si].ci_qin.ioq_end
  1006.         cmp     dx,[si].ci_qin.ioq_base
  1007.         jne     er50
  1008.  
  1009. er40:   inc     cx                      ; 'subtract' from negated count
  1010.  
  1011. er50:   neg     cx                      ; (cx) = transfer count
  1012.         jc      er53                    ; carry set, then (cx) not zero
  1013.  
  1014.         jmp     er90                    ; no room in que for rx data
  1015.  
  1016.         ; (cx) = room left in qin
  1017.         ; Handle ridiculous DSR sensitivity first
  1018. er53:   cmp     [si].ci_qty_good,0
  1019.         je      er57
  1020.  
  1021.         sub     [si].ci_qty_good,cx
  1022.         jg      er60
  1023.         mov     cx,[si].ci_qty_good
  1024.         mov     [si].ci_qty_good,0
  1025.         jmp     SHORT er60
  1026.  
  1027. er57:   SaveReg         <cx>
  1028.         GetRxBytes                             ; (ax) = bytes ready in ESP
  1029.         RestoreReg      <cx>
  1030.         xchg    al,ah
  1031.         cmp     [si].ci_rx_request,DMA_REQ_DISABLE
  1032.         je      er58                            ; don't test for RxBytes=0
  1033.         cmp     ax,0                            ; no bytes available
  1034.         lje     er90
  1035.  
  1036. er58:   cmp     cx,ax
  1037.         ja      er60                            ; There's room for all
  1038.         mov     ax,cx                           ; not enough room
  1039. er60:
  1040.         ; (ax) = bytes to transfer
  1041.         ; Are we doing DMA or PIO?
  1042.         cmp     [si].ci_rx_request,DMA_REQ_DISABLE
  1043.         jne     er62
  1044.  
  1045.         ; Do that PIO
  1046.         mov     cx,ax                           ; RxPIO expects count in CX
  1047.         call    RxPIO
  1048.         jmp     er85
  1049.  
  1050. er62:
  1051.         ; Set up DMA controller for WRITE transfer
  1052.         mov     [di].pi_xfer_count,ax
  1053.         cmp     Kernel_Type,ABIOS_COM
  1054.         je      er65
  1055.         mov     al,AT_DMA_MODE_WRITE
  1056.         mov     ah,[di].pi_dma_chan
  1057.         call    ATsetupDMA
  1058.         jmp     SHORT er69
  1059.  
  1060. er65:   mov     bl,ABIOS_FUNC_WRITEMEM
  1061.         call    MCAbeginDMA
  1062.  
  1063.         ; DMAC ready, tell ESP to start
  1064. er69:   mov     [di].pi_DMA_outstanding,si          ; save ComInfo ptr
  1065. mov bl,sid_buf_index
  1066. dec bl
  1067. xor bh,bh
  1068. mov dx,si
  1069. mov dma_buf[bx],dl
  1070.         mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  1071. er70:   in      al,dx
  1072.         test    al,ESP_RDY_CMD1
  1073.         jz      er70
  1074.         add     dx,ESP_R_CMD1-ESP_R_RDY         ; (dx) -> cmd1 reg
  1075.         mov     al,ESP_CMD_DMARX
  1076.         add     al,[si].ci_cmd_offset
  1077.         out     dx,al
  1078.         add     dx,ESP_R_RDY-ESP_R_CMD1         ; (dx) -> ready reg
  1079. er80:    in      al,dx
  1080.         test    al,ESP_RDY_STATUS1
  1081.         jz      er80
  1082.         add     dx,ESP_R_STATUS1-ESP_R_RDY      ; (dx) -> status1 reg
  1083.         in      al,dx
  1084.  
  1085.         ; Set flag in my pinfo to let everyone know ESP is busy doing DMA
  1086.         SET     [di].pi_flagx,PIF_PECAN_BUSY
  1087.         CLR     [di].pi_flagx,PIF_DMA_READ      ; remember DMA was a Write
  1088.         CLR     [di].pi_flagx,PIF_RESET_MASK
  1089.  
  1090.         ; Clear Tx and Rx bits in pi_sid -- only allow one DMA transfer per isr.
  1091. er85:   mov     al,ESP_SID_TXBOTH OR ESP_SID_RXBOTH
  1092.         not     al
  1093.         and     [di].pi_sid,al
  1094.  
  1095. ; TEST FOR MSR
  1096. er90:
  1097.         test    [si].ci_errshadow1,ESP_ERR1_MSR
  1098.         jz      er130
  1099.         mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  1100. er100:  in      al,dx
  1101.         test    al,ESP_RDY_CMD1
  1102.         jz      er100
  1103.         add     dx,ESP_R_CMD1-ESP_R_RDY         ; (dx) -> cmd1 reg
  1104.         mov     al,ESP_CMD_GETUARTS
  1105.         add     al,[si].ci_cmd_offset
  1106.         out     dx,al
  1107.         add     dx,ESP_R_RDY-ESP_R_CMD1         ; (dx) -> ready reg
  1108. er110:  in      al,dx
  1109.         test    al,ESP_RDY_STATUS1
  1110.         jz      er110
  1111.         add     dx,ESP_R_STATUS1-ESP_R_RDY      ; (dx) -> status1
  1112.         in      al,dx                           ; (al) = LSR, throw away
  1113.         add     dx,ESP_R_RDY-ESP_R_STATUS1      ; (dx) -> ready reg
  1114. er120:   in      al,dx
  1115.         test    al,ESP_RDY_STATUS2
  1116.         jz      er120
  1117.         add     dx,ESP_R_STATUS2-ESP_R_RDY      ; (dx) -> status2 reg
  1118.         in      al,dx                           ; (al) = MSR reg
  1119.         call    EMxInt
  1120.  
  1121. ; TEST FOR RX OVERFLOW
  1122. er130:  test    [si].ci_errshadow1,ESP_ERR1_RXOF
  1123.         jz      er240
  1124.  
  1125.         ; ignore ESP overruns if DSR sensitivity turned on
  1126.         test    [si].ci_dcb_flags1,F1_IN_DSR_SENSE
  1127.         jnz     er240
  1128.         ; DO WE FLAG AS OVERRUN, OR MAYBE "ESP prevents hw overruns"
  1129.         ;SET     [si].ci_comerr,CE_HW_OVERRUN
  1130.  
  1131. ifdef PERFVIEW
  1132.         ; If flagged as overrun, then update perfview counter    ;@PVW
  1133.         ;pvw_SW_Overrun              ;inc PerfView flag          ;@PVW
  1134. endif
  1135.  
  1136. ; TEST FOR XON/XOFF
  1137. er240:  test    [si].ci_errshadow2,ESP_ERR2_OFFLOCAL
  1138.         jz      er250
  1139.  
  1140.         ; If we're waiting for transmitter to empty (RTS toggling) and get
  1141.         ; xoff'ed, then drop RTS. Raise it again when xon'ed.
  1142.         test    [si].ci_flagx,FX_WAITING_TX_EMPTY
  1143.         jz      er250
  1144.         CLR     [si].ci_esp_flow1,ESP_FC1_ON_RTS        ; drop RTS
  1145.         mov     ah,[si].ci_esp_flow1
  1146.         mov     al,[si].ci_esp_flow2
  1147.         SetFCType       ah,al
  1148.  
  1149. er250:  test    [si].ci_errshadow2,ESP_ERR2_ONLOCAL
  1150.         jz      erxx
  1151.  
  1152.         ; If we're waiting for transmitter to empty (RTS toggling) and get
  1153.         ; xon'ed, then raise RTS.
  1154.         test    [si].ci_flagx,FX_WAITING_TX_EMPTY
  1155.         jz      erxx
  1156.         SET     [si].ci_esp_flow1,ESP_FC1_ON_RTS        ; raise RTS
  1157.         mov     ah,[si].ci_esp_flow1
  1158.         mov     al,[si].ci_esp_flow2
  1159.         SetFCType       ah,al
  1160.  
  1161. erxx:   ret
  1162.  
  1163. EndProc ErrInt
  1164.  
  1165. Procedure StripNulls,NEAR
  1166.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1167.  
  1168.         push    bp
  1169.         push    si
  1170.         push    di
  1171.         push    ds
  1172.         push    es
  1173.  
  1174.         mov     cx,[di].pi_xfer_count
  1175.         mov     di,WORD PTR [si].ci_qin.ioq_in  ;(ds:di) -> qin new data
  1176.         push    ds
  1177.         pop     es                              ;(es:di) -> qin new data
  1178.         ASSUME  ds:nothing
  1179.         ;Careful, can't access driver data segment until DS is restored from stack
  1180.         sub     bx,bx
  1181.         sub     ax,ax
  1182. scan:
  1183.         jcxz    thats_all                       ;(cx) = bytes left to scan
  1184.         repnz   scasb
  1185.         jnz     thats_all
  1186.  
  1187.         inc     bx                              ;(bx) = nulls removed
  1188.         mov     dx,cx                           ;(dx) = bytes left to scan
  1189.         mov     si,di                           ;(si) -> byte after null
  1190.         dec     di                              ;(di) -> null byte
  1191.         mov     bp,di                           ;(bp) -> null, and also new
  1192.                                                 ;  data after "rep movsb"
  1193.         rep     movsb                           ;copy over null byte
  1194.         mov     di,bp                           ;(di) -> new bytes to scan
  1195.         mov     cx,dx                           ;(cx) = bytes left to scan
  1196.         jmp     scan
  1197.  
  1198. thats_all:
  1199.         pop     es
  1200.         pop     ds
  1201.         pop     di
  1202.         pop     si
  1203.         ASSUME  ds:DSEG
  1204.         sub     [di].pi_xfer_count,bx           ;(bx) = number of nulls removed
  1205.         pop     bp
  1206.         ret
  1207.  
  1208. EndProc StripNulls
  1209.  
  1210. ;***    ATsetupDMA - Set the DMA channel up to do the I/O
  1211. ;
  1212. ;       ENTRY   AL = DMA mode
  1213. ;               AH = DMA channel numbe
  1214. ;
  1215. ;       EXIT    AX is preserved
  1216. ;
  1217. ;       USES     BX, CX, DX, Flags
  1218.  
  1219. Procedure ATsetupDMA,NEAR
  1220.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1221.  
  1222.         push    ax
  1223.         mov     bx,ax                   ; (bl) = DMA mode
  1224.         cli
  1225.         xchg    ah,al                   ; (ah) = DMA Mode
  1226.         or      al,4
  1227.         out     AT_DMA_MASK,al          ; set channel's mask bit
  1228.         IOWait
  1229.         out     AT_DMA_CLEAR,al         ; clear byte pointer F/F
  1230.         IOWait
  1231.         pop     ax                      ; restore channel and mode
  1232.         push    ax
  1233.         or      al,ah                   ; add channel number to command
  1234.         out     AT_DMA_MODE,al          ; Set DMA mode
  1235.         IOWait
  1236.         xor     dx,dx
  1237.         rol     ah,1
  1238.         add     dl,ah                   ; (dx) -> address register
  1239.  
  1240.         push    bx
  1241.         test    bl,AT_DMA_MODE_READ
  1242.         jz      at10                    ; mode == WRITE
  1243.  
  1244.         ; DMA mode == READ
  1245.         mov     cx,[si].ci_qout.ioq_phys._hi
  1246.         mov     [si].ci_qout.ioq_page,cx        ; (page) = hi byte of phys addr
  1247.         mov     ax,[si].ci_qout.ioq_out
  1248.         sub     ax,[si].ci_qout.ioq_base        ; (ax) = offset of start from base
  1249.         mov     cx,[si].ci_qout.ioq_phys._lo    ; (cx) = que base phys address
  1250.         add     ax,cx                           ; (ax) = start transfer address
  1251.         mov     bx,ax
  1252.         add     bx,[di].pi_xfer_count           ; (bx) = finish transfer address
  1253.         jmp     SHORT at20
  1254.  
  1255.         ; DMA mode == WRITE
  1256. at10:   mov     cx,[si].ci_qin.ioq_phys._hi
  1257.         mov     [si].ci_qin.ioq_page,cx         ; (page) = hi byte of phys addr
  1258.         mov     ax,[si].ci_qin.ioq_in
  1259.         sub     ax,[si].ci_qin.ioq_base         ; (ax) = offset of start from base
  1260.         mov     cx,[si].ci_qin.ioq_phys._lo     ; (cx) = que base phys address
  1261.         add     ax,cx                           ; (ax) = start transfer address
  1262.         mov     bx,ax
  1263.         add     bx,[di].pi_xfer_count           ; (bx) = finish transfer address
  1264.  
  1265.         ; If phys address of ioq_in/ioq_out plus transfer length is less than
  1266.         ; phys address of que base, que will wrap to next physical page.
  1267.         ; DMAC can't handle two different pages, so shorten transfer length,
  1268.         ; and do another transfer next time to get the rest.
  1269.         ; 
  1270.         ; (ax) = start transfer address, (bx) = finish transfer address
  1271.         ; (cx) = que base address
  1272. at20:   cmp    ax,cx
  1273.         jb     at25                             ; already on 2nd page
  1274.  
  1275.         cmp     bx,cx
  1276.         jae     at30                            ; no wrap
  1277.  
  1278.         ; Que would wrap, so calculate new shorter transfer length (go to
  1279.         ; page boundary)
  1280.         mov     bx,0
  1281.         sub     bx,ax                           ; (bx) = bytes to boundary
  1282.         ; (bx) = bytes to end of page boundary
  1283.         mov     [di].pi_xfer_count,bx
  1284.         jmp     SHORT at30
  1285.  
  1286. at25:   pop     bx
  1287.         test    bl,AT_DMA_MODE_READ
  1288.         jnz     at27
  1289.         inc     [si].ci_qin.ioq_page            ; begin transfer at 2nd page
  1290.         jmp     SHORT at35
  1291.  
  1292. at27:   inc     [si].ci_qout.ioq_page
  1293.         jmp     SHORT at35
  1294.  
  1295. at30:   pop     bx
  1296. at35:   out     dx,al                           ; Out low byte of address
  1297.         IOWait
  1298.         xchg    al,ah
  1299.         out     dx,al                           ; Out second byte of address
  1300.         IOWait
  1301.         inc     dx                              ; (dx) -> count register
  1302.         mov     ax,[di].pi_xfer_count           ; # bytes to transfer
  1303.         dec     ax
  1304.         out     dx,al                           ; Out lo byte of count
  1305.         IOWait
  1306.         xchg    al,ah
  1307.         out     dx,al                           ; Out hi byte of count
  1308.         IOWait
  1309.         pop     ax                              ; get back DMA channel number
  1310.         push    ax
  1311.         cmp     ah,1                            ; test channel is 1
  1312.         jne     at40                            ; no, channel is 3
  1313.         mov     dx,AT_DMA_PAGE_CH1
  1314.         jmp     SHORT at50
  1315.  
  1316. at40:   mov     dx,AT_DMA_PAGE_CH3
  1317. at50:   mov     ax,[si].ci_qout.ioq_page        ; assume mode is READ
  1318.         test    bl,AT_DMA_MODE_READ             ; test DMA mode is READ
  1319.         jnz     at60                            ; mode is READ, ax ready
  1320.         mov     ax,[si].ci_qin.ioq_page         ; mode is WRITE, set up ax
  1321. at60:   out     dx,al                           ; Out highest byte of address
  1322.         IOWait
  1323.         pop     ax
  1324.         push    ax
  1325.         xchg    ah,al
  1326.         out     AT_DMA_MASK,al                  ; enable DMAC for our channel
  1327.         pop     ax
  1328.         sti
  1329.         ret
  1330.  
  1331. Endproc ATsetupDMA
  1332.  
  1333. ;***    MCAbeginDMA
  1334. ;
  1335. ;       ENTRY   BL = ABIOS function code for DMA READ or DMA WRITE
  1336. ;
  1337. ;       USES     BX, CX, DX, Flags
  1338. Procedure MCAbeginDMA,NEAR
  1339.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1340.  
  1341.         SaveReg         <ds,es>
  1342.         SaveReg         <bx>
  1343.  
  1344.         ; Allocate ESP's arbitration level
  1345.         mov     di,[si].ci_pinfo
  1346.         mov     al,[di].pi_DMA_chan             ; actually DMA arb level
  1347.         setDS   HSEG
  1348.         mov     bx,alloc_ptr
  1349.         mov     [bx].arb,al
  1350.         mov     [bx].arbfunc,ABIOS_FUNC_ALLOCARB
  1351.         mov     [bx].arbrval,0FFFFh
  1352.         sub     ax,ax
  1353.         mov     WORD PTR [bx].arbres1,ax
  1354.         mov     WORD PTR [bx].arbres1+2,ax
  1355.         mov     [bx].arbres2,ax
  1356.         mov     WORD PTR [bx].arbres3,ax
  1357.         mov     WORD PTR [bx].arbres3+2,ax
  1358.         mov     [bx].arbres4,al
  1359.  
  1360.         xchg    si,bx
  1361.         ; (ds:si) -> ABIOS request block
  1362.         mov     dh,0                            ; use Start entry point
  1363.         mov     dl,DevHlp_ABIOSCommonEntry
  1364.         setES   DSEG
  1365.         call    es:[DevHlp]
  1366.         jc      alloc_failed
  1367.         cmp     [si].arbrval,0
  1368.         je      mca5
  1369. alloc_failed:
  1370.         mov     si,bx                           ; (si) -> ComInfo block
  1371.         ComErr  <MCABeginDMA: call to ABIOS_FUNC_ALLOC_ARB failed>,CALLFAR
  1372.  
  1373. mca5:
  1374.         setDS   DSEG
  1375.         xchg    si,bx                           ; (ds:si) -> ComInfo block
  1376.         RestoreReg      <bx>
  1377.         SaveReg         <bx>
  1378.         cmp     bl,ABIOS_FUNC_READMEM
  1379.         jne     mca10
  1380.  
  1381.         ; DMA Read from memory
  1382.         mov     cx,[si].ci_qout.ioq_phys._hi
  1383.         mov     [si].ci_qout.ioq_page,cx        ; (page) = hi byte of phys addr
  1384.         mov     ax,[si].ci_qout.ioq_out
  1385.         sub     ax,[si].ci_qout.ioq_base        ; (ax) = offset of start from base
  1386.         mov     cx,[si].ci_qout.ioq_phys._lo    ; (cx) = que base phys address
  1387.         add     ax,cx                           ; (ax) = start transfer address
  1388.         mov     bx,ax
  1389.         add     bx,[di].pi_xfer_count           ; (bx) = finish transfer address
  1390.         jmp     SHORT mca20
  1391.  
  1392.         ; DMA Write to memory
  1393. mca10:  mov     cx,[si].ci_qin.ioq_phys._hi
  1394.         mov     [si].ci_qin.ioq_page,cx         ; (page) = hi byte of phys addr
  1395.         mov     ax,[si].ci_qin.ioq_in
  1396.         sub     ax,[si].ci_qin.ioq_base         ; (ax) = offset of start from base
  1397.         mov     cx,[si].ci_qin.ioq_phys._lo     ; (cx) = que base phys address
  1398.         add     ax,cx                           ; (ax) = start transfer address
  1399.         mov     bx,ax
  1400.         add     bx,[di].pi_xfer_count           ; (bx) = finish transfer address
  1401.  
  1402.         ; If phys address of ioq_in/ioq_out plus transfer length is less than
  1403.         ; phys address of que base, que will wrap to next physical page.
  1404.         ; DMAC can't handle two different pages, so shorten transfer length,
  1405.         ; and do another transfer next time to get the rest.
  1406.         ; 
  1407.         ; (ax) = start transfer address, (bx) = finish transfer address
  1408.         ; (cx) = que base address
  1409. mca20:  cmp    ax,cx
  1410.         jb      mca25
  1411.  
  1412.         cmp     bx,cx
  1413.         jae     mca30
  1414.  
  1415.         ; Que would wrap, so calculate shorter transfer length
  1416.         ; (go to page boundardy)
  1417.         mov     bx,0
  1418.         sub     bx,ax
  1419.         ; (bx) = bytes to end of page boundary
  1420.         mov     [di].pi_xfer_count,bx
  1421.         jmp     SHORT mca30
  1422.  
  1423. mca25:  RestoreReg      <bx>                    ; (bx) = read or write
  1424.         cmp     bl,ABIOS_FUNC_READMEM
  1425.         je      mca27
  1426.         inc     [si].ci_qin.ioq_page
  1427.         jmp     SHORT mca35
  1428.  
  1429. mca27:  inc     [si].ci_qout.ioq_page
  1430.         jmp     SHORT mca35
  1431.  
  1432. mca30:  pop     bx
  1433.  
  1434.         ; (ax) = phys addr
  1435. mca35:  mov     cx,bx                           ; (cx) = read/write
  1436.  
  1437.         cmp     cl,ABIOS_FUNC_READMEM
  1438.         je      mca40
  1439.         mov     dx,[si].ci_qin.ioq_page
  1440.         jmp     mca45
  1441. mca40:
  1442.         mov     dx,[si].ci_qout.ioq_page
  1443.  
  1444. mca45:
  1445.         ; (ax) = phys address lo word
  1446.         ; (dx) = phys address high word
  1447.         ; (cl) = ABIOS_FUNC_READMEM or ABIOS_FUNC_WRITE_MEM
  1448.         ; Load as much as we can of ABIOS request block using registers.
  1449.         ; Loading from ESPInfo struc forces segment override since request
  1450.         ; block and ESPInfo are in different segments.
  1451.         setDS   HSEG
  1452.         setES   DSEG
  1453.         mov     bx,si                           ; (bx) -> ComInfo
  1454.         mov     si,read_write_ptr
  1455.         ; (ds:si) -> request block
  1456.         ; (es:di) -> ESPInfo
  1457.                       xor     ch,ch
  1458.         mov     [si].rwfunc,cx
  1459.         mov     [si].memaddr._lo,ax
  1460.         mov     [si].memaddr._hi,dx
  1461.         mov     ax,es:[di].pi_xfer_count
  1462.         dec     ax
  1463.         mov     [si].count._lo,ax
  1464.         mov     [si].count._hi,0
  1465.         mov     al,es:[di].pi_DMA_chan          ; actually DMA arb level
  1466.         mov     [si].rwarb,al
  1467.         mov     [si].arbrval,0FFFFh
  1468.         sub     ax,ax
  1469.         mov     WORD PTR [si].rwres1,ax
  1470.         mov     WORD PTR [si].rwres1+2,ax
  1471.         mov     [si].ioaddr._lo,ax
  1472.         mov     [si].ioaddr._hi,ax
  1473.         mov     [si].mode,al
  1474.         mov     [si].rwtc1,al
  1475.         mov     [si].rwtc2,al
  1476.  
  1477.         mov     dh,0                            ; use Start entry point
  1478.         mov     dl,DevHlp_ABIOSCommonEntry
  1479.         DevHelp
  1480.         jc      read_failed
  1481.         cmp     [si].arbrval,0
  1482.         je      mcaix
  1483. read_failed:
  1484.         mov     si,bx                           ; (si) -> ComInfo
  1485.         ComErr  <MCABeginDMA: call to ABIOS_FUNC_READ or WRITE failed>,CALLFAR
  1486.  
  1487. mcaix:  xchg    si,bx
  1488.         RestoreReg      <es,ds>
  1489.         ret
  1490.  
  1491. Endproc MCAbeginDMA
  1492.  
  1493. Procedure MCAendDMA,NEAR
  1494.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1495.  
  1496.         SaveReg         <ds,es>
  1497.         mov     di,[si].ci_pinfo
  1498.         mov     al,[di].pi_DMA_chan             ; actually arb level
  1499.         setDS   HSEG
  1500.         mov     bx,disable_ptr
  1501.         ; Disable arbitration level
  1502.         mov     [bx].arb,al
  1503.         mov     [bx].arbfunc,ABIOS_FUNC_DISABLEARB
  1504.         mov     [bx].arbrval,0FFFFh
  1505.         sub     ax,ax
  1506.         mov     WORD PTR [bx].arbres1,ax
  1507.         mov     WORD PTR [bx].arbres1+2,ax
  1508.         mov     [bx].arbres2,ax
  1509.         mov     WORD PTR [bx].arbres3,ax
  1510.         mov     WORD PTR [bx].arbres3+2,ax
  1511.         mov     [bx].arbres4,al
  1512.         xchg    si,bx
  1513.         ; (si) -> ABIOS request block, (bx) -> ComInfo
  1514.         mov     dh,0                            ; use Start entry point
  1515.         mov     dl,DevHlp_ABIOSCommonEntry
  1516.         setES   DSEG
  1517.         call    es:[DevHlp]
  1518.         jc      disable_failed
  1519.         cmp     [si].arbrval,0
  1520.         je      ed10
  1521. disable_failed:
  1522.         mov     si,bx                           ; (si) -> ComInfo
  1523.         ComErr  <MCAEndDMA: call to ABIOS_FUNC_DISABLE_ARB failed>,CALLFAR
  1524.  
  1525.         ; Deallocate arbitration level.
  1526.         ; (si) -> ABIOS request block, (bx) -> ComInfo
  1527. ed10:
  1528.         mov     si,dealloc_ptr
  1529.         mov     [si].arbfunc,ABIOS_FUNC_DEALLOCARB
  1530.         mov     al,es:[di].pi_DMA_chan          ; actually arb level
  1531.         mov     [si].arb,al
  1532.         mov     [si].arbrval,0FFFFh
  1533.         sub     ax,ax
  1534.         mov     WORD PTR [si].arbres1,ax
  1535.         mov     WORD PTR [si].arbres1+2,ax
  1536.         mov     [si].arbres2,ax
  1537.         mov     WORD PTR [si].arbres3,ax
  1538.         mov     WORD PTR [si].arbres3+2,ax
  1539.         mov     [si].arbres4,al
  1540.         mov     dh,0                            ; use Start entry point
  1541.         mov     dl,DevHlp_ABIOSCommonEntry
  1542.         DevHelp
  1543.         jc      dealloc_failed
  1544.         cmp     [si].arbrval,0
  1545.         je      edix
  1546. dealloc_failed:
  1547.         mov     si,bx                           ; (si) -> ComInfo
  1548.         ComErr  <MCAEndDMA: call to ABIOS_FUNC_DEALLOC_ARB failed>,CALLFAR
  1549.  
  1550. edix:   xchg    si,bx
  1551.         RestoreReg      <es,ds>
  1552.         ret
  1553.  
  1554. Endproc MCAendDMA
  1555.  
  1556.  
  1557. Procedure FinishWriteReq,NEAR
  1558.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1559.  
  1560.         les     di,[si].ci_w_rp                 ; (es:di) -> request packet
  1561.         cmp     [si].ci_w_to_move,0
  1562.         jne     fw50                            ; data still to move, req not done
  1563.         cmp     [si].ci_qout.ioq_count,0
  1564.         jne     fwx                             ; data still in queue, req not done
  1565.  
  1566.         ; Request is done
  1567.         ProcReady       CALLFAR                  ; put request on Ready list
  1568.         mov     [si].ci_w_rp._hi,0              ; no longer current write req
  1569.  
  1570.         SaveReg         <di>
  1571.  
  1572.         ; Start the next write request packet and trigger a new TxFIFO int,
  1573.         ; or if no next write request packet turn off the TxFIFO int
  1574.         CALLFAR GetNextWRP
  1575.         pushf                                   ; 'C' set if no more requests
  1576.         call    TriggerTX
  1577.         popf                                    ; restore 'C' from GetNextWRP
  1578.  
  1579.         RestoreReg      <di>                    ; (es:di) -> request packet
  1580.         jc      fwx                             ; no more requests
  1581.  
  1582.         ; More write requests, this is a chance to move data from user space
  1583.         ; to out que.
  1584. fw50:   mov     cx,[si].ci_qout.ioq_count
  1585.         cmp     cx,TX_MOVE_PROT
  1586.         ja      fwx                             ; not down to prot mode mark
  1587.  
  1588.         WHATMODE
  1589.         jc      fw60                            ; protect mode, go move data
  1590.  
  1591.         cmp     cx,TX_MOVE_REAL                 ; check real mode mark
  1592.         ja      fwx                             ; above real mode mark, don't move
  1593.  
  1594.         ; hit low water mark, move more data
  1595. fw60:   SET     [si].ci_flagx,FX_DATA_MOVED     ; mark data moved
  1596.         mov     cx,[si].ci_w_to_move            ; set up count
  1597.  
  1598.         CALLFAR WriteQueue                      ; move data into queue
  1599.                                                 ; updates ci_w_to_move
  1600.  
  1601. fwx:    ret
  1602.  
  1603. EndProc FinishWriteReq
  1604.  
  1605. Procedure FinishReadReq,NEAR
  1606.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1607.  
  1608.         SaveReg         <di>
  1609.  
  1610.         ; see if the current read request can be completed.
  1611.         cmp     [si].ci_r_rp._hi,0
  1612.         lje     frx                     ; no current read request
  1613.  
  1614.         mov     cx,[si].ci_qin.ioq_count; (cx) = number of bytes in queue
  1615.         cmp     cx,[si].ci_r_to_move
  1616.         jae     fr10                    ; enough to complete request
  1617.  
  1618.         mov     al,[si].ci_dcb_flags3
  1619.         and     al,F3_READ_TO_MASK      ; (al) = read timeout mode
  1620.  
  1621.         ; BUGBUG - no wait mode
  1622.         ; 'no wait' mode can get here if there were queued read requests
  1623.         ; and then 'no wait' mode was set.
  1624.         ; Each queued request will remain blocked until the first interrupt
  1625.         ; of any type (rx, tx, mx).
  1626.         ; We could complete the current read request and flush all other read
  1627.         ; requests when 'no wait' mode is specified in Set DCB.
  1628.  
  1629.         cmp     al,F3_READ_TO_NW
  1630.         je      fr10                    ; no wait mode
  1631.  
  1632.         cmp     al,F3_READ_TO_WFS
  1633.         jne     fr20                    ; not wait for something mode
  1634.  
  1635.         jcxz    fr20                    ; wait for something mode, but no data
  1636.  
  1637. fr10:    ; enough to finish request (done, no wait or wait for something)
  1638.         les     di,[si].ci_r_rp         ; (es:di) -> request packet
  1639.         ASSUME  es:NOTHING
  1640.         ChkRPPtr
  1641.         ChkRPType       CMDINPUT
  1642.  
  1643.         test    es:[di].PktStatus,STDON
  1644.         jnz     frx                     ; already marked done
  1645.  
  1646.         or      es:[di].PktStatus,STDON ; mark request done
  1647.                                         ; (so we don't run it twice)
  1648.  
  1649.         ProcReady       CALLFAR         ; put request on 'ready' list
  1650.         jmp     SHORT frx
  1651.  
  1652.         ; may have enough data to move up to user buffer
  1653.         ; make mark higher for real mode hopeing for it to get moved in prot mode
  1654. fr20:    cmp    cx,RX_MOVE_PROT         ; (cx) = # of bytes in qin from above
  1655.         jb      frx                     ; below prot mode mark, don't move
  1656.  
  1657.         test    [si].ci_flagx,FX_DATA_MOVED
  1658.         jnz     frx                     ; data already moved on this interrupt
  1659.                                         ; set here and in TxInt
  1660.  
  1661.         WHATMODE
  1662.         jc      fr30                    ; protect mode, go move data
  1663.  
  1664.         cmp     cx,RX_MOVE_REAL         ; check real mode mark
  1665.         jb      frx                     ; below real mode mark, don't move
  1666.  
  1667. fr30:    or     [si].ci_flagx,FX_DATA_MOVED     ; mark data moved
  1668.  
  1669.         les     di,[si].ci_r_rp         ; (es:di) -> request packet
  1670.         ASSUME  es:NOTHING
  1671.         ChkRPPtr
  1672.         ChkRPType       CMDINPUT
  1673.  
  1674.         ; have to move data to user space
  1675.         sti                             ; allow interrupts while moving data
  1676.         mov     cx,[si].ci_r_to_move    ; set up count
  1677.  
  1678.         CALLFAR ReadQueue               ; move data to user space
  1679.                                         ; updates ci_r_to_move
  1680.  
  1681. frx:    RestoreReg      <di>
  1682.         ret
  1683.  
  1684. EndProc FinishReadReq
  1685.  
  1686. Procedure GetError,NEAR
  1687. ;       ENTRY
  1688. ;       EXIT            error condition in errshadow1 and errshadow2
  1689.  
  1690.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1691.  
  1692.         mov     dx,[si].ci_esp_address          ; (dx) -> ready reg
  1693. ges10:  in      al,dx
  1694.         test    al,ESP_RDY_CMD1
  1695.         jz      ges10
  1696.         add     dx,ESP_R_CMD1-ESP_R_RDY         ; (dx) -> cmd1 reg
  1697.         mov     al,ESP_CMD_GETERRS
  1698.         add     al,[si].ci_cmd_offset
  1699.         out     dx,al
  1700.         add     dx,ESP_R_RDY-ESP_R_CMD1         ; (dx) -> ready reg
  1701. ges20:  in      al,dx
  1702.         test    al,ESP_RDY_STATUS1
  1703.         jz      ges20
  1704.         add     dx,ESP_R_STATUS1-ESP_R_RDY      ; (dx) -> status1 reg
  1705.         in      al,dx
  1706.         mov     [si].ci_errshadow1,al
  1707.  
  1708.         add     dx,ESP_R_RDY-ESP_R_STATUS1      ; (dx) -> ready reg
  1709. ges30:  in      al,dx
  1710.         test    al,ESP_RDY_STATUS2
  1711.         jz      ges30
  1712.         add     dx,ESP_R_STATUS2-ESP_R_RDY      ; (dx) -> status2 reg
  1713.         in      al,dx
  1714.  
  1715.         mov     [si].ci_errshadow2,al
  1716.         ret
  1717.  
  1718. EndProc GetError
  1719.  
  1720.  
  1721. Procedure LineStatusError,NEAR
  1722.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1723.  
  1724.         ; Handle DMA and PIO differently
  1725.         cmp     [si].ci_rx_request,DMA_REQ_DISABLE
  1726.         lje     lse200
  1727.  
  1728.         ; If this error caused last DMA transfer to be halted, update que ptrs
  1729.         cmp     si,[di].pi_DMA_outstanding
  1730.         ljne    lse200
  1731.  
  1732.         ; Get number of bytes actually transferred from ESP to inque
  1733.         cmp     Kernel_Type,ABIOS_COM
  1734.         je      lse183
  1735.         mov     dx,AT_DMA_CLEAR                 ; clear byte pointer before using count
  1736.         mov     al,0
  1737.         out     dx,al
  1738.  
  1739.         cmp     [di].pi_DMA_chan,3
  1740.         je      lse150
  1741.         mov     dx,AT_DMA_COUNT_CH1
  1742.         jmp     SHORT lse180
  1743.  
  1744. lse150: mov     dx,AT_DMA_COUNT_CH3
  1745.  
  1746. lse180: in      al,dx                   ; (al) = LSB bytes left to xfer
  1747.         mov     ah,al                   ; (ah) = LSB bytes left to xfer
  1748.         in      al,dx                   ; (al) = MSB bytes left to xfer
  1749.         xchg    al,ah                   ; (ax) = bytes left to xfer
  1750.         mov     dx,[di].pi_xfer_count   ; (dx) = bytes attempted to xfer
  1751.         jmp     SHORT lse185
  1752.  
  1753. lse183:
  1754.         mov     di,[si].ci_pinfo
  1755.         mov     al,[di].pi_DMA_chan     ; actually arb level
  1756.         setDS   HSEG                    ; tcount_ptr/tcount_rb in HSEG
  1757.         mov     bx,tcount_ptr
  1758.         mov     [bx].func,ABIOS_FUNC_XFERSTATUS
  1759.         mov     [bx].tcarb,al
  1760.         xchg    si,bx
  1761.         ; (si) -> ABIOS request block, (bx) -> ComInfo
  1762.         mov     dh,0                            ; use Start entry point
  1763.         mov     dl,DevHlp_ABIOSCommonEntry
  1764.         push    es
  1765.         setES   DSEG
  1766.         call    es:[DevHlp]
  1767.         pop     es
  1768.         jc      status_failed
  1769.         cmp     [si].arbrval,0
  1770.         je      lse184
  1771. status_failed:
  1772.         mov     si,bx                           ; (si) -> ComInfo block
  1773.         ComErr  <LineStatusError : call to ABIOS_FUNC_XFER_STATUS failed>,CALLFAR
  1774. lse184:  mov     dx,[si].tcount._lo
  1775.  
  1776. lse185:
  1777.         setDS   DSEG                    ; finished with req block, put it back
  1778.         sub     dx,ax                   ; (dx) = bytes ACTUALLY xferred
  1779.         ; (dx) = bytes ACTUALLY transferred
  1780.         ; Update inque pointers
  1781.         add     [si].ci_qin.ioq_count,dx        ; adjust que count
  1782.         add     [si].ci_qin.ioq_in,dx
  1783.         mov     ax,[si].ci_qin.ioq_in
  1784.         cmp     ax,[si].ci_qin.ioq_end          ; adjust for wrap if necessary
  1785.         jne     lse190                            ; did not wrap
  1786.         mov     ax,[si].ci_qin.ioq_base         ; wrap
  1787.         mov     [si].ci_qin.ioq_in,ax
  1788. lse190:  mov     [di].pi_DMA_outstanding,0
  1789.  
  1790.         ; Que ptrs are updated, now take care of flags and replacement chars
  1791. lse200:  test    [si].ci_errshadow1,ESP_ERR1_FRAME OR ESP_ERR1_PARITY
  1792.         jz      lse220
  1793.         mov     al,[si].ci_errshadow1
  1794.         xor     ah,ah                           ; don't need errs in high byte
  1795.         and     ax,CE_RX_PARITY OR CE_FRAME     ; mask error bits
  1796.         or      [si].ci_comerr,ax               ; combine error bits with
  1797.                                                 ; previous errors
  1798.         SET     [si].ci_event,EV_ERR            ; mark line status error
  1799.  
  1800.         test    [si].ci_dcb_flags2,F2_ERR_CHAR
  1801.         jz      lse220
  1802.  
  1803.         ; Last byte transferred into rx que by ESP was byte containing parity
  1804.         ; or framing error. Now replace this last byte with error char.
  1805. lse210: mov     bx,[si].ci_qin.ioq_in
  1806.         cmp     bx,[si].ci_qin.ioq_base         ; in == base?
  1807.         jne     lse215                           ; didn't wrap when placing
  1808.                                                 ;  byte in rx que
  1809.         mov     bx,[si].ci_qin.ioq_end          ; 'unwrap' back to end of que
  1810.  
  1811. lse215: dec     bx                              ; (bx) -> last byte in que
  1812.         mov     [si].ci_qin.ioq_in,bx           ; in points to position for
  1813.                                                 ;  replacement char
  1814.         dec     [si].ci_qin.ioq_count
  1815.         mov     al,[si].ci_dcb_ErrChar
  1816.         CALLFAR WriteQueueByte                  ; also updates in ptr
  1817.  
  1818.         ; check for received break
  1819. lse220: test    [si].ci_errshadow1,ESP_ERR1_BRK
  1820.         jz      lsex
  1821.  
  1822.         SET     [si].ci_event,EV_BREAK
  1823.         test    [si].ci_dcb_flags2,F2_BRK_CHAR
  1824.         ljz     lsex
  1825.  
  1826.         ; Last byte transferred into rx que by ESP was byte containing break.
  1827.         ; Now replace this last byte with error char.
  1828.         mov     bx,[si].ci_qin.ioq_in
  1829.         cmp     bx,[si].ci_qin.ioq_base         ; in == base?
  1830.         jne     lse235                           ; didn't wrap when placing err
  1831.                                                 ; byte into que
  1832.         mov     bx,[si].ci_qin.ioq_end
  1833.  
  1834. lse235: dec     bx                              ; (bx) -> last byte in que
  1835.         mov     al,[si].ci_dcb_BrkChar
  1836.         mov     [si].ci_qin.ioq_in,bx           ; in points to position for
  1837.                                                 ;  replacement char
  1838.         CALLFAR WriteQueueByte                  ; also updates in ptr
  1839.  
  1840. lsex:   ret
  1841.  
  1842. EndProc LineStatusError
  1843.  
  1844. Procedure TurnOffESP,NEAR
  1845.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1846.  
  1847.         ; Reset service mask so that ESP doesn't interrupt when RxFIFO
  1848.         ; trigger is reached
  1849.         ; DO WE FLAG AS OVERRUN?
  1850.         SET     [si].ci_event,CE_SW_OVERRUN
  1851.  
  1852. ifdef PERFVIEW
  1853.         pvw_SW_Overrun              ;inc PerfView flag          ;@PVW
  1854. endif
  1855.  
  1856.         mov     [si].ci_rx_state,RX_STATE_HOLDING
  1857.         cmp     [si].ci_cmd_offset,0
  1858.         jne     toe80
  1859.         CLR     [di].pi_svcmask,ESP_SID_RX1
  1860.         jmp     SHORT toe90
  1861.  
  1862. toe80:  CLR     [di].pi_svcmask,ESP_SID_RX2
  1863. toe90:  mov     dx,[si].ci_esp_address
  1864. toe100: in      al,dx
  1865.         test    al,ESP_RDY_CMD1
  1866.         jz      toe100
  1867.  
  1868.         mov     al,ESP_CMD_SETSVCMASK
  1869.         add     al,[si].ci_cmd_offset
  1870.         add     dx,ESP_R_CMD1-ESP_R_RDY
  1871.         out     dx,al
  1872.  
  1873.         add     dx,ESP_R_RDY-ESP_R_CMD1
  1874. toe110: in      al,dx
  1875.         test    al,ESP_RDY_CMD2
  1876.         jz      toe110
  1877.  
  1878.         add     dx,ESP_R_CMD2-ESP_R_RDY
  1879.         mov     al,[di].pi_svcmask
  1880.         out     dx,al
  1881.  
  1882.         mov     dx,[si].ci_esp_address
  1883. toe115: in      al,dx
  1884.         test    al,ESP_RDY_CMD1
  1885.         jz      toe115
  1886.         add     dx,ESP_R_CMD1-ESP_R_RDY
  1887.         mov     al,ESP_CMD_GDIPS
  1888.         out     dx,al
  1889.  
  1890.         add     dx,ESP_R_RDY-ESP_R_CMD1
  1891. toe117: in      al,dx
  1892.         test    al,ESP_RDY_STATUS1
  1893.         jz      toe117
  1894.  
  1895.         add     dx,ESP_R_STATUS1-ESP_R_RDY
  1896.         in      al,dx
  1897.  
  1898.         ret
  1899.  
  1900. EndProc TurnOffESP
  1901.  
  1902.  
  1903. Procedure ResetTriggerLevel,NEAR
  1904.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1905.  
  1906.         mov     dx,[si].ci_esp_address                  ; (dx) -> ready reg
  1907. rtl10:  in      al,dx
  1908.         test    al,ESP_RDY_CMD1
  1909.         jz      rtl10
  1910.         add     dx,ESP_R_CMD1-ESP_R_RDY                 ; (dx) -> cmd1 reg
  1911.         mov     al,ESP_CMD_SETTRIGGER
  1912.         add     al,[si].ci_cmd_offset
  1913.         out     dx,al
  1914.         add     dx,ESP_R_RDY-ESP_R_CMD1                 ; (dx) -> ready reg
  1915. rtl20:  in      al,dx
  1916.         test    al,ESP_RDY_CMD2
  1917.         jz      rtl20
  1918.         add     dx,ESP_R_CMD2-ESP_R_RDY                 ; (dx) -> cmd2 reg
  1919.         mov     ax,[si].ci_rx_trigger
  1920.         xchg    ah,al                                   ; send MSB first
  1921.         out     dx,al
  1922.         add     dx,ESP_R_RDY-ESP_R_CMD2                 ; (dx) -> ready reg
  1923. rtl30:  in      al,dx
  1924.         test    al,ESP_RDY_CMD2
  1925.         jz      rtl30
  1926.         add     dx,ESP_R_CMD2-ESP_R_RDY                 ; (dx) -> cmd2 reg
  1927.         mov     al,ah                                   ; send LSB next
  1928.         out     dx,al
  1929.         add     dx,ESP_R_RDY-ESP_R_CMD2                 ; (dx) -> ready reg
  1930. rtl40:  in      al,dx
  1931.         test    al,ESP_RDY_CMD2
  1932.         jz      rtl40
  1933.         add     dx,ESP_R_CMD2-ESP_R_RDY                 ; (dx) -> cmd2 reg
  1934.         mov     al,HIGH(ESP_DEF_TRIGGER_TX)
  1935.         out     dx,al
  1936.         add     dx,ESP_R_RDY-ESP_R_CMD2                 ; (dx) -> ready reg
  1937. rtl50:  in      al,dx
  1938.         test    al,ESP_RDY_CMD2
  1939.         jz      rtl50
  1940.         add     dx,ESP_R_CMD2-ESP_R_RDY                 ; (dx) -> cmd2 reg
  1941.         mov     al,LOW(ESP_DEF_TRIGGER_TX)
  1942.         out     dx,al
  1943.  
  1944.         ret
  1945.  
  1946. EndProc ResetTriggerLevel
  1947.  
  1948. Procedure RxPIO,NEAR
  1949.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  1950.  
  1951.         ; Transfer bytes via PIO from ESP's RX register to driver's in que
  1952.         ; Expecting number of bytes to transfer in CX.
  1953.         inc     cx                              ; byte count from ESP doesn't
  1954.                                                 ; include byte in the RX reg
  1955.         cmp     [si].ci_cmd_offset,0
  1956.         jne     rp10
  1957.         mov     bl,ESP_RDY_RX1
  1958.         mov     bh,ESP_R_RX1-ESP_R_RDY
  1959.         jmp     SHORT rp20
  1960. rp10:   mov     bl,ESP_RDY_RX2
  1961.         mov     bh,ESP_R_RX2-ESP_R_RDY
  1962.  
  1963.         ; (bh) = offset of proper rx register; (bl) = ready register mask
  1964. rp20:   mov     dx,[si].ci_esp_address
  1965. rp30:   in      al,dx
  1966.         test    al,bl                           ; is rx register ready?
  1967.         jz      rp30
  1968.         add     dl,bh                           ; (dx) = rx register
  1969.         in      al,dx                           ; (al) = receive byte
  1970.  
  1971.         ; If the byte we just got from RX reg contained an error (Parity,
  1972.         ; Framing, or Break), then ESP won't give us the next byte until
  1973.         ; the error status is cleared.
  1974.         push    bx                              ; save mask and offset
  1975.         mov     bx,ax                           ; (bx) = (ax) = new rx byte
  1976.         mov     dx,[si].ci_esp_address
  1977.         add     dx,ESP_R_SID
  1978.         in      al,dx
  1979.         test    al,ESP_SID_ERROR1 OR ESP_SID_ERROR2
  1980.         jz      rp40
  1981.  
  1982.         cmp     [si].ci_cmd_offset,0
  1983.         jne     rp35
  1984.         test    al,ESP_SID_ERROR1
  1985.         jz      rp40
  1986.         jmp     SHORT rp37
  1987.  
  1988. rp35:   test    al,ESP_SID_ERROR2
  1989.         jz      rp40
  1990.  
  1991. rp37:   call    GetError                        ; fills in errshadow1 and errshadow2
  1992.         test    [si].ci_errshadow1,ESP_ERR1_BRK OR ESP_ERR1_FRAME OR ESP_ERR1_PARITY
  1993.         jz      rp40                            ; nothing       with the byte after all!
  1994.         call    LineStatusError                 ; handle the error byte
  1995.         clc
  1996.         jmp     SHORT rp50                      ; don't add to queue
  1997.  
  1998. rp40:   mov     ax,bx
  1999.         call    ESPWriteQueueByte               ; (al) = byte to add to in queue
  2000.  
  2001. rp50:   pop     bx                              ; restore offset and mask
  2002.         jc      rp60                            ; in queue is full
  2003.         loop    rp20                            ; got all bytes yet?
  2004.  
  2005.         ; ESP is empty or driver's in que is full
  2006. rp60:   call    FinishReadReq
  2007.  
  2008.         ret
  2009.  
  2010. EndProc RxPIO
  2011.  
  2012. Procedure ESPWriteQueueByte,NEAR
  2013.         ASSUME cs:E_CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  2014.  
  2015.         test    [si].ci_flagx,FX_LAST_CLOSE
  2016.         jnz     wqb2            ; last close in progress, drop character
  2017.  
  2018.         ; reset timeout anytime a character is put into the receive queue
  2019.         mov     bx,[si].ci_r_to_start   ; get start value for timeout
  2020.         mov     [si].ci_r_to,bx         ; reset timeout countdown
  2021.  
  2022.         mov     bx,[si].ci_qin.ioq_in
  2023.         mov     [bx],al                         ; put byte in queue
  2024.         inc     bx                              ; adjust in pointer
  2025.         cmp     bx,[si].ci_qin.ioq_end
  2026.         jne     wqb1                            ; did not wrap
  2027.  
  2028.         mov     bx,[si].ci_qin.ioq_base  ; wrapped
  2029.  
  2030. wqb1:   cmp     bx,[si].ci_qin.ioq_out
  2031.         je      wqb2                            ; (in + 1) == out
  2032.                                                 ; queue was already full
  2033.  
  2034.         mov     [si].ci_qin.ioq_in,bx           ; update in pointer
  2035.         inc     [si].ci_qin.ioq_count           ; adjust count
  2036.  
  2037.         or      [si].ci_event,EV_RX_CHAR        ; flag rx character
  2038.  
  2039.         clc
  2040.         ret
  2041.  
  2042. wqb2:   stc
  2043.         ret
  2044.  
  2045. EndProc ESPWriteQueueByte
  2046.  
  2047. E_CSEG  ENDS
  2048.  
  2049. RSEG    SEGMENT
  2050.         ASSUME cs:RSEG
  2051.  
  2052. Procedure ESPInt1,FAR
  2053.         ASSUME ds:HSEG,es:NOTHING,ss:NOTHING
  2054.  
  2055.         setDS   DSEG
  2056.         mov     di,ESP1         ; pointer to ESP1 info structure
  2057.         jmp     ESPInt
  2058.  
  2059. Entry ESPInt2,,,nocheck
  2060.         ASSUME ds:HSEG,es:NOTHING,ss:NOTHING
  2061.  
  2062.         setDS   DSEG
  2063.         mov     di,ESP2         ; pointer to ESP2 info structure
  2064.         jmp     ESPInt
  2065.  
  2066. EndProc ESPInt1
  2067.  
  2068. RSEG    ENDS
  2069.  
  2070. END
  2071.         ; Unfortunately, ABIOS request blocks are all in HSEG, since
  2072.         ; DevHlp_ABIOSCommonEntry requires them in driver's RESIDENT data seg.
  2073.         ; This requires (slow) segment overrides when loading request blocks.
  2074.         setES   DSEG
  2075.  
  2076.  
  2077.