home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1987 / 06 / excom.asm < prev    next >
Assembly Source File  |  1987-08-05  |  21KB  |  891 lines

  1.     title    extended int 14 handler version 2
  2.     name    excom
  3. ;
  4. ;    by    Tom Zimniewicz
  5. ;
  6. ;    this file is one of three, the other two are exmode.c and excom.txt
  7. ;
  8. ;
  9. ;    (C) 1987, Crystal Computer Consulting Inc.
  10. ;    This software may be used freely, at your own risk,
  11. ;    as long as this notice is not removed.
  12. ;
  13. _text    segment  word public 'code'
  14.  
  15.     assume  cs:_text, ss:_text, ds:_text, es:_text
  16.  
  17.     org    0100h            ; com-able
  18.  
  19. start:                    ; must be first
  20.     jmp    excom
  21.  
  22.  
  23.     even
  24. ;    misc constants
  25. INSZ    equ    0100h            ; input buffer size, must be > 20h
  26. XOFFSZ    equ    INSZ - 010h        ; input flow control turn off point
  27. XONSZ    equ    INSZ - 020h        ; input flow control turn on point
  28. OUTSZ    equ    0100h            ; output buffer size, must be > 0
  29. NOCTS    equ    010h            ; CTS not required to transmit
  30. NODSR    equ    020h            ; DSR not required to transmit
  31. DTR    equ    001h            ; select DTR input flow control
  32. RTS    equ    002h            ; select RTS input flow control
  33. XNXFIN    equ    001h            ; select XON/XOFF input flow control
  34. XNXFOUT    equ    002h            ; select XON/XOFF output flow control
  35. ANYXOUT    equ    004h            ; any char restarts output after XOFF
  36. B19200    equ    010h            ; set baud rate to 19200
  37. B38400    equ    020h            ; set baud rate to 38400
  38. OUT2    equ    008h            ; bit to set OUT2
  39. C1MSK    equ    010h            ; com1 mask for 8259
  40. C2MSK    equ    008h            ; com2 mask for 8259
  41. UARTMSK    equ    00Bh            ; 8250 mask for xmit, recv and status
  42. XMTINT    equ    002h            ; transmit ready interrupt
  43. RCVINT    equ    004h            ; receive data interrupt
  44.  
  45. ;    structure for port control blocks
  46. pcbs    struc
  47.     ; in & out buffers parameters
  48. putin    dw    ?            ; points to last in char put
  49. getin    dw    ?            ; points to next in char to get
  50. incnt    dw    ?            ; number of in chars in buffer
  51. inend    dw    ?            ; address past in buffer end
  52. putout    dw    ?            ; points to last out char put
  53. getout    dw    ?            ; points to next out char to get
  54. outcnt    dw    ?            ; number of out chars in buffer
  55. outend    dw    ?            ; address past out buffer end
  56. inbuf    dw    INSZ dup (?)        ; the input buffer
  57. outbuf    db    OUTSZ dup (?)        ; the output buffer
  58.     ; other stuff
  59. pbase    dw    ?            ; port address
  60. timeout    db    ?            ; timeout outer loop
  61. mask    db    ?            ; mask to enable port interrupt
  62. vector    db    ?            ; uart hardware interrupt vector
  63. mscopts    db    ?            ; misc in/out options
  64. inopts    db    ?            ; holds receive protocol options
  65. outopts    db    ?            ; holds transmit protocol options
  66. oldier    db    ?            ; old interrupt enable register
  67. oldlcr    db    ?            ; old line control register
  68. oldmcr    db    ?            ; old modem control register
  69. olddll    db    ?            ; old baud low divisor latch
  70. olddlm    db    ?            ; old baud high divisor latch
  71. inoff    db    ?            ; set if recv has been stopped
  72. outxoff    db    ?            ; set if xmit stopped by ^S
  73. outbsy    db    ?            ; set if xmit is busy
  74. xmtxnxf    db    ?            ; protocol character to xmit
  75. modstt    db    ?            ; modem status
  76. lchar    db    ?            ; holds character attributes
  77. baudndx    db    ?            ; baud rate table index
  78. pcbs    ends
  79.  
  80. ;    allocate storage for port control blocks
  81. pcb    pcbs    2 dup (<>)        ; array of port control blocks
  82.  
  83. old0B    dd    ?            ; old vector for int0B
  84. old0C    dd    ?            ; old vector for int0C
  85. old14    dd    ?            ; old vector for int14
  86. oldmsk    db    ?            ; old mask for 8259
  87.  
  88. ;    baud rate table for UART initialization
  89. baudtbl    dw    0417h            ; divisor for 110 baud
  90.     dw    0300h            ; divisor for 150 baud
  91.     dw    0180h            ; divisor for 300 baud
  92.     dw    00C0h            ; divisor for 600 baud
  93.     dw    0060h            ; divisor for 1200 baud
  94.     dw    0030h            ; divisor for 2400 baud
  95.     dw    0018h            ; divisor for 4800 baud
  96.     dw    000Ch            ; divisor for 9600 baud
  97. baud19    dw    0006h            ; divisor for 19200 baud
  98.     dw    0003h            ; divisor for 38400 baud
  99.  
  100.  
  101.  
  102. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  103. ;                                    ;
  104. ;    0Bh & 0Ch (com2 & com1) interrupt handler            ;
  105. ;        put characters into the appropriate buffer        ;
  106. ;        input flow control - stop input when buffer nears full    ;
  107. ;                                    ;
  108. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  109.  
  110. int0B:
  111.     ; point to com2 port control block with ds:si
  112.     push    ds
  113.     push    si
  114.     mov    si, cs
  115.     mov    ds, si
  116.     lea    si, pcb + size pcbs
  117.     jmp    short a00
  118.  
  119. int0C:
  120.     ; point to com1 port control block with ds:si
  121.     push    ds
  122.     push    si
  123.     mov    si, cs
  124.     mov    ds, si
  125.     lea    si, pcb
  126.  
  127. a00:
  128.     push    di
  129.     push    dx
  130.     push    bx
  131.     push    ax
  132.     ; determine interrupt type, jump to the handler
  133.     mov    dx, [si].pbase
  134.     inc    dx
  135.     inc    dx
  136.     in    al, dx
  137.     dec    dx
  138.     dec    dx
  139.     cmp    al, XMTINT
  140.     je    a100            ; transmit interrupt
  141.     cmp    al, RCVINT
  142.     jne    a000            ; assume status interrupt
  143.     jmp    a200            ; receive interrupt
  144.  
  145. a10:
  146.     ; send interrupt complete command to interrupt controller
  147.     mov    al, 020h
  148.     out    020h, al
  149.     pop    ax
  150.     pop    bx
  151.     pop    dx
  152.     pop    di
  153.     pop    si
  154.     pop    ds
  155.     iret
  156.  
  157.  
  158.     ;
  159.     ; modem status change interrupt
  160. a000:
  161.     add    dx, 6
  162.     in    al, dx            ; modem status
  163.     mov    [si].modstt, al
  164.     ; restart output if required and ok
  165.     or    al, [si].outopts
  166.     cmp    al, 0FFh
  167.     jne    a10            ; status inhibits output
  168.     cmp    [si].outxoff, 0
  169.     jne    a10            ; xoff inhibits output
  170.     sub    dx, 6
  171.     call    a010            ; restart output
  172.     jmp    short a10
  173.  
  174.     ;
  175.     ; subroutine to start up output if required, called several
  176.     ; places below uses al, assumes dx is port base
  177. a010:
  178.     cmp    [si].outbsy, 0
  179.     jne    a030
  180. a020:    ; call here if outbsy already checked or to be ignored
  181.     inc    dx
  182.     mov    al, UARTMSK
  183.     out    dx, al
  184.     mov    [si].outbsy, 1
  185.     dec    dx
  186. a030:
  187.     ret
  188.  
  189.  
  190.     ;
  191.     ; transmit interrupt
  192. a100:
  193.     cmp    [si].xmtxnxf, 0
  194.     je    a110
  195.     mov    al, [si].xmtxnxf    ; must send ^S or ^Q
  196.     out    dx, al
  197.     mov    [si].xmtxnxf, 0
  198.     jmp    short a10
  199. a110:
  200.     cmp    [si].outxoff, 0
  201.     jne    a130            ; xoff inhibits output
  202.     mov    al, [si].modstt
  203.     or    al, [si].outopts
  204.     cmp    al, 0FFh
  205.     jne    a130            ; status inhibits output
  206.     mov    ax, [si].outcnt
  207.     dec    ax
  208.     jl    a130            ; output buffer empty
  209.     mov    [si].outcnt, ax
  210.     mov    di, [si].getout
  211.     mov    al, [di]
  212.     out    dx, al            ; send the character
  213.  
  214.     ; inc buffer pointer, wrap if req'd
  215.     inc    di
  216.     cmp    di, [si].outend
  217.     jne    a120
  218.     lea    di, [si].outbuf
  219. a120:
  220.     mov    [si].getout, di
  221.     jmp    short a10
  222.  
  223. a130:
  224.     mov    [si].outbsy, 0
  225.     jmp    a10
  226.  
  227.  
  228.     ;
  229.     ; receive interrupt
  230. a200:
  231.     ; read character
  232.     mov    di, [si].putin        ; buffer put pointer
  233.     in    al, dx            ; read character and clear interrupt
  234.     mov    ah, al
  235.  
  236.     ; do output XON-XOFF processing, if it's ^S, stop output
  237.     ; if ^Q or ANYXOUT is set, restart output
  238.     test    [si].mscopts, XNXFOUT
  239.     jz    a230
  240.     cmp    al, 'Q' - '@'
  241.     je    a210            ; it's a ^Q, restart the output
  242.     cmp    [si].outxoff, 0
  243.     je    a220
  244.     test    [si].mscopts, ANYXOUT    ; can any char restart it
  245.     jz    a220
  246. a210:
  247.     mov    [si].outxoff, 0
  248.     call    a010            ; restart output
  249.     jmp    a10
  250. a220:
  251.     cmp    al, 'S' - '@'
  252.     jne    a230
  253.     mov    [si].outxoff, 1        ; it's a ^S, stop the output
  254.     jmp    a10
  255.  
  256. a230:
  257.     ; if this fills buffer to XOFFSZ, then send XOFF or
  258.     ; drop DTR and/or RTS as indicated by extended options
  259.     cmp    [si].incnt, XOFFSZ
  260.     jl    a260            ; jump if buffer below turnoff point
  261.     cmp    [si].inoff, 0
  262.     jne    a250            ; jump if receive already disabled
  263.     mov    [si].inoff, 1        ; indicate receiver now disabled
  264.     test    [si].mscopts, XNXFIN
  265.     jz    a240
  266.     mov    [si].xmtxnxf, 'S' - '@'    ; get ^S sent
  267.     call    a020            ; restart output
  268. a240:
  269.     mov    bl, [si].inopts
  270.     cmp    bl, 0
  271.     je    a250
  272.     add    dx, 4
  273.     in    al, dx
  274.     not    bl
  275.     and    al, bl
  276.     out    dx, al            ; drop DTR and/or RTS
  277.     sub    dx, 4
  278.  
  279. a250:
  280.     ; if the buffer is full, set overflow status and exit
  281.     cmp    [si].incnt, INSZ
  282.     jl    a260
  283.     or    word ptr [di], 0200h
  284.     jmp    a10
  285.  
  286. a260:
  287.     ; read the port status
  288.     add    dx, 5
  289.     in    al, dx
  290.     ; get new buffer pointer, adjust for wrap around if required
  291.     inc    di
  292.     inc    di
  293.     cmp    di, [si].inend
  294.     jne    a270
  295.     lea    di, [si].inbuf
  296. a270:
  297.     ; store new buffer pointer and put status:char into buffer
  298.     mov    [si].putin, di
  299.     xchg    ah, al
  300.     mov    [di], ax
  301.     inc    [si].incnt
  302.     jmp    a10
  303.  
  304.  
  305. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  306. ;                                    ;
  307. ;    14h interrupt handler                        ;
  308. ;        emulate pc bios functions plus extensions        ;
  309. ;                                    ;
  310. ;    dx is used to select the port for all calls            ;
  311. ;        dx = 0 for com1,  dx = 1 for com2            ;
  312. ;                                    ;
  313. ;    ah = 0    initialize the port, parameters in al            ;
  314. ;        al bits 7-5 set the baud rate                ;
  315. ;          000 = 110,   001 = 150,   010 = 300,   011 = 600    ;
  316. ;          100 = 1200,  101 = 2400,  110 = 4800,  111 = 9600    ;
  317. ;        al bits 4-3 set the parity                ;
  318. ;          00 = none,  01 = odd,  11 = even            ;
  319. ;        al bit 2 is number of stop bits                ;
  320. ;          0 = 1 stop bit,  1 = 2 stop bits            ;
  321. ;        al bits 1-0 set the word length                ;
  322. ;          00 = 5,  01 = 6, 10 = 7, 11 = 8            ;
  323. ;        returns ah & al as per comm status (ah=3) below        ;
  324. ;        example:  ah = 10101110 is 2400 baud,            ;
  325. ;            odd parity, 2 stop bits, 7 bit characters    ;
  326. ;                                    ;
  327. ;    ah = 1  transmit the character in al, al preserved        ;
  328. ;        returns ah as per comm status (ah=3) below        ;
  329. ;                                    ;
  330. ;    ah = 2    return receive character in al                ;
  331. ;        returns ah as per comm status (ah=3) below        ;
  332. ;        only bits 1-2-3-4-7 can be set                ;
  333. ;        ah having any bits set is a receive error or timeout    ;
  334. ;                                    ;
  335. ;    ah = 3    return comm port status in ah & al            ;
  336. ;        ah bits are:                        ;
  337. ;          b0 = data ready        b1 = overrun        ;
  338. ;          b2 = parity error        b3 = framing error        ;
  339. ;          b4 = break detect        b5 = xmit holding reg empty    ;
  340. ;          b6 = xmit shift reg empty b7 = timeout        ;
  341. ;        al bits are:                        ;
  342. ;          b0 = delta CTS        b1 = delta DSR        ;
  343. ;          b2 = trail edge ring        b3 = delta recv detect    ;
  344. ;          b4 = CTS            b5 = DSR            ;
  345. ;          b6 = ring indicator        b7 = recv signal detect    ;
  346. ;                                    ;
  347. ;    ah = 4    extended options                    ;
  348. ;        returns 05A5Ah in ax, used to identify excom        ;
  349. ;        al contains options as follows:                ;
  350. ;          bit 0 enables XON/XOFF input flow control        ;
  351. ;          bit 1 enables XON/XOFF output flow control        ;
  352. ;          bit 2 set to restart upon any character after XOFF    ;
  353. ;          bit 4 sets baud rate to 19200                ;
  354. ;          bit 5 sets baud rate to 38400                ;
  355. ;        ch contains options as follows:                ;
  356. ;          bit 0 enables DTR input flow control            ;
  357. ;          bit 1 enables RTS input flow control            ;
  358. ;        cl contains options as follows:                ;
  359. ;          bit 4 don't require CTS to transmit            ;
  360. ;          bit 5 don't require DSR to transmit            ;
  361. ;                                    ;
  362. ;    ah = 5    remove excom, restore old vectors, release memory    ;
  363. ;                                    ;
  364. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  365.  
  366. int14:
  367.     sti
  368.     push    ds
  369.     push    si
  370.     push    dx
  371.     push    cx
  372.     push    bx
  373.     ; point to selected com port control block with ds:si
  374.     mov    bx, cs
  375.     mov    ds, bx
  376.     lea    si, pcb
  377.     or    dx, dx
  378.     jz    b00
  379.     add    si, size pcbs
  380. b00:
  381.     ; get port address in dx, return if port not installed
  382.     mov    dx, [si].pbase
  383.     or    dx, dx
  384.     jz    b20
  385.  
  386.     ; ah has request type, jump to selected routine
  387.     cmp    ah, 5
  388.     ja    b20
  389.     mov    bl, ah
  390.     add    bl, bl
  391.     sub    bh, bh
  392.     jmp    word ptr [bx+b10]
  393. b10:
  394.     dw    b000            ; initialize
  395.     dw    b100            ; transmit a char
  396.     dw    b200            ; receive a char
  397.     dw    b300            ; get status
  398.     dw    b400            ; extended initialize
  399.     dw    b500            ; remove excom
  400.  
  401. b20:
  402.     pop    bx
  403.     pop    cx
  404.     pop    dx
  405.     pop    si
  406.     pop    ds
  407.     iret
  408.  
  409.  
  410.     ;
  411.     ; ah = 0
  412.     ; initialize the port
  413. b000:
  414.     push    ax
  415.  
  416.     ; initialize the pcb, this 'empties' the buffers
  417.     lea    ax, [si].inbuf
  418.     mov    [si].putin, ax
  419.     inc    ax
  420.     inc    ax
  421.     mov    [si].getin, ax
  422.     add    ax, (INSZ * 2) - 2
  423.     mov    [si].inend, ax
  424.  
  425.     lea    ax, [si].outbuf
  426.     mov    [si].putout, ax
  427.     mov    [si].getout, ax
  428.     add    ax, OUTSZ
  429.     mov    [si].outend, ax
  430.     sub    ax, ax
  431.     mov    [si].incnt, ax
  432.     mov    [si].outcnt, ax
  433.     mov    [si].inoff, al
  434.     mov    [si].outxoff, al
  435.     mov    [si].outbsy, al
  436.     mov    [si].xmtxnxf, al
  437.  
  438.     ; set up baud rates and character attributes
  439.     pop    ax
  440.     mov    bl, al
  441.     and    al, 01Fh
  442.     mov    [si].lchar, al
  443.     mov    al, [si].mscopts
  444.     and    al, B19200 or B38400
  445.     jz    short b010
  446.     mov    bl, baud19 - baudtbl    ; this is an extended baud rate
  447.     test    al, B19200
  448.     jnz    b020
  449.     add    bl, 2
  450.     jmp    short b020
  451. b010:
  452.     mov    cl, 4            ; normal baud rate
  453.     rol    bl, cl
  454.     and    bl, 0Eh
  455. b020:
  456.     mov    [si].baudndx, bl
  457.     call    b030            ; init the hardware
  458.     jmp    b300            ; return status
  459.  
  460.     ;
  461.     ; subroutine to do hardware initialization
  462.     ; assumes dx is port base, changes ax and bx
  463. b030:
  464.     ; set up interrupt vectors for 0Bh & 0Ch
  465.     push    dx
  466.     lea    dx, int0B
  467.     mov    ah, 025h
  468.     mov    al, 0Bh
  469.     int    021h
  470.     lea    dx, int0C
  471.     mov    ah, 025h
  472.     mov    al, 0Ch
  473.     int    021h
  474.     pop    dx
  475.     ; init the baud rate and character attributes
  476.     add    dx, 3
  477.     mov    al, 080h
  478.     out    dx, al
  479.     mov    bl, [si].baudndx
  480.     sub    bh, bh
  481.     mov    ax, [bx+baudtbl]
  482.     sub    dx, 3
  483.     out    dx, al            ; set low order divisor on uart
  484.     inc    dx
  485.     mov    al, ah
  486.     out    dx, al            ; set high order divisor on uart
  487.     inc    dx
  488.     inc    dx
  489.     mov    al, [si].lchar
  490.     out    dx, al            ; set character attributes
  491.     add    dx, 3
  492.     in    al, dx            ; get modem status
  493.     mov    [si].modstt, al
  494.     ; init interrupts
  495.     dec    dx
  496.     dec    dx
  497.     mov    al, DTR or RTS or OUT2
  498.     out    dx, al
  499.     cli
  500.     in    al, 021h
  501.     and    al, [si].mask
  502.     out    021h, al        ; unmask com port on int controller
  503.     sti
  504.     sub    dx, 3
  505.     mov    al, UARTMSK
  506.     out    dx, al            ; enable interrupts on uart
  507.     dec    dx
  508.     ret
  509.  
  510.  
  511.     ;
  512.     ; ah = 1
  513.     ; transmit the character in al
  514. b100:
  515.     push    ax
  516.     cmp    [si].outcnt, OUTSZ
  517.     jl    b130            ; room in buffer
  518.  
  519.     ; wait for room to appear, or return timeout
  520.     mov    bl, [si].timeout
  521.     add    bl, bl            ; shorter timeout loop, so loop more
  522. b110:
  523.     sub    cx, cx
  524. b120:
  525.     cmp    [si].outcnt, OUTSZ
  526.     jl    b130
  527.     loop    b120
  528.     dec    bl
  529.     jnz    b110
  530.     call    b310            ; get line status
  531.     or    ah, 080h        ; indicate a timeout
  532.     jmp    short b170
  533.  
  534. b130:
  535.     ; put the character in the buffer, inc pointer and fix for wrap
  536.     mov    bx, [si].putout
  537.     mov    [bx], al
  538.     inc    bx
  539.     cmp    bx, [si].outend
  540.     jne    b140
  541.     lea    bx, [si].outbuf
  542. b140:
  543.     mov    [si].putout, bx
  544.     cli
  545.     inc    [si].outcnt
  546.     cmp    [si].outbsy, 0
  547.     jne    b160
  548.     ; spot check for damage, has the UART vector been changed
  549.     mov    bl, [si].vector
  550.     mov    cx, cs
  551.     sub    ax, ax
  552.     push    ds
  553.     mov    ds, ax
  554.     mov    bh, al
  555.     cmp    cx, [bx]
  556.     pop    ds
  557.     je    b150
  558.     sti
  559.     call    b030            ; re-init the hardware
  560.     cli
  561. b150:
  562.     call    a020            ; restart output
  563. b160:
  564.     sti
  565.     call    b310            ; get line status
  566. b170:
  567.     pop    cx
  568.     mov    al, cl            ; restore al
  569.     jmp    b20
  570.  
  571.  
  572.     ;
  573.     ; ah = 2
  574.     ; receive a character, put it in al
  575. b200:
  576.     cmp    [si].incnt, 0
  577.     jne    b230            ; chars in buffer, return one
  578.  
  579.     call    b030            ; re-init the hardware
  580.     ; wait for a character to appear in the buffer, or return timeout
  581.     mov    al, [si].timeout
  582.     add    al, al            ; shorter timeout loop, so loop more
  583. b210:
  584.     sub    cx, cx
  585. b220:
  586.     cmp    [si].incnt, 0
  587.     jne    b230
  588.     loop    b220
  589.     dec    al
  590.     jnz    b210
  591.     mov    ax, 08000h        ; timeout return value
  592.     jmp    b20
  593.  
  594. b230:
  595.     ; if receiver is disabled and room now exists, enable receiver
  596.     cmp    [si].inoff, 0
  597.     je    b250            ; receive is already enabled
  598.     cmp    [si].incnt, XONSZ
  599.     jg    b250            ; buffer fuller than turn on point
  600.     mov    [si].inoff, 0        ; indicate receiver enabled
  601.     test    [si].mscopts, XNXFIN
  602.     jz    b240
  603.     cli
  604.     mov    [si].xmtxnxf, 'Q' - '@'    ; get ^Q sent
  605.     call    a020            ; restart output
  606.     sti
  607. b240:
  608.     ; it's easier to just assert DTR & RTS rather than see if needed
  609.     add    dx, 4
  610.     in    al, dx
  611.     or    al, DTR or RTS
  612.     out    dx, al            ; assert DTR and RTS
  613.  
  614. b250:
  615.     ; read the buffer, update get pointer, and wrap if needed
  616.     mov    bx, [si].getin
  617.     mov    ax, [bx]        ; get status:char
  618.     inc    bx
  619.     inc    bx
  620.     cmp    bx, [si].inend
  621.     jne    b260
  622.     lea    bx, [si].inbuf
  623. b260:
  624.     mov    [si].getin, bx        ; updated pointer
  625.     dec    [si].incnt
  626.     jmp    b20
  627.  
  628.  
  629.     ;
  630.     ; ah = 3
  631.     ; get port status
  632. b300:
  633.     call    b310
  634.     mov    al, [si].modstt        ; modem status
  635.     jmp    b20
  636.  
  637.     ;
  638.     ; subroutine to get line status from hardware and/or input buffer
  639.     ; returns in ah, assumes dx is port base, changes al, bx, cl, & dx
  640. b310:
  641.     add    dx, 5
  642.     in    al, dx            ; line status
  643.     cmp    [si].incnt, 0
  644.     je    b320
  645.  
  646.     ; when chars in buffer, fix status as per status in buffer
  647.     mov    bx, [si].getin
  648.     mov    ah, [bx + 1]        ; status
  649.     mov    cl, 01Eh        ; these status bits from buffer
  650.     and    ah, cl
  651.     not    cl
  652.     and    al, cl
  653.     or    al, ah            ; phys & buffer status combined
  654.     or    al, 1            ; char in buffer, show data ready
  655. b320:
  656.     ; show xmit holding register empty if room in xmit buffer
  657.     cmp    [si].outcnt, OUTSZ
  658.     jl    b330
  659.     and    al, 0DFh        ; no room
  660.     jmp    short b340
  661. b330:
  662.     or    al, 020h        ; room in xmit buffer
  663. b340:
  664.     mov    ah, al
  665.     ret
  666.  
  667.  
  668.     ;
  669.     ; ah = 4
  670.     ; extended initialization
  671. b400:
  672.     ; save the options in the pcb
  673.     mov    [si].mscopts, al
  674.     mov    [si].inopts, ch
  675.     or    cl, not (NOCTS or NODSR); simplify later use
  676.     mov    [si].outopts, cl
  677.     mov    ax, 05A5Ah        ; magic value to identify excom
  678.     jmp    b20
  679.  
  680.  
  681.     ;
  682.     ; ah = 5
  683.     ; remove excom
  684. b500:
  685.     push    ds
  686.     push    ds
  687.  
  688.     ; restore status of interrupt controller and uarts
  689.     cli
  690.     mov    ah, oldmsk
  691.     and    ah, C1MSK or C2MSK
  692.     in    al, 021h
  693.     and    al, not (C1MSK or C2MSK)
  694.     or    al, ah
  695.     out    021h, al
  696.     sti
  697.     lea    si, pcb            ; com1 pcb
  698.     call    b510            ; restore com1 uart status
  699.     lea    si, pcb + size pcbs    ; com2 pcb
  700.     call    b510            ; restore com1 uart status
  701.     jmp    short b530
  702.  
  703.     ; subroutine to restore uart status
  704.     ; only called from just above
  705. b510:
  706.     mov    dx, [si].pbase
  707.     or    dx, dx
  708.     jz    b520            ; no port
  709.     add    dx, 3
  710.     mov    al, 080h
  711.     out    dx, al            ; set access to baud divisors
  712.     sub    dx, 3
  713.     mov    al, [si].olddll
  714.     out    dx, al            ; baud divisor low
  715.     inc    dx
  716.     mov    al, [si].olddlm
  717.     out    dx, al            ; baud divisor high
  718.     add    dx, 2
  719.     mov    al, [si].oldlcr
  720.     out    dx, al            ; line control register
  721.     inc    dx
  722.     mov    al, [si].oldmcr
  723.     out    dx, al            ; modem control register
  724.     sub    dx, 3
  725.     mov    al, [si].oldier
  726.     out    dx, al            ; interrupt enable register
  727. b520:
  728.     ret
  729.  
  730. b530:
  731.     ; restore old int 0Bh vector
  732.     lds    dx, old0B
  733.     mov    ah, 025h
  734.     mov    al, 0Bh
  735.     int    021h
  736.  
  737.     ; restore old int 0Ch vector
  738.     pop    ds
  739.     lds    dx, old0C
  740.     mov    ah, 025h
  741.     mov    al, 0Ch
  742.     int    021h
  743.  
  744.     ; restore old int 14h vector
  745.     pop    ds
  746.     lds    dx, old14
  747.     mov    ah, 025h
  748.     mov    al, 14h
  749.     int    021h
  750.  
  751.     ; free excom's memory, this memory
  752.     push    es
  753.     mov    ax, cs
  754.     mov    es, ax
  755.     mov    ah, 049h
  756.     int    021h
  757.     pop    es
  758.     jmp    b20
  759.  
  760.  
  761. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  762. ;                                    ;
  763. ;    installation entry point, must be at file end            ;
  764. ;        initialize and stay resident                ;
  765. ;                                    ;
  766. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  767.  
  768. excom:
  769.  
  770.     ; initialize constant parts of each pcb
  771.     mov    ax, 040h
  772.     mov    es, ax            ; bios data segment
  773.     sub    di, di            ; offset to com1 base address
  774.     mov    bx, 07Ch        ; offset to com1 timeout
  775.     mov    ch, 032h        ; offset to com2 interrupt vector
  776.     mov    cl, not C1MSK        ; com1 interrupt mask
  777.     lea    si, pcb            ; com1 pcb address
  778.     call    c00            ; init com1
  779.     inc    di
  780.     inc    di            ; offset to com2 base address
  781.     inc    bx            ; offset to com2 timeout
  782.     mov    ch, 02Eh        ; offset to com2 interrupt vector
  783.     mov    cl, not C2MSK        ; com2 interrupt mask
  784.     add    si, size pcbs        ; com2 pcb address
  785.     call    c00            ; init com2
  786.     jmp    short c10
  787.  
  788.     ; subroutine to initialize parts of a pcb
  789.     ; only called from just above
  790. c00:
  791.     mov    dx, es:[di]        ; port base from bios
  792.     mov    [si].pbase, dx
  793.     mov    al, es:[bx]
  794.     mov    [si].timeout, al    ; copy timeout from bios
  795.     mov    [si].vector, ch        ; interrupt vector
  796.     mov    [si].mask, cl        ; save interrupt mask
  797.     sub    al, al
  798.     mov    [si].mscopts, al
  799.     mov    [si].inopts, al
  800.     mov    [si].outopts, not (NOCTS or NODSR)
  801.     ret
  802.  
  803. c10:
  804.     ; save old status of interrupt controller and uarts
  805.     in    al, 021h
  806.     mov    oldmsk, al
  807.     lea    si, pcb            ; com1 pcb
  808.     call    c20            ; save old com1 uart status
  809.     lea    si, pcb + size pcbs    ; com2 pcb
  810.     call    c20            ; save old com1 uart status
  811.     jmp    short c40
  812.  
  813.     ; subroutine to save uart status
  814.     ; only called from just above
  815. c20:
  816.     mov    dx, [si].pbase
  817.     or    dx, dx
  818.     jz    c30            ; no port
  819.     add    dx, 3
  820.     in    al, dx
  821.     and    al, 07Fh
  822.     mov    [si].oldlcr, al        ; line control register
  823.     mov    al, 080h
  824.     out    dx, al            ; set access to baud divisors
  825.     sub    dx, 3
  826.     in    al, dx
  827.     mov    [si].olddll, al        ; baud divisor low
  828.     inc    dx
  829.     in    al, dx
  830.     mov    [si].olddlm, al        ; baud divisor high
  831.     add    dx, 2
  832.     mov    al, [si].oldlcr
  833.     out    dx, al            ; restore register access
  834.     inc    dx
  835.     in    al, dx
  836.     mov    [si].oldmcr, al        ; modem control register
  837.     sub    dx, 3
  838.     in    al, dx
  839.     mov    [si].oldier, al        ; interrupt enable register
  840. c30:
  841.     ret
  842.  
  843. c40:
  844.     ; release environment memory, not used
  845.     mov    bx, 02Ch
  846.     mov    ax, [bx]
  847.     mov    es, ax            ; address of env
  848.     mov    ah, 049h
  849.     int    021h            ; free memory
  850.  
  851.     ; save old int 0Bh vector, install new handler
  852.     mov    ah, 035h
  853.     mov    al, 0Bh
  854.     int    021h
  855.     mov    word ptr old0B, bx
  856.     mov    ax, es
  857.     mov    word ptr old0B + 2, ax
  858.  
  859.     ; save old int 0Ch vector, install new handler
  860.     mov    ah, 035h
  861.     mov    al, 0Ch
  862.     int    021h
  863.     mov    word ptr old0C, bx
  864.     mov    ax, es
  865.     mov    word ptr old0C + 2, ax
  866.  
  867.     ; save old int 14h vector, install new handler
  868.     mov    ah, 035h
  869.     mov    al, 014h
  870.     int    021h
  871.     mov    word ptr old14, bx
  872.     mov    ax, es
  873.     mov    word ptr old14 + 2, ax
  874.     lea    dx, int14
  875.     mov    ah, 025h
  876.     mov    al, 014h
  877.     int    021h
  878.  
  879.     ; exit and keep everything above the entry point 'excom'
  880.     lea    dx, excom
  881.     mov    cl, 4
  882.     shr    dx, cl
  883.     inc    dx
  884.     mov    ah, 031h
  885.     mov    al, 0
  886.     int    021h            ; terminate-and-stay-resident
  887.  
  888. _text    ends
  889.     end    start
  890.     endm
  891.