home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / new / slip8250.asm < prev    next >
Assembly Source File  |  1992-02-10  |  25KB  |  992 lines

  1. version    equ    6
  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. ; Stopped failures from lost transmit interrupts (by eliminating the ints
  10. ; altogether). Remove unneeded transmitter buffer.
  11. ; Version 6 by Joe Doupnik, jrd@cc.usu.edu, Utah State University, Dec 1991.
  12.  
  13. ;  Copyright, 1988, 1991, Russell Nelson
  14.  
  15. ;   This program is free software; you can redistribute it and/or modify
  16. ;   it under the terms of the GNU General Public License as published by
  17. ;   the Free Software Foundation, version 1.
  18. ;
  19. ;   This program is distributed in the hope that it will be useful,
  20. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22. ;   GNU General Public License for more details.
  23. ;
  24. ;   You should have received a copy of the GNU General Public License
  25. ;   along with this program; if not, write to the Free Software
  26. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27.  
  28. code    segment    word public
  29.     assume    cs:code, ds:code
  30.  
  31. ;8250 definitions
  32. ;Control/status register offsets from base address
  33. THR    equ    0        ;Transmitter holding register
  34. RBR    equ    0        ;Receiver buffer register
  35. DLL    equ    0        ;Divisor latch LSB
  36. DLM    equ    1        ;Divisor latch MSB
  37. IER    equ    1        ;Interrupt enable register
  38. IIR    equ    2        ;Interrupt ident register
  39. FCR    equ    2        ;16550 FIFO control register
  40. LCR    equ    3        ;Line control register
  41. MCR    equ    4        ;Modem control register
  42. LSR    equ    5        ;Line status register
  43. MSR    equ    6        ;Modem status register
  44.  
  45. ;8250 Line Control Register
  46. LCR_5BITS    equ    0    ;5 bit words
  47. LCR_6BITS    equ    1    ;6 bit words
  48. LCR_7BITS    equ    2    ;7 bit words
  49. LCR_8BITS    equ    3    ;8 bit words
  50. LCR_NSB        equ    4    ;Number of stop bits
  51. LCR_PEN        equ    8    ;Parity enable
  52. LCR_EPS        equ    10h    ;Even parity select
  53. LCR_SP        equ    20h    ;Stick parity
  54. LCR_SB        equ    40h    ;Set break
  55. LCR_DLAB    equ    80h    ;Divisor Latch Access Bit
  56.  
  57. ;16550 FIFO control register values
  58. FIFO_ENABLE     equ     001h    ;Enable TX and RX fifo
  59. FIFO_CLR_RX     equ     002h    ;Clear RX fifo
  60. FIFO_CLR_TX     equ     004h    ;Clear TX fifo
  61. FIFO_START_DMA  equ     008h    ;Enable TXRDY/RXRDY pin DMA handshake
  62. FIFO_SIZE_1     equ     000h    ;RX fifo trigger levels
  63. FIFO_SIZE_4     equ     040h
  64. FIFO_SIZE_8     equ     080h
  65. FIFO_SIZE_14    equ     0c0h
  66. FIFO_SIZE_MASK  equ     0c0h
  67.  
  68. FIFO_TRIGGER_LEVEL equ FIFO_SIZE_4
  69. FIFO_SETUP         equ FIFO_ENABLE+FIFO_CLR_RX+FIFO_CLR_TX+FIFO_TRIGGER_LEVEL
  70. OUTPUT_FIFO_SIZE   equ 16
  71.  
  72. ;8250 Line Status Register
  73. LSR_DR    equ    1    ;Data ready
  74. LSR_OE    equ    2    ;Overrun error
  75. LSR_PE    equ    4    ;Parity error
  76. LSR_FE    equ    8    ;Framing error
  77. LSR_BI    equ    10h    ;Break interrupt
  78. LSR_THRE equ    20h    ;Transmitter line holding register empty
  79. LSR_TSRE equ    40h    ;Transmitter shift register empty
  80.  
  81. ;8250 Interrupt Identification Register
  82. IIR_IP        equ    1    ;0 if interrupt pending
  83. IIR_ID        equ    6    ;Mask for interrupt ID
  84. IIR_RLS        equ    6    ;Receiver Line Status interrupt
  85. IIR_RDA        equ    4    ;Receiver data available interrupt
  86. IIR_THRE    equ    2    ;Transmitter holding register empty int
  87. IIR_MSTAT    equ    0    ;Modem status interrupt
  88. IIR_FIFO_TIMEOUT  equ   008h    ;FIFO timeout interrupt pending - 16550 only
  89. IIR_FIFO_ENABLED  equ   080h    ;FIFO enabled (FCR0 = 1) - 16550 only
  90.  
  91. ;8250 interrupt enable register bits
  92. IER_DAV    equ    1    ;Data available interrupt
  93. IER_TxE    equ    2    ;Tx buffer empty interrupt
  94. IER_RLS    equ    4    ;Receive line status interrupt
  95. IER_MS    equ    8    ;Modem status interrupt
  96.  
  97. ;8250 Modem control register
  98. MCR_DTR    equ    1    ;Data Terminal Ready
  99. MCR_RTS    equ    2    ;Request to Send
  100. MCR_OUT1 equ    4    ;Out 1 (not used)
  101. MCR_OUT2 equ    8    ;Master interrupt enable (actually OUT 2)
  102. MCR_LOOP equ    10h    ;Loopback test mode
  103.  
  104. ;8250 Modem Status Register
  105. MSR_DCTS equ    1    ;Delta Clear-to-Send
  106. MSR_DDSR equ    2    ;Delta Data Set Ready
  107. MSR_TERI equ    4    ;Trailing edge ring indicator
  108. MSR_DRLSD equ    8    ;Delta Rx Line Signal Detect
  109. MSR_CTS equ    10h    ;Clear to send
  110. MSR_DSR equ    20h    ;Data set ready
  111. MSR_RI    equ    40h    ;Ring indicator
  112. MSR_RLSD equ    80h    ;Received line signal detect
  113.  
  114. ;Slip Definitions
  115. FR_END        equ    0c0h        ;Frame End
  116. FR_ESC        equ    0dbh        ;Frame Escape
  117. T_FR_END    equ    0dch        ;Transposed frame end
  118. T_FR_ESC    equ    0ddh        ;Transposed frame escape
  119.  
  120.     public    int_no
  121. int_no        db    4,0,0,0        ; interrupt number.
  122. io_addr        dw    03f8h,0        ; I/O address for COM1
  123. baud_rate    dw    12c0h,0        ; support baud higher than 65535
  124. baudclk        label    word
  125.         dd    115200        ; 1.8432 Mhz / 16
  126. hardware_switch    db    0        ; if zero, don't use hw handshaking
  127. is_16550        db      0               ; 0=no, 1=yes (try using fifo)
  128.  
  129.     public    driver_class, driver_type, driver_name 
  130.     public    driver_function, parameter_list
  131. driver_class    db    6,0,0,0        ;from the packet spec
  132. driver_type    db    0,0,0,0        ;from the packet spec
  133. driver_name    db    'SLIP8250',0    ;name of the driver.
  134. driver_function    db    2
  135. parameter_list    label    byte
  136.     db    1    ;major rev of packet driver
  137.     db    9    ;minor rev of packet driver
  138.     db    14    ;length of parameter list
  139.     db    EADDR_LEN    ;length of MAC-layer address
  140.     dw    GIANT    ;MTU, including MAC headers
  141.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  142.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  143.     dw    0    ;(# of successive xmits) - 1
  144. int_num    dw    0    ;Interrupt # to hook for post-EOI
  145.             ;processing, 0 == none,
  146.  
  147.   ifdef debug
  148.     public recv_buf_size, recv_buf,    recv_buf_end, recv_buf_head
  149.     public recv_buf_tail, recv_pkt_ready
  150.   endif
  151. recv_buf_size    dw    3000,0        ;receive buffer size
  152. recv_buf    dw    ?        ;->receive buffer
  153. recv_buf_end    dw    ?        ;->after end of buffer
  154. recv_buf_head    dw    ?        ;->next character to get
  155. recv_buf_tail    dw    ?        ;->next character to store
  156. recv_pkt_ready    dw    0        ; flag indicating a packet is ready
  157. IP_TYPE    DW    0800H
  158.  
  159.   ifdef debug
  160.     public packet_sem, xmit_time
  161.   endif
  162. packet_sem    dw    0        ; semaphore for    packets received
  163. asyrxint_cnt    dw    0        ; loop counter in asyrxint
  164. xmit_time    dw    0        ; loop timer for asyrxint
  165.  
  166.     public    rcv_modes
  167. rcv_modes    dw    4        ;number    of receive modes in our table
  168.         dw    0,0,0,rcv_mode_3
  169.  
  170.  
  171.     public    as_send_pkt
  172. ; The Asynchronous Transmit Packet routine.
  173. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  174. ;   interrupts possibly enabled.
  175. ; Exit with nc if ok, or else cy if error, dh set to error number.
  176. ;   es:di and interrupt enable flag preserved on exit.
  177. as_send_pkt:
  178.     ret
  179.  
  180.     public    drop_pkt
  181. ; Drop a packet from the queue.
  182. ; Enter with es:di -> iocb.
  183. drop_pkt:
  184.     assume    ds:nothing
  185.     ret
  186.  
  187.     public    xmit
  188. ; Process a transmit interrupt with the least possible latency to achieve
  189. ;   back-to-back packet transmissions.
  190. ; May only use ax and dx.
  191. xmit:
  192.     assume    ds:nothing
  193.     ret
  194.  
  195.  
  196.     public    send_pkt
  197. ;
  198. ; mod 7/25/89 John Grover
  199. ; - operates with interrupts on. Xmits one byte per interrupt
  200. ; - only turns transmitter buffer empty interrupt off when
  201. ; - all bytes of all packets are transmitted.
  202.  
  203. send_pkt:
  204. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  205. ;  (only if the high-performance bit is set in driver_function)
  206.  
  207. ;enter with ds:si -> packet, cx = packet length.
  208. ;exit with nc if ok, or else cy if error, dh set to error number.
  209. ;called from telnet layer via software interrupt
  210. ; We just send each byte in turn. No UART interrupts are needed nor wanted.
  211. ; In fact the overdone receiver material omits to note that xmtr interrupts
  212. ; can be lost while processing rcvr ones. Small benefits are no stalled
  213. ; programs, no transmitter buffer, no problems at 19200 b/s. Joe Doupnik
  214.     assume    ds:nothing, es:nothing
  215.     sti                ; enable interrupts
  216.     cld
  217.     mov    al,FR_END        ; Flush out any line garbage
  218.     call    send_char
  219.     jc    send_pkt_end        ; c = failure to send
  220.  
  221. ;Copy input to output, escaping special characters
  222. send_pkt_1:
  223.     lodsb
  224.     cmp    al,FR_ESC      ; escape FR_ESC with FR_ESC and T_FR_ESC
  225.     jne    send_pkt_2
  226.     mov    al,FR_ESC
  227.     call    send_char
  228.     jc    send_pkt_end
  229.     mov    al,T_FR_ESC
  230.     jmp    short send_pkt_3
  231. send_pkt_2:
  232.     cmp    al,FR_END      ; escape FR_END with FR_ESC and T_FR_END
  233.     jne    send_pkt_3
  234.     mov    al,FR_ESC
  235.     call    send_char
  236.     jc    send_pkt_end
  237.     mov    al,T_FR_END
  238. send_pkt_3:
  239.     call    send_char
  240.     jc    send_pkt_end
  241.     loop    send_pkt_1        ; do cx user characters
  242.     mov    al,FR_END        ; terminate it with a FR_END
  243.     call    send_char
  244.     jc    send_pkt_end
  245.     clc
  246. send_pkt_end:
  247.     ret
  248.  
  249. ; mod 7/25/89 John Grover
  250. ; redone by Joe Doupnik, Dec 1991
  251.     assume    ds:nothing, es:nothing
  252. send_char:                ; send the character in al
  253.     push    dx
  254.     push    cx
  255.     xchg    ah,al            ; put data char into ah
  256.     xor    cx,cx            ; 64K retry counter
  257. sendch1:mov    dx,io_addr        ; 03f8h base address
  258.     add    dx,LSR            ; 03fdh get port status
  259.     in    al,dx
  260.     test    al,LSR_THRE        ; Transmitter (THRE) ready?
  261.     jnz    sendch2            ; nz = yes
  262.     jmp    $+2            ; use time, prevent overdriving UART
  263.     jmp    $+2
  264.     loop    sendch1
  265.     stc                ; carry set for failure
  266.     jmp    short sendch3        ; timeout
  267. sendch2:xchg    al,ah            ; now send it
  268.     mov    dx,io_addr        ; 03f8h, use a little time
  269.     jmp    $+2
  270.     out    dx,al            ; send the byte
  271.     clc                ; status of success
  272. sendch3:pop    cx
  273.     pop    dx
  274.     ret
  275.  
  276.  
  277.     public    get_address
  278. get_address:
  279. ;get the address of the interface.
  280. ;enter with es:di -> place to get the address, cx = size of address buffer.
  281. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  282.     assume    ds:code
  283.     xor    cx,cx
  284.     clc
  285.     ret
  286.  
  287.  
  288.     public    set_address
  289. set_address:
  290. ;set the address of the interface.
  291. ;enter with es:di -> place to get the address, cx = size of address buffer.
  292. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  293.     assume    ds:nothing
  294.     clc
  295.     ret
  296.  
  297.  
  298. rcv_mode_3:
  299. ;receive mode 3 is the only one we support, so we don't have to do anything.
  300.     ret
  301.  
  302.  
  303.     public    set_multicast_list
  304. set_multicast_list:
  305. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  306. ;return nc if we set all of them, or cy,dh=error if we didn't.
  307.     mov    dh,NO_MULTICAST
  308.     stc
  309.     ret
  310.  
  311.  
  312.     public    get_multicast_list
  313. get_multicast_list:
  314. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  315. ;return    cy, NO_ERROR if we don't remember all of the addresses ourselves.
  316. ;return cy, NO_MULTICAST if we don't implement multicast.
  317.     mov    dh,NO_MULTICAST
  318.     stc
  319.     ret
  320.  
  321.  
  322.     public    terminate
  323. terminate:
  324.     ret
  325.  
  326.     public    reset_interface
  327. reset_interface:
  328. ;reset the interface.
  329.     assume    ds:code
  330.     ret
  331.  
  332.  
  333. ;called    when we    want to determine what to do with a received packet.
  334. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  335.     extrn    recv_find: near
  336.  
  337. ;called after we have copied the packet into the buffer.
  338. ;enter with ds:si ->the packet, cx = length of the packet.
  339.     extrn    recv_copy: near
  340.  
  341.     extrn    count_in_err: near
  342.     extrn    count_out_err: near
  343.  
  344.     public    recv
  345.  
  346. ;
  347. ; mod 7/25/89 John Grover
  348. ;
  349. ; - added code to check modem status change interrupt. If CTS is
  350. ; - low  turn off transmitter buffer empty interrupt. If CTS is
  351. ; - high turn it on.
  352.  
  353. recv:
  354. ;called from the recv isr.  All registers have been saved, and ds=cs.
  355. ;Upon exit, the interrupt will be acknowledged.
  356.     assume    ds:code
  357. recv_2:
  358.     loadport
  359.     setport    IIR
  360.     in    al,dx            ;any interrupts at all?
  361.     test    al,IIR_IP
  362.     jne    recv_1            ;no.
  363.     and    al,IIR_ID
  364.     cmp    al,IIR_RDA        ;Receiver interrupt
  365.     jne    recv_3
  366.     call    asyrxint
  367.     jmp    recv_2
  368. recv_3:
  369. recv_5:
  370. ;process IIR_MSTAT here.
  371. ;  If CTS and packet ready then
  372. ;    enable the    transmit buffer empty interrupt
  373. ;  else
  374. ;    disable the transmit buffer empty interrupt
  375. ;
  376.     cmp    al, IIR_MSTAT
  377.     jne    recv_1
  378.     setport    MSR            ; make sure of CTS status
  379.     in    al, dx
  380. ;    test    al, MSR_CTS        ; is CTS bit set
  381. ;    jz    recv_5_1        ; no - disable xmit buffer empty int
  382.     jmp    recv_2
  383.  
  384. recv_5_1:
  385.     jmp    recv_2
  386.  
  387. ;process IIR_RLS here
  388. recv_1:
  389.     ret
  390.  
  391.  
  392. ;Process 8250 receiver interrupts
  393. ;
  394. ; mod 7/25/89 John Grover
  395. ; - this branches off when bps < 9600. See asyrxint_a.
  396. ; - Above 9600 bps we go into a loop to process a packet at
  397. ; - a time. If not data ready for a certain amount of time,
  398. ; - the process exits and waits for the next byte. This certain
  399. ; - amount of time to wait depends on the bps and CPU processor speed
  400. ; - and is determined in the initialization of the driver.
  401. ; - Upon receiving the FR_END character for the first frame in the
  402. ; - buffer a semaphore is set which tells recv_frame to run.
  403.  
  404. asyrxint:
  405.  
  406.     push    ds            ; get set up for the routine
  407.     pop    es
  408.     xor    bx, bx
  409.     cmp    baud_rate, 9600         ; below 9600 we're strictly
  410.     jbe    asyrxint_a              ; interrupt driven
  411.     mov    bx, xmit_time
  412. asyrxint_a:
  413.     mov    di,recv_buf_tail
  414.     xor    bp, bp            ; set flag to indicate 1st char
  415.                     ; processed
  416.     mov    si, packet_sem          ; optimization
  417.     loadport
  418.     mov    ah, LSR_DR
  419.  
  420. asyrxint_again:
  421.     xor    cx, cx            ; initialize counter
  422.     setport    LSR
  423. asyrxint_in:
  424.     in    al,dx            ; check for data ready
  425.     test    al,LSR_DR
  426.     jnz    asyrxint_gotit        ; yes - break out of loop
  427.     inc    cx            ; no - increase loop counter
  428.     cmp    cx, bx            ; timeout?
  429.     jae    asyrxint_exit        ; yes - leave
  430.     jmp    asyrxint_in        ; no - keep looping
  431.  
  432. asyrxint_gotit:
  433.     setport    RBR
  434.     in    al,dx
  435.  
  436. ;Process incoming data;
  437. ; If buffer is full, we have no choice but
  438. ; to drop the character
  439.     cmp    di,recv_buf_head    ; check for buffer collision
  440.     jne    asyrxint_ok        ; none - continue
  441.     or    si, si                  ; maybe - if there are packets
  442.     jnz    asyrxint_exit        ; yes exit
  443.  
  444. asyrxint_ok:
  445.     stosb
  446.  
  447.     cmp    di,recv_buf_end        ; did we hit the end of the buffer?
  448.     jne    asyrxint_3        ; no.
  449.     mov    di,recv_buf        ; yes - wrap around.
  450.  
  451. asyrxint_3:
  452.     cmp    al,FR_END        ; might    this be    the end of a frame?
  453.     jne    asyrxint_reset        ; no - reset flag and loop
  454.     inc    si                      ; yes - indicate packet ready
  455.     cmp    si, 1                   ; determine if semaphore is <> 1
  456.     jne    asyrxint_chk_flg        ; yes - recv_frame must be active
  457.     inc    recv_pkt_ready          ; no - set flag to start recv_frame
  458.  
  459. asyrxint_chk_flg:
  460.     cmp    bp, 0                   ; was this the first char?
  461.     jne    asyrxint_1              ; no - exit handler
  462. asyrxint_reset:
  463.     inc    bp            ; set 1st character flag
  464.     jmp    asyrxint_again        ; get another character
  465.  
  466. asyrxint_exit:
  467. asyrxint_1:
  468.     mov    recv_buf_tail,di
  469.     mov    packet_sem, si
  470.  
  471.     ret
  472.  
  473.  
  474. ; --------------------------------------------------------------
  475. ;
  476. ;  recv_exiting
  477. ;
  478.     public    recv_exiting
  479. recv_exiting:
  480.     cmp    recv_pkt_ready, 1       ; is a packet ready?
  481.     jne    recv_isr_exit           ; no - skip to end
  482.     push    ax
  483.     push    bx
  484.     push    cx
  485.     push    dx
  486.     push    ds
  487.     push    es
  488.     push    bp
  489.     push    di
  490.     push    si
  491.     push    cs            ; point ds properly
  492.     pop    ds
  493.     mov    recv_pkt_ready,    0    ; reset flag
  494.     sti                ; enable interrupts
  495.  
  496.     call    recv_frame
  497.  
  498.     cli
  499.     pop    si
  500.     pop    di
  501.     pop    bp
  502.     pop    es
  503.     pop    ds
  504.     pop    dx
  505.     pop    cx
  506.     pop    bx
  507.     pop    ax
  508. recv_isr_exit:
  509.     ret
  510.  
  511.  
  512. ; --------------------------------------------------------------
  513. ;
  514. ;  recv_frame
  515. ;
  516. ; mod 7/25/89 John Grover
  517. ;
  518. ; - recv_frame now operates with interrupts on. It is triggered
  519. ; - by the recv_pkt_ready flag and continues until all bytes
  520. ; - in all packets in the buffer have been transmitted to the upper
  521. ; - layer.
  522. ;
  523.   ifdef debug
  524.     public recv_frame
  525.   endif
  526. recv_frame:
  527.     cmp    packet_sem, 0        ; should we do this?
  528.     jz    recv_frame_end        ; no - exit
  529.     mov    si,recv_buf_head    ;process characters.
  530.     xor    cx,cx            ;count up the size here.
  531. recv_frame_1:
  532.  
  533.     call    recv_char        ;get a char.
  534.     je    recv_frame_2        ;go if no more chars.
  535.     cmp    al,FR_ESC        ;an escape?
  536.     je    recv_frame_1        ;yes - don't count this char.
  537.     inc    cx            ;no - count this one.
  538.     jmp    recv_frame_1
  539. recv_frame_2:
  540.  
  541.     jcxz    recv_frame_3        ;count zero? yes - free the frame
  542. ;we don't need to set the type because none are defined for SLIP.
  543.     push    si            ;save si in case we reject it.
  544.     push    bx
  545.     MOV    DI,CS
  546.     MOV    ES,DI
  547.     mov    di,0
  548.     mov    dl,cs:driver_class
  549.     call    recv_find        ;look up our type.
  550.     pop    bx
  551.     pop    si
  552.  
  553.     mov    ax,es            ;is this pointer null?
  554.     or    ax,di
  555.     je    recv_frame_3        ;yes - just free the frame.
  556.  
  557.     push    cx
  558.     push    es            ;remember where the buffer pointer is
  559.     push    di
  560.  
  561.     mov    si,recv_buf_head    ;process characters.
  562. recv_frame_4:
  563.     call    recv_char
  564.     je    recv_frame_6        ;yes - we're all done.
  565.     cmp    al,FR_ESC        ;an escape?
  566.     jne    recv_frame_5        ;no - just store it.
  567.  
  568.     call    recv_char        ;get the next character.
  569.     je    recv_frame_6
  570.     cmp    al,T_FR_ESC
  571.     mov    al,FR_ESC        ;assume T_FR_ESC
  572.     je    recv_frame_5        ;yup, that's it    - store FR_ESC
  573.     mov    al,FR_END        ;nope, store FR_END
  574. recv_frame_5:
  575.     stosb                ;store the byte.
  576.     jmp    recv_frame_4
  577. recv_frame_6:
  578.     mov    recv_buf_head,si    ;we're skipped to the end.
  579.  
  580.     pop    si            ;now give the frame to the client.
  581.     pop    ds
  582.     pop    cx
  583.     assume    ds:nothing
  584.  
  585.     call    recv_copy
  586.     push    cs
  587.     pop    ds
  588.     assume    ds:code
  589.     jmp    recv_frame_end
  590.  
  591. recv_frame_3:
  592.     mov    recv_buf_head,si    ;remember the new starting point.
  593. recv_frame_end:
  594.     dec    packet_sem
  595.     cmp    packet_sem, 0        ; are there more packets ready?
  596.     ja    recv_frame              ; yes - execute again
  597.     ret
  598.  
  599.  
  600. ; --------------------------------------------------------------
  601. ;
  602. ;  recv_char
  603. ;
  604. ; mod 7/25/89 John Grover
  605. ; - Now    uses buffer pointers to determine if there are
  606. ; - characters left.
  607. ;
  608.  
  609. recv_char:
  610. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  611. ;return with nz, al = next char.  Return zr if there are no more chars in
  612. ;  this frame.
  613. ;
  614.     lodsb
  615.     cmp    si,recv_buf_end
  616.     jb    recv_char_1
  617.     mov    si,recv_buf
  618. recv_char_1:
  619.     mov    bx, recv_buf_tail
  620.     cmp    si, bx
  621.     je    recv_char_2
  622.     cmp    al,FR_END
  623. recv_char_2:
  624.     ret
  625.  
  626.  
  627. ;Set bit(s) in I/O port
  628. setbit:
  629. ;enter with dx = port, ah = bit to set.
  630.     in    al,dx
  631.     or    al,ah
  632.     out    dx,al
  633.     ret
  634.  
  635.  
  636. ;Clear bit(s) in I/O port
  637. clrbit:
  638. ;enter with dx = port, ah = bit to set.
  639.     in    al,dx
  640.     not    al            ;perform an and-not using DeMorgan's.
  641.     or    al,ah
  642.     not    al
  643.     out    dx,al
  644.     ret
  645.  
  646.  
  647. ;any code after this will not be kept after initialization.
  648. end_resident    label    byte
  649.  
  650.     public    usage_msg
  651. usage_msg    db    "usage: SLIP8250 [-n] [-d] [-w] packet_int_no "
  652.         db    "[-h] [driver_class] [int_no]",CR,LF
  653.         db    "   [io_addr] [baud_rate]",CR,LF
  654.         db    "   [recv_buf_size]",CR,LF
  655.         db    "   -h enables hardware handshaking",CR,LF
  656.         db    "   The driver_class should be SLIP, KISS, AX.25,"
  657.         db    " or a number.",CR,LF,'$'
  658.  
  659.     public    copyright_msg
  660. copyright_msg    db    "Packet driver for SLIP8250, version ",'0'+majver
  661.         db    ".",'0'+version,CR,LF
  662.         db    "Portions Copyright 1988 Phil Karn",CR,LF
  663.         db    "Portions Copyright 1991 Joe Doupnik",cr,lf,'$'
  664.  
  665. approximate_msg    db    "Warning: This baud rate can only be approximated"
  666.         db    "using the 8250",CR,LF
  667.         db    "because it is not an even divisor of 115200"
  668.         db    cr,lf,'$'
  669.  
  670. is_16550_msg    db      "16550 Uart detected, FIFO will be used",CR,LF,'$'
  671.  
  672. class_name_ptr    dw    ?
  673. class_name    db    "Interface class ",'$'
  674. kiss_name    db    "KISS",CR,LF,'$'
  675. ax25_name    db    "AX.25",CR,LF,'$'
  676. slip_name    db    "SLIP",CR,LF,'$'
  677. int_no_name    db    "Interrupt number ",'$'
  678. io_addr_name    db    "I/O port ",'$'
  679. baud_rate_name    db    "Baud rate ",'$'
  680. recv_buf_name    db    "Receive buffer size ",'$'
  681. unusual_com1    db    "That's unusual!  Com1 (0x3f8) usually uses IRQ 4!"
  682.         db    CR,LF,'$'
  683. unusual_com2    db    "That's unusual!  Com2 (0x2f8) usually uses IRQ 3!"
  684.         db    CR,LF,'$'
  685.  
  686.     extrn    set_recv_isr: near
  687.  
  688. ;enter with si -> argument string, di -> word to store.
  689. ;if there is no number, don't change the number.
  690.     extrn    get_number: near
  691.  
  692. ;enter with dx -> name of word, di -> dword to print.
  693.     extrn    print_number: near
  694.  
  695. ;enter with si -> argument string.
  696. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  697.     extrn    skip_blanks: near
  698.  
  699.  
  700.     public    parse_args
  701. parse_args:
  702. ;exit with nc if all went well, cy otherwise.
  703.     call    skip_blanks
  704.     cmp    al,'-'            ;did they specify a switch?
  705.     jne    not_switch
  706.     cmp    byte ptr [si+1],'h'    ;did they specify '-h'?
  707.     je    got_hardware_switch
  708.     stc                ;no, must be an error.
  709.     ret
  710. got_hardware_switch:
  711.     mov    hardware_switch,1
  712.     add    si,2            ;skip past the switch's characters.
  713.     jmp    parse_args        ;go parse more arguments.
  714. not_switch:
  715.     or    al,20h            ; to lower case (assuming letter)
  716.     cmp    al,'k'
  717.     jne    parse_args_2
  718.     mov    driver_class,10        ;KISS, from packet spec
  719.     mov    dx,offset kiss_name
  720.     jmp    short parse_args_1
  721. parse_args_2:
  722.     cmp    al,'s'
  723.     jne    parse_args_3
  724.     mov    driver_class,6        ;SLIP, from packet spec
  725.     mov    dx,offset slip_name
  726.     jmp    short parse_args_1
  727. parse_args_3:
  728.     cmp    al,'a'
  729.     jne    parse_args_4
  730.     mov    driver_class,9        ;AX.25, from packet spec.
  731.     mov    dx,offset ax25_name
  732.     jmp    short parse_args_1
  733. parse_args_4:
  734.     mov    di,offset driver_class
  735.     mov    bx,offset class_name
  736.     call    get_number
  737.     mov    class_name_ptr,0
  738.     jmp    short parse_args_6
  739. parse_args_1:
  740.     mov    class_name_ptr,dx
  741. parse_args_5:
  742.     mov    al,[si]            ;skip to the next blank or CR.
  743.     cmp    al,' '
  744.     je    parse_args_6
  745.     cmp    al,CR
  746.     je    parse_args_6
  747.     inc    si            ;skip the character.
  748.     jmp    parse_args_5
  749. parse_args_6:
  750.     mov    di,offset int_no
  751.     call    get_number
  752.     mov    di,offset io_addr
  753.     call    get_number
  754.     mov    di,offset baud_rate
  755.     call    get_number
  756.     mov    di,offset recv_buf_size
  757.     call    get_number
  758.     clc
  759.     ret
  760.  
  761.  
  762. ; --------------------------------------------------------------
  763. ;
  764. ;  etopen
  765. ;
  766. ; mod 7/25/89 John Grover
  767. ; - Contains a loop to determine a pseudo timeout for asyrxint.
  768. ; - The value is determined by transmitting characters in a
  769. ; - loop whose clock cycles are nearly the same as the "sister"
  770. ; - loop in asyrxint. The per character, maximum time used
  771. ; - basis which is then multiplied by a factor to achieve a timeout
  772. ; - value for the particular bps and CPU speed of the host.
  773.  
  774.     public    etopen
  775. etopen:
  776.     pushf
  777.     cli
  778. ;
  779. ; mod  3/16/90  Denis DeLaRoca
  780. ; - determine if 16550 uart is present
  781. ; - if so initialize fifo buffering
  782. ;
  783.     loadport
  784.     setport    FCR
  785.     mov    al,FIFO_ENABLE
  786.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_ENABLE)
  787.     setport    IIR
  788.     in    al,dx                   ;inportb(base+IIR)
  789.     and    al,IIR_FIFO_ENABLED     ;     & IIR_FIFO_ENABLED
  790.     cmp    al,IIR_FIFO_ENABLED    ;both bits must be on   NEW, 11/20/90
  791.     jnz    not_16550               ;nope, we don't have 16550 chip
  792.     mov    is_16550,1              ;yes, note fact
  793.     mov    al,FIFO_SETUP           ;and setup FIFO
  794.     setport    FCR
  795.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_SETUP)
  796.  
  797.     mov    dx,offset is_16550_msg
  798.     mov    ah,9
  799.     int    21h            ;let user know about 16550
  800.  
  801. not_16550:
  802.     loadport            ;Purge the receive data buffer
  803.     setport    RBR
  804.     in    al,dx
  805.  
  806.     ;Set line control register: 8 bits, no parity
  807.     mov    al,LCR_8BITS
  808.     setport    LCR
  809.     out    dx,al
  810.  
  811.     ;Turn on receive interrupt enable in 8250, leave transmit
  812.     ; and modem status interrupts turned off for now
  813.     mov    al,IER_DAV
  814.     setport    IER
  815.     out    dx,al
  816.  
  817.     ;Set modem control register: assert DTR, RTS, turn on 8250
  818.     ; master interrupt enable (connected to OUT2)
  819.  
  820.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  821.     setport    MCR
  822.     out    dx,al
  823.  
  824. ;compute the divisor given the baud rate.
  825.     mov    dx,baudclk+2
  826.     mov    ax,baudclk
  827.     mov    bx,0
  828. asy_speed_1:
  829.     inc    bx
  830.     sub    ax,baud_rate
  831.     sbb    dx,baud_rate+2
  832.     jnc    asy_speed_1
  833.     dec    bx
  834.     add    ax,baud_rate
  835.     adc    dx,baud_rate+2
  836.     or    ax,dx
  837.     je    asy_speed_2
  838.  
  839.     mov    dx,offset approximate_msg
  840.     mov    ah,9
  841.     int    21h
  842.  
  843. asy_speed_2:
  844.  
  845.     loadport            ;Purge the receive data buffer
  846.     setport    RBR
  847.     in    al,dx
  848.  
  849.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  850.     setport    LCR
  851.     call    setbit
  852.  
  853.     mov    al,bl            ;Load the two bytes of the divisor.
  854.     setport    DLL
  855.     out    dx,al
  856.     mov    al,bh
  857.     setport    DLM
  858.     out    dx,al
  859.  
  860.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  861.     setport    LCR
  862.     call    clrbit
  863.  
  864.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  865.  
  866. ;set up the various pointers.
  867.     mov    dx,offset end_resident
  868.  
  869.     mov    recv_buf,dx
  870.     mov    recv_buf_head,dx
  871.     mov    recv_buf_tail,dx
  872.     add    dx,recv_buf_size
  873.     mov    recv_buf_end,dx
  874.     push    dx            ;save the ending address.
  875.  
  876.     ; the following code attempts to determine a pseudo timeout
  877.     ; value    to use in the loop that waits for an incoming character
  878.     ; in asyrxint. The value returned in xmit_time is the number of
  879.     ; loops processed between characters - therefore the loop used below
  880.     ; is and should    remain similar to the loop used in asyrxint.
  881.  
  882.     xor    ax, ax            ; we'll send a 0
  883.     mov    ah, LSR_THRE
  884.     mov    cx, 10h            ; take the highest of 16 runs
  885.     xor    si, si            ; will hold highest value
  886.  
  887. xmit_time_start:
  888.  
  889.     xor    di, di            ; initialize counter
  890.     loadport
  891.     setport    THR            ; xmit a character
  892.     out    dx, al
  893.     setport    LSR               ; set up    to check for an empty buffer
  894.  
  895.     ; next is the loop actually being timed
  896.  
  897. xmit_time_top:
  898.     in    al, dx
  899.     test    al, ah
  900.     jnz    xmit_time_done
  901.     inc    di
  902.     cmp    cx, cx            ; these next few instructions do nothing
  903.     jmp    xmit_time_1        ;  except maintain similarity with the
  904.                     ;  "sister" loop in asyrxint
  905. xmit_time_1:
  906.     jmp    xmit_time_top
  907.  
  908. xmit_time_done:                ; end of timed loop
  909.  
  910.  
  911.  
  912.     cmp    si, di            ; compare highest value with new value
  913.     ja    xmit_time_end        ; no bigger - just loop
  914.     mov    si, di            ; bigger - save it
  915.  
  916. xmit_time_end:
  917.     loop    xmit_time_start        ; bottom of outer loop
  918.  
  919.     shl    si, 1            ; we'll wait 8 characters worth
  920.     shl    si, 1
  921.     shl    si, 1
  922.     mov    xmit_time, si        ; retain largest value
  923.  
  924.     ; end of pseudo timer determination
  925.  
  926.     mov    al, int_no        ; Get board's interrupt vector
  927.     add    al, 8
  928.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  929.     jb    set_int_num        ; No.
  930.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  931. set_int_num:
  932.     xor    ah, ah            ; Clear high byte
  933.     mov    int_num, ax        ; Set parameter_list int num.
  934.  
  935.     pop    dx            ;return the ending address.
  936.     popf
  937.     clc                ;indicate no errors.
  938.     ret
  939.  
  940.     public    print_parameters
  941. print_parameters:
  942. ;echo our command-line parameters
  943.     cmp    class_name_ptr,0
  944.     je    echo_args_1
  945.  
  946.     mov    dx,offset class_name
  947.     mov    ah,9
  948.     int    21h
  949.     mov    dx,class_name_ptr
  950.     mov    ah,9
  951.     int    21h
  952.     jmp    short echo_args_2
  953. echo_args_1:
  954.     mov    di,offset driver_class
  955.     mov    dx,offset class_name
  956.     call    print_number
  957. echo_args_2:
  958.  
  959.     mov    di,offset int_no
  960.     mov    dx,offset int_no_name
  961.     call    print_number
  962.     mov    di,offset io_addr
  963.     mov    dx,offset io_addr_name
  964.     call    print_number
  965.  
  966.     cmp    io_addr,03f8h        ;is this com1?
  967.     jne    ia_com2
  968.     mov    dx,offset unusual_com1
  969.     cmp    int_no,4        ;com1 usually uses IRQ 4.
  970.     jne    ia_unusual
  971.     jmp    short ia_usual
  972. ia_com2:
  973.     cmp    io_addr,02f8h        ;is this com2?
  974.     jne    ia_usual        ;no.
  975.     mov    dx,offset unusual_com2
  976.     cmp    int_no,3        ;com2 usually uses IRQ 3.
  977.     je    ia_usual
  978. ia_unusual:
  979.     mov    ah,9
  980.     int    21h
  981. ia_usual:
  982.     mov    di,offset baud_rate
  983.     mov    dx,offset baud_rate_name
  984.     call    print_number
  985.     mov    di,offset recv_buf_size
  986.     mov    dx,offset recv_buf_name
  987.     call    print_number
  988.     ret
  989. code    ends
  990.     end
  991.  
  992.