home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / driver6s / ni6510.asm < prev    next >
Assembly Source File  |  1990-03-22  |  20KB  |  871 lines

  1. version    equ    0
  2.  
  3. ; Copyright, 1990, Russell Nelson
  4.  
  5. ;   This program is free software; you can redistribute it and/or modify
  6. ;   it under the terms of the GNU General Public License as published by
  7. ;   the Free Software Foundation, version 1.
  8. ;
  9. ;   This program is distributed in the hope that it will be useful,
  10. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ;   GNU General Public License for more details.
  13. ;
  14. ;   You should have received a copy of the GNU General Public License
  15. ;   along with this program; if not, write to the Free Software
  16. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.     .286                ;the 6510 requires a 286.
  19.  
  20.     include    defs.asm
  21.  
  22. DATA_REG    equ    0
  23. ADDR_REG    equ    2
  24.     CSR0        equ    0
  25.     CSR1        equ    1
  26.     CSR2        equ    2
  27.     CSR3        equ    3
  28. RESET        equ    4
  29. CONFIG        equ    5
  30. EBASE        equ    8
  31.  
  32. DMA_8MASK_REG    equ    0Ah
  33. DMA_16MASK_REG    equ    0D4h
  34.  
  35. DMA_8MODE_REG    equ    0Bh
  36. DMA_16MODE_REG    equ    0D6h
  37.  
  38. CASCADE_MODE      equ    0D0h
  39. SET_DMA_MASK      equ    4
  40. DMA_CHANNEL_FIELD equ    3
  41.  
  42.  
  43. outport    macro    reg
  44.     push    ax
  45.     setport    ADDR_REG
  46.     mov    ax,reg
  47.     out    dx,ax
  48.     in    ax,dx            ;always follow a write by a read
  49.  
  50.     setport    DATA_REG
  51.     pop    ax
  52.     out    dx,ax
  53.     in    ax,dx            ;always follow a write by a read
  54.  
  55.     endm
  56.  
  57.  
  58. ;
  59. ;     Control and Status Register 0 (CSR0) bit definitions
  60. ;
  61. CSR0_ERR    equ     8000h    ; Error summary
  62. CSR0_BABL    equ     4000h    ; Babble transmitter timeout error
  63. CSR0_CERR    equ    2000h    ; Collision Error
  64. CSR0_MISS    equ    1000h    ; Missed packet
  65. CSR0_MERR    equ    0800h    ; Memory Error
  66. CSR0_RINT    equ    0400h    ; Reciever Interrupt
  67. CSR0_TINT       equ    0200h    ; Transmit Interrupt
  68. CSR0_IDON    equ    0100h    ; Initialization Done
  69. CSR0_INTR    equ    0080h    ; Interrupt Flag
  70. CSR0_INEA    equ    0040h    ; Interrupt Enable
  71. CSR0_RXON    equ    0020h    ; Receiver on
  72. CSR0_TXON    equ    0010h   ; Transmitter on
  73. CSR0_TDMD    equ    0008h    ; Transmit Demand
  74. CSR0_STOP    equ    0004h     ; Stop
  75. CSR0_STRT    equ    0002h    ; Start
  76. CSR0_INIT    equ    0001h    ; Initialize
  77.  
  78. ;
  79. ;     Initialization Block  Mode operation Bit Definitions.
  80. ;
  81. M_PROM        equ    8000h    ; Promiscuous Mode
  82. M_INTL        equ    0040h   ; Internal Loopback
  83. M_DRTY        equ    0020h   ; Disable Retry
  84. M_COLL        equ    0010h    ; Force Collision
  85. M_DTCR        equ    0008h    ; Disable Transmit CRC)
  86. M_LOOP        equ    0004h    ; Loopback
  87. M_DTX        equ    0002h    ; Disable the Transmitter
  88. M_DRX        equ    0001h   ; Disable the Reciever
  89.  
  90.  
  91. ;
  92. ;     Receive message descriptor bit definitions.
  93. ;
  94. RCV_OWN        equ    8000h    ; owner bit 0 = host, 1 = lance
  95. RCV_ERR        equ    4000h    ; Error Summary
  96. RCV_FRAM    equ     2000h    ; Framing Error
  97. RCV_OFLO    equ    1000h    ; Overflow Error
  98. RCV_CRC        equ    0800h    ; CRC Error
  99. RCV_BUF_ERR    equ     0400h    ; Buffer Error
  100. RCV_START    equ    0200h    ; Start of Packet
  101. RCV_END        equ    0100h    ; End of Packet
  102.  
  103.  
  104. ;
  105. ;    Transmit  message descriptor bit definitions.
  106. ;
  107. XMIT_OWN    equ    8000h    ; owner bit 0 = host, 1 = lance
  108. XMIT_ERR    equ    4000h   ; Error Summary
  109. XMIT_RETRY    equ    1000h   ; more the 1 retry needed to Xmit
  110. XMIT_1_RETRY    equ    0800h    ; one retry needed to Xmit
  111. XMIT_DEF    equ    0400h    ; Deferred
  112. XMIT_START    equ    0200h    ; Start of Packet
  113. XMIT_END    equ    0100h    ; End of Packet
  114.  
  115. ;
  116. ;    Miscellaneous Equates
  117. ;
  118.  
  119. TRANSMIT_BUF_COUNT    equ    1
  120. RECEIVE_BUF_COUNT    equ    8
  121. TRANSMIT_BUF_SIZE    equ    1518
  122. RECEIVE_BUF_SIZE    equ    1518
  123.  
  124. ;
  125. ;    Receive Message Descriptor
  126. ;
  127. rcv_msg_dscp struc
  128.     rmd0    dw    ?    ; Rec. Buffer Lo-Address
  129.     rmd1    dw    ?    ; Status bits / Hi-Address
  130.     rmd2    dw    ?    ; Buff Byte-length (2's Comp)
  131.     rmd3    dw    ?    ; Receive message length
  132. rcv_msg_dscp ends
  133.  
  134.  
  135. ;
  136. ;    Transmit Message Descriptor
  137. ;
  138. xmit_msg_dscp struc
  139.     tmd0    dw    ?    ; Xmit Buffer Lo-Address
  140.     tmd1    dw    ?    ; Status bits / Hi-Address
  141.     tmd2     dw    ?    ; Buff Byte-length (2's Comp)
  142.     tmd3    dw    ?    ; Buffer Status bits & TDR value
  143. xmit_msg_dscp ends
  144.  
  145. ;
  146. ;    Upcall structure.  MUST be the same size as xmit_msg_dscp!
  147. ;
  148. upcall_struc    struc
  149. upcall_upcall    dd    ?
  150. upcall_buffer    dd    ?
  151. upcall_struc    ends
  152.  
  153.  
  154. code    segment    para public
  155.     assume    cs:code, ds:code
  156.  
  157.     public    int_no
  158. int_no    db    2,0,0,0            ;must be four bytes long for get_number.
  159. io_addr    dw    -1,-1
  160. dma_no    db    ?
  161.  
  162.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  163. driver_class    db    1        ;from the packet spec
  164. driver_type    db    35        ;from the packet spec
  165. driver_name    db    'NI6510',0    ;name of the driver.
  166. driver_function    db    2        ;basic, extended
  167. parameter_list    label    byte
  168.     db    1    ;major rev of packet driver
  169.     db    9    ;minor rev of packet driver
  170.     db    14    ;length of parameter list
  171.     db    EADDR_LEN    ;length of MAC-layer address
  172.     dw    GIANT    ;MTU, including MAC headers
  173.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  174.     dw    RECEIVE_BUF_COUNT-1    ;(# of back-to-back MTU rcvs) - 1
  175.     dw    TRANSMIT_BUF_COUNT-1    ;(# of successive xmits) - 1
  176.     dw    0    ;Interrupt # to hook for post-EOI
  177.             ;processing, 0 == none,
  178.  
  179.     public    rcv_modes
  180. rcv_modes    dw    7        ;number of receive modes in our table.
  181.         dw    0               ;There is no mode zero
  182.         dw    rcv_mode_1
  183.         dw    0        ;only ours.
  184.         dw    rcv_mode_3    ;ours plus broadcast
  185.         dw    0        ;some multicasts
  186.         dw    rcv_mode_5    ;all multicasts
  187.         dw    rcv_mode_6    ;all packets
  188.  
  189. multi_filter    db    0        ;<>0 if we need to filter multicasts.
  190. mcast_list_bits    db    8 dup(0)
  191.  
  192. ;
  193. ;the LANCE requires that the descriptor pointers be on a qword boundary.
  194. ;
  195.     align    8
  196.  
  197. transmit_dscps    xmit_msg_dscp    TRANSMIT_BUF_COUNT dup(<>)
  198. receive_dscps    rcv_msg_dscp    RECEIVE_BUF_COUNT dup(<>)
  199.  
  200. transmit_upcall    upcall_struc    TRANSMIT_BUF_COUNT dup(<>)
  201.  
  202. transmit_head    dw    transmit_dscps    ;->next packet to be filled by host.
  203. receive_head    dw    receive_dscps    ;->next packet to be filled by LANCE.
  204.  
  205. ;
  206. ;      LANCE Initialization Block
  207. ;
  208.     align    2
  209. init_block        label    byte
  210. init_mode        dw    0
  211. init_addr        db    EADDR_LEN dup(?)    ; Our Ethernet address
  212. init_filter        db    8 dup(0)    ;Multicast filter.
  213. init_receive        dw    ?,?        ;Receive Ring Pointer.
  214. init_transmit          dw    ?,?          ;Transmit Ring Pointer.
  215.  
  216.     public    send_pkt
  217. send_pkt:
  218. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  219. ;  (only if the high-performance bit is set in driver_function)
  220. ;enter with ds:si -> packet, cx = packet length.
  221. ;exit with nc if ok, or else cy if error, dh set to error number.
  222.     assume    ds:nothing
  223.  
  224.     xor    bx,bx
  225.  
  226.     mov    ax,18
  227.     call    set_timeout
  228. send_pkt_1:
  229.     test    transmit_dscps[bx].tmd1,XMIT_OWN    ;Did the lance chip give it back?
  230.     je    send_pkt_2
  231.     call    do_timeout
  232.     jne    send_pkt_1
  233.     mov    dh,CANT_SEND
  234.     stc
  235.     ret
  236. send_pkt_2:
  237. ;remember the upcall pointer for later upcalls.
  238.     mov    transmit_upcall[bx].upcall_upcall.offs,di
  239.     mov    transmit_upcall[bx].upcall_upcall.segm,es
  240.     mov    transmit_upcall[bx].upcall_buffer.offs,si
  241.     mov    transmit_upcall[bx].upcall_buffer.segm,ds
  242.  
  243. ;reset error indications.
  244.     and    transmit_dscps[bx].tmd1,not (XMIT_ERR or XMIT_DEF or XMIT_1_RETRY or XMIT_RETRY)    ;Did the lance chip give it back?
  245.     mov    transmit_dscps[bx].tmd3,0    ;reset all error bits.
  246.  
  247.     mov    ax,cx            ;store the count.
  248.     cmp    ax,RUNT            ; minimum length for Ether
  249.     ja    oklen
  250.     mov    ax,RUNT            ; make sure size at least RUNT
  251. oklen:
  252.     neg    ax
  253.     mov    transmit_dscps[bx].tmd2,ax
  254.  
  255.     mov    ax,transmit_dscps[bx].tmd0    ;store the packet.
  256.     mov    dx,transmit_dscps[bx].tmd1
  257.     call    phys_to_segmoffs
  258.     rep    movsb
  259.  
  260.     or    transmit_dscps[bx].tmd1,XMIT_OWN    ;give it to the lance chip.
  261.  
  262. ;Inform LANCE that it should poll for a packet.
  263.     loadport
  264.     mov    ax,CSR0_INEA or CSR0_TDMD
  265.     outport    CSR0
  266.     clc
  267.     ret
  268.  
  269.  
  270.     public    get_address
  271. get_address:
  272. ;get the address of the interface.
  273. ;enter with es:di -> place to get the address, cx = size of address buffer.
  274. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  275.     assume    ds:code
  276.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  277.     jb    get_address_2
  278.     mov    cx,EADDR_LEN
  279.     loadport            ; Get our Ethernet address base.
  280.     setport    EBASE
  281.     cld
  282. get_address_1:
  283.     insb                ; get a byte of the eprom address
  284.     inc    dx            ; next register
  285.     loop    get_address_1        ; go back for rest
  286.     mov    cx,EADDR_LEN
  287.     clc
  288.     ret
  289. get_address_2:
  290.     stc
  291.     ret
  292.  
  293.  
  294.     public    set_address
  295. set_address:
  296. ;enter with ds:si -> Ethernet address, CX = length of address.
  297. ;exit with nc if okay, or cy, dh=error if any errors.
  298.     assume    ds:nothing
  299.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  300.     je    set_address_4
  301.     mov    dh,BAD_ADDRESS
  302.     stc
  303.     jmp    short set_address_done
  304. set_address_4:
  305.  
  306.     push    cs
  307.     pop    es
  308.     mov    di,offset init_addr
  309.     rep    movsb
  310.     call    initialize        ;initialize with our new address.
  311.  
  312. set_address_okay:
  313.     mov    cx,EADDR_LEN        ;return their address length.
  314.     clc
  315. set_address_done:
  316.     push    cs
  317.     pop    ds
  318.     assume    ds:code
  319.     ret
  320.  
  321.  
  322. rcv_mode_1:
  323.     mov    ax,M_DRX or M_DTX    ;disable the receiver and transmitter.
  324.     jmp    initialize_nomulti
  325. rcv_mode_3:
  326.     xor    ax,ax            ;don't accept any multicast frames.
  327.     call    initialize_multi
  328.     mov    ax,0            ;non-promiscuous mode
  329.     jmp    short initialize_nomulti
  330. rcv_mode_5:
  331.     mov    ax,0            ;non-promiscuous mode
  332.     mov    ax,-1            ;accept any multicast frames.
  333.     call    initialize_multi
  334.     jmp    short initialize_nomulti
  335. rcv_mode_6:
  336.     mov    ax,M_PROM    ;promiscuous mode
  337. initialize_nomulti:
  338.     mov    multi_filter,0
  339. initialize:
  340.     mov    init_mode,ax
  341.     loadport
  342.     mov    ax,CSR0_STOP        ;reset the INIT bit.
  343.     outport    CSR0
  344.  
  345.     mov    ax,CSR0_INEA or CSR0_STRT or CSR0_INIT    ;reinit and restart.
  346.     outport    CSR0
  347.  
  348.     setport    DATA_REG
  349.  
  350.     mov    ax,36            ;wait one second for the board
  351.     call    set_timeout        ;  to timeout.
  352. initialize_1:
  353.     in    ax,dx
  354.     test    ax,CSR0_IDON
  355.     jne    initialize_2
  356.     call    do_timeout
  357.     jne    initialize_1
  358.     stc
  359.     ret
  360. initialize_2:
  361.     clc
  362.     ret
  363.  
  364.  
  365. initialize_multi:
  366. ;enter with ax = value for all multicast hash bits.
  367.     push    cs
  368.     pop    es
  369.     mov    di,offset init_filter
  370.     mov    cx,8/2
  371.     rep    stosw
  372.     ret
  373.  
  374.  
  375.     public    set_multicast_list
  376. set_multicast_list:
  377. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  378. ;return nc if we set all of them, or cy,dh=error if we didn't.
  379.     mov    dh,NO_MULTICAST        ;for some reason we can't do multi's.
  380.     stc
  381.     ret
  382.  
  383.  
  384.     public    terminate
  385. terminate:
  386.     call    rcv_mode_1        ;don't receive any apckets.
  387.  
  388. ;This routine will remove the (host) DMA controller from
  389. ;cascade mode of operation.
  390.     mov    al,dma_no
  391.     or    al,SET_DMA_MASK
  392.     cmp    dma_no,4        ;If channel 5 or 6,
  393.     ja    terminate_16        ;  use sixteen bit dma.
  394. terminate_8:
  395.     out    DMA_8MASK_REG,al
  396.     jmp    short terminate_done
  397. terminate_16:
  398.     out    DMA_16MASK_REG,al
  399. terminate_done:
  400.     ret
  401.  
  402.     public    reset_interface
  403. reset_interface:
  404. ;reset the interface.
  405.     assume    ds:code
  406.     ret
  407.  
  408.  
  409. ;called when we want to determine what to do with a received packet.
  410. ;enter with cx = packet length, es:di -> packet type.
  411.     extrn    recv_find: near
  412.  
  413. ;called after we have copied the packet into the buffer.
  414. ;enter with ds:si ->the packet, cx = length of the packet.
  415.     extrn    recv_copy: near
  416.  
  417.     extrn    count_in_err: near
  418.     extrn    count_out_err: near
  419.  
  420. NI6510_ISR_ACKNOWLEDGE equ (CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  421.  
  422.     public    recv
  423. recv:
  424. ;called from the recv isr.  All registers have been saved, and ds=cs.
  425. ;Upon exit, the interrupt will be acknowledged.
  426.     assume    ds:code
  427.  
  428.     loadport
  429.     setport    ADDR_REG
  430.     mov    ax,CSR0
  431.     out    dx,ax
  432.     in    ax,dx
  433.     setport    DATA_REG
  434.     in    ax,dx
  435.     mov    bx,ax            ;make a copy.
  436.  
  437. ; Acknowledge the Interrupt from the controller, but disable further
  438. ; controller Interrupts until we service the current interrupt.
  439. ;
  440. ;(CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  441. ;
  442.     and    ax,not NI6510_ISR_ACKNOWLEDGE
  443.     out    dx,ax
  444.     in    ax,dx        ; follow all writes by a read
  445.  
  446.     test    bx,CSR0_RINT        ;receive interrupt?
  447.     je    recv_done        ;no, we're done.
  448.  
  449.     mov    bx,receive_head
  450.  
  451. recv_search:
  452.     test    code:[bx].rmd1,RCV_OWN    ;do we own this buffer?
  453.     je    recv_own        ;yes - process it.
  454.     call    inc_recv_ring        ;go to the next one.
  455.     cmp    bx,receive_head        ;did we get back to the beginning?
  456.     jne    recv_search        ;not yet.
  457.     jmp    short recv_done        ;yes -- spurious interrupt!
  458. recv_own:
  459.     test    code:[bx].rmd1,RCV_ERR    ;Any errors in this buffer?
  460.     jne    recv_err        ;yes -- ignore this packet.
  461.  
  462.     mov    ax,code:[bx].rmd0    ;fetch the packet.
  463.     mov    dx,code:[bx].rmd1
  464.     call    phys_to_segmoffs
  465.  
  466.   if 0    ;not in this release, sigh.
  467.     cmp    multi_filter,0        ;should we filter multicasts?
  468.     je    recv_filter        ;no.
  469.     call    multicast_filter    ;yes -- is it one of ours?
  470.     jc    recv_free        ;no - ignore it.
  471. recv_filter:
  472.   endif
  473.  
  474.     push    es
  475.     push    di
  476.     push    bx
  477.  
  478.     mov    cx,code:[bx].rmd3
  479.     and    cx,0fffh        ;strip off the reserved bits
  480.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  481.                     ;  point to the packet type.
  482.     push    cx
  483.     call    recv_find
  484.     pop    cx
  485.  
  486.     pop    bx
  487.     pop    si
  488.     pop    ds
  489.     assume    ds:nothing
  490.  
  491.     mov    ax,es            ;is this pointer null?
  492.     or    ax,di
  493.     je    recv_free        ;yes - just free the frame.
  494.  
  495.     push    es
  496.     push    di
  497.     push    cx
  498.     rep    movsb
  499.     pop    cx
  500.     pop    si
  501.     pop    ds
  502.     assume    ds:nothing
  503.  
  504.     call    recv_copy
  505.  
  506.     jmp    short recv_free
  507.  
  508. recv_err:
  509.     call    count_in_err
  510. recv_free:
  511.     push    cs
  512.     pop    ds
  513.     assume    ds:code
  514.  
  515. ;clear any error bits.
  516.     and    code:[bx].rmd1,not (RCV_ERR or RCV_FRAM or RCV_OFLO or RCV_CRC or RCV_BUF_ERR)
  517.     or    code:[bx].rmd1,RCV_OWN    ;give it back to the lance.
  518.     call    inc_recv_ring        ;go to the next one.
  519.     test    code:[bx].rmd1,RCV_OWN    ;Do we own this one?
  520.     je    recv_own
  521.     mov    receive_head,bx        ;remember where the next one starts.
  522. recv_done:
  523.     loadport            ;enable interrupts again.
  524.     setport    DATA_REG
  525.     mov    ax,CSR0_INEA
  526.     out    dx,ax
  527.     ret
  528.  
  529.  
  530. inc_recv_ring:
  531. ;advance bx to the next receive ring descriptor.
  532.     assume    ds:nothing
  533.     add    bx,(size rcv_msg_dscp)
  534.     cmp    bx,offset receive_dscps + RECEIVE_BUF_COUNT * (size rcv_msg_dscp)
  535.     jb    inc_recv_ring_1
  536.     mov    bx,offset receive_dscps
  537. inc_recv_ring_1:
  538.     ret
  539.  
  540.  
  541.     public    recv_exiting
  542. recv_exiting:
  543. ;called from the recv isr after interrupts have been acknowledged.
  544. ;Only ds and ax have been saved.
  545.     assume    ds:nothing
  546.     ret
  547.  
  548.  
  549. phys_to_segmoffs:
  550. ;enter with dx:ax as the physical address of the buffer,
  551. ;exit with es:di -> buffer.
  552.     shl    dx,16-4            ;move the upper four bits into position.
  553.     mov    di,ax            ;now get the low 12 bits of the segment.
  554.     shr    di,4
  555.     or    dx,di            ;combine them.
  556.     mov    es,dx
  557.     mov    di,ax
  558.     and    di,0fh            ;now compute the offset.
  559.     ret
  560.  
  561.     include    timeout.asm
  562.  
  563. ;we use this memory for buffers once we've gone resident.
  564. transmit_bufs    equ    $
  565. receive_bufs    equ    transmit_bufs + TRANSMIT_BUF_COUNT * TRANSMIT_BUF_SIZE
  566. end_resident    equ    receive_bufs + RECEIVE_BUF_COUNT * RECEIVE_BUF_SIZE
  567.  
  568.     public    usage_msg
  569. usage_msg    db    "usage: ni6510 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  570. no_board_msg    db    "No NI6510 detected.",CR,LF,'$'
  571. io_addr_funny_msg    label    byte
  572.         db    "No NI6510 detected, continuing anyway.",CR,LF,'$'
  573. bad_reset_msg    db    "Unable to reset the NI6510.",CR,LF,'$'
  574. bad_init_msg    db    "Unable to initialize the NI6510.",CR,LF,'$'
  575.  
  576.     public    copyright_msg
  577. copyright_msg    db    "Packet driver for a Racal Interlan NI6510, version ",'0'+majver,".",'0'+version,CR,LF
  578.         db    '$'
  579.  
  580. int_nos        db    9, 12, 15, 5    ;interrupt numbers.
  581. dma_nos        db    0, 3, 5, 6    ;dma channel numbers
  582.  
  583. int_no_name    db    "Interrupt number ",'$'
  584. io_addr_name    db    "I/O port ",'$'
  585.  
  586.     extrn    set_recv_isr: near
  587.     extrn    maskint: near
  588.  
  589. ;enter with si -> argument string, di -> dword to store.
  590. ;if there is no number, don't change the number.
  591.     extrn    get_number: near
  592.  
  593. ;enter with dx -> name of word, di -> dword to print.
  594.     extrn    print_number: near
  595.  
  596.     public    parse_args
  597. parse_args:
  598. ;exit with nc if all went well, cy otherwise.
  599.     assume    ds:code
  600.     mov    di,offset int_no
  601.     call    get_number
  602.     mov    di,offset io_addr
  603.     call    get_number
  604.     clc
  605.     ret
  606.  
  607.  
  608.     public    etopen
  609. etopen:
  610.     assume    ds:code
  611.  
  612.     cmp    io_addr,-1        ;Did they ask for auto-detect?
  613.     je    find_board
  614.  
  615.     call    detect_board        ;no, just verify its existance.
  616.     je    find_board_found
  617.  
  618.     mov    dx,offset io_addr_funny_msg
  619.     mov    ah,9
  620.     int    21h
  621.  
  622.     jmp    find_board_found
  623.  
  624. find_board:
  625.     mov    io_addr,300h        ;Search for the Ethernet address.
  626.     mov    io_addr+2,0
  627. find_board_0:
  628.     call    detect_board
  629.     je    find_board_found
  630. find_board_again:
  631.     add    io_addr,20h        ;not at this port, try another.
  632.     cmp    io_addr,360h
  633.     jbe    find_board_0
  634.  
  635.     mov    dx,offset no_board_msg    ;Tell them that we can't find it.
  636.     mov    ah,9
  637.     int    21h
  638.  
  639.     stc
  640.     ret
  641. find_board_found:
  642.  
  643.     loadport            ;get the configuration register and
  644.     setport    CONFIG            ;  determine the interrupt number.
  645.     in    al,dx
  646.     shr    al,2
  647.     and    al,3
  648.     mov    bl,al
  649.     xor    bh,bh
  650.     mov    al,int_nos[bx]
  651.     mov    int_no,al
  652.  
  653. ;This routine will put the (host) DMA controller into
  654. ;cascade mode of operation.
  655.  
  656.     in    al,dx            ;get the dma channel field.
  657.     and    al,3
  658.     mov    bl,al
  659.     xor    bh,bh
  660.     mov    al,dma_nos[bx]
  661.     mov    dma_no,al
  662.     mov    ah,al            ;save a copy.
  663.     or    al,SET_DMA_MASK
  664.     cmp    ah,4            ;If channel 5 or 6,
  665.     ja    dma_16            ;  use sixteen bit dma.
  666. dma_8:
  667.     out    DMA_8MASK_REG,al
  668.     mov    al,ah
  669.     or    al,CASCADE_MODE
  670.     out    DMA_8MODE_REG,al
  671.     mov    al,ah
  672.     out    DMA_8MASK_REG,al
  673.     jmp    short dma_done
  674. dma_16:
  675.     out    DMA_16MASK_REG,al
  676.     mov    al,ah
  677.     or    al,CASCADE_MODE
  678.     out    DMA_16MODE_REG,al
  679.     mov    al,ah
  680.     out    DMA_16MASK_REG,al
  681. dma_done:
  682.  
  683.     mov    di,offset int_no
  684.     mov    dx,offset int_no_name
  685.     call    print_number
  686.  
  687.     mov    di,offset io_addr
  688.     mov    dx,offset io_addr_name
  689.     call    print_number
  690.  
  691.     mov    al,int_no
  692.     call    maskint            ;disable these interrupts.
  693.  
  694.     loadport
  695.     setport    RESET
  696.     out    dx,al
  697.  
  698.     setport    CSR0
  699.     in    ax,dx
  700.     cmp    ax,CSR0_STOP
  701.     je    reset_ok
  702.  
  703.     mov    dx,offset bad_reset_msg
  704.     mov    ah,9
  705.     int    21h
  706.  
  707.     stc
  708.     ret
  709. reset_ok:
  710.  
  711. ;set up transmit descriptor ring.
  712.     push    ds
  713.     pop    es
  714.     mov    cx,TRANSMIT_BUF_COUNT
  715.     mov    bx,offset transmit_dscps
  716.     mov    di,offset transmit_bufs
  717. setup_transmit:
  718.     call    segmoffs_to_phys
  719.  
  720.     or    dx,XMIT_START or XMIT_END
  721.     mov    [bx].tmd0,ax        ;points to the buffer.
  722.     mov    [bx].tmd1,dx
  723.  
  724.     add    bx,(size xmit_msg_dscp)
  725.     add    di,TRANSMIT_BUF_SIZE
  726.     loop    setup_transmit
  727.  
  728. ;set up receive descriptor ring.
  729.     mov    cx,RECEIVE_BUF_COUNT
  730.     mov    bx,offset receive_dscps
  731.     mov    di,offset receive_bufs
  732. setup_receive:
  733.     call    segmoffs_to_phys
  734.  
  735.     or    dx,RCV_OWN
  736.     mov    [bx].rmd0,ax        ;points to the buffer.
  737.     mov    [bx].rmd1,dx
  738.  
  739.     mov    [bx].rmd2,-RECEIVE_BUF_SIZE
  740.     mov    [bx].rmd3,0
  741.  
  742.   if 0
  743.     push    di            ;initialize the buffers to 55aa.
  744.     push    cx
  745.     mov    cx,RECEIVE_BUF_SIZE/2
  746.     mov    ax,55aah
  747.     rep    stosw
  748.     pop    cx
  749.     pop    di
  750.   endif
  751.  
  752.     add    bx,(size rcv_msg_dscp)
  753.     add    di,RECEIVE_BUF_SIZE
  754.     loop    setup_receive
  755.  
  756. ;initialize the board.
  757.     mov    cx,EADDR_LEN        ;get our address.
  758.     mov    di,offset init_addr
  759.     call    get_address
  760.  
  761.     mov    cx,RECEIVE_BUF_COUNT
  762.     call    compute_log2
  763.  
  764.     mov    di,offset receive_dscps
  765.     call    segmoffs_to_phys
  766.     or    dx,cx            ;include the buffer size bits.
  767.     mov    init_receive[0],ax
  768.     mov    init_receive[2],dx
  769.  
  770.     mov    cx,TRANSMIT_BUF_COUNT
  771.     call    compute_log2
  772.  
  773.     mov    di,offset transmit_dscps
  774.     call    segmoffs_to_phys
  775.     or    dx,cx            ;include the buffer size bits.
  776.     mov    init_transmit[0],ax
  777.     mov    init_transmit[2],dx
  778.  
  779.     mov    di,offset init_block    ;now tell the board where the init
  780.     call    segmoffs_to_phys    ;  block is.
  781.  
  782.     push    dx
  783.     push    ax
  784.  
  785.     loadport
  786.     mov    ax,0            ;write the bus config register.
  787.     outport    CSR3
  788.  
  789.     pop    ax            ;write the low word.
  790.     outport    CSR1
  791.  
  792.     pop    ax            ;write the high word.
  793.     outport    CSR2
  794.  
  795.     mov    ax,0            ;non-promiscuous mode
  796.     call    initialize
  797.     jnc    init_ok
  798.  
  799.     mov    dx,offset bad_init_msg
  800.     mov    ah,9
  801.     int    21h
  802.  
  803.     stc
  804.     ret
  805.  
  806. init_ok:
  807. ;
  808. ; Now hook in our interrupt
  809. ;
  810.     call    set_recv_isr
  811.  
  812.     mov    dx,offset end_resident
  813.     clc
  814.     ret
  815.  
  816.  
  817. compute_log2:
  818. ;enter with cx = number of buffers.
  819. ;exit with cx = log2(number of buffers) << 13.
  820.     mov    ax,-1
  821. compute_log2_1:
  822.     inc    ax
  823.     shr    cx,1
  824.     jne    compute_log2_1
  825.     shl    ax,13
  826.     mov    cx,ax
  827.     ret
  828.  
  829.  
  830. segmoffs_to_phys:
  831. ;enter with es:di -> buffer.
  832. ;exit with dx:ax as the physical address of the buffer,
  833.  
  834.     mov    dx,es            ;get the high 4 bits of the segment,
  835.     shr    dx,16-4
  836.     mov    ax,es            ;and the low 12 bits of the segment.
  837.     shl    ax,4
  838.     add    ax,di            ;add in the offset.
  839.     adc    dx,0
  840.     ret
  841.  
  842.  
  843. detect_board:
  844. ;test to see if a board is located at io_addr.
  845. ;return nz if not.
  846.     loadport
  847.     setport    EBASE
  848.     in    al,dx            ;Check for Interlan's prefix word.
  849.     cmp    al,2
  850.     jne    detect_board_exit
  851.  
  852.     setport    EBASE+1
  853.     in    al,dx
  854.     cmp    al,7
  855.     jne    detect_board_exit
  856.  
  857.     setport    EBASE+EADDR_LEN        ;first byte following should be 0
  858.     in    al,dx
  859.     cmp    al,0
  860.     jne    detect_board_exit
  861.  
  862.     setport    EBASE+EADDR_LEN+1    ;second byte should be 55h
  863.     in    al,dx
  864.     cmp    al,55h
  865. detect_board_exit:
  866.     ret
  867.  
  868. code    ends
  869.  
  870.     end
  871.