home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / connect / tcpip / crynwr / pktd11c / lance.asm < prev    next >
Assembly Source File  |  1993-12-14  |  20KB  |  873 lines

  1. lance_version    equ    3
  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 9 (keyboard).
  383.     lds    dx,their_9
  384.     mov    ax,2519h
  385.     int    21h
  386.     pop    ds
  387.  
  388.     push    ds            ;restore their interrupt 19 (reboot).
  389.     lds    dx,their_19
  390.     mov    ax,2519h
  391.     int    21h
  392.     pop    ds
  393.  
  394.     ret
  395.  
  396. our_19:
  397.     assume    ds:nothing
  398.     push    ax
  399.     push    dx
  400.     loadport
  401.     mov    ax,CSR0_STOP        ;reset the INIT bit
  402.     outport    CSR0
  403.     pop    dx
  404.     pop    ax
  405.     db    0eah            ;jmp xxxx:yyyy
  406. their_19    dd    ?
  407.  
  408.  
  409. our_9:
  410.     assume    ds:nothing
  411.     push    ax            ;did they press delete?
  412.     in    al,60h
  413.     cmp    al,53h
  414.     jnz    our_9_2            ;no.
  415.     push    es            ;are control and alt pressed also?
  416.     mov    ax,40h
  417.     mov    es,ax
  418.     mov    al,es:[17h]
  419.     and    al,0ch
  420.     cmp    al,0ch
  421.     jnz    our_9_1            ;no, don't do the reboot thing.
  422.  
  423.     push    dx            ;loadport and outport use dx.
  424.     loadport
  425.     mov    ax,CSR0_STOP        ;reset the INIT bit
  426.     outport    CSR0
  427.     pop    dx
  428.  
  429. our_9_1:
  430.     pop    es
  431. our_9_2:
  432.     pop    ax
  433.     db    0eah
  434. their_9    dd    ?
  435.  
  436.  
  437.  
  438.     public    reset_interface
  439. reset_interface:
  440. ;reset the interface.
  441.     assume    ds:code
  442.     ret
  443.  
  444.  
  445. ;called when we want to determine what to do with a received packet.
  446. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  447.     extrn    recv_find: near
  448.  
  449. ;called after we have copied the packet into the buffer.
  450. ;enter with ds:si ->the packet, cx = length of the packet.
  451.     extrn    recv_copy: near
  452.  
  453. ;call this routine to schedule a subroutine that gets run after the
  454. ;recv_isr.  This is done by stuffing routine's address in place
  455. ;of the recv_isr iret's address.  This routine should push the flags when it
  456. ;is entered, and should jump to recv_exiting_exit to leave.
  457. ;enter with ax = address of routine to run.
  458.     extrn    schedule_exiting: near
  459.  
  460. ;recv_exiting jumps here to exit, after pushing the flags.
  461.     extrn    recv_exiting_exit: near
  462.  
  463. ;enter with dx = amount of memory desired.
  464. ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
  465.     extrn    malloc: near
  466.  
  467.     extrn    count_in_err: near
  468.     extrn    count_out_err: near
  469.  
  470. LANCE_ISR_ACKNOWLEDGE equ (CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  471.  
  472.     public    recv
  473. recv:
  474. ;called from the recv isr.  All registers have been saved, and ds=cs.
  475. ;Upon exit, the interrupt will be acknowledged.
  476.     assume    ds:code
  477.  
  478.     loadport
  479.     setport    ADDR_REG
  480.     mov    ax,CSR0
  481.     out    dx,ax
  482.     in    ax,dx
  483.     setport    DATA_REG
  484.     in    ax,dx
  485.     mov    bx,ax            ;make a copy.
  486.  
  487. ; Acknowledge the Interrupt from the controller, but disable further
  488. ; controller Interrupts until we service the current interrupt.
  489. ;
  490. ;(CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  491. ;
  492.     and    ax,not LANCE_ISR_ACKNOWLEDGE
  493.     out    dx,ax
  494.     in    ax,dx        ; follow all writes by a read
  495.  
  496.     test    bx,CSR0_RINT        ;receive interrupt?
  497.     je    recv_done_1        ;no, we're done.
  498.  
  499.     mov    bx,receive_head
  500.  
  501. recv_search:
  502.     test    code:[bx].rmd1,RCV_OWN    ;do we own this buffer?
  503.     je    recv_own        ;yes - process it.
  504.     call    inc_recv_ring        ;go to the next one.
  505.     cmp    bx,receive_head        ;did we get back to the beginning?
  506.     jne    recv_search        ;not yet.
  507. recv_done_1:
  508.     jmp    short recv_done        ;yes -- spurious interrupt!
  509. recv_own:
  510.     test    code:[bx].rmd1,RCV_ERR    ;Any errors in this buffer?
  511.     jne    recv_err        ;yes -- ignore this packet.
  512.  
  513.     mov    ax,code:[bx].rmd0    ;fetch the packet.
  514.     mov    dx,code:[bx].rmd1
  515.     call    phys_to_segmoffs
  516.  
  517.     push    es
  518.     push    di
  519.     push    bx
  520.  
  521.     mov    cx,code:[bx].rmd3
  522.     and    cx,0fffh        ;strip off the reserved bits
  523.     sub    cx,4            ;leave the CRC behind.
  524.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  525.                     ;  point to the packet type.
  526.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  527.     mov    ax, es:[di]
  528.     xchg    ah, al
  529.     cmp     ax, 1500
  530.     ja    BlueBookPacket
  531.     inc    di            ;set di to 802.2 header
  532.     inc    di
  533.     mov    dl, IEEE8023
  534. BlueBookPacket:
  535.     push    cx
  536.     call    recv_find
  537.     pop    cx
  538.  
  539.     pop    bx
  540.     pop    si
  541.     pop    ds
  542.     assume    ds:nothing
  543.  
  544.     mov    ax,es            ;is this pointer null?
  545.     or    ax,di
  546.     je    recv_free        ;yes - just free the frame.
  547.  
  548.     push    es
  549.     push    di
  550.     push    cx
  551.     shr    cx,1
  552.     rep    movsw
  553.     jnc    rec_pkt_3
  554.     movsb
  555. rec_pkt_3:
  556.     pop    cx
  557.     pop    si
  558.     pop    ds
  559.     assume    ds:nothing
  560.  
  561.     call    recv_copy
  562.  
  563.     jmp    short recv_free
  564.  
  565. recv_err:
  566.     call    count_in_err
  567. recv_free:
  568.     movseg    ds,cs
  569.     assume    ds:code
  570.  
  571. ;clear any error bits.
  572.     and    code:[bx].rmd1,not (RCV_ERR or RCV_FRAM or RCV_OFLO or RCV_CRC or RCV_BUF_ERR)
  573.     or    code:[bx].rmd1,RCV_OWN    ;give it back to the lance.
  574.     call    inc_recv_ring        ;go to the next one.
  575.     test    code:[bx].rmd1,RCV_OWN    ;Do we own this one?
  576.     je    recv_own
  577.     mov    receive_head,bx        ;remember where the next one starts.
  578. recv_done:
  579.     loadport            ;enable interrupts again.
  580.     setport    DATA_REG
  581.     mov    ax,CSR0_INEA
  582.     out    dx,ax
  583.     ret
  584.  
  585.  
  586. inc_recv_ring:
  587. ;advance bx to the next receive ring descriptor.
  588.     assume    ds:nothing
  589.     add    bx,(size rcv_msg_dscp)
  590.     cmp    bx,offset receive_dscps + RECEIVE_BUF_COUNT * (size rcv_msg_dscp)
  591.     jb    inc_recv_ring_1
  592.     mov    bx,offset receive_dscps
  593. inc_recv_ring_1:
  594.     ret
  595.  
  596.  
  597. phys_to_segmoffs:
  598. ;enter with dx:ax as the physical address of the buffer,
  599. ;exit with es:di -> buffer.
  600.     shl    dx,16-4            ;move the upper four bits into position.
  601.     mov    di,ax            ;now get the low 12 bits of the segment.
  602.     shr    di,4
  603.     or    dx,di            ;combine them.
  604.     mov    es,dx
  605.     mov    di,ax
  606.     and    di,0fh            ;now compute the offset.
  607.     ret
  608.  
  609.     include    multicrc.asm
  610.     include    timeout.asm
  611.  
  612.     public    timer_isr
  613. timer_isr:
  614. ;if the first instruction is an iret, then the timer is not hooked
  615.     iret
  616.  
  617. ;any code after this will not be kept.  Buffers used by the program, if any,
  618. ;are allocated from the memory between end_resident and end_free_mem.
  619.     public end_resident,end_free_mem
  620.     align    4            ;just for efficiency's sake.
  621. end_resident    label    byte
  622.     db    (RECEIVE_BUF_COUNT*RECEIVE_BUF_SIZE) + (TRANSMIT_BUF_COUNT*TRANSMIT_BUF_SIZE) dup(?)
  623. end_free_mem    label    byte
  624.  
  625. int_no_name    db    "Interrupt number ",'$'
  626. io_addr_name    db    "I/O port ",'$'
  627. dma_no_name    db    "DMA number ",'$'
  628.  
  629.     extrn    set_recv_isr: near
  630.     extrn    maskint: near
  631.  
  632. ;enter with si -> argument string, di -> dword to store.
  633. ;if there is no number, don't change the number.
  634.     extrn    get_number: near
  635.  
  636. ;enter with dx -> name of word, di -> dword to print.
  637.     extrn    print_number: near
  638.  
  639. ;-> the assigned Ethernet address of the card.
  640.     extrn    rom_address: byte
  641.  
  642.     public    etopen
  643. etopen:
  644.     assume    ds:code
  645.  
  646.     call    check_board
  647.     jnc    etopen_1
  648.     ret
  649. etopen_1:
  650.  
  651. ;This routine will put the (host) DMA controller into
  652. ;cascade mode of operation.
  653.  
  654.     mov    al,dma_no
  655.     cmp    al,4            ;If channel 5, 6 or 7
  656.     ja    dma_16            ;  use sixteen bit dma.
  657. dma_8:
  658.     or    al,CASCADE_MODE
  659.     out    DMA_8MODE_REG,al    ;set the mode first, then unmask it.
  660.     and    al,DMA_CHANNEL_FIELD
  661.     out    DMA_8MASK_REG,al
  662.     jmp    short dma_done
  663. dma_16:
  664.     and    al,DMA_CHANNEL_FIELD    ;set the mode first, then unmask it.
  665.     or    al,CASCADE_MODE
  666.     out    DMA_16MODE_REG,al
  667.     and    al,DMA_CHANNEL_FIELD
  668.     out    DMA_16MASK_REG,al
  669. dma_done:
  670.  
  671.     mov    al, int_no        ; Get board's interrupt vector
  672.     add    al, 8
  673.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  674.     jb    set_int_num        ; No.
  675.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  676. set_int_num:
  677.     xor    ah, ah            ; Clear high byte
  678.     mov    int_num, ax        ; Set parameter_list int num.
  679.  
  680.     mov    al,int_no
  681.     call    maskint            ;disable these interrupts.
  682.  
  683.     loadport
  684.     reset_lance
  685.  
  686.     mov    ax,20
  687.     call    set_timeout
  688.     setport    ADDR_REG
  689.     mov    ax,CSR0
  690.     out    dx,ax
  691.     in    ax,dx
  692.     setport    DATA_REG
  693. etreset:
  694.     in    ax,dx
  695.     test    ax,CSR0_STOP
  696.     jnz    reset_ok
  697.     call    do_timeout
  698.     jnz    etreset
  699.  
  700.     mov    dx,offset bad_reset_msg
  701.     stc
  702.     ret
  703.  
  704. no_memory:
  705.     mov    dx,offset no_memory_msg
  706.     stc
  707.     ret
  708.  
  709. reset_ok:
  710.  
  711. ;set up transmit descriptor ring.
  712.     movseg    es,ds
  713.     mov    cx,TRANSMIT_BUF_COUNT
  714.     mov    bx,offset transmit_dscps
  715. setup_transmit:
  716.     mov    dx,TRANSMIT_BUF_SIZE
  717.     call    malloc
  718.     jc    no_memory
  719.  
  720.     mov    di,dx
  721.     call    segmoffs_to_phys
  722.  
  723.     or    dx,XMIT_START or XMIT_END
  724.     mov    [bx].tmd0,ax        ;points to the buffer.
  725.     mov    [bx].tmd1,dx
  726.  
  727.     add    bx,(size xmit_msg_dscp)
  728.     loop    setup_transmit
  729.  
  730. ;set up receive descriptor ring.
  731.     mov    cx,RECEIVE_BUF_COUNT
  732.     mov    bx,offset receive_dscps
  733. setup_receive:
  734.     mov    dx,RECEIVE_BUF_SIZE
  735.     call    malloc
  736.     jc    no_memory
  737.  
  738.     mov    di,dx
  739.     call    segmoffs_to_phys
  740.  
  741.     or    dx,RCV_OWN
  742.     mov    [bx].rmd0,ax        ;points to the buffer.
  743.     mov    [bx].rmd1,dx
  744.  
  745.     mov    [bx].rmd2,-RECEIVE_BUF_SIZE
  746.     mov    [bx].rmd3,0
  747.  
  748.   if 0
  749.     push    di            ;initialize the buffers to 55aa.
  750.     push    cx
  751.     mov    cx,RECEIVE_BUF_SIZE/2
  752.     mov    ax,55aah
  753.     rep    stosw
  754.     pop    cx
  755.     pop    di
  756.   endif
  757.  
  758.     add    bx,(size rcv_msg_dscp)
  759.     loop    setup_receive
  760.  
  761. ;initialize the board.
  762.     mov    cx,EADDR_LEN        ;get our address.
  763.     mov    di,offset rom_address
  764.     loadport            ; Get our Ethernet address base.
  765.     setport    EBASE
  766. get_address_1:
  767.     insb                ; get a byte of the eprom address
  768.     inc    dx            ; next register
  769.     loop    get_address_1        ; go back for rest
  770.  
  771.     mov    si,offset rom_address    ; copy it to the init table.
  772.     mov    di,offset init_addr
  773.     mov    cx,EADDR_LEN
  774.     rep    movsb
  775.  
  776.     mov    cx,RECEIVE_BUF_COUNT
  777.     call    compute_log2
  778.  
  779.     mov    di,offset receive_dscps
  780.     call    segmoffs_to_phys
  781.     or    dx,cx            ;include the buffer size bits.
  782.     mov    init_receive[0],ax
  783.     mov    init_receive[2],dx
  784.  
  785.     mov    cx,TRANSMIT_BUF_COUNT
  786.     call    compute_log2
  787.  
  788.     mov    di,offset transmit_dscps
  789.     call    segmoffs_to_phys
  790.     or    dx,cx            ;include the buffer size bits.
  791.     mov    init_transmit[0],ax
  792.     mov    init_transmit[2],dx
  793.  
  794.     mov    di,offset init_block    ;now tell the board where the init
  795.     call    segmoffs_to_phys    ;  block is.
  796.     mov    save_csr1,ax
  797.     mov    save_csr2,dx
  798.  
  799.     call    rcv_mode_3
  800.     jnc    init_ok
  801.  
  802.     mov    dx,offset bad_init_msg
  803.     stc
  804.     ret
  805.  
  806. init_ok:
  807. ;
  808. ; Now hook in our interrupt
  809. ;
  810.     call    set_recv_isr
  811.  
  812.     mov    ax,3519h        ;remember their reboot interrupt.
  813.     int    21h
  814.     mov    their_19.offs,bx
  815.     mov    their_19.segm,es
  816.  
  817.     mov    ah,25h            ;install our reboot interrupt
  818.     mov    dx,offset our_19
  819.     int    21h
  820.  
  821.     mov    ax,3509h        ;remember their reboot interrupt.
  822.     int    21h
  823.     mov    their_9.offs,bx
  824.     mov    their_9.segm,es
  825.  
  826.     mov    ah,25h            ;install our reboot interrupt
  827.     mov    dx,offset our_9
  828.     int    21h
  829.  
  830.     clc
  831.     ret
  832.  
  833.     public    print_parameters
  834. print_parameters:
  835. ;echo our command-line parameters
  836.     mov    di,offset int_no
  837.     mov    dx,offset int_no_name
  838.     call    print_number
  839.     mov    di,offset io_addr
  840.     mov    dx,offset io_addr_name
  841.     call    print_number
  842.     mov    di,offset dma_no
  843.     mov    dx,offset dma_no_name
  844.     call    print_number
  845.     ret
  846.  
  847. compute_log2:
  848. ;enter with cx = number of buffers.
  849. ;exit with cx = log2(number of buffers) << 13.
  850.     mov    ax,-1
  851. compute_log2_1:
  852.     inc    ax
  853.     shr    cx,1
  854.     jne    compute_log2_1
  855.     shl    ax,13
  856.     mov    cx,ax
  857.     ret
  858.  
  859.  
  860. segmoffs_to_phys:
  861. ;enter with es:di -> buffer.
  862. ;exit with dx:ax as the physical address of the buffer,
  863.  
  864.     mov    dx,es            ;get the high 4 bits of the segment,
  865.     shr    dx,16-4
  866.     mov    ax,es            ;and the low 12 bits of the segment.
  867.     shl    ax,4
  868.     add    ax,di            ;add in the offset.
  869.     adc    dx,0
  870.     ret
  871.  
  872.  
  873.