home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / asm / driver6s / slip8250.asm < prev    next >
Assembly Source File  |  1990-03-30  |  28KB  |  1,058 lines

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