home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / drivrs30 / slip8250.asm < prev    next >
Assembly Source File  |  1989-06-08  |  15KB  |  635 lines

  1. version    equ    1
  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.  
  8. ;  Copyright, 1988, 1989, Russell Nelson
  9.  
  10. ;   This program is free software; you can redistribute it and/or modify
  11. ;   it under the terms of the GNU General Public License as published by
  12. ;   the Free Software Foundation, version 1.
  13. ;
  14. ;   This program is distributed in the hope that it will be useful,
  15. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. ;   GNU General Public License for more details.
  18. ;
  19. ;   You should have received a copy of the GNU General Public License
  20. ;   along with this program; if not, write to the Free Software
  21. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23. code    segment    byte public
  24.     assume    cs:code, ds:code
  25.  
  26. ;8250 definitions
  27. ;Control/status register offsets from base address
  28. THR    equ    0        ;Transmitter holding register
  29. RBR    equ    0        ;Receiver buffer register
  30. DLL    equ    0        ;Divisor latch LSB
  31. DLM    equ    1        ;Divisor latch MSB
  32. IER    equ    1        ;Interrupt enable register
  33. IIR    equ    2        ;Interrupt ident register
  34. FCR    equ    2        ;16550 FIFO control register
  35. LCR    equ    3        ;Line control register
  36. MCR    equ    4        ;Modem control register
  37. LSR    equ    5        ;Line status register
  38. MSR    equ    6        ;Modem status register
  39.  
  40. ;8250 Line Control Register
  41. LCR_5BITS    equ    0    ;5 bit words
  42. LCR_6BITS    equ    1    ;6 bit words
  43. LCR_7BITS    equ    2    ;7 bit words
  44. LCR_8BITS    equ    3    ;8 bit words
  45. LCR_NSB        equ    4    ;Number of stop bits
  46. LCR_PEN        equ    8    ;Parity enable
  47. LCR_EPS        equ    10h    ;Even parity select
  48. LCR_SP        equ    20h    ;Stick parity
  49. LCR_SB        equ    40h    ;Set break
  50. LCR_DLAB    equ    80h    ;Divisor Latch Access Bit
  51.  
  52. ;16550 Line Control Register
  53. FCR_RCVR    equ    002h    ;Reset Receive FIFO
  54. FCR_XMIT    equ    004h    ;Reset Transmit FIFO
  55. FCR_1        equ    001h    ;One byte FIFO
  56. FCR_4        equ    041h    ;Four byte FIFO
  57. FCR_8        equ    081h    ;Eight byte FIFO
  58. FCR_14        equ    0c1h    ;Fourteen byte FIFO
  59.  
  60. ;8250 Line Status Register
  61. LSR_DR    equ    1    ;Data ready
  62. LSR_OE    equ    2    ;Overrun error
  63. LSR_PE    equ    4    ;Parity error
  64. LSR_FE    equ    8    ;Framing error
  65. LSR_BI    equ    10h    ;Break interrupt
  66. LSR_THRE equ    20h    ;Transmitter line holding register empty
  67. LSR_TSRE equ    40h    ;Transmitter shift register empty
  68.  
  69. ;8250 Interrupt Identification Register
  70. IIR_IP        equ    1    ;0 if interrupt pending
  71. IIR_ID        equ    6    ;Mask for interrupt ID
  72. IIR_RLS        equ    6    ;Receiver Line Status interrupt
  73. IIR_RDA        equ    4    ;Receiver data available interrupt
  74. IIR_THRE    equ    2    ;Transmitter holding register empty int
  75. IIR_MSTAT    equ    0    ;Modem status interrupt
  76.  
  77. ;8250 interrupt enable register bits
  78. IER_DAV    equ    1    ;Data available interrupt
  79. IER_TxE    equ    2    ;Tx buffer empty interrupt
  80. IER_RLS    equ    4    ;Receive line status interrupt
  81. IER_MS    equ    8    ;Modem status interrupt
  82.  
  83. ;8250 Modem control register
  84. MCR_DTR    equ    1    ;Data Terminal Ready
  85. MCR_RTS    equ    2    ;Request to Send
  86. MCR_OUT1 equ    4    ;Out 1 (not used)
  87. MCR_OUT2 equ    8    ;Master interrupt enable (actually OUT 2)
  88. MCR_LOOP equ    10h    ;Loopback test mode
  89.  
  90. ;8250 Modem Status Register
  91. MSR_DCTS equ    1    ;Delta Clear-to-Send
  92. MSR_DDSR equ    2    ;Delta Data Set Ready
  93. MSR_TERI equ    4    ;Trailing edge ring indicator
  94. MSR_DRLSD equ    8    ;Delta Rx Line Signal Detect
  95. MSR_CTS    equ    10h    ;Clear to send
  96. MSR_DSR equ    20h    ;Data set ready
  97. MSR_RI    equ    40h    ;Ring indicator
  98. MSR_RLSD equ    80h    ;Received line signal detect
  99.  
  100. ;Slip Definitions
  101. FR_END        equ    0c0h        ;Frame End
  102. FR_ESC        equ    0dbh        ;Frame Escape
  103. T_FR_END    equ    0dch        ;Transposed frame end
  104. T_FR_ESC    equ    0ddh        ;Transposed frame escape
  105.  
  106.     public    int_no
  107. int_no        db    4,0,0,0        ; interrupt number.
  108. io_addr        dw    03f8h,0        ; I/O address for COM1.
  109. baud_rate    dw    12c0h,0        ; We support baud rates higher than 65535.
  110. baudclk        label    word
  111.         dd    115200        ;1.8432 Mhz / 16
  112.  
  113.     public    driver_class, driver_type, driver_name
  114. driver_class    db    6,0,0,0        ;from the packet spec
  115. driver_type    db    0,0,0,0        ;from the packet spec
  116. driver_name    db    'SLIP8250',0    ;name of the driver.
  117.  
  118.  
  119. recv_buf_size    dw    3000        ;receive buffer size
  120. recv_buf    dw    ?        ;->receive buffer
  121. recv_buf_end    dw    ?        ;->after end of buffer
  122. recv_buf_head    dw    ?        ;->next character to get
  123. recv_buf_tail    dw    ?        ;->next character to store
  124. recv_cnt    dw    ?        ;number of characters in the queue.
  125.  
  126. send_buf_size    dw    3000        ;send buffer size
  127. send_buf    dw    ?        ;->send buffer
  128. send_buf_end    dw    ?        ;->after end of buffer
  129. send_buf_head    dw    ?        ;->next character to get
  130. send_buf_tail    dw    ?        ;->next character to store
  131. send_cnt    dw    ?        ;number of characters in the queue.
  132.  
  133.  
  134.     public    send_pkt
  135. send_pkt:
  136. ;enter with ds:si -> packet, cx = packet length.
  137. ;exit with nc if ok, or else cy if error, dh set to error number.
  138.     assume    ds:nothing
  139.  
  140.     push    cs
  141.     pop    es
  142.     mov    di,send_buf_tail
  143.     mov    bx,send_cnt
  144.  
  145.     mov    al,FR_END        ;Flush out any line garbage
  146.     call    send_char
  147.  
  148. ;Copy input to output, escaping special characters
  149. send_pkt_1:
  150.     lodsb
  151.     cmp    al,FR_ESC        ;escape FR_ESC with FR_ESC and T_FR_ESC
  152.     jne    send_pkt_2
  153.     mov    al,FR_ESC
  154.     call    send_char
  155.     mov    al,T_FR_ESC
  156.     jmp    short send_pkt_3
  157. send_pkt_2:
  158.     cmp    al,FR_END        ;escape FR_END with FR_ESC and T_FR_END
  159.     jne    send_pkt_3
  160.     mov    al,FR_ESC
  161.     call    send_char
  162.     mov    al,T_FR_END
  163. send_pkt_3:
  164.     call    send_char
  165.     loop    send_pkt_1
  166.     mov    al,FR_END        ;terminate it with a FR_END
  167.     call    send_char
  168.     mov    send_buf_tail,di
  169.     mov    send_cnt,bx
  170.  
  171. ;Enable transmitter buffer empty interrupt.
  172.  
  173.     mov    ah,IER_TxE
  174.     loadport
  175.     setport    IER
  176.     call    setbit
  177.  
  178.     clc
  179.     ret
  180.  
  181.  
  182. send_char:
  183. ;stuff the character in al into the transmit buffer, but only if there
  184. ;is enough room, otherwise ignore the char.
  185.     assume    ds:nothing
  186.     cmp    bx,send_buf_size    ;too many chars?
  187.     je    send_char_1        ;yes.
  188.     inc    bx            ;count up a char.
  189.     stosb                ;store the char.
  190.     cmp    di,send_buf_end        ;do we need to wrap around?
  191.     jne    send_char_1        ;no.
  192.     mov    di,send_buf        ;yes - reload with beginning.
  193. send_char_1:
  194.     ret
  195.  
  196.  
  197.     public    get_address
  198. get_address:
  199. ;get the address of the interface.
  200. ;enter with es:di -> place to get the address, cx = size of address buffer.
  201. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  202.     assume    ds:code
  203.     mov    cx,0
  204.     clc
  205.     ret
  206.  
  207.  
  208.     public    set_address
  209. set_address:
  210. ;set the address of the interface.
  211. ;enter with es:di -> place to get the address, cx = size of address buffer.
  212. ;exit with nc if okay, or cy, dh=error if any errors.
  213.     assume    ds:nothing
  214.     clc
  215.     ret
  216.  
  217.  
  218.     public    reset_interface
  219. reset_interface:
  220. ;reset the interface.
  221.     assume    ds:code
  222.     ret
  223.  
  224.  
  225. ;called when we want to determine what to do with a received packet.
  226. ;enter with cx = packet length, es:di -> packet type.
  227.     extrn    recv_find: near
  228.  
  229. ;called after we have copied the packet into the buffer.
  230. ;enter with ds:si ->the packet, cx = length of the packet.
  231.     extrn    recv_copy: near
  232.  
  233.     extrn    count_in_err: near
  234.     extrn    count_out_err: near
  235.  
  236.     public    recv
  237. recv:
  238. ;called from the recv isr.  All registers have been saved, and ds=cs.
  239. ;Upon exit, the interrupt will be acknowledged.
  240.     assume    ds:code
  241. recv_2:
  242.     loadport
  243.     setport    IIR
  244.     in    al,dx            ;any interrupts at all?
  245.     test    al,IIR_IP
  246.     jne    recv_1            ;no.
  247.     and    al,IIR_ID
  248.     cmp    al,IIR_RDA        ;Receiver interrupt
  249.     jne    recv_3
  250.     call    asyrxint
  251.     jmp    recv_2
  252. recv_3:
  253.     cmp    al,IIR_THRE        ;Transmit interrupt
  254.     jne    recv_4
  255.     call    asytxint
  256.     jmp    recv_2
  257. recv_4:
  258. ;process IIR_RLS here.
  259. recv_1:
  260.     ret
  261.  
  262.  
  263. ;Process 8250 receiver interrupts
  264. asyrxint:
  265.  
  266. asyrxint_2:
  267.     loadport
  268.     setport    LSR
  269.     in    al,dx
  270.     test    al,LSR_DR
  271.     je    asyrxint_1
  272.  
  273.     setport    RBR
  274.     in    al,dx
  275. ;Process incoming data;
  276. ; If buffer is full, we have no choice but
  277. ; to drop the character
  278.  
  279.     mov    cx,recv_cnt
  280.     cmp    cx,recv_buf_size
  281.     je    asyrxint_1
  282.  
  283.     push    ds
  284.     pop    es
  285.     mov    di,recv_buf_tail
  286.     stosb
  287.  
  288.     cmp    di,recv_buf_end        ;did we hit the end of the buffer?
  289.     jne    asyrxint_3        ;no.
  290.     mov    di,recv_buf        ;yes - wrap around.
  291. asyrxint_3:
  292.     mov    recv_buf_tail,di
  293.     inc    recv_cnt
  294.  
  295.     cmp    al,FR_END        ;might this be the end of a frame?
  296.     jne    asyrxint_4        ;no.
  297.     call    recv_frame
  298. asyrxint_4:
  299.  
  300.     jmp    asyrxint_2
  301. asyrxint_1:
  302.     ret
  303.  
  304.  
  305. recv_frame:
  306.     mov    si,recv_buf_head    ;process characters.
  307.     mov    bx,recv_cnt
  308.     mov    cx,0            ;count up the size here.
  309. recv_frame_1:
  310.     call    recv_char        ;get a char.
  311.     je    recv_frame_2        ;go if no more chars.
  312.     cmp    al,FR_ESC        ;an escape?
  313.     je    recv_frame_1        ;yes - don't count this char.
  314.     inc    cx            ;no - count this one.
  315.     jmp    recv_frame_1
  316. recv_frame_2:
  317.  
  318.     jcxz    recv_frame_3        ;count zero? yes - just free the frame.
  319. ;we don't need to set the type because none are defined for SLIP.
  320.     push    si            ;save si in case we reject it.
  321.     push    bx
  322.     mov    di,0            ;but we avoid any segment end trouble.
  323.     call    recv_find        ;look up our type.
  324.     pop    bx
  325.     pop    si
  326.  
  327.     mov    ax,es            ;is this pointer null?
  328.     or    ax,di
  329.     je    recv_frame_3        ;yes - just free the frame.
  330.  
  331.     push    cx
  332.     push    es            ;remember where the buffer pointer is.
  333.     push    di
  334.  
  335.     mov    si,recv_buf_head    ;process characters.
  336.     mov    bx,recv_cnt
  337. recv_frame_4:
  338.     call    recv_char
  339.     je    recv_frame_6        ;yes - we're all done.
  340.     cmp    al,FR_ESC        ;an escape?
  341.     jne    recv_frame_5        ;no - just store it.
  342.  
  343.     call    recv_char        ;get the next character.
  344.     je    recv_frame_6
  345.     cmp    al,T_FR_ESC
  346.     mov    al,FR_ESC        ;assume T_FR_ESC
  347.     je    recv_frame_5        ;yup, that's it - store FR_ESC
  348.     mov    al,FR_END        ;nope, store FR_END
  349. recv_frame_5:
  350.     stosb                ;store the byte.
  351.     jmp    recv_frame_4
  352. recv_frame_6:
  353.     mov    recv_buf_head,si    ;we're skipped to the end.
  354.     mov    recv_cnt,bx
  355.  
  356.     pop    si            ;now give the frame to the client.
  357.     pop    ds
  358.     pop    cx
  359.     assume    ds:nothing
  360.  
  361.     call    recv_copy
  362.     push    cs
  363.     pop    ds
  364.     assume    ds:code
  365.     ret
  366.  
  367. recv_frame_3:
  368.     mov    recv_buf_head,si    ;remember the new starting point.
  369.     mov    recv_cnt,bx
  370.     ret
  371.  
  372.  
  373. recv_char:
  374. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  375. ;return with nz, al = next char.  Return zr if there are no more chars in
  376. ;  this frame.
  377.     lodsb
  378.     cmp    si,recv_buf_end
  379.     jb    recv_char_1
  380.     mov    si,recv_buf
  381. recv_char_1:
  382.     dec    bx
  383.     je    recv_char_2
  384.     cmp    al,FR_END
  385. recv_char_2:
  386.     ret
  387.  
  388.  
  389. ;Handle 8250 transmitter interrupts
  390. asytxint:
  391.  
  392.     mov    si,send_buf_head
  393.     mov    cx,send_cnt
  394. asytxint_2:
  395.     loadport            ;can we load another character?
  396.     setport    LSR
  397.     in    al,dx
  398.     test    al,LSR_THRE
  399.     je    asytxint_1        ;no.
  400.  
  401.     lodsb                ;fill up the transmit buffer.
  402.     cmp    si,send_buf_end        ;have we hit the end yet?
  403.     jb    asytxint_3        ;no.
  404.     mov    si,send_buf
  405. asytxint_3:
  406.     setport    THR
  407.     out    dx,al
  408.  
  409.     loop    asytxint_2        ;keep sending until we run out.
  410.  
  411. ;No more characters to transmit -- disable transmit interrupts.
  412.  
  413.     setport    IER            ;Disable transmit interrupts
  414.     mov    ah,IER_TxE
  415.     call    clrbit
  416. ;Call completion interrupt here
  417. asytxint_1:
  418.     mov    send_cnt,cx
  419.     mov    send_buf_head,si
  420.     ret
  421.  
  422.  
  423. ;Set bit(s) in I/O port
  424. setbit:
  425. ;enter with dx = port, ah = bit to set.
  426.     in    al,dx
  427.     or    al,ah
  428.     out    dx,al
  429.     ret
  430.  
  431.  
  432. ;Clear bit(s) in I/O port
  433. clrbit:
  434. ;enter with dx = port, ah = bit to set.
  435.     in    al,dx
  436.     not    al            ;perform an and-not using DeMorgan's.
  437.     or    al,ah
  438.     not    al
  439.     out    dx,al
  440.     ret
  441.  
  442.  
  443. ;any code after this will not be kept after initialization.
  444. end_resident    label    byte
  445.  
  446.     public    usage_msg
  447. usage_msg    db    "usage: SLIP8250 packet_int_no [driver_class] [int_no] [io_addr] [baud_rate]",CR,LF,"   [send_buf_size] [recv_buf_size]",CR,LF
  448.         db    "   The driver_class should be SLIP, KISS, AX.25, or a number.",CR,LF,'$'
  449.  
  450.     public    copyright_msg
  451. copyright_msg    db    "Packet driver for SLIP8250, version ",'0'+majver,".",'0'+version,CR,LF
  452.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  453.  
  454. approximate_msg    db    "Warning: This baud rate can only be approximated using the 8250",CR,LF
  455.         db    "because it is not an even divisor of 115200",CR,LF,'$'
  456.  
  457. class_name    db    "Interface class ",'$'
  458. kiss_name    db    "KISS",CR,LF,'$'
  459. ax25_name    db    "AX.25",CR,LF,'$'
  460. slip_name    db    "SLIP",CR,LF,'$'
  461. int_no_name    db    "Interrupt number ",'$'
  462. io_addr_name    db    "I/O port ",'$'
  463. baud_rate_name    db    "Baud rate ",'$'
  464. send_buf_name    db    "Send buffer size ",'$'
  465. recv_buf_name    db    "Receive buffer size ",'$'
  466.  
  467.     extrn    set_recv_isr: near
  468.  
  469. ;enter with si -> argument string, di -> word to store.
  470. ;if there is no number, don't change the number.
  471.     extrn    get_number: near
  472.  
  473. ;enter with si -> argument string.
  474. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  475.     extrn    skip_blanks: near
  476.  
  477.  
  478.     public    parse_args
  479. parse_args:
  480.     call    skip_blanks
  481.     mov    al,[si]            ;now classify the argument.
  482.     or    al,20h            ;convert to lower case (assuming letter).
  483.     cmp    al,'k'
  484.     jne    parse_args_2
  485.     mov    driver_class,10        ;KISS, from packet spec.
  486.     mov    dx,offset kiss_name
  487.     jmp    short parse_args_1
  488. parse_args_2:
  489.     cmp    al,'s'
  490.     jne    parse_args_3
  491.     mov    driver_class,6        ;SLIP, from packet spec.
  492.     mov    dx,offset slip_name
  493.     jmp    short parse_args_1
  494. parse_args_3:
  495.     cmp    al,'a'
  496.     jne    parse_args_4
  497.     mov    driver_class,9        ;AX.25, from packet spec.
  498.     mov    dx,offset ax25_name
  499.     jmp    short parse_args_1
  500. parse_args_4:
  501.     mov    di,offset driver_class
  502.     mov    bx,offset class_name
  503.     call    get_number
  504.     jmp    short parse_args_6
  505. parse_args_1:
  506.     push    dx
  507.     mov    dx,offset class_name
  508.     mov    ah,9
  509.     int    21h
  510.     pop    dx
  511.     mov    ah,9
  512.     int    21h
  513. parse_args_5:
  514.     mov    al,[si]            ;skip to the next blank or CR.
  515.     cmp    al,' '
  516.     je    parse_args_6
  517.     cmp    al,CR
  518.     je    parse_args_6
  519.     inc    si            ;skip the character.
  520.     jmp    parse_args_5
  521. parse_args_6:
  522.     mov    di,offset int_no
  523.     mov    bx,offset int_no_name
  524.     call    get_number
  525.     mov    di,offset io_addr
  526.     mov    bx,offset io_addr_name
  527.     call    get_number
  528.     mov    di,offset baud_rate
  529.     mov    bx,offset baud_rate_name
  530.     call    get_number
  531.     mov    di,offset send_buf_size
  532.     mov    bx,offset send_buf_name
  533.     call    get_number
  534.     mov    di,offset recv_buf_size
  535.     mov    bx,offset recv_buf_name
  536.     call    get_number
  537.     ret
  538.  
  539.  
  540.     public    etopen
  541. etopen:
  542.     pushf
  543.     cli
  544.  
  545.     loadport            ;Purge the receive data buffer
  546.     setport    RBR
  547.     in    al,dx
  548.  
  549.     ;Enable FIFO, set FIFO trigger level to 8
  550.     mov    al,FCR_8
  551.     setport    FCR
  552.     out    dx,al
  553.  
  554.     ;Set line control register: 8 bits, no parity
  555.     mov    al,LCR_8BITS
  556.     setport    LCR
  557.     out    dx,al
  558.  
  559.     ;Turn on receive interrupt enable in 8250, leave transmit
  560.     ; and modem status interrupts turned off for now
  561.     mov    al,IER_DAV
  562.     setport    IER
  563.     out    dx,al
  564.  
  565.     ;Set modem control register: assert DTR, RTS, turn on 8250
  566.     ; master interrupt enable (connected to OUT2)
  567.  
  568.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  569.     setport    MCR
  570.     out    dx,al
  571.  
  572. ;compute the divisor given the baud rate.
  573.     mov    dx,baudclk+2
  574.     mov    ax,baudclk
  575.     mov    bx,0
  576. asy_speed_1:
  577.     inc    bx
  578.     sub    ax,baud_rate
  579.     sbb    dx,baud_rate+2
  580.     jnc    asy_speed_1
  581.     dec    bx
  582.     add    ax,baud_rate
  583.     adc    dx,baud_rate+2
  584.     or    ax,dx
  585.     je    asy_speed_2
  586.  
  587.     mov    dx,offset approximate_msg
  588.     mov    ah,9
  589.     int    21h
  590.  
  591. asy_speed_2:
  592.  
  593.     loadport            ;Purge the receive data buffer
  594.     setport    RBR
  595.     in    al,dx
  596.  
  597.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  598.     setport    LCR
  599.     call    setbit
  600.  
  601.     mov    al,bl            ;Load the two bytes of the divisor.
  602.     setport    DLL
  603.     out    dx,al
  604.     mov    al,bh
  605.     setport    DLM
  606.     out    dx,al
  607.  
  608.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  609.     setport    LCR
  610.     call    clrbit
  611.  
  612.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  613.  
  614. ;set up the various pointers.
  615.     mov    dx,offset end_resident
  616.     mov    send_buf,dx
  617.     mov    send_buf_head,dx
  618.     mov    send_buf_tail,dx
  619.     add    dx,send_buf_size
  620.     mov    send_buf_end,dx
  621.  
  622.     mov    recv_buf,dx
  623.     mov    recv_buf_head,dx
  624.     mov    recv_buf_tail,dx
  625.     add    dx,recv_buf_size
  626.     mov    recv_buf_end,dx
  627.  
  628.     popf
  629.     clc                ;indicate no errors.
  630.     ret
  631.  
  632. code    ends
  633.  
  634.     end
  635.