home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / driver6s / ne2000.asm < prev    next >
Assembly Source File  |  1990-04-10  |  37KB  |  1,336 lines

  1. version    equ    3
  2.     page    ,132
  3.     include    defs.asm
  4.  
  5. ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec,
  6. ;*  for the NE2000 interface card.
  7. ;*  Robert C Clements, K1BC, 14 February, 1989
  8. ;*  Portions (C) Copyright 1988, 1989 Robert C Clements
  9. ;*  Modified from 3com503 driver by D.J.Horne
  10. ;*
  11. ;  Copyright, 1988, 1989, Russell Nelson
  12.  
  13. ;   This program is free software; you can redistribute it and/or modify
  14. ;   it under the terms of the GNU General Public License as published by
  15. ;   the Free Software Foundation, version 1.
  16. ;
  17. ;   This program is distributed in the hope that it will be useful,
  18. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. ;   GNU General Public License for more details.
  21. ;
  22. ;   You should have received a copy of the GNU General Public License
  23. ;   along with this program; if not, write to the Free Software
  24. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. ;* Change history:
  27. ;*  Updated to driver spec version 1.08 Feb. 17, 1989 by Russell Nelson.
  28. ;*  Changes 27 Jul 89 by Bob Clements (/Rcc)
  29. ;*    Added Thick versus Thin Ethernet switch  27 Jul 89 by Bob Clements (/Rcc)
  30. ;*    Added call to memory_test.
  31. ;*    Added rcv_mode logic.  Started, but didn't finish, multicast logic. 
  32. ;*      Fixed get_address to return current, not PROM, address.
  33. ;*      Minor races fixed.
  34. ;*  Changes 19 Oct 89, Dave Horne
  35. ;*    Modified for NE2000, use i/o instead of shared memory,
  36. ;*    remove thick/thin logic, remove gate array logic
  37.  
  38. code    segment    byte public
  39.     assume    cs:code, ds:code
  40.  
  41. ; Stuff specific to the NE2000 Ethernet controller board
  42. ; WD version in C by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
  43. ; 3Com version based on WD8003E version in .ASM, also by Bob Clements, dated
  44. ;  19 August 1988.  The WD and 3Com cards both use the National DS8390.
  45. ; NE2000 based on 3COM503 version.
  46.  
  47. ; Symbol prefix "EN" is for Ethernet, National chip
  48. ; Symbol prefix "NE" is for NE2000 register(s)
  49.  
  50. ; The EN registers - the DS8390 chip registers
  51. ; These appear at Base+0 through Base+0F
  52. ; There are two (really 3) pages of registers in the chip. You select
  53. ; which page you want, then address them at offsets 00-0F from base.
  54. ; The chip command register (EN_CCMD) appears in both pages.
  55.  
  56. EN_CCMD        equ    000h    ; Chip's command register
  57.  
  58. ; Page 0
  59.  
  60. EN0_STARTPG    equ    001h    ; Starting page of ring bfr
  61. EN0_STOPPG    equ    002h    ; Ending page +1 of ring bfr
  62. EN0_BOUNDARY    equ    003h    ; Boundary page of ring bfr
  63. EN0_TSR        equ    004h    ; Transmit status reg
  64. EN0_TPSR    equ    004h    ; Transmit starting page
  65. EN0_TCNTLO    equ    005h    ; Low  byte of tx byte count
  66. EN0_TCNTHI    equ    006h    ; High byte of tx byte count
  67. EN0_ISR        equ    007h    ; Interrupt status reg
  68. EN0_RSARLO    equ    008h    ; Remote start address reg 0
  69. EN0_RSARHI    equ    009h    ; Remote start address reg 1
  70. EN0_RCNTLO    equ    00ah    ; Remote byte count reg
  71. EN0_RCNTHI    equ    00bh    ; Remote byte count reg
  72. EN0_RXCR    equ    00ch    ; RX control reg
  73. EN0_TXCR    equ    00dh    ; TX control reg
  74. EN0_COUNTER0    equ    00dh    ; Rcv alignment error counter
  75. EN0_DCFG    equ    00eh    ; Data configuration reg
  76. EN0_COUNTER1    equ    00eh    ; Rcv CRC error counter
  77. EN0_IMR        equ    00fh    ; Interrupt mask reg
  78. EN0_COUNTER2    equ    00fh    ; Rcv missed frame error counter
  79.  
  80. ; Page 1
  81.  
  82. EN1_PHYS    equ    001h    ; This board's physical enet addr
  83. EN1_CURPAG    equ    007h    ; Current memory page
  84. EN1_MULT    equ    008h    ; Multicast filter mask array (8 bytes)
  85.  
  86. ; Board regs
  87.  
  88. NE_DATAPORT    equ    10h
  89. NE_OTHERPORT    equ    1fh
  90.  
  91. ; Chip commands in EN_CCMD
  92. ENC_STOP    equ    001h    ; Stop the chip
  93. ENC_START    equ    002h    ; Start the chip
  94. ENC_TRANS    equ    004h    ; Transmit a frame
  95. ENC_RREAD    equ    008h    ; remote read
  96. ENC_RWRITE    equ    010h    ; remote write
  97. ENC_NODMA    equ    020h    ; No remote DMA used on this card
  98. ENC_PAGE0    equ    000h    ; Select page 0 of chip registers
  99. ENC_PAGE1    equ    040h    ; Select page 1 of chip registers
  100.  
  101. ; Commands for RX control reg
  102. ENRXCR_MON    equ    020h    ; Monitor mode (no packets rcvd)
  103. ENRXCR_PROMP    equ    010h    ; Promiscuous physical addresses 
  104. ENRXCR_MULTI    equ    008h    ; Multicast (if pass filter)
  105. ENRXCR_BCST    equ    004h    ; Accept broadcasts
  106. ENRXCR_BAD    equ    003h    ; Accept runts and bad CRC frames
  107.  
  108. ; Commands for TX control reg
  109. ENTXCR_LOOP    equ    002h    ; Set loopback mode
  110.  
  111. ; Bits in EN0_DCFG - Data config register
  112. ENDCFG_BM8    equ    049h    ; Set burst mode, 8 deep FIFO, words
  113.  
  114. ; Bits in EN0_ISR - Interrupt status register
  115. ENISR_RX    equ    001h    ; Receiver, no error
  116. ENISR_TX    equ    002h    ; Transmitter, no error
  117. ENISR_RX_ERR    equ    004h    ; Receiver, with error
  118. ENISR_TX_ERR    equ    008h    ; Transmitter, with error
  119. ENISR_OVER    equ    010h    ; Receiver overwrote the ring
  120. ENISR_COUNTERS    equ    020h    ; Counters need emptying
  121. ENISR_RDC    equ    040h    ; remote dma complete
  122. ENISR_RESET    equ    080h    ; Reset completed
  123. ENISR_ALL    equ    03fh    ; Interrupts we will enable
  124.  
  125. ; Bits in received packet status byte and EN0_RSR
  126. ENPS_RXOK    equ    001h    ; Received a good packet
  127.  
  128. ; Bits in TX status reg
  129.  
  130. ENTSR_PTX    equ    001h    ; Packet transmitted without error
  131. ENTSR_COLL    equ    004h    ; Collided at least once
  132. ENTSR_COLL16    equ    008h    ; Collided 16 times and was dropped
  133. ENTSR_FU    equ    020h    ; TX FIFO Underrun
  134.  
  135. ; Shared memory management parameters
  136.  
  137. XMIT_MTU    equ    600h    ; Largest packet we have room for.
  138. SM_TSTART_PG    equ    040h    ; First page of TX buffer
  139. SM_RSTART_PG    equ    046h    ; Starting page of RX ring
  140. SM_RSTOP_PG    equ    080h    ; Last page +1 of RX ring
  141.  
  142. ; Description of header of each packet in receive area of memory
  143.  
  144. EN_RBUF_STAT    equ    0    ; Received frame status
  145. EN_RBUF_NXT_PG    equ    1    ; Page after this frame
  146. EN_RBUF_SIZE_LO    equ    2    ; Length of this frame
  147. EN_RBUF_SIZE_HI    equ    3    ; Length of this frame
  148. EN_RBUF_NHDR    equ    4    ; Length of above header area
  149.  
  150. ; End of NE2000 parameter definitions
  151.  
  152. pause_    macro
  153.     jmp    $+2
  154. endm
  155.  
  156. longpause macro
  157.     push    cx
  158.     mov    cx,0
  159.     loop    $
  160.     pop    cx
  161. endm
  162.  
  163. ; The following two values may be overridden from the command line.
  164. ; If they are omitted from the command line, these defaults are used.
  165. ; The shared memory base is set by a jumper.  We read it from the
  166. ; card and set up accordingly.
  167.  
  168.     public    int_no, io_addr
  169. int_no        db    2,0,0,0        ; Interrupt level
  170. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  171.  
  172.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  173. driver_class    db    1        ;from the packet spec
  174. driver_type    db    54        ;from the packet spec
  175. driver_name    db    'NE2000',0    ;name of the driver.
  176. driver_function    db    2
  177. parameter_list    label    byte
  178.     db    1    ;major rev of packet driver
  179.     db    9    ;minor rev of packet driver
  180.     db    14    ;length of parameter list
  181.     db    EADDR_LEN    ;length of MAC-layer address
  182.     dw    GIANT    ;MTU, including MAC headers
  183.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  184.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  185.     dw    0    ;(# of successive xmits) - 1
  186.     dw    0    ;Interrupt # to hook for post-EOI
  187.             ;processing, 0 == none,
  188.  
  189. rxcr_bits       db      ENRXCR_BCST     ; Default to ours plus multicast
  190.  
  191.  
  192.     public    card_hw_addr, curr_hw_addr, mcast_list_bits, mcast_all_flag
  193. card_hw_addr    db    0,0,0,0,0,0    ;Physical ethernet address
  194. curr_hw_addr    db    0,0,0,0,0,0    ;Address set into the 8390
  195. mcast_list_bits db      0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
  196. mcast_all_flag  db      0               ;Non-zero if hware should have all
  197.                     ; ones in mask rather than this list.
  198. mcast_sw_filter    db    0        ; set if software filter is required.
  199. is_186        db    0
  200. mcast_sw_fin    dw    0
  201. mcast_sw_fout    dw    0
  202.  
  203.     public    rcv_modes
  204. rcv_modes    dw    7        ;number of receive modes in our table.
  205.         dw    0               ;There is no mode zero
  206.         dw    rcv_mode_1
  207.         dw    rcv_mode_2
  208.         dw    rcv_mode_3
  209.         dw    rcv_mode_4
  210.         dw    rcv_mode_5
  211.         dw    rcv_mode_6
  212.  
  213.     public    mcast_tab
  214. mcast_hcount    dw    0        ; multicast header count
  215. mcast_tab_b    db    0ffh,0ffh,0ffh,0ffh,0ffh,0ffh ; entry for broadcast
  216. mcast_tab    db    (MAX_MULTICAST*EADDR_LEN) dup (0)
  217. ;
  218. ;    a temp buffer for the received header
  219. ;
  220. RCV_HDR_SIZE    equ    18        ; 2 ids @6 + protocol, + 4byte header
  221. rcv_hdr        db    RCV_HDR_SIZE dup(0)
  222.  
  223. ;
  224. ;    The board data
  225. ;
  226.         public    board_data
  227. BOARD_DATA_SIZE equ    32
  228. board_data    db     BOARD_DATA_SIZE dup(0)
  229. soft_tx_errors        dw    0,0
  230. soft_tx_err_bits    db    0
  231. soft_rx_errors        dw    0,0
  232. soft_rx_err_bits    db    0
  233.  
  234.  
  235.  
  236. ; send_pkt: - The Transmit Frame routine
  237.  
  238.     public    send_pkt
  239. send_pkt:
  240. ;enter with ds:si -> packet, cx = packet length.
  241. ;exit with nc if ok, or else cy if error, dh set to error number.
  242.     assume    ds:nothing
  243.     loadport        ; Point at chip command register
  244.     setport EN_CCMD        ; ..
  245.     pause_
  246.     mov bx,    8000h        ; Avoid infinite loop
  247. tx_wait:
  248.     in al,    dx        ; Get chip command state
  249.     test al,ENC_TRANS    ; Is transmitter still running?
  250.     jz    tx_idle        ; Go if free
  251.     dec    bx        ; Count the timeout
  252.     jnz    tx_wait        ; Fall thru if TX is stuck
  253.     call    count_out_err    ; Should count these error timeouts
  254.                 ; Maybe need to add recovery logic here
  255. tx_idle:
  256.     cmp    cx,XMIT_MTU    ; Is this packet too large?
  257.     ja    send_pkt_toobig
  258.  
  259.     cmp cx,    RUNT        ; Is the frame long enough?
  260.     jnb    tx_oklen    ; Go if OK
  261.     mov cx,    RUNT        ; Stretch frame to minimum allowed
  262. tx_oklen:
  263.     push    cx        ; Hold count for later
  264.     loadport        ; Set up for address
  265.     setport EN0_ISR
  266.     pause_
  267.     mov    al,ENISR_RDC    ; clear remote interrupt int.
  268.     out    dx,al
  269.     setport    EN0_TCNTLO    ; Low byte of TX count
  270.     pause_
  271.     mov al,    cl        ; Get the count
  272.     out dx,    al        ; Tell card the count
  273.     setport    EN0_TCNTHI    ; High byte of TX count
  274.     pause_
  275.     mov al,    ch        ; Get the count
  276.     out dx,    al        ; Tell card the count
  277.     xor ax,    ax        ; Set up ax at base of tx buffer
  278.     mov ah,    SM_TSTART_PG    ; Where to put tx frame
  279.     pop    cx        ; Get back count to give to board
  280.     call    block_output
  281.     loadport
  282.     mov    cx,0
  283.     setport    EN0_ISR
  284.     in    al,dx
  285. tx_check_rdc:
  286.     test    al,ENISR_RDC    ; dma done ???
  287.     jnz    tx_start
  288.     loop    tx_check_rdc
  289.     jmp    tx_no_rdc
  290. tx_start:
  291.     setport    EN0_TPSR    ; Transmit Page Start Register
  292.     pause_
  293.     mov al,    SM_TSTART_PG
  294.     out dx,    al        ; Start the transmitter
  295.     setport    EN_CCMD        ; Chip command reg
  296.     pause_
  297.     mov al,    ENC_TRANS+ENC_NODMA+ENC_START
  298.     out dx,    al        ; Start the transmitter
  299.     clc            ; Successfully started
  300.     sti
  301.     ret            ; End of transmit-start routine
  302. send_pkt_toobig:
  303.     mov    dh,NO_SPACE
  304.     stc
  305.     sti
  306.     ret
  307. tx_no_rdc:
  308.     mov    dh,CANT_SEND
  309.     stc
  310.     sti
  311.     ret
  312.  
  313. count_soft_err:
  314.     add    word ptr soft_tx_errors,1
  315.     adc    word ptr soft_tx_errors+2,0
  316.     or    byte ptr soft_tx_err_bits,al
  317.     ret
  318.  
  319. movemem:
  320. ;does the same thing as "rep movsb", only 50% faster.
  321. ;moves words instead of bytes, and handles the case of both addresses odd
  322. ;efficiently.  There is no way to handle one address odd efficiently.
  323. ;This routine always aligns the source address in the hopes that the
  324. ;destination address will also get aligned.  This is from Phil Karn's
  325. ;code from ec.c, a part of his NET package.  I bummed a few instructions
  326. ;out.
  327.     jcxz    movemem_cnte        ; If zero, we're done already.
  328.     test    si,1            ; Does source start on odd byte?
  329.     jz    movemem_adre        ; Go if not
  330.     movsb                ; Yes, move the first byte
  331.     dec    cx            ; Count that byte
  332. movemem_adre:
  333.     shr    cx,1            ; convert to word count
  334.     rep    movsw            ; Move the bulk as words
  335.     jnc    movemem_cnte        ; Go if the count was even
  336.     movsb                ; Move leftover last byte
  337. movemem_cnte:
  338.     ret
  339.  
  340.  
  341.     public    get_address
  342. get_address:
  343. ;get the address of the interface.
  344. ;enter with es:di -> place to get the address, cx = size of address buffer.
  345. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  346. ; Give caller the one currently in the 8390, not necessarily the one in PROM.
  347.     assume ds:code
  348.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  349.     jb    get_addr_x    ; No, fail.
  350.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  351.     mov si, offset curr_hw_addr     ; Copy from most recent setting
  352.     rep     movsb
  353.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  354.     clc            ; Carry off says success
  355.     ret
  356. get_addr_x:
  357.     stc            ; Tell caller our addr is too big for him
  358.     ret
  359.  
  360. ;
  361. ;get the board data. This is (16) bytes starting at remote
  362. ;dma address 0. Put it in a buffer called board_data.
  363.  
  364. get_board_data:
  365.     mov    cx,10h        ; get 16 bytes,
  366.     push    ds
  367.     pop    es        ; set es to ds
  368.     mov    di,offset board_data
  369.     mov    ax,0        ; from address 0
  370.     call    sp_block_input
  371.     ret
  372.  
  373.     public    set_address
  374. set_address:
  375.     assume    ds:nothing
  376. ;enter with ds:si -> Ethernet address, CX = length of address.
  377. ;exit with nc if okay, or cy, dh=error if any errors.
  378. ;
  379.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  380.     je    set_address_4
  381.     mov    dh,BAD_ADDRESS
  382.     stc
  383.     jmp    short set_address_done
  384. set_address_4:
  385.     push    cs              ; Copy from them to our RAM copy
  386.     pop     es              ; Destination of move
  387.     mov di, offset curr_hw_addr
  388.     rep     movsb           ; Move their address
  389.     call    set_8390_eaddr  ; Put that address in the chip
  390. set_address_okay:
  391.     mov    cx,EADDR_LEN        ;return their address length.
  392.     clc
  393. set_address_done:
  394.     push    cs
  395.     pop    ds
  396.     assume    ds:code
  397.     ret
  398.  
  399. ; Copy our Ethernet address from curr_hw_addr into the DS8390
  400. set_8390_eaddr:
  401.     push    cs              ; Get it from our local RAM copy
  402.     pop     ds
  403.     mov si, offset curr_hw_addr
  404.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  405.     loadport
  406.     setport    EN_CCMD        ; Chip command register
  407.     pause_
  408.     cli            ; Protect from irq changing page bits
  409.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_STOP
  410.     out dx,    al        ; Switch to page one for writing eaddr
  411.     setport    EN1_PHYS    ; Where it goes in 8390
  412.     pause_
  413. set_8390_1:
  414.     lodsb
  415.     out    dx,al
  416.     inc    dx
  417.     loop    set_8390_1
  418.     loadport
  419.     setport    EN_CCMD        ; Chip command register
  420.     pause_
  421.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  422.     out dx,    al        ; Restore to page zero
  423.     sti            ; OK for interrupts now
  424.     ret
  425.  
  426. ; Routines to set address filtering modes in the DS8390
  427. rcv_mode_1:     ; Turn off receiver
  428.     mov al,    ENRXCR_MON      ; Set to monitor for counts but accept none
  429.     jmp short rcv_mode_set
  430. rcv_mode_2:     ; Receive only packets to this interface
  431.     mov al, 0               ; Set for only our packets
  432.     jmp short rcv_mode_set
  433. rcv_mode_3:     ; Mode 2 plus broadcast packets (This is the default)
  434.     mov al,    ENRXCR_BCST     ; Set four ours plus broadcasts
  435.     jmp short rcv_mode_set
  436. rcv_mode_4:     ; Mode 3 plus selected multicast packets
  437.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  438.     mov     mcast_all_flag,0    ; need to do sw filter.
  439.     mov    mcast_sw_filter,1    ; because chip filter is not 100%
  440.     jmp short rcv_mode_set
  441. rcv_mode_5:     ; Mode 3 plus ALL multicast packets
  442.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  443.     mov     mcast_all_flag,1
  444.     jmp short rcv_mode_set
  445. rcv_mode_6:     ; Receive all packets (Promiscuous physical plus all multi)
  446.     mov al,    ENRXCR_BCST+ENRXCR_MULTI+ENRXCR_PROMP
  447.     mov     mcast_all_flag,1
  448. rcv_mode_set:
  449.     push    ax              ; Hold mode until masks are right
  450.     call    set_8390_multi  ; Set the multicast mask bits in chip
  451.     pop     ax
  452.     loadport
  453.     setport    EN0_RXCR    ; Set receiver to selected mode
  454.     pause_
  455.     out dx,    al
  456.     mov     rxcr_bits,al    ; Save a copy of what we set it to
  457.     ret
  458.  
  459.  
  460.     public    set_multicast_list
  461. set_multicast_list:
  462. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  463. ;return nc if we set all of them, or cy,dh=error if we didn't.
  464.     assume ds:nothing
  465.     push    cs
  466.     pop    es        ; set es to destination
  467.     mov    di,offset mcast_tab
  468.     mov    ax,cx        ; save byte count
  469.     repz    movsb
  470.     mov    dx,0
  471.     mov    cx,6
  472.     div    cx
  473.     mov    mcast_hcount,ax
  474. ;
  475.     mov    word ptr mcast_list_bits,0
  476.     mov    word ptr mcast_list_bits+2,0
  477.     mov    word ptr mcast_list_bits+4,0
  478.     mov    word ptr mcast_list_bits+6,0
  479. ;
  480.     mov    cx,mcast_hcount
  481.     inc    cx
  482.     mov    di,offset mcast_tab_b
  483. set_mcl_1:
  484.     call    add_mc_bits
  485.     add    di,6
  486.     loop    set_mcl_1
  487.     call    set_8390_multi  ; Set the multicast mask bits in chip
  488.     clc
  489.     mov    dh,0
  490.     ret
  491.  
  492. ;
  493. ;    multicast is at es:di
  494.     assume    ds:nothing
  495. add_mc_bits:
  496.     push    cx
  497.     push    di
  498.     mov    cx,6
  499.     mov    dx,0ffffh            ; this is msw.
  500.     mov    bx,0ffffh            ; set 32 bit number
  501. add_mcb_1:
  502.     mov    al,es:[di]
  503.     inc    di
  504.     call    upd_crc            ; update crc
  505.     loop    add_mcb_1        ; and loop.
  506.     mov    ah,0
  507.     mov    al,dh            ; get ms 8 bits,
  508.     rol    al,1
  509.     rol    al,1
  510.     rol    al,1            ; put 3 bits at bottom
  511.     and    al,7
  512.     mov    dl,al            ; save in dl
  513.     mov    al,dh            ; get ms 8 bits,
  514.     ror    al,1
  515.     ror    al,1            ; but at bottom
  516.     and    al,7
  517.     mov    cl,al            ; save in cl
  518.     mov    al,1
  519.     rol    al,cl            ; set the correct bit,
  520.     mov    di,offset mcast_list_bits
  521.     mov    dh,0
  522.     add    di,dx
  523.     or    cs:[di],al
  524.     pop    di
  525.     pop    cx
  526.     ret
  527.  
  528. ;
  529. ;    dx is high,
  530. ;    bx is low.
  531. ;    al is data
  532.  
  533. upd_crc:
  534.     push    cx
  535.     mov    cx,8        ; do 8 bits
  536.     mov    ah,0
  537. upd_crc1:
  538.     shl    bx,1        ; shift bx
  539.     rcl    dx,1        ; through dx
  540.     rcl    ah,1        ; carry is at bottom of ah
  541.     xor    ah,al        ; xor with lsb of data
  542.     rcr    ah,1        ; and put in carry bit        
  543.     jnc    upd_crc2
  544. ;
  545. ;    autodin is x^32+x^26+x^23x^22+x^16+
  546. ;    x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+1
  547.  
  548.     xor    dx,0000010011000001b
  549.     xor    bx,0001110110110111b
  550. upd_crc2:
  551.     shr    al,1        ; shift the data
  552.     loop    upd_crc1
  553.     pop    cx
  554.     ret
  555.  
  556. ; Set the multicast filter mask bits in case promiscuous rcv wanted
  557. set_8390_multi:
  558.     push    cs
  559.     pop     ds
  560.     assume    ds:code
  561.     loadport
  562.     setport    EN_CCMD        ; Chip command register
  563.     pause_
  564.     mov cx,    8        ; Eight bytes of multicast filter
  565.     mov si, offset mcast_list_bits  ; Where bits are, if not all ones
  566.     cli            ; Protect from irq changing page bits
  567.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_STOP
  568.     out dx,    al        ; Switch to page one for writing eaddr
  569.     setport    EN1_MULT    ; Where it goes in 8390
  570.     pause_
  571.     mov al, mcast_all_flag  ; Want all ones or just selected bits?
  572.     or al,  al
  573.     je      set_mcast_2     ; Just selected ones
  574.     mov al,    0ffh        ; Ones for filter
  575. set_mcast_all:
  576.     out dx,    al        ; Write a mask byte
  577.     inc    dl        ; Step to next one
  578.     loop    set_mcast_all    ; ..    
  579.     jmp short set_mcast_x
  580.  
  581. set_mcast_2:
  582.     lodsb                   ; Get a byte of mask bits
  583.     out dx,    al        ; Write a mask byte
  584.     inc    dl        ; Step to next I/O register
  585.     loop    set_mcast_2     ; ..    
  586. set_mcast_x:
  587.     loadport
  588.     setport    EN_CCMD        ; Chip command register
  589.     pause_
  590.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  591.     out dx,    al        ; Restore to page zero
  592.     sti            ; OK for interrupts now
  593.     ret
  594.  
  595.  
  596.     public    reset_chip
  597.  
  598. reset_chip:
  599.     assume ds:nothing
  600.     loadport        ; Base of I/O regs
  601.     setport    NE_OTHERPORT
  602.     in    al,dx
  603.     longpause
  604.     out    dx,al        ; should set command 21, 80
  605.     longpause
  606.     setport    EN_CCMD        ; Chip command reg
  607.     pause_
  608.     mov al,    ENC_STOP+ENC_NODMA
  609.     out dx,    al        ; Stop the DS8390
  610.     setport EN0_ISR
  611.     pause_
  612.     mov    cx,0
  613. reset_chip_loop:
  614.     in    al,dx        ; get isr
  615.     and    al,ENISR_RESET
  616.     jnz    reset_chip_done
  617.     jmp    reset_chip_loop
  618. reset_chip_done:
  619.     ret
  620.  
  621.     public    terminate
  622. terminate:
  623.     ret
  624.  
  625.     public    reset_interface
  626. reset_interface:
  627.     assume ds:code
  628.     call    reset_chip
  629.     loadport        ; Base of I/O regs
  630.     setport    EN0_ISR        ; Interrupt status reg
  631.     pause_
  632.     mov al,    0ffh        ; Clear all pending interrupts
  633.     out dx,    al        ; ..
  634.     setport    EN0_IMR        ; Interrupt mask reg
  635.     pause_
  636.     xor al,    al        ; Turn off all enables
  637.     out dx,    al        ; ..
  638.     ret
  639.  
  640. ;
  641. ;    Special case Block input routine. Used on extra memory
  642. ;    space for board ID etc. DMA count is set X2,
  643. ;    CX = byte count, es:si = buffer location, ax = buffer address
  644.  
  645. sp_block_input:
  646.     push    ax        ; save buffer address
  647.     loadport
  648.     setport EN_CCMD
  649.     pause_
  650.     mov    al,ENC_NODMA+ENC_STOP
  651.     out    dx,al        ; stop & clear the chip
  652.     setport    EN0_RCNTLO    ; remote byte count 0
  653.     pause_
  654.     mov    ax,cx
  655.     add    ax,ax    
  656.     out    dx,al
  657.     setport    EN0_RCNTHI
  658.     pause_
  659.     mov    al,ah
  660.     out    dx,al
  661.     pop    ax        ; get our page back
  662.     setport    EN0_RSARLO
  663.     pause_
  664.     out    dx,al        ; set as hi address
  665.     setport    EN0_RSARHI
  666.     pause_
  667.     mov    al,ah
  668.     out    dx,al
  669.     setport EN_CCMD
  670.     pause_
  671.     mov    al,ENC_RREAD+ENC_START    ; read and start
  672.     out    dx,al
  673.     setport    NE_DATAPORT
  674.     pause_
  675.     jmp    read_loop
  676. ;
  677. ;    Block input routine
  678. ;    CX = byte count, es:si = buffer location, ax = buffer address
  679.  
  680.     public    block_input
  681. block_input:
  682.     push    ax        ; save buffer address
  683.     loadport
  684.     setport EN_CCMD
  685.     pause_
  686.     mov    al,ENC_NODMA+ENC_PAGE0+ENC_START
  687.     out    dx,al
  688.     setport    EN0_RCNTLO    ; remote byte count 0
  689.     pause_
  690.     mov    al,cl    
  691.     out    dx,al
  692.     setport    EN0_RCNTHI
  693.     pause_
  694.     mov    al,ch
  695.     out    dx,al
  696.     pop    ax        ; get our page back
  697.     setport    EN0_RSARLO
  698.     pause_
  699.     out    dx,al        ; set as hi address
  700.     setport    EN0_RSARHI
  701.     pause_
  702.     mov    al,ah
  703.     out    dx,al
  704.     setport EN_CCMD
  705.     pause_
  706.     mov    al,ENC_RREAD+ENC_START    ; read and start
  707.     out    dx,al
  708.     setport    NE_DATAPORT
  709.     pause_
  710.     cmp    byte ptr is_186,0
  711.     jnz    read_186
  712. read_loop:
  713.     in    al,dx        ; get a byte
  714.     stosb            ; save it
  715.     loop    read_loop
  716.     ret
  717. read_186:
  718.     inc    cx        ; make even
  719.     shr    cx,1        ; word count
  720.     db    0f3h, 06dh    ;masm 4.0 doesn't grok "rep insw"
  721.     ret
  722. ;
  723. ;    Block output routine
  724. ;    CX = byte count, ds:si = buffer location, ax = buffer address
  725.  
  726. block_output:
  727.     assume    ds:nothing
  728.     push    ax        ; save buffer address
  729.     inc    cx        ; make even
  730.     and    cx,0fffeh
  731.     loadport
  732.     setport EN_CCMD
  733.     pause_
  734.     mov    al,ENC_NODMA+ENC_START
  735.     out    dx,al        ; stop & clear the chip
  736.     setport    EN0_RCNTLO    ; remote byte count 0
  737.     pause_
  738.     mov    al,cl    
  739.     out    dx,al
  740.     setport    EN0_RCNTHI
  741.     pause_
  742.     mov    al,ch
  743.     out    dx,al
  744.     pop    ax        ; get our page back
  745.     setport    EN0_RSARLO
  746.     pause_
  747.     out    dx,al        ; set as lo address
  748.     setport    EN0_RSARHI
  749.     pause_
  750.     mov    al,ah
  751.     out    dx,al
  752.     setport EN_CCMD
  753.     pause_
  754.     mov    al,ENC_RWRITE+ENC_START    ; write and start
  755.     out    dx,al
  756.     setport    NE_DATAPORT
  757.     pause_
  758.     cmp    byte ptr is_186,0
  759.     jnz    write_186
  760. write_loop:
  761.     lodsb            ; get a byte
  762.     out    dx,al        ; save it
  763.     loop    write_loop
  764.     ret
  765. write_186:
  766.     shr    cx,1        ; word count
  767.     db    0f3h, 06fh    ;masm 4.0 doesn't grok "rep outsw"
  768.     ret
  769.  
  770.  
  771.  
  772. ; Linkages to non-device-specific routines
  773. ;called when we want to determine what to do with a received packet.
  774. ;enter with cx = packet length, es:di -> packet type.
  775. ;It returns with es:di = 0 if don't want this type or if no buffer available.
  776.     extrn    recv_find: near
  777.  
  778. ;called after we have copied the packet into the buffer.
  779. ;enter with ds:si ->the packet, cx = length of the packet.
  780.     extrn    recv_copy: near
  781.  
  782.     extrn    count_in_err: near
  783.     extrn    count_out_err: near
  784.  
  785.     public    recv
  786. recv:
  787. ;called from the recv isr.  All registers have been saved, and ds=cs.
  788. ;Actually, not just receive, but all interrupts come here.
  789. ;Upon exit, the interrupt will be acknowledged.
  790.  
  791.     assume    ds:code
  792. check_isr:            ; Was there an interrupt from this card?
  793.  
  794.     loadport        ; Point at card's I/O port base
  795.     setport EN0_IMR        ; point at interrupt masks
  796.     pause_            ; switch off, this way we can
  797.     mov    al,0        ; leave the chip running.
  798.     out    dx,al        ; no interrupts please.
  799.     setport    EN0_ISR        ; Point at interrupt status register
  800.     pause_
  801.     in al,    dx        ; Get pending interrupts
  802.     and al,    ENISR_ALL    ; Any?
  803.     jnz    isr_test_overrun
  804.     jmp    interrupt_done    ; Go if none
  805. ; First, a messy procedure for handling the case where the rcvr
  806. ; over-runs its ring buffer.  This is spec'ed by National for the chip.
  807. ; This is handled differently in sample code from 3Com and from WD.
  808. ; This is close to the WD version.  May need tweaking if it doesn't
  809. ; work for the 3Com card.
  810.  
  811. isr_test_overrun: 
  812.     test al,ENISR_OVER    ; Was there an overrun?
  813.     jnz    recv_overrun    ; Go if so.
  814.     jmp    recv_no_overrun    ; Go if not.
  815. recv_overrun:
  816.     setport    EN_CCMD        ; Stop the chip
  817.     pause_
  818.     mov al,    ENC_STOP+ENC_NODMA
  819.     out dx,    al        ; Write "stop" to command register
  820.  
  821.  
  822.     mov al, ENC_NODMA+ENC_PAGE1    ; Could be in previous out, but
  823.     out dx,al        ; was only tested this way
  824.     setport EN1_CURPAG    ; Get current page
  825.     in al,dx
  826.     mov bl,al        ; save it
  827.     setport    EN_CCMD        ;
  828.     mov al, ENC_NODMA+ENC_PAGE0
  829.     out dx,al        ; Back to page 0
  830.  
  831. ; Remove one frame from the ring
  832.     setport    EN0_BOUNDARY    ; Find end of this frame
  833.     pause_
  834.     in al,    dx        ; Get memory page number
  835.     inc    al        ; Page plus 1
  836.     cmp al,    SM_RSTOP_PG    ; Wrapped around ring?
  837.     jnz    rcv_ovr_nwrap    ; Go if not
  838.     mov al,    SM_RSTART_PG    ; Yes, wrap the page pointer
  839. rcv_ovr_nwrap:
  840.  
  841.     cmp    al,bl        ; Check if buffer emptry
  842.     je    rcv_ovr_empty    ; Yes ? Don't receive anything
  843.  
  844.     mov    ah,al        ; make a byte address. e.g. page
  845.     mov    bl,ah        ; and save in bl
  846.     mov    al,0        ; 46h becomes 4600h into buffer
  847.     mov    cx,RCV_HDR_SIZE    ; size of rcv_hdr
  848.     mov    di,offset rcv_hdr ;point to header
  849.     push    ds
  850.     pop    es        ; set es to right place
  851.     call    block_input
  852.     mov al,    rcv_hdr+EN_RBUF_STAT    ; Get the buffer status byte
  853.     test al,ENPS_RXOK    ; Is this frame any good?
  854.     jz    rcv_ovr_ng    ; Skip if not
  855.      call    rcv_frm        ; Yes, go accept it
  856. rcv_ovr_ng:
  857.     mov al,    rcv_hdr+EN_RBUF_NXT_PG    ; Get pointer to next frame
  858.     dec    al        ; Back up one page
  859.     cmp al,    SM_RSTART_PG    ; Did it wrap?
  860.     jge    rcv_ovr_nwr2
  861.     mov al,    SM_RSTOP_PG-1    ; Yes, back to end of ring
  862. rcv_ovr_nwr2:
  863.     loadport        ; Point at boundary reg
  864.     setport    EN0_BOUNDARY    ; ..
  865.     pause_
  866.     out dx,    al        ; Set the boundary
  867. rcv_ovr_empty:
  868.     setport    EN0_RCNTLO    ; Point at byte count regs
  869.     pause_
  870.     xor al,    al        ; Clear them
  871.     out dx,    al        ; ..
  872.     setport    EN0_RCNTHI
  873.     pause_
  874.     out dx,    al
  875.     setport    EN0_ISR        ; Point at status reg
  876.     pause_
  877.     mov cx,    8000h        ; Timeout counter
  878. rcv_ovr_rst_loop:
  879.     in al,    dx        ; Is it finished resetting?
  880.     test al,ENISR_RESET    ; ..
  881.     jnz    rcv_ovr_rst    ; Go if so
  882.     dec    cx        ; Loop til reset, or til timeout
  883.     jnz    rcv_ovr_rst_loop
  884. rcv_ovr_rst:
  885.     loadport        ; Point at Transmit control reg
  886.      setport    EN0_TXCR    ; ..
  887.     pause_
  888.     mov al,    ENTXCR_LOOP    ; Put transmitter in loopback mode
  889.     out dx,    al        ; ..
  890.     setport    EN_CCMD        ; Point at Chip command reg
  891.     pause_
  892.     mov al,    ENC_START+ENC_NODMA
  893.     out dx,    al        ; Start the chip running again
  894.     setport    EN0_TXCR    ; Back to TX control reg
  895.     pause_
  896.     xor al,    al        ; Clear the loopback bit
  897.     out dx,    al        ; ..
  898.     setport    EN0_ISR        ; Point at Interrupt status register
  899.     pause_
  900.     mov al,    ENISR_OVER    ; Clear the overrun interrupt bit
  901.     out dx,    al        ; ..
  902.     call    count_in_err    ; Count the anomaly
  903.      jmp    check_isr    ; Done with the overrun case
  904.  
  905. recv_no_overrun:
  906. ; Handle receive flags, normal and with error (but not overrun).
  907.     test al,ENISR_RX+ENISR_RX_ERR    ; Frame received without overrun?
  908.     jnz    recv_frame    ; Go if so.
  909.     jmp    recv_no_frame    ; Go if not.
  910. recv_frame:
  911.     loadport        ; Point at Chip's Command Reg
  912.      setport    EN_CCMD        ; ..
  913.     pause_
  914.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_START
  915.     out dx,    al        ; Switch to page 1 registers
  916.     setport    EN1_CURPAG    ;Get current page of rcv ring
  917.     pause_
  918.     in al,    dx        ; ..
  919.     mov ah,    al        ; Hold current page in AH
  920.      setport    EN_CCMD        ; Back to page zero registers
  921.     pause_
  922.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  923.     out dx,    al        ; Switch back to page 0 registers
  924.     setport    EN0_BOUNDARY    ;Get boundary page
  925.     pause_
  926.     in al,    dx        ; ..
  927.     inc    al        ; Step boundary from last used page
  928.     cmp al,    SM_RSTOP_PG    ; Wrap if needed
  929.     jne    rx_nwrap3    ; Go if not
  930.     mov al,    SM_RSTART_PG    ; Wrap to first RX page
  931. rx_nwrap3:
  932.     cmp al,    ah        ; Read all the frames?
  933.     je    recv_frame_break    ; Finished them all
  934.  
  935.     mov    ah,al        ; make a byte address. E.G. page
  936.     mov    al,0        ; 46h becomes 4600h into buffer
  937.     mov    bl,ah
  938.     mov    cx,RCV_HDR_SIZE
  939.     mov    di,offset rcv_hdr
  940.     push    ds
  941.     pop    es        ; set es to right place
  942.     call    block_input
  943.     mov al,    rcv_hdr+EN_RBUF_STAT    ; Get the buffer status byte
  944.     test al,ENPS_RXOK    ; Good frame?
  945.     jz    recv_err_no_rcv
  946.     call    rcv_frm        ; Yes, go accept it
  947.     jmp    recv_no_rcv
  948. recv_err_no_rcv:
  949.     or    byte ptr soft_rx_err_bits,al
  950.     add    word ptr soft_rx_errors,1
  951.     adc    word ptr soft_rx_errors+2,0
  952. recv_no_rcv:
  953.     mov al,    rcv_hdr+EN_RBUF_NXT_PG    ; Start of next frame
  954.     dec    al        ; Make previous page for new boundary
  955.     cmp al,    SM_RSTART_PG    ; Wrap around the bottom?
  956.     jge    rcv_nwrap4
  957.     mov al,    SM_RSTOP_PG-1    ; Yes
  958. rcv_nwrap4:
  959.     loadport        ; Point at the Boundary Reg again
  960.      setport    EN0_BOUNDARY    ; ..
  961.     pause_
  962.     out dx,    al        ; Set new boundary
  963.     jmp    recv_frame    ; See if any more frames
  964.  
  965. recv_frame_break:
  966.     loadport        ; Point at Interrupt Status Reg
  967.      setport    EN0_ISR        ; ..
  968.     pause_
  969.     mov al,    ENISR_RX+ENISR_RX_ERR+ENISR_OVER
  970.     out dx,    al        ; Clear those requests
  971.     setport EN_CCMD
  972.     pause_
  973.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  974.     out    dx,al
  975.     jmp    check_isr    ; See if any other interrupts pending
  976.  
  977. recv_no_frame:                ; Handle transmit flags.
  978.     test al,ENISR_TX+ENISR_TX_ERR    ; Frame transmitted?
  979.     jnz    isr_tx        ; Go if so.
  980.     jmp    isr_no_tx    ; Go if not.
  981. isr_tx:
  982.     mov ah,    al        ; Hold interrupt status bits
  983.     loadport        ; Point at Transmit Status Reg
  984.      setport    EN0_TSR        ; ..
  985.     pause_
  986.     in al,    dx        ; ..
  987.     test ah,ENISR_TX    ; Non-error TX?
  988.     jz    isr_tx_err    ; No, do TX error completion
  989.     call    count_soft_err    ; soft error ??
  990.     test al,ENTSR_COLL16    ; Jammed for 16 transmit tries?
  991.     jz    isr_tx_njam    ; Go if not
  992.     call    count_out_err    ; Yes, count those
  993. isr_tx_njam:
  994.     setport    EN0_ISR        ; Clear the TX complete flag
  995.     pause_
  996.     mov al,    ENISR_TX    ; ..
  997.     out dx,    al        ; ..    
  998.     jmp    isr_tx_done
  999. isr_tx_err:
  1000.     test al,ENTSR_FU    ; FIFO Underrun?
  1001.     jz    isr_txerr_nfu
  1002.     call    count_out_err    ; Yes, count those
  1003. isr_txerr_nfu:
  1004.     loadport        ; Clear the TX error completion flag
  1005.     setport    EN0_ISR        ; ..
  1006.     pause_
  1007.     mov al,    ENISR_TX_ERR    ; ..
  1008.     out dx,    al        ; ..    
  1009. isr_tx_done:
  1010. ; If TX queue and/or TX shared memory ring buffer were being
  1011. ; used, logic to step through them would go here.  However,
  1012. ; in this version, we just clear the flags for background to notice.
  1013.  
  1014.      jmp    check_isr    ; See if any other interrupts on
  1015.  
  1016. isr_no_tx:
  1017. ; Now check to see if any counters are getting full
  1018.     test al,ENISR_COUNTERS    ; Interrupt to handle counters?
  1019.     jnz    isr_stat    ; Go if so.
  1020.     jmp    isr_no_stat    ; Go if not.
  1021. isr_stat:
  1022. ; We have to read the counters to clear them and to clear the interrupt.
  1023. ; Version 1 of the PC/FTP driver spec doesn't give us
  1024. ; anything useful to do with the data, though.
  1025. ; Fix this up for V2 one of these days.
  1026.     loadport        ; Point at first counter
  1027.      setport    EN0_COUNTER0    ; ..
  1028.     pause_
  1029.     in al,    dx        ; Read the count, ignore it.
  1030.     setport    EN0_COUNTER1
  1031.     pause_
  1032.     in al,    dx        ; Read the count, ignore it.
  1033.     setport    EN0_COUNTER2
  1034.     pause_
  1035.     in al,    dx        ; Read the count, ignore it.
  1036.     setport    EN0_ISR        ; Clear the statistics completion flag
  1037.     pause_
  1038.     mov al,    ENISR_COUNTERS    ; ..
  1039.     out dx,    al        ; ..
  1040. isr_no_stat:
  1041.      jmp    check_isr    ; Anything else to do?
  1042.  
  1043. interrupt_done:
  1044.     ret
  1045.  
  1046. ; Do the work of copying out a receive frame.
  1047. ; Called with bl/ the page number of the frame header in shared memory
  1048.  
  1049.     public    rcv_frm
  1050. rcv_frm:
  1051. ; first do a software multicast filter.
  1052.     push    bx            ; save page.
  1053.     cmp    mcast_sw_filter,1    ; do software check of mcast ?
  1054.     jnz    rcv_frm_ok        ; no, accept.
  1055.     mov    ax,word ptr rcv_hdr+EN_RBUF_NHDR ; get first word of address
  1056.     test al,1            ; odd first byte
  1057.     jz    rcv_frm_ok        ; must be our address if even
  1058.     inc    word ptr mcast_sw_fin
  1059.  
  1060.     mov    bx,word ptr rcv_hdr+EN_RBUF_NHDR+2 ; get second word of address
  1061.     mov    dx,word ptr rcv_hdr+EN_RBUF_NHDR+4 ; get third word of address
  1062.  
  1063.     mov    di,offset mcast_tab_b    ; point to table and broadcast
  1064.     mov    cx,mcast_hcount        ; get number in table
  1065.     inc    cx            ; plus the broadcast
  1066. rcv_loop:
  1067.     mov    si,di            ; save this table entry
  1068.     cmp    ax,[di]
  1069.     jnz    rcv_trynext
  1070.     inc    di
  1071.     inc    di
  1072.     cmp    bx,[di]
  1073.     jnz    rcv_trynext
  1074.     inc    di
  1075.     inc    di
  1076.     cmp    dx,[di]
  1077.     jz    rcv_mc_ok        ; got it.
  1078. rcv_trynext:
  1079.     mov    di,si            ; get table back,
  1080.     add    di,6
  1081.     loop    rcv_loop
  1082.     pop    bx            ; restore bx
  1083.     jmp    rcv_no_copy
  1084.     
  1085. rcv_mc_ok:
  1086.     inc    word ptr mcast_sw_fout
  1087. rcv_frm_ok:
  1088. ; Set cx to length of this frame.
  1089.     mov ch,    rcv_hdr+EN_RBUF_SIZE_HI    ; Extract size of frame
  1090.     mov cl,    rcv_hdr+EN_RBUF_SIZE_LO    ; Extract size of frame
  1091.     sub cx,    EN_RBUF_NHDR        ; Less the header stuff
  1092. ; Set es:di to point to Ethernet type field.
  1093.     mov di,    offset rcv_hdr+EN_RBUF_NHDR+EADDR_LEN+EADDR_LEN
  1094.     push    cx            ; Save frame size
  1095.     push    es
  1096.     mov ax,    cs            ; Set ds = code
  1097.     mov ds,    ax
  1098.     mov es,ax
  1099.     assume    ds:code
  1100.     call    recv_find        ; See if type and size are wanted
  1101.     pop    ds            ; RX page pointer in ds now
  1102.     assume    ds:nothing
  1103.     pop    cx
  1104.     pop    bx
  1105.     cld            ; Copies below are forward, please
  1106.     mov ax,    es        ; Did recv_find give us a null pointer?
  1107.     or ax,    di        ; ..
  1108.     je    rcv_no_copy    ; If null, don't copy the data    
  1109.  
  1110.     push    cx        ; We will want the count and pointer
  1111.     push    es        ;  to hand to client after copying,
  1112.     push    di        ;  so save them at this point
  1113.     mov    ah,bl        ; set ax to page to start from
  1114.     mov    al,EN_RBUF_NHDR    ; skip the header stuff
  1115.     call    block_input
  1116.     pop    si        ; Recover pointer to destination
  1117.     pop    ds        ; Tell client it's his source
  1118.     pop    cx        ; And it's this long
  1119.     assume    ds:nothing
  1120.     call    recv_copy    ; Give it to him
  1121. rcv_no_copy:
  1122.     push    cs        ; Put ds back in code space
  1123.     pop    ds        ; ..
  1124.     assume    ds:code
  1125.     ret            ; That's it for rcv_frm
  1126.  
  1127.  
  1128.     public    recv_exiting
  1129. recv_exiting:
  1130. ;called from the recv isr after interrupts have been acknowledged.
  1131. ;Only ds and ax have been saved.
  1132.     assume    ds:nothing
  1133.     push    dx
  1134.     loadport
  1135.     setport    EN0_IMR        ; Tell card it can cause these interrupts
  1136.     pause_
  1137.     mov al,    ENISR_ALL
  1138.     out dx,    al
  1139.     pop    dx
  1140.     ret
  1141.  
  1142.  
  1143. ;any code after this will not be kept after initialization.
  1144. end_resident    label    byte
  1145.  
  1146.  
  1147.     public    usage_msg
  1148. usage_msg    db    "usage: NE2000 <packet_int_no> <int_level> <io_addr>",CR,LF,'$'
  1149.  
  1150.     public    copyright_msg
  1151. copyright_msg    db    "Packet driver for Novell NE2000, version ",'0'+majver,".",'0'+version,CR,LF
  1152.         db    "Portions Copyright 1989, Robert C. Clements, K1BC",CR,LF,'$'
  1153.  
  1154. cfg_err_msg:
  1155.     db    "NE2000 Configuration failed. Check parameters.",CR,LF,'$'
  1156. int_no_name:
  1157.     db    "Interrupt number ",'$'
  1158. io_addr_name:
  1159.     db    "I/O port ",'$'
  1160. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  1161.  
  1162.     extrn    set_recv_isr: near
  1163.  
  1164. ;enter with si -> argument string, di -> word to store.
  1165. ;if there is no number, don't change the number.
  1166.     extrn    get_number: near
  1167.  
  1168.     public    parse_args
  1169. parse_args:
  1170. ;exit with nc if all went well, cy otherwise.
  1171.     mov di,    offset int_no        ; May override interrupt channel
  1172.     mov bx,    offset int_no_name    ; Message for it
  1173.     call    get_number
  1174.     mov di,    offset io_addr        ; May override I/O address
  1175.     mov bx,    offset io_addr_name    ; Message for it
  1176.     call    get_number
  1177. ;    mov di,    offset mem_base        ; Not movable in 3C503
  1178. ;    mov bx,    offset mem_base_name    ; Message for it
  1179. ;    call    get_number        ; Must get from jumpers.
  1180.     clc
  1181.     ret
  1182.  
  1183.  
  1184. cfg_error:
  1185.     mov    dx,offset cfg_err_msg
  1186. error:
  1187.     mov    ah,9        ; Type the msg
  1188.     int    21h
  1189.     stc            ; Indicate error
  1190.     ret            ; Return to common code
  1191.  
  1192. ; Called once to initialize the NE2000 card
  1193.  
  1194.     extrn    memory_test: near
  1195.     public    etopen
  1196. etopen:                ; Initialize interface
  1197.  
  1198. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  1199. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  1200. ;This bit lifted from NI5010 driver.
  1201.  
  1202.     mov    cl,33
  1203.     mov    ax,0ffffh
  1204.     shl    ax,cl
  1205.     jz    not_186
  1206.     mov    is_186,1
  1207.     mov    dx,offset using_186_msg
  1208.     mov    ah,9
  1209.     int    21h
  1210. not_186:
  1211.  
  1212. ; Now, initialize the DS8390 Ethernet Controller chip
  1213. ini_8390:
  1214.     call    reset_chip
  1215.     loadport
  1216.     setport    EN0_DCFG    ; Configure the fifo organization
  1217.     pause_
  1218.     mov al,    ENDCFG_BM8    ; Fifo threshold = 8 bytes
  1219.     out dx,    al
  1220.     setport    EN_CCMD        ; DS8390 chip's command register
  1221.     pause_
  1222.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  1223.     out dx,    al        ; Switch to page zero
  1224.  
  1225.     setport    EN0_TXCR    ; Set transmitter mode to normal
  1226.     pause_
  1227.     xor al,    al
  1228.     out dx,    al
  1229.     setport    EN0_RXCR    ; Set receiver to monitor mode
  1230.     pause_
  1231.     mov al,    ENRXCR_MON
  1232.     out dx,    al
  1233.  
  1234.  
  1235. ; Set up control of shared memory, buffer ring, etc.
  1236.  
  1237.     setport    EN0_STARTPG    ; Set receiver's first buffer page
  1238.     pause_
  1239.     mov al,    SM_RSTART_PG
  1240.     out dx,    al
  1241.  
  1242.     setport    EN0_STOPPG    ;  and receiver's last buffer page + 1
  1243.     pause_
  1244.     mov al,    SM_RSTOP_PG
  1245.     out dx,    al
  1246.  
  1247.     setport    EN0_BOUNDARY    ; Set initial "last page we have emptied"
  1248.     pause_
  1249.     mov al,    SM_RSTOP_PG    ; (WD doc says set to RSTART_PG)
  1250.     dec    al        ; (3Com doc says set to RSTOP_PG-1 ?)
  1251. ;                ; (and 3Com handling of BOUNDARY is
  1252. ;                ;  different throughout.)
  1253.     out dx,    al        ; (Check out why WD and 3Com disagree)
  1254. ;
  1255.  
  1256.     setport    EN0_IMR        ; Clear all interrupt enable flags
  1257.     pause_
  1258.     xor al,    al
  1259.     out dx,    al
  1260.  
  1261.     setport    EN0_ISR        ; Clear all interrupt assertion flags
  1262.     pause_
  1263.     mov al,    0ffh
  1264.     out dx,    al
  1265.  
  1266.     setport    EN_CCMD
  1267.     pause_
  1268.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_STOP
  1269.     out    dx,al
  1270.     
  1271.     setport    EN1_CURPAG
  1272.     pause_
  1273.     mov al,    SM_RSTART_PG
  1274.     out dx,    al
  1275.     
  1276.     setport    EN_CCMD
  1277.     pause_
  1278.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  1279.     out    dx,al
  1280.     
  1281.     call    get_board_data    ; read board data
  1282.  
  1283.     push    ds              ; Copy from card's address to current address
  1284.     pop     es
  1285.  
  1286.     mov si, offset board_data    ; address is at start
  1287.     mov di, offset curr_hw_addr
  1288.     mov cx, EADDR_LEN       ; Copy one address length
  1289.     rep     movsb           ; ..
  1290.     call    set_8390_eaddr  ; Now set the address in the 8390 chip
  1291.     call    set_8390_multi  ; Put the right stuff into 8390's multicast masks
  1292.     loadport        ; Base of I/O regs
  1293.     setport    EN_CCMD        ; Chip command register
  1294.     pause_
  1295.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  1296.     out dx,    al        ; Back to page zero
  1297.     setport    EN0_RCNTLO    ; Clear the byte count registers
  1298.     pause_
  1299.     xor al,    al        ; ..
  1300.     out dx,    al
  1301.     setport    EN0_RCNTHI
  1302.     pause_
  1303.     out dx,    al        ; Clear high byte, too
  1304.     setport    EN0_IMR        ; Clear all interrupt enable flags
  1305.     pause_
  1306.     xor al,    al
  1307.     out dx,    al
  1308.     setport    EN0_ISR        ; Clear all interrupt assertion flags
  1309.     pause_
  1310.     mov al,    0ffh        ; again for safety before making the
  1311.     out dx,    al        ; interrupt be enabled
  1312.     call    set_recv_isr    ; Put ourselves in interrupt chain
  1313.     loadport
  1314.     setport    EN_CCMD        ; Now start the DS8390
  1315.     pause_
  1316.     mov al,    ENC_START+ENC_NODMA
  1317.     out dx,    al        ; interrupt be enabled
  1318.     setport    EN0_RXCR    ; Tell it what frames to accept
  1319.     pause_
  1320.     mov al,    rxcr_bits       ; As most recently set by set_mode
  1321.     out dx,    al
  1322.     setport    EN0_IMR        ; Tell card it can cause these interrupts
  1323.     pause_
  1324.     mov al,    ENISR_ALL
  1325.     out dx,    al
  1326. done:    mov dx,    offset end_resident    ; Report our size
  1327.     clc                ; Say no error
  1328.     ret                ; Back to common code
  1329.  
  1330.  
  1331.  
  1332.  
  1333. code    ends
  1334.  
  1335.     end
  1336.