home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / lance.asm < prev    next >
Assembly Source File  |  1995-06-25  |  19KB  |  866 lines

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