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

  1. version    equ    3
  2. ;History:685,1
  3.  
  4. ;  Copyright, 1991-1992, Russell Nelson, Crynwr Software
  5.  
  6. ;   This program is free software; you can redistribute it and/or modify
  7. ;   it under the terms of the GNU General Public License as published by
  8. ;   the Free Software Foundation, version 1.
  9. ;
  10. ;   This program is distributed in the hope that it will be useful,
  11. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ;   GNU General Public License for more details.
  14. ;
  15. ;   You should have received a copy of the GNU General Public License
  16. ;   along with this program; if not, write to the Free Software
  17. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     include    defs.asm
  20.  
  21. NI_CSR        equ    0
  22. RBI        equ    2
  23. DATA_REG    equ    4
  24. ADDR_REG    equ    6
  25.     CSR0        equ    0
  26.     CSR1        equ    1
  27.     CSR2        equ    2
  28.     CSR3        equ    3
  29. EBASE        equ    0ch
  30. RBSA        equ    0eh
  31.  
  32. ;CSR bit definitions
  33. CSR_RBT        equ    100h
  34. CSR_SHE        equ    80h
  35. CSR_SWAP32    equ    40h
  36. CSR_BUF        equ    20h
  37. CSR_RBE        equ    10h
  38. CSR_DUM        equ    08h        ;for rev E. DEPCA compatability
  39. CSR_IM        equ    04h
  40. CSR_IEN        equ    02h
  41. CSR_LED        equ    01h
  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    ;must be a power of two.
  120. RECEIVE_BUF_COUNT    equ    16    ;must be a power of two.
  121. RECEIVE_BUF_SIZE    equ    1518
  122.  
  123. ;
  124. ;    Receive Message Descriptor
  125. ;
  126. rcv_msg_dscp struc
  127.     rmd0    dw    ?    ; Rec. Buffer Lo-Address
  128.     rmd1    dw    ?    ; Status bits / Hi-Address
  129.     rmd2    dw    ?    ; Buff Byte-length (2's Comp)
  130.     rmd3    dw    ?    ; Receive message length
  131. rcv_msg_dscp ends
  132.  
  133.  
  134. ;
  135. ;    Transmit Message Descriptor
  136. ;
  137. xmit_msg_dscp struc
  138.     tmd0    dw    ?    ; Xmit Buffer Lo-Address
  139.     tmd1    dw    ?    ; Status bits / Hi-Address
  140.     tmd2     dw    ?    ; Buff Byte-length (2's Comp)
  141.     tmd3    dw    ?    ; Buffer Status bits & TDR value
  142. xmit_msg_dscp ends
  143.  
  144. lance_seg    segment at 0
  145.  
  146. ;
  147. ;the LANCE requires that the descriptor pointers be on a qword boundary.
  148. ;
  149.     align    8
  150.  
  151. transmit_dscps    xmit_msg_dscp    TRANSMIT_BUF_COUNT dup(<>)
  152. receive_dscps    rcv_msg_dscp    RECEIVE_BUF_COUNT dup(<>)
  153.  
  154. ;
  155. ;      LANCE Initialization Block
  156. ;
  157.     align    2
  158. init_block        label    byte
  159. init_mode        dw    0
  160. init_addr        db    EADDR_LEN dup(?)    ; Our Ethernet address
  161. init_filter        db    8 dup(0)    ;Multicast filter.
  162. init_receive        dw    ?,?        ;Receive Ring Pointer.
  163. init_transmit          dw    ?,?          ;Transmit Ring Pointer.
  164.  
  165. transmit_bufs    equ    800h
  166. receive_bufs    equ    1000h
  167.  
  168. lance_seg    ends
  169.  
  170. code    segment    para public
  171.     assume    cs:code, ds:code
  172.  
  173.         public    int_no
  174. int_no        db    2,0,0,0            ;must be four bytes long for get_number.
  175. io_addr        dw    -1,-1
  176. base_addr    dw    -1,-1
  177.  
  178.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  179. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  180. driver_type    db    66        ;from the packet spec
  181. driver_name    db    'DEPCA',0    ;name of the driver.
  182. driver_function    db    2        ;basic, extended
  183. parameter_list    label    byte
  184.     db    1    ;major rev of packet driver
  185.     db    9    ;minor rev of packet driver
  186.     db    14    ;length of parameter list
  187.     db    EADDR_LEN    ;length of MAC-layer address
  188.     dw    GIANT    ;MTU, including MAC headers
  189.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  190.     dw    RECEIVE_BUF_COUNT-1    ;(# of back-to-back MTU rcvs) - 1
  191.     dw    TRANSMIT_BUF_COUNT-1    ;(# of successive xmits) - 1
  192. int_num    dw    0    ;Interrupt # to hook for post-EOI
  193.             ;processing, 0 == none,
  194.  
  195.     public    rcv_modes
  196. rcv_modes    dw    7        ;number of receive modes in our table.
  197.         dw    0               ;There is no mode zero
  198.         dw    0        ;none at all.
  199.         dw    0        ;only ours.
  200.         dw    rcv_mode_3    ;ours plus broadcast
  201.         dw    0        ;some multicasts
  202.         dw    0        ;all multicasts
  203.         dw    rcv_mode_6    ;all packets
  204.  
  205. save_csr1    dw    ?
  206. save_csr2    dw    ?
  207.  
  208. transmit_head    dw    transmit_dscps    ;->next packet to be filled by host.
  209. receive_head    dw    receive_dscps    ;->next packet to be filled by LANCE.
  210.  
  211. ni_csr_value    db    CSR_SHE or CSR_DUM or CSR_IEN or CSR_SWAP32
  212.  
  213. translate_address    dw    ?    ;->routine to translate the address.
  214. ;enter with ax = address.
  215. ;exit with di = translated address, RBI/NI_CSR set as needed.
  216. ;may trash dx.
  217.  
  218.     assume    ds:nothing
  219. translate_64k:
  220.     mov    di,ax
  221.     ret
  222.  
  223. translate_32k:
  224. ;move the window to the appropriate address.
  225.     mov    di,ax
  226.  
  227.     loadport
  228.     setport    NI_CSR
  229.     mov    al,ni_csr_value
  230.     test    di,8000h
  231.     je    translate_32k_1
  232.     and    al,not CSR_SWAP32
  233. translate_32k_1:
  234.     out    dx,al
  235.  
  236.     and    di,7fffh        ;only 32K of memory.
  237.     ret
  238.  
  239.  
  240. translate_2k:
  241. ;move the window to the appropriate address.
  242.     loadport
  243.     setport    RBI
  244.  
  245.     shr    ax,1            ;compute the 2K window.
  246.     shr    ax,1            ;divide by 8
  247.     shr    ax,1
  248.     mov    al,ah            ;divide by 256 (8*256 = 2K).
  249.     out    dx,al
  250.  
  251.     xor    di,di
  252.     ret
  253.  
  254.  
  255.     public bad_command_intercept
  256. bad_command_intercept:
  257. ;called with ah=command, unknown to the skeleton.
  258. ;exit with nc if okay, cy, dh=error if not.
  259.     mov    dh,BAD_COMMAND
  260.     stc
  261.     ret
  262.  
  263.     public    as_send_pkt
  264. ; The Asynchronous Transmit Packet routine.
  265. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  266. ;   interrupts possibly enabled.
  267. ; Exit with nc if ok, or else cy if error, dh set to error number.
  268. ;   es:di and interrupt enable flag preserved on exit.
  269. as_send_pkt:
  270.     ret
  271.  
  272.     public    drop_pkt
  273. ; Drop a packet from the queue.
  274. ; Enter with es:di -> iocb.
  275. drop_pkt:
  276.     assume    ds:nothing
  277.     ret
  278.  
  279.     public    xmit
  280. ; Process a transmit interrupt with the least possible latency to achieve
  281. ;   back-to-back packet transmissions.
  282. ; May only use ax and dx.
  283. xmit:
  284.     assume    ds:nothing
  285.     ret
  286.  
  287.  
  288.     public    send_pkt
  289. send_pkt:
  290. ;enter with ds:si -> packet, cx = packet length.
  291. ;exit with nc if ok, or else cy if error, dh set to error number.
  292.     assume    ds:nothing
  293.  
  294.     cmp    cx,GIANT        ; Is this packet too large?
  295.     ja    send_pkt_toobig
  296.  
  297.     mov    es,base_addr
  298.     assume    es:lance_seg
  299.  
  300.     xor    ax,ax            ;go back to base window (if changed).
  301.     call    translate_address
  302.  
  303.     xor    bx,bx
  304.  
  305.     mov    ax,18
  306.     call    set_timeout
  307. send_pkt_1:
  308.     test    transmit_dscps[bx].tmd1,XMIT_OWN    ;Did the lance chip give it back?
  309.     je    send_pkt_2
  310.     call    do_timeout
  311.     jne    send_pkt_1
  312.     mov    dh,CANT_SEND
  313.     stc
  314.     ret
  315. send_pkt_toobig:
  316.     mov    dh,NO_SPACE
  317.     stc
  318.     ret
  319. send_pkt_2:
  320. ;reset error indications.
  321.     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?
  322.     mov    transmit_dscps[bx].tmd3,0    ;reset all error bits.
  323.  
  324.     mov    ax,cx            ;store the count.
  325.     cmp    ax,RUNT            ; minimum length for Ether
  326.     ja    oklen
  327.     mov    ax,RUNT            ; make sure size at least RUNT
  328. oklen:
  329.     neg    ax
  330.     mov    transmit_dscps[bx].tmd2,ax    ;store the negative of the cnt.
  331.  
  332.     mov    ax,transmit_dscps[bx].tmd0    ;store the packet.
  333.     call    translate_address
  334.  
  335.     shr    cx,1
  336.     rep    movsw
  337.     jnc    send_pkt_3
  338.     movsb
  339. send_pkt_3:
  340.  
  341.     xor    ax,ax
  342.     call    translate_address
  343.  
  344.     mov    es,base_addr
  345.     assume    es:lance_seg
  346.     or    transmit_dscps[bx].tmd1,XMIT_OWN    ;give it to the lance chip.
  347.  
  348. ;Inform LANCE that it should poll for a packet.
  349.     loadport
  350.     mov    ax,CSR0_INEA or CSR0_TDMD
  351.     outport    CSR0
  352.     clc
  353.     ret
  354.  
  355.  
  356. detect_board:
  357. ;test to see if a board is located at io_addr.
  358. ;setup to read first byte of ethernet address rom when successful.
  359. ;return nz if not.
  360.     assume    cs:code, ds:code
  361.  
  362.     loadport
  363.     setport    NI_CSR            ;enable the rev. E DEPCA card.
  364.     mov    al,CSR_DUM
  365.     out    dx,al
  366.     setport    EBASE            ;is it in this port?
  367.     call    detect_port
  368.     je    detect_board_1        ;yup!
  369.     setport    EBASE+1            ;look on the next port for rev. E
  370.     call    detect_port
  371. detect_board_1:
  372.     pushf                ;preserve the result.
  373.     loadport
  374.     setport    NI_CSR            ;restore the NI_CSR contents.
  375.     mov    al,ni_csr_value
  376.     out    dx,al
  377.     popf
  378.     ret
  379.  
  380.  
  381. depca_pattern    db    0FFh, 00h, 55h, 0AAh, 0FFh, 00h, 55h, 0AAh
  382.  
  383. detect_port:
  384. ;enter with dx = port to read from, looking for depca_pattern.
  385. ;exit with zr if we found it, nz if not.
  386.     mov    cx,32+8            ;do 32 reps, plus look at 8 to match.
  387.     mov    di,0            ;start at the beginning of the string.
  388. detect_port_1:
  389.     in    al,dx            ;input byte.
  390.     cmp    al,depca_pattern[di]    ;do they match?
  391.     jne    detect_port_2        ;no, try again.
  392.     inc    di            ;yes, look at another character.
  393.     cmp    di, 8            ;need to match eight chars.
  394.     jne    short detect_port_3
  395.     ret
  396. detect_port_2:
  397.     xor    di,di            ;start at the beginning of the pattern.
  398. detect_port_3:
  399.     loop    detect_port_1
  400.     or    sp,sp            ;return nz.
  401.     ret
  402.  
  403.  
  404.     public    set_address
  405. set_address:
  406. ;enter with ds:si -> Ethernet address, CX = length of address.
  407. ;exit with nc if okay, or cy, dh=error if any errors.
  408.     assume    ds:nothing
  409.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  410.     je    set_address_4
  411.     mov    dh,BAD_ADDRESS
  412.     stc
  413.     jmp    short set_address_done
  414. set_address_4:
  415.  
  416.     mov    es,base_addr
  417.     mov    di,offset init_addr
  418.     rep    movsb
  419.     call    initialize        ;initialize with our new address.
  420.  
  421. set_address_okay:
  422.     mov    cx,EADDR_LEN        ;return their address length.
  423.     clc
  424. set_address_done:
  425.     movseg    ds,cs
  426.     assume    ds:code
  427.     ret
  428.  
  429.  
  430. rcv_mode_1:
  431.     mov    ax,M_DRX        ;disable the receiver.
  432.     jmp    initialize_nomulti
  433. rcv_mode_3:
  434.     xor    ax,ax            ;don't accept any multicast frames.
  435.     call    initialize_multi
  436.     mov    ax,0            ;non-promiscuous mode
  437.     jmp    short initialize_nomulti
  438. rcv_mode_5:
  439.     mov    ax,-1            ;accept any multicast frames.
  440.     call    initialize_multi
  441.     mov    ax,0            ;non-promiscuous mode
  442.     jmp    short initialize_nomulti
  443. rcv_mode_6:
  444.     mov    ax,M_PROM        ;promiscuous mode
  445. initialize_nomulti:
  446.     mov    es,base_addr
  447.     mov    es:init_mode,ax
  448.  
  449. initialize:
  450.     loadport
  451.     mov    ax,CSR0_STOP        ;reset the INIT bit.
  452.     outport    CSR0
  453.  
  454.     mov    ax,2            ;write the bus config register.
  455.     outport    CSR3
  456.  
  457.     mov    ax,save_csr1        ;write the low word.
  458.     outport    CSR1
  459.  
  460.     mov    ax,save_csr2        ;write the high word.
  461.     outport    CSR2
  462.  
  463.     mov    ax,CSR0_INEA or CSR0_STRT or CSR0_INIT    ;reinit and restart.
  464.     outport    CSR0
  465.  
  466.     setport    DATA_REG
  467.  
  468.     mov    ax,36            ;wait one second for the board
  469.     call    set_timeout        ;  to timeout.
  470. initialize_1:
  471.     in    ax,dx
  472.     test    ax,CSR0_IDON
  473.     jne    initialize_2
  474.     call    do_timeout
  475.     jne    initialize_1
  476.     stc
  477.     ret
  478. initialize_2:
  479.     clc
  480.     ret
  481.  
  482.  
  483. initialize_multi:
  484. ;enter with ax = value for all multicast hash bits.
  485.     mov    es,base_addr
  486.     mov    di,offset init_filter
  487.     mov    cx,8/2
  488.     rep    stosw
  489.     ret
  490.  
  491.  
  492.     public    set_multicast_list
  493. set_multicast_list:
  494. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  495. ;  cx = number of bytes.
  496. ;return nc if we set all of them, or cy,dh=error if we didn't.
  497.     mov    dh,NO_MULTICAST        ;for some reason we can't do multi's.
  498.     stc
  499.     ret
  500.  
  501.  
  502.     public    terminate
  503. terminate:
  504.     call    rcv_mode_1        ;don't receive any packets.
  505.  
  506.     loadport            ;disable the RAM, enable ROM.
  507.     setport    NI_CSR
  508.     in    al,dx
  509.     and    al,not CSR_SHE
  510.     out    dx,al
  511.  
  512.     ret
  513.  
  514.     public    reset_interface
  515. reset_interface:
  516. ;reset the interface.
  517.     assume    ds:code
  518.     ret
  519.  
  520.  
  521. ;called when we want to determine what to do with a received packet.
  522. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  523.     extrn    recv_find: near
  524.  
  525. ;called after we have copied the packet into the buffer.
  526. ;enter with ds:si ->the packet, cx = length of the packet.
  527.     extrn    recv_copy: near
  528.  
  529. ;call this routine to schedule a subroutine that gets run after the
  530. ;recv_isr.  This is done by stuffing routine's address in place
  531. ;of the recv_isr iret's address.  This routine should push the flags when it
  532. ;is entered, and should jump to recv_exiting_exit to leave.
  533. ;enter with ax = address of routine to run.
  534.     extrn    schedule_exiting: near
  535.  
  536. ;recv_exiting jumps here to exit, after pushing the flags.
  537.     extrn    recv_exiting_exit: near
  538.  
  539.     extrn    count_in_err: near
  540.     extrn    count_out_err: near
  541.  
  542. LANCE_ISR_ACKNOWLEDGE equ (CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  543.  
  544.     public    recv
  545. recv:
  546. ;called from the recv isr.  All registers have been saved, and ds=cs.
  547. ;Upon exit, the interrupt will be acknowledged.
  548.     assume    ds:code
  549.  
  550.     xor    ax,ax
  551.     call    translate_address
  552.  
  553.     loadport
  554.     setport    ADDR_REG
  555.     mov    ax,CSR0
  556.     out    dx,ax
  557.     in    ax,dx
  558.     setport    DATA_REG
  559.     in    ax,dx
  560.     mov    bx,ax            ;make a copy.
  561.  
  562. ; Acknowledge the Interrupt from the controller, but disable further
  563. ; controller Interrupts until we service the current interrupt.
  564. ;
  565. ;(CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  566. ;
  567.     and    ax,not LANCE_ISR_ACKNOWLEDGE
  568.     out    dx,ax
  569.     in    ax,dx            ; follow all writes by a read
  570.  
  571.     test    bx,CSR0_RINT        ;receive interrupt?
  572.     jne    recv_RINT        ;yes.
  573.     jmp    recv_done        ;no, we're done.
  574. recv_RINT:
  575.  
  576.     mov    es,base_addr
  577.     assume    es:lance_seg
  578.     mov    bx,receive_head
  579.  
  580. recv_search:
  581.     test    lance_seg:[bx].rmd1,RCV_OWN    ;do we own this buffer?
  582.     je    recv_own        ;yes - process it.
  583.     call    inc_recv_ring        ;go to the next one.
  584.     cmp    bx,receive_head        ;did we get back to the beginning?
  585.     jne    recv_search        ;not yet.
  586.     jmp    recv_done        ;yes -- spurious interrupt!
  587. recv_own:
  588.     test    lance_seg:[bx].rmd1,RCV_ERR    ;Any errors in this buffer?
  589.     jne    recv_err        ;yes -- ignore this packet.
  590.  
  591.     mov    cx,lance_seg:[bx].rmd3
  592.     and    cx,0fffh        ;strip off the reserved bits
  593.     sub    cx,4            ;leave the CRC behind.
  594.  
  595.     mov    ax,lance_seg:[bx].rmd0    ;get the pointer into di.
  596.     call    translate_address
  597.  
  598.     push    es
  599.     push    di
  600.     push    bx
  601.  
  602.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  603.                     ;  point to the packet type.
  604.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  605.     mov    ax, es:[di]
  606.     xchg    ah, al
  607.     cmp    ax, 1500
  608.     ja    BlueBookPacket
  609.     inc    di            ;set di to 802.2 header
  610.     inc    di
  611.     mov    dl, IEEE8023
  612. BlueBookPacket:
  613.     push    cx
  614.     call    recv_find
  615.     pop    cx
  616.  
  617.     pop    bx
  618.     pop    si
  619.     pop    ds
  620.     assume    ds:nothing, es:nothing
  621.  
  622.     mov    ax,es            ;is this pointer null?
  623.     or    ax,di
  624.     je    recv_free        ;yes - just free the frame.
  625.  
  626.     push    es
  627.     push    di
  628.     push    cx
  629.  
  630.     shr    cx,1
  631.     rep    movsw
  632.     jnc    rec_pkt_3
  633.     movsb
  634. rec_pkt_3:
  635.  
  636.     pop    cx
  637.     pop    si
  638.     pop    ds
  639.     assume    ds:nothing
  640.  
  641.     call    recv_copy
  642.  
  643.     jmp    short recv_free
  644.  
  645. recv_err:
  646.     call    count_in_err
  647. recv_free:
  648.     xor    ax,ax
  649.     call    translate_address
  650.  
  651.     movseg    ds,cs
  652.     assume    ds:code
  653.     mov    es,base_addr
  654.     assume    es:lance_seg
  655.  
  656. ;clear any error bits.
  657.     and    lance_seg:[bx].rmd1,not (RCV_ERR or RCV_FRAM or RCV_OFLO or RCV_CRC or RCV_BUF_ERR)
  658.     or    lance_seg:[bx].rmd1,RCV_OWN    ;give it back to the lance.
  659.     call    inc_recv_ring            ;go to the next one.
  660.     test    lance_seg:[bx].rmd1,RCV_OWN    ;Do we own this one?
  661.     jne    recv_free_1
  662.     jmp    recv_own        ;yes, go parse it.
  663. recv_free_1:
  664.     mov    receive_head,bx        ;remember where the next one starts.
  665. recv_done:
  666.     loadport            ;enable interrupts again.
  667.     setport    DATA_REG
  668.     mov    ax,CSR0_INEA
  669.     out    dx,ax
  670.  
  671.     ret
  672.  
  673.  
  674. inc_recv_ring:
  675. ;advance bx to the next receive ring descriptor.
  676.     assume    ds:nothing
  677.     add    bx,(size rcv_msg_dscp)
  678.     cmp    bx,offset receive_dscps + RECEIVE_BUF_COUNT * (size rcv_msg_dscp)
  679.     jb    inc_recv_ring_1
  680.     mov    bx,offset receive_dscps
  681. inc_recv_ring_1:
  682.     ret
  683.  
  684.  
  685.     include    popf.asm
  686.     include    timeout.asm
  687.  
  688.     public    timer_isr
  689. timer_isr:
  690. ;if the first instruction is an iret, then the timer is not hooked
  691.     iret
  692.  
  693. ;any code after this will not be kept.  Buffers used by the program, if any,
  694. ;are allocated from the memory between end_resident and end_free_mem.
  695.     public end_resident,end_free_mem
  696. end_resident    label    byte
  697. end_free_mem    label    byte
  698.  
  699.  
  700.     public    usage_msg
  701. usage_msg    db    "usage: depca [options] <packet_int_no> <hardware_irq> <io_addr> <mem_addr>",CR,LF,'$'
  702. no_board_msg    db    "No DEPCA detected.",CR,LF,'$'
  703. io_addr_funny_msg    label    byte
  704.         db    "No DEPCA detected, continuing anyway.",CR,LF,'$'
  705. bad_reset_msg    db    "Unable to reset the DEPCA.",CR,LF,'$'
  706. bad_init_msg    db    "Unable to initialize the DEPCA.",CR,LF,'$'
  707. mem_busy_msg    db    "Memory already present at your chosen address.",CR,LF,'$'
  708. mem_bad_msg    db    "No DEPCA memory found at that memory address.",CR,LF,'$'
  709. addr_bad_msg    db    "Memory address should be between 0x8000 and 0xdf80 inclusive,",CR,LF
  710.         db    "and must be on a 2K boundary (increments of 0x80).",CR,LF,'$'
  711.  
  712.     public    copyright_msg
  713. copyright_msg    db    "Packet driver for a Digital Equipment Corporation DEPCA, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  714.         db    '$'
  715.  
  716. int_no_name    db    "Interrupt number ",'$'
  717. io_addr_name    db    "I/O port ",'$'
  718. base_addr_name    db    "Memory address ",'$'
  719.  
  720. memory_amount    dw    ?    ;-> one of the following
  721. have_64k    db    "Configured for 64K of memory",CR,LF,'$'
  722. have_32k    db    "Configured for 32K of memory",CR,LF,'$'
  723. have_2k        db    "Configured for 2K of memory",CR,LF,'$'
  724.  
  725. depca_signature    db    "DEPCA"
  726. depca_signature_len    equ    $-depca_signature
  727.  
  728.     extrn    set_recv_isr: near
  729.     extrn    maskint: near
  730.  
  731. ;enter with si -> argument string, di -> dword to store.
  732. ;if there is no number, don't change the number.
  733.     extrn    get_number: near
  734.  
  735. ;enter with dx -> name of word, di -> dword to print.
  736.     extrn    print_number: near
  737.  
  738. ;-> the assigned Ethernet address of the card.
  739.     extrn    rom_address: byte
  740.  
  741.     public    parse_args
  742. parse_args:
  743. ;exit with nc if all went well, cy otherwise.
  744.     assume    ds:code
  745.     mov    di,offset int_no
  746.     call    get_number
  747.     mov    di,offset io_addr
  748.     call    get_number
  749.     mov    di,offset base_addr
  750.     call    get_number
  751.     clc
  752.     ret
  753.  
  754.  
  755.     public    etopen
  756. etopen:
  757.     assume    ds:code
  758.  
  759.     cmp    io_addr,-1        ;Did they ask for auto-detect?
  760.     je    find_board
  761.  
  762.     call    detect_board        ;no, just verify its existance.
  763.     je    find_board_found
  764.  
  765.     mov    dx,offset io_addr_funny_msg
  766.     mov    ah,9
  767.     int    21h
  768.  
  769.     jmp    find_board_found
  770.  
  771. find_board:
  772.     mov    io_addr,300h        ;Search for the Ethernet address at 300h
  773.     mov    io_addr+2,0
  774.     call    detect_board
  775.     je    find_board_found
  776.     mov    io_addr,200h        ;Search at 200h
  777.     call    detect_board
  778.     je    find_board_found
  779.  
  780.     mov    dx,offset no_board_msg    ;Tell them that we can't find it.
  781.     stc
  782.     ret
  783. find_board_found:
  784.     test    base_addr.offs,007fh    ;must be on at least a 2K boundary.
  785.     jne    etopen_1
  786.     test    base_addr.offs,8000h    ;must be in upper 512K.
  787.     je    etopen_1
  788.     cmp    base_addr.segm,0    ;high word of segment must be zero.
  789.     je    etopen_2
  790. etopen_1:
  791.     mov    dx,offset addr_bad_msg
  792.     stc
  793.     ret
  794. etopen_2:
  795.  
  796. ; now we detect whether we're set to 2K, 32K, or 64K.
  797.  
  798.     pushf                ;we're about to re-map the DEPCA
  799.     cli                ;  memory onto somewhere illicit.
  800.  
  801. ;first, we see if the ROM is mappable in and out.
  802.  
  803.     loadport            ;disable the RAM, enable ROM.
  804.     setport    NI_CSR
  805.     in    al,dx
  806.     and    al,not CSR_SHE
  807.     out    dx,al
  808.  
  809.     mov    bx,base_addr        ;get the segment of the ROM.
  810.     add    bx,400h            ;go up by 16K.
  811.     mov    translate_address,offset translate_32k
  812.     mov    memory_amount,offset have_32k
  813.     test    al,CSR_BUF        ;32k or 64k mode?
  814.     jne    got_rom_address        ;go if 32K.
  815.     and    ni_csr_value,not CSR_SWAP32
  816.     mov    al,ni_csr_value
  817.     and    al,not CSR_SHE
  818.     out    dx,al
  819.     mov    translate_address,offset translate_64k
  820.     mov    memory_amount,offset have_64k
  821.     add    bx,800h            ;up it by 32K more.
  822. got_rom_address:
  823.     push    bx
  824.     mov    ax,bx
  825.     mov    cx,4000h        ;16K
  826.     call    memory_test
  827.     pop    bx
  828.     jz    not_rom_address        ;we found RAM there...
  829.  
  830.     loadport
  831.     setport    NI_CSR
  832.     in    al,dx
  833.     or    al,CSR_SHE        ;enable the RAM.
  834.     out    dx,al
  835.  
  836.     push    bx
  837.     mov    ax,bx
  838.     mov    cx,4000h        ;there should be 16K of RAM there.
  839.     call    memory_test
  840.     pop    bx
  841.     je    have_depca_mem        ;there is -- we're cool.
  842.  
  843.     mov    es,bx
  844.     cmp    word ptr es:[0],0aa55h    ;is there a ROM there still?
  845.     jne    not_rom_address
  846.  
  847.     mov    di,6            ;see if the DEPCA ROM signature is there.
  848.     mov    si,offset depca_signature
  849.     mov    cx,depca_signature_len
  850.     repe    cmpsb
  851.     je    have_depca_mem        ;it is, we've got an old DEPCA.
  852.  
  853. not_rom_address:
  854.  
  855. ;we got here because we decided that the ROM couldn't be mapped into memory.
  856.  
  857.     mov    translate_address,offset translate_2k
  858.     mov    memory_amount,offset have_2k
  859.     and    ni_csr_value,not CSR_SWAP32
  860.  
  861.     loadport            ;put our memory somewhere it can't be.
  862.     setport    RBSA
  863.     mov    ax,0f000h
  864.     out    dx,ax
  865.  
  866. ;make sure the memory *isn't* there.
  867.     mov    bx,base_addr
  868.     mov    di,2048 / 16
  869.     call    occupied_chk
  870.  
  871.     pushf
  872.     loadport            ;the memory block is empty - put our
  873.     setport    RBSA            ;  memory there.
  874.     mov    ax,base_addr
  875.     out    dx,ax
  876.     popf
  877.     jnc    depca_mem_empty
  878.  
  879.     popf
  880.     mov    dx,offset mem_busy_msg
  881.     stc
  882.     ret
  883. depca_mem_empty:
  884.  
  885.     mov    ax,base_addr        ;now test our memory.
  886.     mov    cx,2048
  887.     call    memory_test
  888.     jz    have_depca_mem
  889.  
  890.     popf                ;restore the original EI.
  891.     mov    dx,offset mem_bad_msg
  892.     stc
  893.     ret
  894. have_depca_mem:
  895.     popf                ;restore the original EI.
  896.  
  897.     movseg    es,cs
  898.     mov    di,offset rom_address
  899.     mov    cx,EADDR_LEN
  900.     loadport            ; Get our Ethernet address base.
  901.     setport    EBASE
  902. get_address_1:
  903.     in    al,dx            ; get a byte of the eprom address
  904.     stosb
  905.     loop    get_address_1        ; go back for rest
  906.  
  907.     mov    si,offset rom_address    ; copy it to the init table.
  908.     mov    es,base_addr
  909.     mov    di,offset init_addr
  910.     mov    cx,EADDR_LEN
  911.     rep    movsb
  912.  
  913.     mov    al, int_no        ; Get board's interrupt vector
  914.     add    al, 8
  915.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  916.     jb    set_int_num        ; No.
  917.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  918. set_int_num:
  919.     xor    ah, ah            ; Clear high byte
  920.     mov    int_num, ax        ; Set parameter_list int num.
  921.  
  922.     mov    al,int_no
  923.     call    maskint            ;disable these interrupts.
  924.  
  925.     loadport
  926.     mov    ax,CSR0_STOP        ;reset the INIT bit.
  927.     outport    CSR0
  928.  
  929.     xor    ax,ax
  930.     call    translate_address
  931.  
  932. ;set up transmit descriptor ring.
  933.     mov    es,base_addr
  934.     assume    es:lance_seg
  935.     mov    cx,TRANSMIT_BUF_COUNT
  936.     mov    bx,offset transmit_dscps
  937.     mov    di,offset transmit_bufs
  938. setup_transmit:
  939.     call    segmoffs_to_phys
  940.  
  941.     or    dx,XMIT_START or XMIT_END
  942.     mov    lance_seg:[bx].tmd0,ax    ;points to the buffer.
  943.     mov    lance_seg:[bx].tmd1,dx
  944.  
  945.     add    bx,(size xmit_msg_dscp)
  946.     add    di,800h
  947.     loop    setup_transmit
  948.  
  949. ;set up receive descriptor ring.
  950.     mov    cx,RECEIVE_BUF_COUNT
  951.     mov    bx,offset receive_dscps
  952.     mov    di,offset receive_bufs
  953. setup_receive:
  954.     call    segmoffs_to_phys
  955.  
  956.     or    dx,RCV_OWN
  957.     mov    lance_seg:[bx].rmd0,ax    ;points to the buffer.
  958.     mov    lance_seg:[bx].rmd1,dx
  959.  
  960.     mov    lance_seg:[bx].rmd2,-RECEIVE_BUF_SIZE
  961.     mov    lance_seg:[bx].rmd3,0
  962.  
  963.     add    bx,(size rcv_msg_dscp)
  964.     add    di,800h
  965.     loop    setup_receive
  966.  
  967.     mov    cx,RECEIVE_BUF_COUNT
  968.     call    compute_log2
  969.  
  970.     mov    di,offset receive_dscps
  971.     call    segmoffs_to_phys
  972.     or    dx,cx            ;include the buffer size bits.
  973.     mov    init_receive[0],ax
  974.     mov    init_receive[2],dx
  975.  
  976.     mov    cx,TRANSMIT_BUF_COUNT
  977.     call    compute_log2
  978.  
  979.     mov    di,offset transmit_dscps
  980.     call    segmoffs_to_phys
  981.     or    dx,cx            ;include the buffer size bits.
  982.     mov    init_transmit[0],ax
  983.     mov    init_transmit[2],dx
  984.  
  985.     mov    di,offset init_block    ;now tell the board where the init
  986.     call    segmoffs_to_phys    ;  block is.
  987.     mov    save_csr1,ax
  988.     mov    save_csr2,dx
  989.  
  990.     call    rcv_mode_3
  991.     jnc    init_ok
  992.  
  993.     mov    dx,offset bad_init_msg
  994.     stc
  995.     ret
  996.  
  997. init_ok:
  998. ;
  999. ; Now hook in our interrupt
  1000. ;
  1001.     call    set_recv_isr
  1002.  
  1003.     loadport
  1004.     setport    NI_CSR
  1005.     mov    al,ni_csr_value        ;disable ROM, enable rev. E DEPCA,
  1006.                     ;  enable the interrupt line,
  1007.     out    dx,al
  1008.  
  1009.     clc
  1010.     ret
  1011.  
  1012.     public    print_parameters
  1013. print_parameters:
  1014. ;echo our command-line parameters
  1015.     mov    di,offset int_no
  1016.     mov    dx,offset int_no_name
  1017.     call    print_number
  1018.     mov    di,offset io_addr
  1019.     mov    dx,offset io_addr_name
  1020.     call    print_number
  1021.     mov    di,offset base_addr
  1022.     mov    dx,offset base_addr_name
  1023.     call    print_number
  1024.     mov    dx,memory_amount
  1025.     mov    ah,9
  1026.     int    21h
  1027.     ret
  1028.  
  1029. compute_log2:
  1030. ;enter with cx = number of buffers.
  1031. ;exit with cx = log2(number of buffers) << 13.
  1032.     mov    ax,-1
  1033. compute_log2_1:
  1034.     inc    ax
  1035.     shr    cx,1
  1036.     jne    compute_log2_1
  1037.     mov    cl,13
  1038.     shl    ax,cl
  1039.     mov    cx,ax
  1040.     ret
  1041.  
  1042.  
  1043. segmoffs_to_phys:
  1044. ;enter with es:di -> buffer.
  1045. ;exit with dx:ax as the physical address of the buffer,
  1046.  
  1047.   if 0    ; The DEPCA doesn't use system memory, it uses its own.
  1048.     mov    dx,es            ;get the high 4 bits of the segment,
  1049.     shr    dx,16-4
  1050.     mov    ax,es            ;and the low 12 bits of the segment.
  1051.     shl    ax,4
  1052.     add    ax,di            ;add in the offset.
  1053.     adc    dx,0
  1054.   else
  1055.     xor    dx,dx            ;the offset is the only part of the
  1056.     mov    ax,di            ;  address.
  1057.   endif
  1058.     ret
  1059.  
  1060.  
  1061.     include    memtest.asm
  1062.     include    occupied.asm
  1063.  
  1064. code    ends
  1065.  
  1066.     end
  1067.