home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / asm / RS232DVR.ZIP / IBMRS232.ASM < prev    next >
Encoding:
Assembly Source File  |  1987-08-13  |  27.3 KB  |  728 lines

  1.         page    60,132
  2. ;
  3. ;***********************************************************
  4. ;**                                                       **
  5. ;**  Device Driver for RS232 communications               **
  6. ;**  IBM PC Version                                       **
  7. ;**  Copyright (C) Texas Instruments 1986                 **
  8. ;**  Author: Greg Haley                                   **
  9. ;**                                                       **
  10. ;**  THIS SOURCE CODE MAY BE DISTRIBUTED AND MODIFIED     **
  11. ;**  ONLY IF THE ORIGINAL COPYRIGHT AND AUTHOR CREDITS    **
  12. ;**  REMAIN INTACT.                                       **
  13. ;**                                                       **
  14. ;**  Project Start Date: 11/20/86                         **
  15. ;**                                                       **
  16. ;**  Re: 12/29/86 by Greg Haley                           **
  17. ;**    Added send_xon routine.                            **
  18. ;**    Added 19200 baud.                                  **
  19. ;**                                                       **
  20. ;**  Re: 02/11/87 by Bill Hinkle                          **
  21. ;**    Fixed DLAB baud rate setting bug                   **
  22. ;**                                                       **
  23. ;**  Re: 03/18/87 by Bill Hinkle                          **
  24. ;**    Added support for ports 3 and 4 (3E8h & 2E8H)      **
  25. ;**                                                       **
  26. ;**  Re: 8/10/87 by Joe McDaniel              **
  27. ;**    Fixed numerous bugs in xon/xoff protocol      **
  28. ;**    Made transmit interrupt driven              **
  29. ;**    Really installed 19,200 baud support          **
  30. ;***********************************************************
  31.  
  32.         name    ibmrs232
  33.         title   Device Driver for IBM PC Communications
  34.  
  35. code    segment byte
  36.    assume cs:code,ds:nothing,es:nothing
  37.  
  38.         include rs232.inc
  39.  
  40.         page
  41.  
  42. ;***********************************************************
  43. ;**  Communications Routines                              **
  44. ;***********************************************************
  45. trans_size    equ    200h        ; Transmit buffer size
  46. recv_size       equ     200h            ; Receive buffer size
  47.                                         ; Both must be one of these values:
  48.                                         ; 0004h = 4 bytes
  49.                                         ; 0008h = 8 bytes
  50.                                         ; 0010h = 16 bytes
  51.                                         ; 0020h = 32 bytes
  52.                                         ; 0040h = 64 bytes
  53.                                         ; 0080h = 128 bytes
  54.                                         ; 0100h = 256 bytes
  55.                                         ; 0200h = 512 bytes
  56.                                         ; 0400h = 1024 bytes
  57.                                         ; 0800h = 2048 bytes
  58.                                         ; 1000h = 4096 bytes
  59.                                         ; 2000h = 8192 bytes
  60.                                         ; 4000h = 16384 bytes
  61.                                         ; 8000h = 32768 bytes
  62.  
  63. recv_limit      equ     recv_size-1    ; Receive buffer limit mask
  64. tran_limit    equ    trans_size-1    ; Receive buffer limit mask
  65. busy_len        equ     recv_size *3 /4 ; Go busy at 3/4 buf length
  66. not_busy_len    equ     recv_size /2    ; Not busy at 1/2 buf length
  67.  
  68.  
  69. int_controller  equ     21h             ; 8259A Interrupt Controller port
  70. int_ack         equ     20h             ; 8259A Interrupt Acknowledge port
  71.  
  72. enable_ints     equ     00001111b       ; Enable interrupts
  73. disable_ints    equ     00000000b       ; Disable interrupts
  74. dcd_bit         equ     128             ; DCD bit in modem status register
  75. cts_bit         equ     16              ; CTS bit in modem status register
  76. dsr_bit         equ     32              ; DSR bit in modem status register
  77. ri_bit          equ     64              ; RI bit in modem status register
  78.  
  79. dtr_rts_out2    equ     00001011b       ; DTR, RTS, & OUT2
  80. dlab            equ     10000000b       ; DLAB (Divisor Latch Access Bit)
  81. char_waiting    equ     00000001b       ; Receive buffer full bit
  82. int_pending     equ     00000001b       ; Int pending bit in 8250
  83.  
  84. xon             equ     11h             ; xmit on busy char
  85. xoff            equ     13h             ; xmit off busy char
  86.  
  87.         page
  88. ;***********************************************************
  89. ;**     Variables                                         **
  90. ;***********************************************************
  91.  
  92. old_ss  dw      0                       ; Old SS reg
  93. old_sp  dw      0                       ; Old SP reg
  94.         db      80 dup (?)              ; Stack
  95. i_stack label   byte
  96.  
  97. rq_head dw      0                       ; Receive Queue start
  98. rq_tail dw      0                       ; Receive Queue stop
  99. rq_len  dw      0                       ; Current receive Queue length
  100. rqueue  db      recv_size dup (?)       ; Receive queue
  101.  
  102. tq_head dw      0                       ; Transmit Queue start
  103. tq_tail dw      0                       ; Transmit Queue stop
  104. tq_len  dw      0                       ; Current transmit Queue length
  105. tqueue    db    trans_size dup(?)    ; Transmit queue
  106.  
  107. oldseg  dw      0                       ; Old segment for int vector
  108. oldoff  dw      0                       ; Old offset for int vector
  109. busy_hand       db      0               ; busy handling type
  110. r_busy  db      0                       ; recv busy flag
  111. t_busy  db      0                       ; xmit busy flag (protocol control)
  112. xmit_busy       db      0               ; xmit busy flag (interrupts active)
  113. m_stat  db      0                       ; Current modem status
  114. l_stat  db      0                       ; Current line status
  115. dcw     dw      1110000001000000b       ; default raw mode, 1200, 8, N, 1
  116. parity_on       db      0               ; Parity flag
  117.  
  118. int_tbl dw      mod_stat                ; Interrupt branch table
  119.         dw      xmit_mt
  120.         dw      rec_full
  121.         dw      lin_stat
  122.  
  123. ; table for baud rate constants
  124. baud_tbl        dw      417h            ; 110
  125.                 dw      300h            ; 150
  126.                 dw      180h            ; 300
  127.                 dw      0c0h            ; 600
  128.                 dw      60h             ; 1200
  129.                 dw      30h             ; 2400
  130.                 dw      18h             ; 4800
  131.                 dw      0ch             ; 9600
  132.                 dw      06h             ;19200
  133.  
  134. speed   dw      0060h                   ; Default baud rate to use (1200)
  135. comm_parms      db      00000011b       ; No parity, 8 data, 1 stop
  136.  
  137. ; table for port number init tables
  138. p_table dw      port1_tbl
  139.         dw      port2_tbl
  140.         dw      port3_tbl
  141.         dw      port4_tbl
  142.  
  143. port_n  dw      port1_tbl               ; default port is 1
  144.  
  145. ; port 1 init table
  146. port1_tbl       dw      0ch             ; Interrupt vector for irq
  147.                 db      11101111b       ; Mask to enable irq
  148.                 db      00010000b       ; Mask to unable irq
  149.                 dw      3f8h            ; Receive buffer port
  150.                 dw      3f8h            ; Transmit buffer port
  151.                 dw      3f8h            ; Divisor least significant byte
  152.                 dw      3f9h            ; Divisor most significant byte
  153.                 dw      3fbh            ;  8250 UART Control port
  154.                 dw      3fdh            ;  8250 UART Status port
  155.                 dw      3fch            ;  8250 Modem Control port
  156.                 dw      3feh            ;  8250 Modem Status port
  157.                 dw      3f9h            ;  8250 interrupt enable register
  158.                 dw      3fah            ;  8250 interrupt ack register
  159.                 db      64h             ;  8259 Specific EOI
  160. p_tbl_size      equ     $-port1_tbl
  161.  
  162. ; port 2 init table
  163. port2_tbl       dw      0bh             ; Interrupt vector for irq
  164.                 db      11110111b       ; Mask to enable irq
  165.                 db      00001000b       ; Mask to unable irq
  166.                 dw      2f8h            ; Receive buffer port
  167.                 dw      2f8h            ; Transmit buffer port
  168.                 dw      2f8h            ; Divisor least significant byte
  169.                 dw      2f9h            ; Divisor most significant byte
  170.                 dw      2fbh            ;  8250 UART Control port
  171.                 dw      2fdh            ;  8250 UART Status port
  172.                 dw      2fch            ;  8250 Modem Control port
  173.                 dw      2feh            ;  8250 Modem Status port
  174.                 dw      2f9h            ;  8250 interrupt enable register
  175.                 dw      2fah            ;  8250 interrupt ack register
  176.                 db      63h             ;  8259 Specific EOI
  177.  
  178. ; port 3 init table
  179. port3_tbl       dw      0ch             ; Interrupt vector for irq
  180.                 db      11101111b       ; Mask to enable irq
  181.                 db      00010000b       ; Mask to unable irq
  182.                 dw      3e8h            ; Receive buffer port
  183.                 dw      3e8h            ; Transmit buffer port
  184.                 dw      3e8h            ; Divisor least significant byte
  185.                 dw      3e9h            ; Divisor most significant byte
  186.                 dw      3ebh            ;  8250 UART Control port
  187.                 dw      3edh            ;  8250 UART Status port
  188.                 dw      3ech            ;  8250 Modem Control port
  189.                 dw      3eeh            ;  8250 Modem Status port
  190.                 dw      3e9h            ;  8250 interrupt enable register
  191.                 dw      3eah            ;  8250 interrupt ack register
  192.                 db      64h             ;  8259 Specific EOI
  193.  
  194. ; port 4 init table
  195. port4_tbl       dw      0bh             ; Interrupt vector for irq
  196.                 db      11110111b       ; Mask to enable irq
  197.                 db      00001000b       ; Mask to unable irq
  198.                 dw      2e8h            ; Receive buffer port
  199.                 dw      2e8h            ; Transmit buffer port
  200.                 dw      2e8h            ; Divisor least significant byte
  201.                 dw      2e9h            ; Divisor most significant byte
  202.                 dw      2ebh            ;  8250 UART Control port
  203.                 dw      2edh            ;  8250 UART Status port
  204.                 dw      2ech            ;  8250 Modem Control port
  205.                 dw      2eeh            ;  8250 Modem Status port
  206.                 dw      2e9h            ;  8250 interrupt enable register
  207.                 dw      2eah            ;  8250 interrupt ack register
  208.                 db      63h             ;  8259 Specific EOI
  209.  
  210. ; defaults for port 1
  211. port_tbl        label   word
  212. comm1_vector    dw      0ch             ; Interrupt vector for irq
  213. irq_enab_mask   db      11101111b       ; Mask to enable irq
  214. irq_unab_mask   db      00010000b       ; Mask to unable irq
  215. recv_buffer     dw      3f8h            ; Receive buffer port
  216. send_buffer     dw      3f8h            ; Transmit buffer port
  217. lsb_divisor     dw      3f8h            ; Divisor least significant byte
  218. msb_divisor     dw      3f9h            ; Divisor most significant byte
  219. line_control    dw      3fbh            ;  8250 UART Control port
  220. line_status     dw      3fdh            ;  8250 UART Status port
  221. modem_control   dw      3fch            ;  8250 Modem Control port
  222. modem_status    dw      3feh            ;  8250 Modem Status port
  223. int_enable      dw      3f9h            ;  8250 interrupt enable register
  224. int_id          dw      3fah            ;  8250 interrupt ID register
  225. SEOI            db      64h             ;  8259 Specific EOI
  226.  
  227.         page
  228. ;***********************************************************
  229. ;**     Subroutine to set up comm chip per the DCW        **
  230. ;**     DCW is in AX                                      **
  231. ;***********************************************************
  232. set_dcw:
  233.  
  234. ; clear comm parms
  235.         xor     dl,dl
  236.  
  237. ; set parity type
  238.         mov     bl,al                   ; get low byte in BL
  239.         and     bl,00000011b            ; mask unused bits
  240.         or      dl,bl                   ; change parity
  241.         mov     cl,3
  242.         shl     dl,cl
  243.         and     bl,00000001b            ; change parity flag
  244.         mov     parity_on,bl            ;
  245.  
  246. ; set num stop bits
  247.         mov     bl,al                   ; get low byte in BL
  248.         and     bl,00001000b            ; mask unused bits
  249.         shr     bl,1
  250.         or      dl,bl
  251.  
  252. ; set data bits
  253.         mov     bl,ah                   ; get high byte in BL
  254.         and     bl,01000000b            ; mask unused bits
  255.         or      bl,10000000b
  256.         mov     cl,6
  257.         shr     bl,cl
  258.         or      dl,bl
  259.  
  260. ; Save comm parms
  261.         mov     comm_parms,dl
  262.  
  263. ; set baud rate
  264.         mov     bl,al                   ; get low byte in BL
  265.         and     bl,11110000b            ; mask unused bits
  266.         mov     cl,3                    ; shift to make word ptr
  267.         shr     bl,cl
  268.         mov     si,offset baud_tbl      ; point to baud table
  269.         xor     bh,bh                   ; make BX a byte ptr
  270.         add     si,bx                   ; SI now points to baud rate const
  271.         mov     dx,word ptr [si]        ; get baud rate in DX
  272.         mov     speed,dx                ; save baud rate
  273.  
  274. ; set busy type
  275.         mov     bl,ah
  276.         and     bl,00000011b            ; mask unwanted bits
  277.         mov     byte ptr busy_hand,bl   ; store it
  278.  
  279. ; set port number
  280.         mov     bl,ah                   ; get high byte in BL
  281.         and     bl,00001000b            ; mask unused bits
  282.         shr     bl,1                    ; shift to make word ptr
  283.         shr     bl,1
  284.         mov     si,offset p_table       ; point to port table
  285.         xor     bh,bh                   ; make BX a byte ptr
  286.         add     si,bx                   ; SI now points to baud rate const
  287.         mov     dx,word ptr [si]        ; get port adrs in DX
  288.         mov     word ptr port_n,dx      ; save port number adrs
  289.         ret
  290.  
  291.         page
  292. ;***********************************************************
  293. ;**     Subroutine to set up interrupt vector             **
  294. ;**     and initialize the  8250 comm chip                **
  295. ;***********************************************************
  296. init_comm:
  297.         push    ds
  298.         push    cs
  299.         pop     ds
  300.  
  301. ; get correct port parameters
  302.         push    es
  303.         push    cs
  304.         pop     es
  305.  
  306.         mov     si,word ptr port_n      ; get port table adrs
  307.         mov     di,offset port_tbl      ; DI points to table to use
  308.         mov     cx,p_tbl_size           ; CX has table length
  309.         repz    movsb                   ; move it
  310.  
  311.         pop     es
  312.  
  313. ; Save old int vector for irq
  314.         mov     di,comm1_vector
  315.         call    get_vector
  316.         mov     word ptr oldseg,bx
  317.         mov     word ptr oldoff,dx
  318.  
  319. ; Set up int vector for irq
  320.         push    cs                      ; Make BX = CS
  321.         pop     bx
  322.         mov     dx,offset isr
  323.         mov     di,comm1_vector
  324.         call    set_vector
  325.  
  326. ; Enable irq from 8259A
  327.         cli
  328.         in      al,int_controller
  329.         jmp     $+2                     ; delay
  330.         and     al,irq_enab_mask
  331.         out     int_controller,al
  332.  
  333. ; Set baud rate, parity, etc.
  334.         mov     dx,line_control
  335.         mov     al,comm_parms
  336.         or      al,dlab                 ; Bring up DLAB
  337.         out     dx,al
  338.         mov     dx,lsb_divisor          ; Set LSB of Divisor Latch
  339.         mov     ax,speed
  340.         out     dx,al
  341.         mov     dx,msb_divisor          ; Set MSB of Divisor Latch
  342.         mov     al,ah
  343.         out     dx,al
  344.         mov     dx,line_control
  345.         in      al,dx
  346.         and     al,not dlab
  347.         out     dx,al
  348.  
  349. ; Read receive buffer register
  350.         call    lin_stat
  351.         test    al,char_waiting
  352.         jz      init_1
  353.         mov     dx,recv_buffer
  354.         in      al,dx
  355. init_1:
  356.  
  357. ; Read modem control register
  358.         mov     dx,modem_control
  359.         in      al,dx
  360.  
  361. ; Read modem status register
  362.         call    mod_stat
  363.  
  364. ; Read UART status register
  365.         call    lin_stat
  366.  
  367. ; Enable 8250 interrupts
  368.         mov     dx,line_control
  369.         in      al,dx
  370.         and     al,not dlab
  371.         out     dx,al
  372.         mov     dx,int_enable
  373.         mov     al,enable_ints
  374.         out     dx,al
  375.  
  376. ; Raise DTR, RTS, & OUT2
  377.         mov     dx,modem_control
  378.         mov     al,dtr_rts_out2
  379.         out     dx,al
  380.  
  381.         pop     ds
  382.         sti
  383.         ret
  384.  
  385.         page
  386. ;***********************************************************
  387. ;**     Subroutine to restore interrupt vector            **
  388. ;**     and reset the  8250 comm chip                     **
  389. ;***********************************************************
  390. de_init:
  391.         cli
  392.  
  393. ; Disable irq
  394.         in      al,int_controller
  395.         or      al,cs:byte ptr irq_unab_mask
  396.         jmp     $+2                     ; delay
  397.         jmp     $+2                     ; delay
  398.         out     int_controller,al
  399.  
  400. ; Disable interrupts on  8250 and drop DTR, RTS
  401.         mov     dx,cs:line_control
  402.         in      al,dx
  403.         jmp     $+2                     ; delay
  404.         and     al,not dlab
  405.         out     dx,al
  406.         mov     dx,cs:int_enable
  407.         xor     al,al
  408.         out     dx,al
  409.  
  410. ; It's probably not a good idea to restore the vector at close in
  411. ; this case, but here's the code to do it:
  412. ;
  413. ; Restore int vector for irq
  414. ;       mov     bx,cs:word ptr oldseg
  415. ;       mov     dx,cs:word ptr oldoff
  416. ;       mov     di,comm1_vector
  417. ;       call    set_vector
  418.         sti
  419.         ret
  420.  
  421.         page
  422. ;***********************************************************
  423. ;**     Interrupt Service Routine                         **
  424. ;***********************************************************
  425. isr:
  426.         cli
  427.         cld
  428. ; Set up new stack
  429.         mov     cs:word ptr old_sp,sp
  430.         mov     cs:word ptr old_ss,ss
  431.         mov     sp,cs
  432.         mov     ss,sp
  433.         mov     sp,offset i_stack
  434.  
  435.         push    ax
  436.         push    bx
  437.         push    cx
  438.         push    dx
  439.         push    ds
  440.  
  441.         push    cs
  442.         pop     ds
  443.  
  444. ; Verify int came from  8250
  445.         mov     dx,int_id
  446.         in      al,dx
  447.         test    al,int_pending
  448.         jnz     isr_exit
  449.  
  450. ; Branch to correct routine
  451.         cbw                             ; make int type a word
  452.         mov     bx,offset int_tbl       ; point to int table
  453.         add     bx,ax                   ; add int type
  454.         sti
  455.         call    cs:word ptr [bx]        ; go do subroutine
  456.         cli
  457.  
  458. isr_exit:
  459. ; Tell 8259A we're done
  460.         mov     al,SEOI
  461.         out     int_ack,al
  462.  
  463.         pop     ds
  464.         pop     dx
  465.         pop     cx
  466.         pop     bx
  467.         pop     ax
  468.  
  469. ; restore stack
  470.         mov     ss,cs:word ptr old_ss
  471.         mov     sp,cs:word ptr old_sp
  472.  
  473.         sti
  474.         iret
  475.  
  476.         page
  477. ;***********************************************************
  478. ;**     Subroutine to read the modem status               **
  479. ;***********************************************************
  480. mod_stat:
  481.         mov     dx,modem_status         ; Read modem status (CHB)
  482.         in      al,dx                   ;   into reg AL
  483.  
  484.         xor     ah,ah
  485.         test    al,ri_bit
  486.         jz      test_dsr
  487.         or      ah,4
  488. test_dsr:
  489.         test    al,dsr_bit
  490.         jz      test_cts
  491.         or      ah,1
  492. test_cts:
  493.         shl     ah,1
  494.         test    al,cts_bit
  495.         jz      test_dcd
  496.         or      ah,1
  497. test_dcd:
  498.         shl     ah,1
  499.         test    al,dcd_bit
  500.         jz      test_done
  501.         or      ah,1
  502. test_done:
  503.  
  504. ; AH now contains the line signals
  505. ; ---------------------------------
  506. ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  507. ; ---------------------------------
  508. ; |   |   |   | RI|   |DSR|CTS|DCD|
  509. ; ---------------------------------
  510. ; 0=down, 1=up
  511.  
  512.         mov     cs:byte ptr m_stat,ah   ; Update current modem status
  513.  
  514. ; Check for busy handling
  515.         shr     ah,1                    ; DSR in bit 0
  516.         shr     ah,1
  517.         cmp     cs:byte ptr busy_hand,2 ; DSR busy handling?
  518.         jne     xit_mod_stat            ;  No, skip
  519.         mov     al,ah                   ; save AH
  520. set_tbusy:
  521.         and     al,1                    ; up = busy on
  522. ;       not     al                      ; down = busy on
  523.         mov     cs:byte ptr t_busy,al   ; set busy
  524.  
  525.  
  526. xit_mod_stat:
  527.         ret
  528.  
  529.         page
  530. ;***********************************************************
  531. ;**     Subroutine to send the next char in queue         **
  532. ;***********************************************************
  533. xmit_mt:
  534.     cmp    cs:byte ptr t_busy,0    ; see if protocol busy in effect
  535.     je    xmit_mt_0        ; no protocol busy for now
  536.  
  537.         mov     cs:byte ptr xmit_busy,0 ; Tell world we're not busy any more
  538.     ret
  539.  
  540. xmit_mt_0:
  541.     cmp    cs:word ptr tq_len,0    ; anything at all to send?
  542.     jne    xmit_mt_1        ; there is something to send
  543.         mov     cs:byte ptr xmit_busy,0 ; Tell world we're not busy any more
  544.     ret
  545.  
  546. xmit_mt_1:
  547.         mov     bx,offset tqueue        ; Dequeue char
  548.         mov     dx,cs:word ptr tq_tail
  549.         add     bx,dx
  550.         mov     al,cs:byte ptr [bx]    ; get the character
  551.         inc     dx
  552.         and     dx,tran_limit           ; wrap if >= receive size
  553.         mov     cs:word ptr tq_tail,dx
  554.         dec     cs:word ptr tq_len      ; Adjust queue length
  555.  
  556.     mov    dx,cs:word ptr send_buffer    ; get port address
  557.     out    dx,al            ; send character
  558.         mov     cs:byte ptr xmit_busy,1 ; Tell world we are busy now
  559.  
  560.         ret
  561.  
  562.         page
  563. ;***********************************************************
  564. ;**     Subroutine to receive a char and queue it         **
  565. ;***********************************************************
  566. rec_full:
  567.         mov     dx,recv_buffer          ; Get char
  568.         in      al,dx
  569.         cmp     cs:byte ptr parity_on,0 ; parity?
  570.         jz      no_par                  ;   No, don't mask off parity bit
  571.         and     al,7fh                  ;   Yes, mask off parity bit
  572. no_par:
  573. ; check for XON-XOFF busy char
  574.         cmp     cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
  575.         jne     queue_char              ;  No, skip busy handling
  576.         cmp     al,xoff                 ; Need to set busy?
  577.         jne     chk_r_xon               ;  No, skip
  578.         mov     cs:byte ptr t_busy,1    ; set busy
  579.         jmp     xit_rec_full            ; We're done
  580.  
  581. chk_r_xon:
  582.         cmp     al,xon                  ; Need to reset busy?
  583.         jne     queue_char              ;  No, skip busy handling
  584.         mov     cs:byte ptr t_busy,0    ; reset busy
  585.         cmp     cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
  586.     jne    xit_rec_full        ; no, just restart transmitter
  587.     cmp    cs:byte ptr xmit_busy,0    ; see if transmitter is already 
  588.                     ;   (still) busy
  589.     jne    xit_rec_full        ; it was. we're done
  590.  
  591.     call    xmit_mt            ; restart transmitter
  592.         jmp     xit_rec_full            ; We're done
  593.  
  594. queue_char:
  595. ; check for buffer overflow
  596.         cmp     cs:word ptr rq_len,recv_limit ; buffer full?
  597.         jb      buf_full1               ; No, skip
  598.         inc     cs:word ptr rq_tail     ; Yes, lose 1 char
  599.         and     cs:word ptr rq_tail,recv_limit
  600.         dec     cs:word ptr rq_len      ; Adjust queue length
  601. buf_full1:
  602.  
  603.         mov     bx,offset rqueue        ; Queue char
  604.         mov     dx,cs:word ptr rq_head
  605.         add     bx,dx
  606.         mov     cs:byte ptr [bx],al
  607.         inc     dx
  608.         and     dx,recv_limit           ; wrap if >= receive size
  609.         mov     cs:word ptr rq_head,dx
  610.         inc     cs:word ptr rq_len      ; Adjust queue length
  611.  
  612. ; set busy if needed
  613.         cmp     cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
  614.         jne     set_rb_done             ; No, skip
  615.         cmp     cs:word ptr rq_len,busy_len ; Need to set busy?
  616.         jb      set_rb_done             ; No, skip
  617.         mov     cs:byte ptr r_busy,1    ; set busy flag
  618.     mov    al,xoff            ; send the xoff character
  619.     call    send_xon
  620. set_rb_done:
  621.  
  622. xit_rec_full:
  623.         ret
  624.  
  625.         page
  626. ;***********************************************************
  627. ;**     Subroutine to send an xon char if needed          **
  628. ;***********************************************************
  629. send_xon:
  630.         cmp     cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
  631.         jne     xit_send_xon            ; No, skip
  632.  
  633.         mov     bx,offset tqueue        ; Queue char
  634.         mov     dx,cs:word ptr tq_tail
  635.         dec     dx
  636.         and     dx,tran_limit           ; wrap if >= receive size
  637.         add     bx,dx
  638.         mov     cs:byte ptr [bx],al    ; put the character in the queue
  639.         mov     cs:word ptr tq_tail,dx
  640.         inc     cs:word ptr tq_len      ; Adjust queue length
  641.  
  642.     cmp    cs:byte ptr xmit_busy,0    ; is transmitter busy?
  643.     jne    xit_send_xon
  644.  
  645. send_xon_1:
  646.     call    xmit_mt            ; force first character out
  647.  
  648. xit_send_xon:
  649.         ret
  650.  
  651.         page
  652. ;***********************************************************
  653. ;**     Subroutine to read the line status                **
  654. ;***********************************************************
  655. lin_stat:
  656.         mov     dx,line_status
  657.         in      al,dx                   ; read status
  658.         mov     cs:byte ptr l_stat,al   ; Update current line status
  659.  
  660.         ret
  661.  
  662.         page
  663. ;***********************************************************
  664. ;**     Subroutine to get an interrupt vector             **
  665. ;**                                                       **
  666. ;**   di = vector number                                  **
  667. ;**                                                       **
  668. ;**   Return:                                             **
  669. ;**   bx = segment                                        **
  670. ;**   dx = offset                                         **
  671. ;***********************************************************
  672. get_vector:
  673.         push    es
  674.         xor     ax,ax
  675.         mov     es,ax
  676.         shl     di,1
  677.         shl     di,1
  678.         mov     dx,es:word ptr[di]
  679.         mov     bx,es:word ptr[di+2]
  680.         pop     es
  681.         ret
  682.  
  683.         page
  684. ;***********************************************************
  685. ;**     Subroutine to set an interrupt vector             **
  686. ;**                                                       **
  687. ;**   di = vector number                                  **
  688. ;**   bx = segment                                        **
  689. ;**   dx = offset                                         **
  690. ;***********************************************************
  691. set_vector:
  692.         push    es
  693.         xor     ax,ax
  694.         mov     es,ax
  695.         shl     di,1
  696.         shl     di,1
  697.         mov     es:word ptr[di],dx
  698.         mov     es:word ptr[di+2],bx
  699.         pop     es
  700.         ret
  701.  
  702.         page
  703. ;***********************************************************
  704. ;**  Everything past here is truncated after install      **
  705. ;***********************************************************
  706.  
  707. init    proc    near
  708.         lds     bx,cs:[ptrsav]
  709.         mov     word ptr [bx].trans,offset init ;set break address
  710.         mov     [bx].trans+2,cs
  711.  
  712.         push    cs
  713.         pop     ds
  714.         mov     dx,offset init_msg
  715.         mov     ah,9
  716.         int     21h
  717.  
  718.         jmp     exit
  719. init    endp
  720.  
  721. init_msg:
  722.         db      cr,lf,'IBM PC Communications Driver v3.00'
  723.         db      ' Copyright (C) Texas Instruments 1986, 1987',cr,lf
  724.         db      ' Copyright (C) Fein-Marquart Associates, 1987'
  725.         db      cr,lf,cr,lf,'$'
  726. code    ends
  727.         end
  728.