home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / slipmerg.asm < prev    next >
Assembly Source File  |  1995-06-25  |  31KB  |  1,325 lines

  1. version    equ    7
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
  6. ;8250 by Russell Nelson.  Any bugs are due to Russell Nelson.
  7. ;16550 support ruthlessly stolen from Phil Karn's 8250.c. 
  8. ;  Bugs by Denis DeLaRoca
  9. ;
  10.  if ETHERSLIP
  11. ; Modified by Michael Martineau to provide a class 1 interface.
  12. ; Additional modifications by Joe Doupnik, jrd@cc.usu.edu, 5 Nov 1991
  13. ;  Do not use "c0h" as leading vendor byte in artifical Ethernet address.
  14. ;  Use originator's Ethernet address as destination of ARP Reply address.
  15. ;
  16.  endif
  17. ; Stopped failures from lost transmit interrupts (by eliminating the ints
  18. ; altogether). Remove unneeded transmitter buffer.
  19. ; Version 6 by Joe Doupnik, jrd@cc.usu.edu, Utah State University, Dec 1991.
  20. ; Fix hardware handshaking problems.  Philip R. "Pib" Burns,
  21. ;   Northwestern University, September, 1992.
  22.  
  23. ;  Copyright, 1988, 1991, Russell Nelson
  24.  
  25. ;   This program is free software; you can redistribute it and/or modify
  26. ;   it under the terms of the GNU General Public License as published by
  27. ;   the Free Software Foundation, version 1.
  28. ;
  29. ;   This program is distributed in the hope that it will be useful,
  30. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  31. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  32. ;   GNU General Public License for more details.
  33. ;
  34. ;   You should have received a copy of the GNU General Public License
  35. ;   along with this program; if not, write to the Free Software
  36. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  37.  
  38. code    segment    word public
  39.     assume    cs:code, ds:code
  40.  
  41.     include    8250defs.asm
  42.  
  43. ;Slip Definitions
  44. FR_END        equ    0c0h        ;Frame End
  45. FR_ESC        equ    0dbh        ;Frame Escape
  46. T_FR_END    equ    0dch        ;Transposed frame end
  47. T_FR_ESC    equ    0ddh        ;Transposed frame escape
  48.  
  49.     public    int_no
  50. int_no        db    4,0,0,0        ; interrupt number.
  51. io_addr        dw    03f8h,0        ; I/O address for COM1
  52. baud_rate    dw    12c0h,0        ; support baud higher than 65535
  53. baudclk        label    word
  54.         dd    115200        ; 1.8432 Mhz / 16
  55. hardware_switch    db    0        ; if zero, don't use hw handshaking
  56. is_16550        db      0               ; 0=no, 1=yes (try using fifo)
  57.  
  58.     public    driver_class, driver_type, driver_name 
  59.     public    driver_function, parameter_list
  60.   if    ETHERSLIP
  61. driver_class    db    1,0,0,0        ;from the packet spec
  62. driver_type    db    0,0,0,0        ;from the packet spec
  63. driver_name    db    'ETHERSLIP',0    ;name of the driver.
  64.   else
  65. driver_class    db    6,0,0,0        ;from the packet spec
  66. driver_type    db    0,0,0,0        ;from the packet spec
  67. driver_name    db    'SLIP8250',0    ;name of the driver.
  68.   endif
  69. driver_function    db    2
  70. parameter_list    label    byte
  71.     db    1    ;major rev of packet driver
  72.     db    9    ;minor rev of packet driver
  73.     db    14    ;length of parameter list
  74.     db    EADDR_LEN    ;length of MAC-layer address
  75.     dw    GIANT    ;MTU, including MAC headers
  76.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  77.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  78.     dw    0    ;(# of successive xmits) - 1
  79. int_num    dw    0    ;Interrupt # to hook for post-EOI
  80.             ;processing, 0 == none,
  81.  
  82.   ifdef debug
  83.     public recv_buf_size, recv_buf,    recv_buf_end, recv_buf_head
  84.     public recv_buf_tail, recv_pkt_ready
  85.   endif
  86. recv_buf_size    dw    3000,0        ;receive buffer size
  87. recv_buf    dw    ?        ;->receive buffer
  88. recv_buf_end    dw    ?        ;->after end of buffer
  89. recv_buf_head    dw    ?        ;->next character to get
  90. recv_buf_tail    dw    ?        ;->next character to store
  91. recv_pkt_ready    dw    0        ; flag indicating a packet is ready
  92.   if ETHERSLIP
  93.   else
  94. IP_TYPE    DW    0800H
  95.   endif
  96.  
  97.   ifdef debug
  98.     public packet_sem, xmit_time
  99.   endif
  100. packet_sem    dw    0        ; semaphore for    packets received
  101. asyrxint_cnt    dw    0        ; loop counter in asyrxint
  102. xmit_time    dw    0        ; loop timer for asyrxint
  103.  
  104.   if    ETHERSLIP
  105. ;
  106. ; ARP request/reply packet structure.
  107. ;
  108. arp        struc 
  109. arp_hw        dw ?         ; Hardware address length, bytes 
  110. arp_prot    dw ?         ; Protocol type 
  111. arp_hwalen    db ?         ; hardware address length, bytes 
  112. arp_pralen     db ?         ; Length of protocol address 
  113. arp_opcode      dw ?         ; ARP opcode (request/reply) 
  114. arp_shwaddr    db 6 dup(?)    ; Sender hardware address field 
  115. arp_sprotaddr    dd ?        ; Sender Protocol address field 
  116. arp_thwaddr    db 6 dup(?)    ; Target hardware address field 
  117. arp_tprotaddr    dd ?        ; Target protocol address field 
  118. arp        ends
  119.  
  120. ;
  121. ; recv_find() requires a pointer to the Ethernet packet type.  Since
  122. ; the incoming packet does not contain an Ethernet packet type field,
  123. ; memory must be allocated to hold the Ethernet packet type.  Space is
  124. ; required for both IP and ARP types.
  125. ;
  126. ip_type        label    byte
  127.         db    08
  128.         db    00    
  129.  
  130. arp_type    label    byte
  131.         db    08
  132.         db    06    
  133.  
  134. ;
  135. ; Pseudo-Ethernet address to return in the ARP reply packet.
  136. ;
  137. your_addr    label     byte
  138.         db    00
  139.         db    00
  140.         db    0
  141.         db    22h
  142.         db    34h
  143.         db    66h
  144.   endif
  145.  
  146. raw_mode    db    0        ;=1 if we send and receive raw chars.
  147.  
  148.     public    rcv_modes
  149. rcv_modes    dw    8        ;number    of receive modes in our table
  150.         dw    0,0,0,rcv_mode_3
  151.         dw    0,0,0,rcv_mode_7
  152.  
  153.  
  154.     public bad_command_intercept
  155. bad_command_intercept:
  156. ;called with ah=command, unknown to the skeleton.
  157. ;exit with nc if okay, cy, dh=error if not.
  158.     mov    dh,BAD_COMMAND
  159.     stc
  160.     ret
  161.  
  162.     public    as_send_pkt
  163. ; The Asynchronous Transmit Packet routine.
  164. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  165. ;   interrupts possibly enabled.
  166. ; Exit with nc if ok, or else cy if error, dh set to error number.
  167. ;   es:di and interrupt enable flag preserved on exit.
  168. as_send_pkt:
  169.     ret
  170.  
  171.     public    drop_pkt
  172. ; Drop a packet from the queue.
  173. ; Enter with es:di -> iocb.
  174. drop_pkt:
  175.     assume    ds:nothing
  176.     ret
  177.  
  178.     public    xmit
  179. ; Process a transmit interrupt with the least possible latency to achieve
  180. ;   back-to-back packet transmissions.
  181. ; May only use ax and dx.
  182. xmit:
  183.     assume    ds:nothing
  184.     ret
  185.  
  186.  
  187.     public    send_pkt
  188. ;
  189. ; mod 7/25/89 John Grover
  190. ; - operates with interrupts on. Xmits one byte per interrupt
  191. ; - only turns transmitter buffer empty interrupt off when
  192. ; - all bytes of all packets are transmitted.
  193.  
  194. send_pkt:
  195. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  196. ;  (only if the high-performance bit is set in driver_function)
  197.  
  198. ;enter with ds:si -> packet, cx = packet length.
  199. ;exit with nc if ok, or else cy if error, dh set to error number.
  200. ;called from telnet layer via software interrupt
  201. ; We just send each byte in turn. No UART interrupts are needed nor wanted.
  202. ; In fact the overdone receiver material omits to note that xmtr interrupts
  203. ; can be lost while processing rcvr ones. Small benefits are no stalled
  204. ; programs, no transmitter buffer, no problems at 19200 b/s. Joe Doupnik
  205. ;
  206. ; Unfortunately the revised code didn't handle hardware handshaking.
  207. ; Added back by Pib, September, 1992.
  208. ;
  209.     assume    ds:nothing, es:nothing
  210.     sti                ; enable interrupts
  211.     cmp    raw_mode,0
  212.     je    not_send_raw
  213. send_raw:
  214.     lodsb
  215.     call    send_char
  216.     loop    send_raw
  217.     clc
  218.     ret
  219. not_send_raw:
  220.   if    ETHERSLIP
  221. ;    
  222. ; Strip off Ethernet header.
  223. ;
  224.     add    si,12
  225.     mov    ax, word ptr ds:[si]
  226.     add    si,2
  227.     sub    cx,14
  228. ;
  229. ; Check packet type.  If an ARP packet then construct an ARP reply
  230. ; packet. Otherwise, process the incoming IP packet.
  231. ;
  232.     cmp    ax,0608h
  233.     jne    noarp
  234.     call    arp_reply
  235.     jmp    send_pkt_end
  236.  
  237. noarp:
  238.   endif
  239.     mov    al,FR_END        ; Flush out any line garbage
  240.     call    send_char
  241.     jc    send_pkt_end        ; c = failure to send
  242.  
  243. ;Copy input to output, escaping special characters
  244. send_pkt_1:
  245.     lodsb
  246.     cmp    al,FR_ESC      ; escape FR_ESC with FR_ESC and T_FR_ESC
  247.     jne    send_pkt_2
  248.     mov    al,FR_ESC
  249.     call    send_char
  250.     jc    send_pkt_end
  251.     mov    al,T_FR_ESC
  252.     jmp    short send_pkt_3
  253. send_pkt_2:
  254.     cmp    al,FR_END      ; escape FR_END with FR_ESC and T_FR_END
  255.     jne    send_pkt_3
  256.     mov    al,FR_ESC
  257.     call    send_char
  258.     jc    send_pkt_end
  259.     mov    al,T_FR_END
  260. send_pkt_3:
  261.     call    send_char
  262.     jc    send_pkt_end
  263.     loop    send_pkt_1        ; do cx user characters
  264.     mov    al,FR_END        ; terminate it with a FR_END
  265.     call    send_char
  266.     jc    send_pkt_end
  267.     clc
  268. send_pkt_end:
  269.     ret
  270.  
  271. ; mod 7/25/89 John Grover
  272. ; redone by Joe Doupnik, Dec 1991
  273. ; CTS check added by Pib, September, 1992.
  274.     assume    ds:nothing, es:nothing
  275. send_char:                ; send the character in al
  276.     push    dx
  277.     push    cx
  278.         push    bx
  279.     xchg    ah,al            ; put data char into ah
  280.     xor    cx,cx            ; 64K retry counter
  281.         mov     bl,hardware_switch      ; Get hardware check (CTS) switch
  282. sendch1:mov    dx,io_addr        ; 03f8h base address
  283.     add    dx,LSR            ; 03fdh get port status
  284.     in    al,dx
  285.     test    al,LSR_THRE        ; Transmitter (THRE) ready?
  286.         jz      sendch4                 ; No -- loop and check again.
  287.         cmp     bl,0                    ; Yes -- check CTS ready if needed.
  288.         jz      sendch2                 ; No check -- send the character.
  289.         mov     dx,io_addr              ; Else get 03f8h base address
  290.         add     dx,MSR                  ; 03fdh get port status
  291.     in    al,dx
  292.         test    al,MSR_CTS              ; Is CTS ready?
  293.         jnz     sendch2                 ; nz = yes
  294. sendch4:jmp     $+2                     ; use time, prevent overdriving UART
  295.     jmp    $+2
  296.     loop    sendch1
  297.     stc                ; carry set for failure
  298.     jmp    short sendch3        ; timeout
  299. sendch2:xchg    al,ah            ; now send it
  300.     mov    dx,io_addr        ; 03f8h, use a little time
  301.     jmp    $+2
  302.     out    dx,al            ; send the byte
  303.     clc                ; status of success
  304. sendch3:pop    bx
  305.     pop    cx
  306.     pop    dx
  307.     ret
  308.  
  309.   if    ETHERSLIP
  310. ;
  311. ; Formulate a dummy ARP reply packet.  ds:si points at the incoming
  312. ; IP packet.
  313. ;
  314.  
  315. arp_reply:
  316.  
  317. ;
  318. ; Save the registers.  Not sure that we need to but it works and I 
  319. ; don't want to change it right now.
  320. ;
  321.     push    ds
  322.     push    es
  323.     push    si
  324.     push    di
  325.     push    cx
  326.  
  327. ;
  328. ; Check to see if the ARP request is to find the hardware address
  329. ; of the local host.  If so, then don't formulate a reply packet.
  330. ;
  331.     mov    cx,4
  332.     mov    ax,si
  333.     mov    di,ax
  334.     mov    ax,ds
  335.     mov    es,ax
  336.     add    di,arp_sprotaddr
  337.     add    si,arp_tprotaddr
  338.     repe    cmpsb            ; Compare source and target
  339.                     ; protocol address
  340.     jnz    arp_reply_2
  341.     pop    cx
  342.     pop    di
  343.     pop    si
  344.     pop    es
  345.     pop    ds
  346.     ret
  347.  
  348. arp_reply_2:
  349. ;
  350. ; Restore registers.
  351. ;
  352.     pop    cx
  353.     pop    di
  354.     pop    si
  355.     push    si
  356.     push    di
  357.     push    cx
  358. ;
  359. ; Restore Ethernet header.
  360. ;
  361.     add    cx,14
  362.     sub    si,14 
  363. ;
  364. ; Ask application layer for a memory buffer in which to store
  365. ; incoming packet.
  366. ;
  367.     push    ds
  368.     push    si            ;save si in case we reject it.
  369.     push    bx
  370.     push    cx
  371.     mov    ax,cs
  372.     mov    es,ax
  373.     mov    ds,ax
  374.     mov    di, offset arp_type
  375.     mov    dl,cs:driver_class
  376.     call    recv_find        ;look up our type.
  377.     pop    cx
  378.     pop    bx
  379.     pop    si
  380.     pop    ds
  381.  
  382.     mov    ax,es            ;is this pointer null?
  383.     or    ax,di
  384.     je    arp_reply_1        ;yes - just free the frame.
  385.  
  386.     push    cx
  387.     push    es
  388.     push    di
  389. ;
  390. ; Save si,di for future use.
  391. ;
  392.     mov    bx,si
  393.     mov    dx,di
  394. ;
  395. ; Set up ARP Reply by first copying the ARP Request packet.
  396. ;
  397.     rep    movsb
  398. ;
  399. ; Skip Ethernet header
  400. ;
  401.     add    bx,14
  402.     add     dx,14
  403. ;
  404. ; Swap target and source protocol addresses from ARP request to ARP 
  405. ; reply packet.
  406. ;
  407.     push    es        ; mods by Joe Doupnik
  408.     mov    si,ds
  409.     mov    es,si
  410.     mov    si,bx        ; incoming packet interior
  411.     sub    si,2+6        ; walk back to originator's Ethernet address
  412.     mov    cx,6        ; six bytes of Ethernet address
  413.     mov    di,dx        ; outgoing packet
  414.     sub    di,2+6+6    ; Ethernet destination address
  415.     rep    movsb        ; copy originator's address as new dest
  416.     pop    es        ;
  417.  
  418.     mov    si,bx
  419.     mov    di,dx    
  420.     mov    cx,4
  421.     add    si,arp_tprotaddr
  422.     add    di,arp_sprotaddr
  423.     rep    movsb
  424.  
  425.     mov    si,bx
  426.     mov    di,dx
  427.     mov    cx,4
  428.     add    si,arp_sprotaddr
  429.     add    di,arp_tprotaddr
  430.     rep    movsb
  431. ;
  432. ; Swap target and source hardware addresses from ARP request to ARP 
  433. ; reply packet.
  434. ;
  435.     mov    si,bx
  436.     mov    di,dx
  437.     mov    cx,6
  438.     add    si,arp_shwaddr
  439.     add    di,arp_thwaddr
  440.     rep    movsb
  441. ;
  442. ; Load source hardware address in ARP reply packet.
  443. ;
  444.     mov    si,bx
  445.     mov    di,dx
  446.     mov    cx,6
  447.     mov    ax,cs
  448.     mov    ds,ax
  449.     mov    si,offset your_addr
  450.     add    di,arp_shwaddr
  451.     rep    movsb
  452. ;
  453. ; Set opcode to REPLY.
  454. ;
  455.     mov    di,dx
  456.     mov    word ptr es:[di].arp_opcode,0200h
  457. ; Give ARP reply packet that has been constructed to the application
  458. ; layer.
  459. ;
  460.     pop    si
  461.     pop    ds
  462.     pop    cx
  463.     assume    ds:nothing
  464.     call    recv_copy
  465.     assume    ds:code
  466.  
  467. arp_reply_1:
  468.  
  469.     pop    cx
  470.     pop    di
  471.     pop    si
  472.     pop    es
  473.     pop    ds
  474.  
  475.     ret
  476.   endif
  477.  
  478.     public    set_address
  479. set_address:
  480. ;set the address of the interface.
  481. ;enter with es:di -> place to get the address, cx = size of address buffer.
  482. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  483.     assume    ds:nothing
  484.     clc
  485.     ret
  486.  
  487.  
  488. rcv_mode_3:
  489. ;exit raw mode
  490.     mov    raw_mode,0
  491.     ret
  492.  
  493. rcv_mode_7:
  494. ;enter raw mode
  495.     mov    raw_mode,1
  496.     ret
  497.  
  498.  
  499.     public    set_multicast_list
  500. set_multicast_list:
  501. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  502. ;  cx = number of bytes.
  503. ;return nc if we set all of them, or cy,dh=error if we didn't.
  504.     mov    dh,NO_MULTICAST
  505.     stc
  506.     ret
  507.  
  508.  
  509.     public    terminate
  510. terminate:
  511.     ret
  512.  
  513.     public    reset_interface
  514. reset_interface:
  515. ;reset the interface.
  516.     assume    ds:code
  517.     ret
  518.  
  519.  
  520. ;called    when we    want to determine what to do with a received packet.
  521. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  522.     extrn    recv_find: near
  523.  
  524. ;called after we have copied the packet into the buffer.
  525. ;enter with ds:si ->the packet, cx = length of the packet.
  526.     extrn    recv_copy: near
  527.  
  528. ;call this routine to schedule a subroutine that gets run after the
  529. ;recv_isr.  This is done by stuffing routine's address in place
  530. ;of the recv_isr iret's address.  This routine should push the flags when it
  531. ;is entered, and should jump to recv_exiting_exit to leave.
  532. ;enter with ax = address of routine to run.
  533.     extrn    schedule_exiting: near
  534.  
  535. ;recv_exiting jumps here to exit, after pushing the flags.
  536.     extrn    recv_exiting_exit: near
  537.  
  538. ;enter with dx = amount of memory desired.
  539. ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
  540.     extrn    malloc: near
  541.  
  542.     extrn    count_in_err: near
  543.     extrn    count_out_err: near
  544.  
  545.     public    recv
  546.  
  547. ;
  548. ; mod 7/25/89 John Grover
  549. ;
  550. ; - added code to check modem status change interrupt. If CTS is
  551. ; - low  turn off transmitter buffer empty interrupt. If CTS is
  552. ; - high turn it on.
  553.  
  554. recv:
  555. ;called from the recv isr.  All registers have been saved, and ds=cs.
  556. ;Upon exit, the interrupt will be acknowledged.
  557.     assume    ds:code
  558.     mov    ax,offset recv_exiting    ;schedule recv_exiting to be called
  559.     call    schedule_exiting    ;  on exit.
  560. recv_2:
  561.     loadport
  562.     setport    IIR
  563.     in    al,dx            ;any interrupts at all?
  564.     test    al,IIR_IP
  565.     jne    recv_1            ;no.
  566.     and    al,IIR_ID
  567.     cmp    al,IIR_RDA        ;Receiver interrupt
  568.     jne    recv_3
  569.     call    asyrxint
  570.     jmp    recv_2
  571. recv_3:
  572. recv_5:
  573. ;process IIR_MSTAT here.
  574. ;  If CTS and packet ready then
  575. ;    enable the    transmit buffer empty interrupt
  576. ;  else
  577. ;    disable the transmit buffer empty interrupt
  578. ;
  579.     cmp    al, IIR_MSTAT
  580.     jne    recv_1
  581. ;    setport    MSR            ; make sure of CTS status
  582. ;    in    al, dx
  583. ;    test    al, MSR_CTS        ; is CTS bit set
  584. ;    jz    recv_5_1        ; no - disable xmit buffer empty int
  585.     jmp    recv_2
  586.  
  587. recv_5_1:
  588.     jmp    recv_2
  589.  
  590. ;process IIR_RLS here
  591. recv_1:
  592.     ret
  593.  
  594.  
  595. ;Process 8250 receiver interrupts
  596. ;
  597. ; mod 7/25/89 John Grover
  598. ; - this branches off when bps < 9600. See asyrxint_a.
  599. ; - Above 9600 bps we go into a loop to process a packet at
  600. ; - a time. If not data ready for a certain amount of time,
  601. ; - the process exits and waits for the next byte. This certain
  602. ; - amount of time to wait depends on the bps and CPU processor speed
  603. ; - and is determined in the initialization of the driver.
  604. ; - Upon receiving the FR_END character for the first frame in the
  605. ; - buffer a semaphore is set which tells recv_frame to run.
  606.  
  607. asyrxint:
  608.  
  609.     movseg    es,ds
  610.     xor    bx, bx
  611.     cmp    baud_rate, 9600         ; below 9600 we're strictly
  612.     jbe    asyrxint_a              ; interrupt driven
  613.     mov    bx, xmit_time
  614. asyrxint_a:
  615.     mov    di,recv_buf_tail
  616.     xor    bp, bp            ; set flag to indicate 1st char
  617.                     ; processed
  618.     mov    si, packet_sem          ; optimization
  619.     loadport
  620.     mov    ah, LSR_DR
  621.  
  622. asyrxint_again:
  623.     xor    cx, cx            ; initialize counter
  624.     setport    LSR
  625. asyrxint_in:
  626.     in    al,dx            ; check for data ready
  627.     test    al,LSR_DR
  628.     jnz    asyrxint_gotit        ; yes - break out of loop
  629.     inc    cx            ; no - increase loop counter
  630.     cmp    cx, bx            ; timeout?
  631.     jae    asyrxint_exit        ; yes - leave
  632.     jmp    asyrxint_in        ; no - keep looping
  633.  
  634. asyrxint_gotit:
  635.     setport    RBR
  636.     in    al,dx
  637.  
  638. ;Process incoming data;
  639. ; If buffer is full, we have no choice but
  640. ; to drop the character
  641.     cmp    di,recv_buf_head    ; check for buffer collision
  642.     jne    asyrxint_ok        ; none - continue
  643.     or    si, si                  ; maybe - if there are packets
  644.     jnz    asyrxint_exit        ; yes exit
  645.  
  646. asyrxint_ok:
  647.     stosb
  648.  
  649.     cmp    di,recv_buf_end        ; did we hit the end of the buffer?
  650.     jne    asyrxint_3        ; no.
  651.     mov    di,recv_buf        ; yes - wrap around.
  652.  
  653. asyrxint_3:
  654.     cmp    raw_mode,0        ;raw mode?
  655.     jne    asyrxint_raw
  656.     cmp    al,FR_END        ; might    this be    the end of a frame?
  657.     jne    asyrxint_reset        ; no - reset flag and loop
  658. asyrxint_raw:
  659.     inc    si                      ; yes - indicate packet ready
  660.     cmp    si, 1                   ; determine if semaphore is <> 1
  661.     jne    asyrxint_chk_flg        ; yes - recv_frame must be active
  662.     inc    recv_pkt_ready          ; no - set flag to start recv_frame
  663.  
  664. asyrxint_chk_flg:
  665.     cmp    bp, 0                   ; was this the first char?
  666.     jne    asyrxint_1              ; no - exit handler
  667. asyrxint_reset:
  668.     inc    bp            ; set 1st character flag
  669.     jmp    asyrxint_again        ; get another character
  670.  
  671. asyrxint_exit:
  672. asyrxint_1:
  673.     mov    recv_buf_tail,di
  674.     mov    packet_sem, si
  675.  
  676.     ret
  677.  
  678.  
  679. ; --------------------------------------------------------------
  680. ;
  681. ;  recv_exiting
  682. ;
  683. recv_exiting:
  684.     assume    ds:nothing
  685.     pushf
  686.     cmp    recv_pkt_ready, 1       ; is a packet ready?
  687.     jne    recv_isr_exit           ; no - skip to end
  688.     push    ax
  689.     push    bx
  690.     push    cx
  691.     push    dx
  692.     push    ds
  693.     push    es
  694.     push    bp
  695.     push    di
  696.     push    si
  697.     movseg    ds,cs
  698.     assume    ds:code
  699.     mov    recv_pkt_ready,    0    ; reset flag
  700.     sti                ; enable interrupts
  701.  
  702.     call    recv_frame
  703.  
  704.     pop    si
  705.     pop    di
  706.     pop    bp
  707.     pop    es
  708.     pop    ds
  709.     pop    dx
  710.     pop    cx
  711.     pop    bx
  712.     pop    ax
  713. recv_isr_exit:
  714.     jmp    recv_exiting_exit
  715.  
  716.  
  717. ; --------------------------------------------------------------
  718. ;
  719. ;  recv_frame
  720. ;
  721. ; mod 7/25/89 John Grover
  722. ;
  723. ; - recv_frame now operates with interrupts on. It is triggered
  724. ; - by the recv_pkt_ready flag and continues until all bytes
  725. ; - in all packets in the buffer have been transmitted to the upper
  726. ; - layer.
  727. ;
  728. recv_frame_end:
  729.     dec    packet_sem
  730.     cmp    packet_sem, 0        ; are there more packets ready?
  731.     jnz    recv_frame              ; yes - execute again
  732.     ret
  733.  
  734.   ifdef debug
  735.     public recv_frame
  736.   endif
  737. recv_frame:
  738.     cmp    packet_sem, 0        ; should we do this?
  739.     jz    recv_frame_end        ; no - exit
  740.     mov    si,recv_buf_head    ;process characters.
  741.     xor    cx,cx            ;count up the size here.
  742.     cmp    raw_mode,0        ;raw mode?
  743.     je    recv_frame_1        ;no, interpret escapes, etc.
  744.     cmp    si,recv_buf_tail    ;any more characters?
  745.     je    recv_frame_end
  746. recv_frame_raw_1:
  747.     inc    cx            ;count a character.
  748.     call    recv_char
  749.     cmp    si,recv_buf_tail
  750.     jne    recv_frame_raw_1
  751.     jmp    short recv_frame_2    ;we have the count here.
  752. recv_frame_1:
  753.  
  754.     call    recv_char        ;get a char.
  755.     je    recv_frame_2        ;go if no more chars.
  756.     cmp    al,FR_ESC        ;an escape?
  757.     je    recv_frame_1        ;yes - don't count this char.
  758. recv_frame_7:
  759.     inc    cx            ;no - count this one.
  760.     jmp    recv_frame_1
  761. recv_frame_2:
  762.  
  763.     jcxz    recv_frame_3        ;count zero? yes - free the frame
  764.   if    ETHERSLIP
  765. ;
  766. ; Add Ethernet header.  As well, ensure that minimum packet size is 60
  767. ; bytes; some application packages actually check for minimum packet size.
  768. ;
  769.     cmp    raw_mode,0        ;in raw mode, we don't fake Ethernet.
  770.     jne    recv_next
  771.     add    cx,14 
  772.     cmp    cx, 60
  773.     jge     recv_next
  774.     mov    cx, 60    
  775. ;
  776. recv_next:
  777.   else
  778. ; we don't need to set the type because none are defined for SLIP.
  779.   endif
  780.     push    cx            ;save the count.
  781.     push    si            ;save si in case we reject it.
  782.     push    bx
  783.   if    ETHERSLIP
  784.     movseg    es,cs
  785.     mov    di,offset ip_type
  786.   else
  787.     MOV    DI,CS
  788.     MOV    ES,DI
  789.     mov    di,0
  790.   endif
  791.     mov    dl,cs:driver_class
  792.     call    recv_find        ;look up our type.
  793.     pop    bx
  794.     pop    si
  795.     pop    cx
  796.  
  797.     mov    ax,es            ;is this pointer null?
  798.     or    ax,di
  799.     je    recv_frame_3        ;yes - just free the frame.
  800.  
  801.     push    cx
  802.     push    es            ;remember where the buffer pointer is
  803.     push    di
  804.   if    ETHERSLIP
  805. ;
  806. ; Fix up the Ethernet header added to the incoming packet.
  807. ;
  808.     call    fix_header
  809.   endif
  810.  
  811.     mov    si,recv_buf_head    ;process characters.
  812.     cmp    raw_mode,0        ;raw mode?
  813.     je    recv_frame_4        ;no, interpret characters.
  814. recv_frame_raw_2:
  815.     call    recv_char        ;get a character.
  816.     stosb                ;store it.
  817.     loop    recv_frame_raw_2    ;get another.
  818.     jmp    short recv_frame_6    ;all done.
  819. recv_frame_4:
  820.     call    recv_char
  821.     je    recv_frame_6        ;yes - we're all done.
  822.     cmp    al,FR_ESC        ;an escape?
  823.     jne    recv_frame_5        ;no - just store it.
  824.  
  825.     call    recv_char        ;get the next character.
  826.     je    recv_frame_6
  827.     cmp    al,T_FR_ESC
  828.     mov    al,FR_ESC        ;assume T_FR_ESC
  829.     je    recv_frame_5        ;yup, that's it    - store FR_ESC
  830.     mov    al,FR_END        ;nope, store FR_END
  831. recv_frame_5:
  832.     stosb                ;store the byte.
  833.     jmp    recv_frame_4
  834. recv_frame_6:
  835.     mov    recv_buf_head,si    ;we're skipped to the end.
  836.  
  837.     pop    si            ;now give the frame to the client.
  838.     pop    ds
  839.     pop    cx
  840.     assume    ds:nothing
  841.  
  842.     call    recv_copy
  843.     movseg    ds,cs
  844.     assume    ds:code
  845.     jmp    recv_frame_end
  846.  
  847. recv_frame_3:
  848.     mov    recv_buf_head,si    ;remember the new starting point.
  849.     jmp    recv_frame_end
  850.  
  851.  
  852. ; --------------------------------------------------------------
  853. ;
  854. ;  recv_char
  855. ;
  856. ; mod 7/25/89 John Grover
  857. ; - Now    uses buffer pointers to determine if there are
  858. ; - characters left.
  859. ;
  860.  
  861. recv_char:
  862. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  863. ;return with nz, al = next char.  Return zr if there are no more chars in
  864. ;  this frame.
  865. ;
  866.     lodsb
  867.     cmp    si,recv_buf_end
  868.     jb    recv_char_1
  869.     mov    si,recv_buf
  870. recv_char_1:
  871.     cmp    si, recv_buf_tail
  872.     je    recv_char_2
  873.     cmp    al,FR_END
  874. recv_char_2:
  875.     ret
  876.   if    ETHERSLIP
  877. ;
  878. ; Set destination and source addressess and packet type in an
  879. ; Ethernet header.
  880. ;
  881. fix_header:
  882. ;
  883. ; Set destination address.
  884. ;
  885.     mov    ax,0000h
  886.     stosw
  887.     mov    ax,0c3c4h
  888.     stosw
  889.     mov    ax,0c2cch
  890.     stosw
  891. ;
  892. ; Set source address.
  893. ;
  894.     mov    ax,0201h
  895.     stosw
  896.     mov    ax,0403h
  897.     stosw
  898.     mov    ax,0605h
  899.     stosw
  900. ;
  901. ; Set packet type to IP.
  902. ;
  903.     mov    ax, 0008h
  904.     stosw    
  905.     ret
  906.   endif
  907.  
  908. ;Set bit(s) in I/O port
  909. setbit:
  910. ;enter with dx = port, ah = bit to set.
  911.     in    al,dx
  912.     or    al,ah
  913.     out    dx,al
  914.     ret
  915.  
  916.  
  917. ;Clear bit(s) in I/O port
  918. clrbit:
  919. ;enter with dx = port, ah = bit to set.
  920.     in    al,dx
  921.     not    al            ;perform an and-not using DeMorgan's.
  922.     or    al,ah
  923.     not    al
  924.     out    dx,al
  925.     ret
  926.  
  927.  
  928.     public    timer_isr
  929. timer_isr:
  930. ;if the first instruction is an iret, then the timer is not hooked
  931.     iret
  932.  
  933. ;any code after this will not be kept after initialization. Buffers
  934. ;used by the program, if any, are allocated from the memory between
  935. ;end_resident and end_free_mem.
  936.     public end_resident,end_free_mem
  937. end_resident    label    byte
  938.     db    3000 dup(?)
  939. end_free_mem    label    byte
  940.  
  941.     public    usage_msg
  942.   if    ETHERSLIP
  943. usage_msg    db    "usage: ETHERSLIP [options] <packet_int_no> [-h] [hardware_irq]",CR,LF
  944.         db    "   [io_addr] [baud_rate]",CR,LF
  945.         db    "   [send_buf_size] [recv_buf_size]",CR,LF
  946.         db    "   -h enables hardware handshaking",CR,LF,'$'
  947.  
  948.     public    copyright_msg
  949. copyright_msg    db    "Packet driver for ETHERSLIP, version ",'0'+(majver / 10),'0'+(majver mod 10),"."
  950.         db    '0'+version,CR,LF
  951.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  952.         db    "Portions Copyright 1991 Michael Martineau",CR,LF
  953.         db    " 5 Nov 1991",cr,lf,'$'
  954.   else
  955. usage_msg    db    "usage: SLIP8250 [options] <packet_int_no> "
  956.         db    "[-h] [driver_class] [hardware_irq]",CR,LF
  957.         db    "   [io_addr] [baud_rate]",CR,LF
  958.         db    "   [recv_buf_size]",CR,LF
  959.         db    "   -h enables hardware handshaking",CR,LF
  960.         db    "   The driver_class should be SLIP, KISS, AX.25,"
  961.         db    " or a number.",CR,LF,'$'
  962.  
  963.     public    copyright_msg
  964. copyright_msg    db    "Packet driver for SLIP8250, version "
  965.         db    '0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  966.         db    "Portions Copyright 1988 Phil Karn",CR,LF
  967.         db    "Portions Copyright 1991 Joe Doupnik",CR,LF
  968.                 db      "Hardware flow-control mods by Philip R. Burns",CR,LF
  969.         db    "Portions Copyright 1992 Crynwr Software",CR,LF,'$'
  970.   endif
  971.  
  972. approximate_msg    db    "Warning: This baud rate can only be approximated"
  973.         db    "using the 8250",CR,LF
  974.         db    "because it is not an even divisor of 115200"
  975.         db    CR,LF,'$'
  976.  
  977. is_16550_msg    db      "16550 Uart detected, FIFO will be used",CR,LF,'$'
  978.  
  979. no_memory_msg    db    "Unable to allocate enough memory, look at end_resident in SLIP8250.ASM",CR,LF,'$'
  980.  
  981. class_name_ptr    dw    ?
  982. class_name    db    "Interface class ",'$'
  983.   if ETHERSLIP
  984.   else
  985. kiss_name    db    "KISS",CR,LF,'$'
  986. ax25_name    db    "AX.25",CR,LF,'$'
  987. slip_name    db    "SLIP",CR,LF,'$'
  988.   endif
  989. int_no_name    db    "Interrupt number ",'$'
  990. io_addr_name    db    "I/O port ",'$'
  991. baud_rate_name    db    "Baud rate ",'$'
  992. recv_buf_name    db    "Receive buffer size ",'$'
  993. unusual_com1    db    "That's unusual!  Com1 (0x3f8) usually uses IRQ 4!"
  994.         db    CR,LF,'$'
  995. unusual_com2    db    "That's unusual!  Com2 (0x2f8) usually uses IRQ 3!"
  996.         db    CR,LF,'$'
  997.  
  998.     extrn    set_recv_isr: near
  999.     extrn    maskint: near
  1000.  
  1001. ;enter with si -> argument string, di -> word to store.
  1002. ;if there is no number, don't change the number.
  1003.     extrn    get_number: near
  1004.  
  1005. ;enter with dx -> name of word, di -> dword to print.
  1006.     extrn    print_number: near
  1007.  
  1008. ;enter with si -> argument string.
  1009. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  1010.     extrn    skip_blanks: near
  1011.  
  1012.  
  1013. ;-> the assigned Ethernet address of the card.
  1014.     extrn    rom_address: byte
  1015.  
  1016.     public    parse_args
  1017. parse_args:
  1018. ;exit with nc if all went well, cy otherwise.
  1019.     call    skip_blanks
  1020.     cmp    al,'-'            ;did they specify a switch?
  1021.     jne    not_switch
  1022.     cmp    byte ptr [si+1],'h'    ;did they specify '-h'?
  1023.     je    got_hardware_switch
  1024.     stc                ;no, must be an error.
  1025.     ret
  1026. got_hardware_switch:
  1027.     mov    hardware_switch,1
  1028.     add    si,2            ;skip past the switch's characters.
  1029.     jmp    parse_args        ;go parse more arguments.
  1030. not_switch:
  1031.   if ETHERSLIP
  1032.   else
  1033.     or    al,20h            ; to lower case (assuming letter)
  1034.     cmp    al,'k'
  1035.     jne    parse_args_2
  1036.     mov    driver_class,10        ;KISS, from packet spec
  1037.     mov    dx,offset kiss_name
  1038.     jmp    short parse_args_1
  1039. parse_args_2:
  1040.     cmp    al,'s'
  1041.     jne    parse_args_3
  1042.     mov    driver_class,6        ;SLIP, from packet spec
  1043.     mov    dx,offset slip_name
  1044.     jmp    short parse_args_1
  1045. parse_args_3:
  1046.     cmp    al,'a'
  1047.     jne    parse_args_4
  1048.     mov    driver_class,9        ;AX.25, from packet spec.
  1049.     mov    dx,offset ax25_name
  1050.     jmp    short parse_args_1
  1051. parse_args_4:
  1052.     mov    di,offset driver_class
  1053.     mov    bx,offset class_name
  1054.     call    get_number
  1055.     mov    class_name_ptr,0
  1056.     jmp    short parse_args_6
  1057. parse_args_1:
  1058.     mov    class_name_ptr,dx
  1059. parse_args_5:
  1060.     mov    al,[si]            ;skip to the next blank or CR.
  1061.     cmp    al,' '
  1062.     je    parse_args_6
  1063.     cmp    al,CR
  1064.     je    parse_args_6
  1065.     inc    si            ;skip the character.
  1066.     jmp    parse_args_5
  1067. parse_args_6:
  1068.   endif
  1069.     mov    di,offset int_no
  1070.     call    get_number
  1071.     mov    di,offset io_addr
  1072.     call    get_number
  1073.     mov    di,offset baud_rate
  1074.     call    get_number
  1075.     mov    di,offset recv_buf_size
  1076.     call    get_number
  1077.     clc
  1078.     ret
  1079.  
  1080.  
  1081. ; --------------------------------------------------------------
  1082. ;
  1083. ;  etopen
  1084. ;
  1085. ; mod 7/25/89 John Grover
  1086. ; - Contains a loop to determine a pseudo timeout for asyrxint.
  1087. ; - The value is determined by transmitting characters in a
  1088. ; - loop whose clock cycles are nearly the same as the "sister"
  1089. ; - loop in asyrxint. The per character, maximum time used
  1090. ; - basis which is then multiplied by a factor to achieve a timeout
  1091. ; - value for the particular bps and CPU speed of the host.
  1092.  
  1093.     public    etopen
  1094. etopen:
  1095.     mov    al,int_no
  1096.     call    maskint            ;disable these interrupts.
  1097.  
  1098.   if ETHERSLIP
  1099. ;
  1100. ; Pseudo-Ethernet address to return when get_address() is called.
  1101. ;
  1102.     mov    word ptr rom_address[0],2*256+0    ;locally assigned
  1103.     mov    word ptr rom_address[2],0*256+12h
  1104.     mov    word ptr rom_address[4],34h*256+56h
  1105.   endif
  1106.  
  1107. ;
  1108. ; mod  3/16/90  Denis DeLaRoca
  1109. ; - determine if 16550 uart is present
  1110. ; - if so initialize fifo buffering
  1111. ;
  1112.     loadport
  1113.     setport    FCR
  1114.     mov    al,FIFO_ENABLE
  1115.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_ENABLE)
  1116.     setport    IIR
  1117.     in    al,dx                   ;inportb(base+IIR)
  1118.     and    al,IIR_FIFO_ENABLED     ;     & IIR_FIFO_ENABLED
  1119.     cmp    al,IIR_FIFO_ENABLED    ;both bits must be on   NEW, 11/20/90
  1120.     jnz    not_16550               ;nope, we don't have 16550 chip
  1121.     mov    is_16550,1              ;yes, note fact
  1122.     mov    al,FIFO_SETUP           ;and setup FIFO
  1123.     setport    FCR
  1124.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_SETUP)
  1125.  
  1126.     mov    dx,offset is_16550_msg
  1127.     mov    ah,9
  1128.     int    21h            ;let user know about 16550
  1129.  
  1130. not_16550:
  1131.     loadport            ;Purge the receive data buffer
  1132.     setport    RBR
  1133.     in    al,dx
  1134.  
  1135.     ;Set line control register: 8 bits, no parity
  1136.     mov    al,LCR_8BITS
  1137.     setport    LCR
  1138.     out    dx,al
  1139.  
  1140.     ;Turn on receive interrupt enable in 8250, leave transmit
  1141.     ; and modem status interrupts turned off for now
  1142.     mov    al,IER_DAV
  1143.     setport    IER
  1144.     out    dx,al
  1145.  
  1146.     ;Set modem control register: assert DTR, RTS, turn on 8250
  1147.     ; master interrupt enable (connected to OUT2)
  1148.  
  1149.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  1150.     setport    MCR
  1151.     out    dx,al
  1152.  
  1153. ;compute the divisor given the baud rate.
  1154.     mov    dx,baudclk+2
  1155.     mov    ax,baudclk
  1156.     mov    bx,0
  1157. asy_speed_1:
  1158.     inc    bx
  1159.     sub    ax,baud_rate
  1160.     sbb    dx,baud_rate+2
  1161.     jnc    asy_speed_1
  1162.     dec    bx
  1163.     add    ax,baud_rate
  1164.     adc    dx,baud_rate+2
  1165.     or    ax,dx
  1166.     je    asy_speed_2
  1167.  
  1168.     mov    dx,offset approximate_msg
  1169.     mov    ah,9
  1170.     int    21h
  1171.  
  1172. asy_speed_2:
  1173.  
  1174.     loadport            ;Purge the receive data buffer
  1175.     setport    RBR
  1176.     in    al,dx
  1177.  
  1178.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  1179.     setport    LCR
  1180.     call    setbit
  1181.  
  1182.     mov    al,bl            ;Load the two bytes of the divisor.
  1183.     setport    DLL
  1184.     out    dx,al
  1185.     mov    al,bh
  1186.     setport    DLM
  1187.     out    dx,al
  1188.  
  1189.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  1190.     setport    LCR
  1191.     call    clrbit
  1192.  
  1193. ;set up the various pointers.
  1194.  
  1195.     mov    dx,recv_buf_size
  1196.     call    malloc
  1197.     jnc    have_memory
  1198.     mov    dx,offset no_memory_msg
  1199.     stc
  1200.     ret
  1201. have_memory:
  1202.     mov    recv_buf,dx
  1203.     mov    recv_buf_head,dx
  1204.     mov    recv_buf_tail,dx
  1205.     add    dx,recv_buf_size
  1206.     mov    recv_buf_end,dx
  1207.  
  1208.     ; the following code attempts to determine a pseudo timeout
  1209.     ; value    to use in the loop that waits for an incoming character
  1210.     ; in asyrxint. The value returned in xmit_time is the number of
  1211.     ; loops processed between characters - therefore the loop used below
  1212.     ; is and should    remain similar to the loop used in asyrxint.
  1213.  
  1214.     xor    ax, ax            ; we'll send a 0
  1215.     mov    ah, LSR_THRE
  1216.     mov    cx, 10h            ; take the highest of 16 runs
  1217.     xor    si, si            ; will hold highest value
  1218.  
  1219. xmit_time_start:
  1220.  
  1221.     xor    di, di            ; initialize counter
  1222.     loadport
  1223.     setport    THR            ; xmit a character
  1224.     out    dx, al
  1225.     setport    LSR               ; set up    to check for an empty buffer
  1226.  
  1227.     ; next is the loop actually being timed
  1228.  
  1229. xmit_time_top:
  1230.     in    al, dx
  1231.     test    al, ah
  1232.     jnz    xmit_time_done
  1233.     inc    di
  1234.     cmp    cx, cx            ; these next few instructions do nothing
  1235.     jmp    xmit_time_1        ;  except maintain similarity with the
  1236.                     ;  "sister" loop in asyrxint
  1237. xmit_time_1:
  1238.     jmp    xmit_time_top
  1239.  
  1240. xmit_time_done:                ; end of timed loop
  1241.  
  1242.  
  1243.  
  1244.     cmp    si, di            ; compare highest value with new value
  1245.     ja    xmit_time_end        ; no bigger - just loop
  1246.     mov    si, di            ; bigger - save it
  1247.  
  1248. xmit_time_end:
  1249.     loop    xmit_time_start        ; bottom of outer loop
  1250.  
  1251.     shl    si, 1            ; we'll wait 8 characters worth
  1252.     shl    si, 1
  1253.     shl    si, 1
  1254.     mov    xmit_time, si        ; retain largest value
  1255.  
  1256.     ; end of pseudo timer determination
  1257.  
  1258.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  1259.  
  1260.     mov    al, int_no        ; Get board's interrupt vector
  1261.     add    al, 8
  1262.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1263.     jb    set_int_num        ; No.
  1264.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1265. set_int_num:
  1266.     xor    ah, ah            ; Clear high byte
  1267.     mov    int_num, ax        ; Set parameter_list int num.
  1268.  
  1269.     clc                ;indicate no errors.
  1270.     ret
  1271.  
  1272.     public    print_parameters
  1273. print_parameters:
  1274. ;echo our command-line parameters
  1275.     cmp    class_name_ptr,0
  1276.     je    echo_args_1
  1277.  
  1278.     mov    dx,offset class_name
  1279.     mov    ah,9
  1280.     int    21h
  1281.     mov    dx,class_name_ptr
  1282.     mov    ah,9
  1283.     int    21h
  1284.     jmp    short echo_args_2
  1285. echo_args_1:
  1286.     mov    di,offset driver_class
  1287.     mov    dx,offset class_name
  1288.     call    print_number
  1289. echo_args_2:
  1290.  
  1291.     mov    di,offset int_no
  1292.     mov    dx,offset int_no_name
  1293.     call    print_number
  1294.     mov    di,offset io_addr
  1295.     mov    dx,offset io_addr_name
  1296.     call    print_number
  1297.  
  1298.     cmp    io_addr,03f8h        ;is this com1?
  1299.     jne    ia_com2
  1300.     mov    dx,offset unusual_com1
  1301.     cmp    int_no,4        ;com1 usually uses IRQ 4.
  1302.     jne    ia_unusual
  1303.     jmp    short ia_usual
  1304. ia_com2:
  1305.     cmp    io_addr,02f8h        ;is this com2?
  1306.     jne    ia_usual        ;no.
  1307.     mov    dx,offset unusual_com2
  1308.     cmp    int_no,3        ;com2 usually uses IRQ 3.
  1309.     je    ia_usual
  1310. ia_unusual:
  1311.     mov    ah,9
  1312.     int    21h
  1313. ia_usual:
  1314.     mov    di,offset baud_rate
  1315.     mov    dx,offset baud_rate_name
  1316.     call    print_number
  1317.     mov    di,offset recv_buf_size
  1318.     mov    dx,offset recv_buf_name
  1319.     call    print_number
  1320.     ret
  1321. code    ends
  1322.     end
  1323.  
  1324.