home *** CD-ROM | disk | FTP | other *** search
/ Netware Super Library / Netware Super Library.iso / drivers / nics / pktdrv7 / ni6510.asm < prev    next >
Encoding:
Assembly Source File  |  1990-07-27  |  21.0 KB  |  922 lines

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