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

  1. ;History:538,1
  2. ; Ian Brabham    28 Apr 1993    Fix problems related to SMC version of 8390
  3.  
  4. dp8390_version    equ    3    ;version number of the generic 8390 driver.
  5.  
  6. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  7.  
  8. ;   This program is free software; you can redistribute it and/or modify
  9. ;   it under the terms of the GNU General Public License as published by
  10. ;   the Free Software Foundation, version 1.
  11. ;
  12. ;   This program is distributed in the hope that it will be useful,
  13. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. ;   GNU General Public License for more details.
  16. ;
  17. ;   You should have received a copy of the GNU General Public License
  18. ;   along with this program; if not, write to the Free Software
  19. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. ; This driver is the work of several people: Bob Clements, Eric Henderson,
  22. ; Dave Horne, Glenn Talbott, Russell Nelson, Jan Engvald, Paul Kranenburg,
  23. ; and Ian Brabham.
  24.  
  25.   ife SM_RSTART_PG
  26.     %err    SM_RSTART_PG cannot be zero because of a decrement/unsigned jump.
  27.   endif
  28.  
  29. ;
  30. ; The longpause macro was originally written as this:
  31. ;
  32. ;longpause macro
  33. ;    push    cx
  34. ;    mov    cx,0
  35. ;    loop    $
  36. ;    pop    cx
  37. ;endm
  38. ;
  39. ; It was only used to stall while hard resetting the card. On my
  40. ; 25Mhz 486 longpause was taking more than 18ms, and almost forever
  41. ; on slower machines, much longer than necessary and not predictable.
  42. ;
  43. ; To be able to utilize longpause elsewhere and make it machine independent and
  44. ; predictable, I have re-written it to be a fixed time of 1.6ms, which just
  45. ; happens to be the time National recommends waiting for the NIC chip to
  46. ; stop sending or receiving after being commanded to stop.
  47. ;
  48. ; Based on the assumption that ISA specs mandate a 1.0 uS minimum I/O cycle
  49. ; Microchannel a 0.5uS minimum I/O cycle, and the NMI Status register (location
  50. ; 61h) is readable via I/O cycle on all machines, the longpause macro is now
  51. ; defined below. - gft - 901604
  52. ; (I realize that on slow machines this may take much longer, but the point
  53. ; is that on FAST machines it should never be faster than 1.6ms)
  54.  
  55. longpause macro
  56.     local lp_not_mc
  57.     push cx
  58.     push ax
  59.     mov  cx,1600    ; 1.6ms = 1600*1.0us
  60.     test sys_features,SYS_MCA
  61.     je   lp_not_mc
  62.     shl  cx,1    ; twice as many loops for Microchannel
  63. lp_not_mc:
  64.     in al,61h
  65.     loop lp_not_mc
  66.     pop  ax
  67.     pop  cx
  68. endm
  69.  
  70.     extrn    sys_features: byte
  71.  
  72. sm_rstop_ptr    db    SM_RSTOP_PG
  73.  
  74. rxcr_bits       db      ENRXCR_BCST     ; Default to ours plus multicast
  75.   ifdef board_features
  76. is_overrun_690    db    0
  77.   endif
  78.  
  79.  
  80. ;-> the assigned Ethernet address of the card.
  81.     extrn    rom_address: byte
  82.  
  83. ;-> current address
  84.     extrn    my_address: byte
  85.  
  86.     public    mcast_list_bits, mcast_all_flag
  87. mcast_list_bits db      0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
  88. mcast_all_flag  db      0               ;Non-zero if hware should have all
  89.                     ; ones in mask rather than this list.
  90.  
  91.     public    rcv_modes
  92. rcv_modes    dw    7        ;number of receive modes in our table.
  93.         dw    0               ;There is no mode zero
  94.         dw    rcv_mode_1
  95.         dw    rcv_mode_2
  96.         dw    rcv_mode_3
  97.         dw    rcv_mode_4
  98.         dw    rcv_mode_5
  99.         dw    rcv_mode_6
  100.  
  101. ;
  102. ;    a temp buffer for the received header
  103. ;
  104. RCV_HDR_SIZE    equ    26        ; 2 ids @6 + protocol @2+8, + header @4
  105. rcv_hdr        db    RCV_HDR_SIZE dup(0)
  106.  
  107. ;
  108. ;    The board data
  109. ;
  110.         public    board_data
  111. BOARD_DATA_SIZE equ    32
  112. board_data    db     BOARD_DATA_SIZE dup(0)
  113.  
  114.  
  115. ; add public for soft errors (how were these extracted before? - gft - 910604
  116.  
  117.         public soft_errors
  118.         public soft_tx_errors,soft_tx_err_bits,soft_tx_collisions
  119.         public soft_rx_errors,soft_rx_err_bits
  120.         public soft_rx_overruns,soft_rx_over_nd
  121. ;
  122. ; Re-arranged the order of these soft_xx_err things so that they can be
  123. ; accessed as a data structure (like the statistics structure defined
  124. ; in the packet driver spec. I don't know if it's necessary but I've always
  125. ; found data structures to be more portable if elements are size aligned.
  126. ;  - gft - 910607
  127. ; Don't rearrange or insert things between these soft error words because
  128. ; they are accessed as a data structure (I don't think I violated my own
  129. ; admonition since they wern't public and I could find no references to 
  130. ; them and only the NEx000 drivers reference the next previous thing,
  131. ; board_data, and they only us 16 bytes of that.)
  132.  
  133. soft_errors         label   dword
  134. soft_tx_errors        dw    0,0
  135. soft_tx_collisions    dw    0,0 ; added - gft - 910607 cause who ever heard
  136.                     ; of a CSMA/CD driver not counting
  137.                     ; collisions.
  138. soft_rx_errors        dw    0,0
  139. soft_rx_overruns    dw    0,0 ; added - gft - 910604 cause I just
  140.                     ; gotta track these so I can findout
  141.                     ; just when I'm pushing a driver or
  142.                     ; application to it's limits
  143. soft_rx_over_nd        dw    0,0 ; Also count when theres no data.
  144. hard_tx_errors        dw    0,0
  145. soft_tx_err_bits    db    0
  146. soft_rx_err_bits    db    0
  147.  
  148. ;
  149. ; Next Packet Pointer (added  - gft - 910603)
  150. ;
  151. ;   Initialize to the same value as the current page pointer (start page 1).
  152. ;   Update after each reception to be the value of the next packet pointer
  153. ;   read from the NIC Header.
  154. ;   Copy value -1 to boundry register after each update.
  155. ;   Compare value with contents of current page pointer to verify that a
  156. ;   packet has been received (don't trust ISR RXE/PRX bits). If !=, one
  157. ;   or more packets have been received.
  158.  
  159. next_packet    db    0
  160. save_curr    db    0
  161.  
  162. ; Added flags and temp storage for new receive overrun processing
  163. ;  - gft - 910604
  164.  
  165. rcv_ovr_resend    db    0,0    ; flag to indicate resend needed
  166. defer_upcall    db    0,0    ; flag to indicate deferred upcall needed
  167. defer_ds    dw    ?    ;   deferred upcall parameters
  168. defer_si    dw    ?
  169. defer_cx    dw    ?
  170.  
  171.  
  172. ifdef    deb2screen
  173. ; Event to screen debugger. Destroys no registers and requires just 3 bytes at
  174. ; each place called. Produces a one-line summary of event types that has ever
  175. ; occured and then some trace lines with the sequence of the last events./Jan E LDC
  176.  
  177. SHOWMIN        equ    'a'
  178. SHOWMAX        equ    'l'
  179. EVENTCOLOR    equ    31h
  180. EVENTLINE    equ    17
  181. TRACECOLOR    equ    2eh
  182.  
  183. ShowEvent    proc    near
  184. x        =    0
  185.         rept    (SHOWMAX-SHOWMIN+1)
  186.         push    ax
  187.         mov    al,x
  188.         jmp    short ShowEventNum
  189. x        =    x+1
  190.         endm
  191.  
  192.   ShowEventNum:
  193.         pushf
  194.         push    di
  195.         push    es
  196.         mov    ah,EVENTCOLOR
  197.         mov    di,ax
  198.         shl    di,1
  199.         add    al,SHOWMIN
  200.         mov    es,cs:EventPar
  201.         cld
  202.         stosw
  203.  
  204.         mov    ah,TRACECOLOR
  205.         mov    es,cs:TracePar
  206.         cli
  207.         mov    di,cs:TraceInd
  208.         stosw
  209.         and    di,01ffh        ; (1ff+1)/2 = 256 log entries
  210.         mov    cs:TraceInd,di
  211.         mov    al,01bh
  212.         not    ah
  213.         stosw
  214.  
  215.         pop    es
  216.         pop    di
  217.         popf
  218.         pop    ax
  219.         ret
  220. ShowEvent    endp
  221.  
  222. EventPar    dw    0b800h+(EVENTLINE-1)*10-2*EVENTCOLOR*16
  223. TracePar    dw    0b800h+EVENTLINE*10
  224. TraceInd    dw    0
  225.  
  226. SHOW_EVENT    macro    id
  227. if id gt SHOWMAX or id lt SHOWMIN
  228.         .err
  229. endif
  230.         call    ShowEvent+((id-SHOWMIN)*(ShowEventNum-ShowEvent)/(SHOWMAX-SHOWMIN+1))
  231.         endm
  232.  
  233. else
  234.  
  235. SHOW_EVENT    macro    num
  236.         endm
  237.  
  238. endif ; deb2screen
  239.  
  240.  
  241. ifdef    debug            ; Include a very useful logging mechanism.  
  242.  
  243. ; The log entry structure.  Log entries include useful data such as
  244. ; a type (each place a log entry is made uses a different type), various
  245. ; chip status, ring buffer status, log entry dependent data, and optionally
  246. ; 8259 interrupt controller status.
  247. logentry    struc
  248. le_type        db    0    ; Log entry type
  249. le_ccmd        db    ?    ; Value of CCMD register
  250. le_isr        db    ?    ; Value of ISR register
  251. le_tsr        db    ?    ; Value of TSR register
  252. le_tcur        dw    ?    ; Value of sm_tcur
  253. le_tboundary    dw    ?    ; Value of sm_tboundary
  254. le_tnum        dw    ?    ; Value of sm_tnum
  255. le_dw        dw    ?    ; Log type specific dw data
  256. ifndef    mkle8259        ; Log 8259 status?
  257. le_dd        dd    ?    ; Log type specific dd data
  258. else
  259. le_irr1        db    ?    ; Value of 8259-1 IRR register
  260. le_isr1        db    ?    ; Value of 8259-1 ISR register
  261. le_irr2        db    ?    ; Value of 8259-2 IRR register
  262. le_isr2        db    ?    ; Value of 8259-2 ISR register
  263. endif
  264. logentry    ends
  265.  
  266. ; The types of log entries.
  267. LE_SP_E        equ    0    ; send_pkt entry
  268. LE_SP_X        equ    1    ; send_pkt exit
  269. LE_ASP_E    equ    2    ; as_send_pkt entry
  270. LE_ASP_X    equ    3    ; as_send_pkt exit
  271. LE_RBALLOC_E    equ    4    ; tx_rballoc entry
  272. LE_RBALLOC_X    equ    5    ; tx_rballoc exit
  273. LE_COPY_E    equ    6    ; sm_copy entry
  274. LE_COPY_X    equ    7    ; sm_copy exit
  275. LE_START_E    equ    8    ; tx_start entry
  276. LE_START_X    equ    9    ; tx_start exit
  277. LE_XMIT_E    equ    0ah    ; xmit entry
  278. LE_XMIT_X    equ    0bh    ; xmit exit
  279. LE_TXISR_E    equ    0ch    ; txisr entry
  280. LE_TXISR_X    equ    0dh    ; txisr exit
  281. LE_RECV_E    equ    0eh    ; recv entry
  282. LE_RECV_X    equ    0fh    ; recv exit
  283. LE_RCVFRM_E    equ    10h    ; rcv_frm entry
  284. LE_RCVFRM_X    equ    11h    ; rcv_frm exit
  285. LE_COPY_L    equ    12h    ; sm_copy loop
  286. LE_TIMER_E    equ    13h    ; timer entry
  287. LE_TIMER_X    equ    14h    ; timer exit
  288.  
  289.     public    log, log_index
  290. log        logentry 256 dup (<>) ; The log itself
  291. log_index    db    0    ; Index to current log entry
  292.  
  293. ; The macro used to create log entries.
  294. mkle    macro    letype, ledw, ledd, ledd2 ; Make an entry in the log
  295.     pushf            ; Save interrupt enable state
  296.     cli            ; Disable interrupts
  297.     push    dx        ; Save registers
  298.     push    bx
  299.     push    ax
  300.     mov bl,    log_index    ; Get current log_index
  301.     xor bh,    bh        ; Clear high byte
  302.     shl bx,    1        ; Multiply by sixteen
  303.     shl bx,    1
  304.     shl bx,    1
  305.     shl bx,    1
  306.     mov log[bx].le_type, letype ; Store log entry type
  307.     loadport        ; Base of device
  308.     setport EN_CCMD    ; Point at chip command register
  309.     in al,    dx        ; Get chip command state
  310.     mov log[bx].le_ccmd, al    ; Store CCMD value
  311.     setport EN0_ISR        ; Point at chip command register
  312.     in al,    dx        ; Get chip command state
  313.     mov log[bx].le_isr, al    ; Store ISR value
  314.     setport EN0_TSR        ; Point at chip command register
  315.     in al,    dx        ; Get chip command state
  316.     mov log[bx].le_tsr, al    ; Store TSR value
  317.     mov ax,    sm_tcur        ; Get current sm_tcur
  318.     mov log[bx].le_tcur, ax    ; Store sm_tcur value
  319.     mov ax,    sm_tboundary    ; Get current sm_tboundary
  320.     mov log[bx].le_tboundary, ax ; Store sm_tboundary value
  321.     mov ax,    sm_tnum        ; Get current sm_tnum
  322.     mov log[bx].le_tnum, ax    ; Store sm_tnum value
  323.     mov log[bx].le_dw, ledw    ; Store log entry dw
  324. ifndef    mkle8259        ; Include extra per-type data
  325.     mov word ptr log[bx].le_dd, ledd ; Store low word of log entry dd
  326.     mov word ptr log[bx].le_dd+2, ledd2 ; Store high word of log entry dd
  327. else                ; Include 8259 status
  328.     mov    al,0ah        ; read request register from
  329.     out    0a0h,al        ; secondary 8259
  330.     pause_
  331.     in    al,0a0h        ; get it
  332.     mov log[bx].le_irr2, al
  333.     mov    al,0bh        ; read in-service register from
  334.     out    0a0h,al        ; secondary 8259
  335.     pause_
  336.     in    al,0a0h        ; get it
  337.     mov log[bx].le_isr2, al
  338.     mov    al,0ah        ; read request register from
  339.     out    020h,al        ; primary 8259
  340.     pause_
  341.     in    al,020h        ; get it
  342.     mov log[bx].le_irr1, al
  343.     mov    al,0bh        ; read in-service register from
  344.     out    020h,al        ; primary 8259
  345.     pause_
  346.     in    al,020h        ; get it
  347.     mov log[bx].le_isr1, al
  348. endif
  349. ifdef    screenlog        ; Log the entry type to the screen too
  350.     push    es
  351.     mov ax,    0b800h        ; Color screen only...
  352.     mov es,    ax
  353.     mov bl,    log_index    ; Get current log_index
  354.     xor bh,    bh        ; Clear high byte
  355.     shl bx,    1        ; Multiply by sixteen
  356.     add bx,    3360
  357.     mov byte ptr es:[bx-1], 07h
  358.     mov byte ptr es:[bx], letype+30h
  359.     mov byte ptr es:[bx+1], 70h
  360.     pop    es
  361. endif
  362.     inc    log_index    ;
  363.     pop    ax        ; Restore registers
  364.     pop    bx
  365.     pop    dx
  366.     popf            ; Restore interrupt enable state
  367.     endm
  368.  
  369. else
  370. mkle    macro    letype, ledw, ledd, ledd2 ; Define an empty macro
  371.     endm
  372. endif
  373.  
  374.     public bad_command_intercept
  375. bad_command_intercept:
  376. ;called with ah=command, unknown to the skeleton.
  377. ;exit with nc if okay, cy, dh=error if not.
  378.     mov    dh,BAD_COMMAND
  379.     stc
  380.     ret
  381.  
  382.     public    as_send_pkt
  383. ; The Asynchronous Transmit Packet routine.
  384. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  385. ;   interrupts possibly enabled.
  386. ; Exit with nc if ok, or else cy if error, dh set to error number.
  387. ;   es:di and interrupt enable flag preserved on exit.
  388. as_send_pkt:
  389.     ret
  390.  
  391.     public    drop_pkt
  392. ; Drop a packet from the queue.
  393. ; Enter with es:di -> iocb.
  394. drop_pkt:
  395.     assume    ds:nothing
  396.     ret
  397.  
  398.     public    xmit
  399. ; Process a transmit interrupt with the least possible latency to achieve
  400. ;   back-to-back packet transmissions.
  401. ; May only use ax and dx.
  402. xmit:
  403.     assume    ds:nothing
  404.     ret
  405.  
  406.  
  407. ; The tx_wait loop had three problems that affected high load throughput.
  408. ; Most seriously, while we are waiting for the previous SEND to finnish,
  409. ; the chip can actually be RECEIVING one or even many packets! But because
  410. ; we were waiting with interrupts disabled, these packets were not emptied
  411. ; from the receive ring and we could get an overrun. We could put in code to
  412. ; test for pending receive interrupts, but that would not help for the
  413. ; third problem, see below. Instead interrupts are now on while waiting.
  414. ; Secondly, the wait loop was not long enough to allow for up to 16 collisions.
  415. ; Thirdly, for a router there are two or more drivers and the busy waiting
  416. ; in one of them prevented interrupt handling for the other(s), giving
  417. ; unnecessary low throughput. /Jan E LDC
  418.  
  419. tx_wait:
  420.     mov    bx,1024*7    ; max coll time in Ethernet slot units
  421. tx_wait_l1:
  422.     mov    ah,51        ; assume 1 us IO
  423.     test    sys_features,SYS_MCA
  424.     jz    tx_wait_l2
  425.     shl    ah,1        ; MCA IO is just 0.5 us
  426. tx_wait_l2:
  427.     sti            ; allow receive interrupts while waiting
  428.     loadport        ; Point at chip command register
  429.     setport EN_CCMD        ; ..
  430.     in al,    dx        ; Get chip command state
  431.     test al,ENC_TRANS    ; Is transmitter still running?
  432.     cli            ; the rest of the code may not work with EI (?)
  433.     jz    tx_idle_0    ; Go if free
  434.  
  435.     dec    ah
  436.     jnz    tx_wait_l2    ; wait 51.2 us (one ethernet slot time)
  437.  
  438.     dec    bx        ; waited more than max collision time?
  439.     jnz    tx_wait_l1    ; -no, probably not stuck yet
  440.  
  441.     SHOW_EVENT    'b'
  442.     add2    hard_tx_errors,1    ;count hard errors.
  443.     call    count_out_err    ; Should count these error timeouts
  444.                 ; Maybe need to add recovery logic here
  445.     jmp    short tx_idle_0
  446.  
  447.  
  448.     public    send_pkt
  449. send_pkt:
  450. ;enter with ds:si -> packet, cx = packet length.
  451. ;exit with nc if ok, or else cy if error, dh set to error number.
  452.     assume    ds:nothing
  453.     mkle LE_SP_E, cx, si, ds
  454.  
  455.     cli
  456.  
  457. ;ne1000 checks the packet size at this point, which is probably more sensible.
  458.     loadport        ; Point at chip command register
  459.     setport EN_CCMD        ; ..
  460.     pause_
  461. ;ne1000 fails to check to see if the transmitter is still busy.
  462.     in al,    dx        ; Get chip command state
  463.     test al,ENC_TRANS    ; Is transmitter still running?
  464. ifdef debug
  465.     mov log_ccmd,al        ; added - gft - 910607
  466. endif
  467. ;
  468. ; Used to just go to tx_idle here if the transmitter was not running, however
  469. ; it is possible to get here with the transmission complete, but since
  470. ; interrupts are off when we get here it is also possible that a transmission
  471. ; JUST DID complete and has not yet had its interrupt acknowledge and errors
  472. ; recorded. Proceding here without checking will work, it just looses the 
  473. ; error status from the last transmission if that transmission has not been
  474. ; acknowledged by the isr_tx code.
  475. ;
  476. ; Changed the jz tx_idle below to the following code - gft - 910607
  477. ;
  478. ;     jz    tx_idle        ; Go if free
  479.  
  480.     jnz    tx_wait
  481.  
  482. ; Check for recent TX completions in the interrupt status register
  483.  
  484.     setport EN0_ISR        ; Point at isr
  485.     pause_
  486.     in    al,dx        ; get state
  487. ifdef debug
  488.     mov    log_isr,al
  489. endif
  490.     test al,ENISR_TX+ENISR_TX_ERR ; pending TX interupts?
  491.     jz    tx_idle        ; No, Go on with new TX
  492.  
  493. tx_idle_0:    ; Added to capture TSR if tx not done on entry
  494.         ; AND added all the below TX error detection down to tx_idle
  495.         ; - gft - 910603
  496.  
  497.     loadport
  498.      setport    EN0_TSR        ; point to TSR
  499.     pause_
  500.     in al,    dx        ; get state from prior TX
  501. ifdef debug
  502.     mov log_tsr,al        ; added - gft - 910603
  503. endif
  504.  
  505. ; Acknowledge the TX interrupt and take care of any TX errors from the 
  506. ; previous transmission
  507.  
  508.     mov    ah,al        ; save the TSR state
  509.  
  510.     setport EN0_ISR        ; Point at the interrupt status register
  511.     pause_
  512.     mov    al,ENISR_TX+ENISR_TX_ERR ; clear either possible TX int bit
  513.     out    dx,al
  514.  
  515.     test ah,ENTSR_COLL+ENTSR_COLL16+ENTSR_FU+ENTSR_OWC+ENTSR_CRS
  516.     jz    tx_idle        ; No usefull errors, skip. See the called
  517.                 ; routine for explanation of the selection
  518.                 ; of TSR bits for consideration as errors.
  519.     call    count_tx_err
  520.  
  521. tx_idle:
  522. ; If IPX + NETX ver 3.26 receives a CANT_SEND it will put a query on the
  523. ; screen if one should abort or retry. This is annoying, causes delay and
  524. ; destroys formatted screens. Even worse, the current NETX, ver 3.32, will
  525. ; hang for any of the replies.
  526.  
  527.     cmp    word ptr [si+2*EADDR_LEN+2],0ffffh ; Novell packet?
  528.     je    tx_nov_noerr    ; -yes, avoid CANT_SEND, causes hang :-(
  529.  
  530.     mov    ax,soft_tx_errors    ;return an error if the previous
  531.     or    ax,hard_tx_errors    ;  packet failed.
  532.     jne    send_pkt_err
  533. tx_nov_noerr:
  534.  
  535.     cmp    cx,GIANT    ; Is this packet too large?
  536.     ja    send_pkt_toobig
  537.  
  538.     cmp cx,    RUNT        ; Is the frame long enough?
  539.     jnb    tx_oklen    ; Go if OK
  540.     mov cx,    RUNT        ; Stretch frame to minimum allowed
  541. tx_oklen:
  542.     push    cx        ; Hold count for later
  543.     loadport        ; Set up for address
  544.     setport EN0_ISR
  545.     pause_
  546.     mov    al,ENISR_RDC    ; clear remote interrupt int.
  547.     out    dx,al
  548.     setport    EN0_TCNTLO    ; Low byte of TX count
  549.     pause_
  550.     mov al,    cl        ; Get the count
  551.     out dx,    al        ; Tell card the count
  552.     setport    EN0_TCNTHI    ; High byte of TX count
  553.     pause_
  554.     mov al,    ch        ; Get the count
  555.     out dx,    al        ; Tell card the count
  556.     xor ax,    ax        ; Set up ax at base of tx buffer
  557.     mov ah,    SM_TSTART_PG    ; Where to put tx frame
  558.     pop    cx        ; Get back count to give to board
  559.     call    block_output
  560.     jc    tx_no_rdc
  561.     loadport
  562.     setport    EN0_TPSR    ; Transmit Page Start Register
  563.     pause_
  564.     mov al,    SM_TSTART_PG
  565.     out dx,    al        ; Start the transmitter
  566.     setport    EN_CCMD        ; Chip command reg
  567.     pause_
  568.     mov al,    ENC_TRANS+ENC_NODMA+ENC_START
  569.     out dx,    al        ; Start the transmitter
  570.     mkle LE_SP_X, cx, 1, 0
  571.  
  572.     mov    ax,soft_tx_errors    ;return an error if the previous
  573.     or    ax,hard_tx_errors    ;  packet failed.
  574.     jne    send_pkt_err
  575.     clc            ; Successfully started
  576.     ret            ; End of transmit-start routine
  577. send_pkt_toobig:
  578.     mov    dh,NO_SPACE
  579.     stc
  580.     ret
  581. send_pkt_err:
  582.     SHOW_EVENT    'e'
  583.     mov    soft_tx_errors,0
  584.     mov    soft_tx_collisions,0
  585.     mov    hard_tx_errors,0
  586.     stc
  587.     mov    dh,CANT_SEND
  588.     ret
  589. tx_no_rdc:
  590.     mov    dh,CANT_SEND
  591.     mkle LE_SP_X, cx, 0, 0
  592.     stc
  593.     ret
  594.  
  595. count_tx_err:
  596. ;
  597. ; Function to count hard and soft TX completion errors and collisions.
  598. ; Entered with ah containing the transmit status register state.
  599. ;  - gft - 910607
  600.  
  601.     test ah,ENTSR_PTX    ; 
  602.     jnz    tx_err_02    ; NO hard tx errors go look for soft ones
  603.  
  604. ; Handle hard tx errors, fifo underrun and abort
  605.  
  606.     add2    hard_tx_errors,1    ;count hard errors.
  607.  
  608.     test ah,ENTSR_COLL16    ; 16 collision abort?
  609.     jz    tx_err_01     ; no skip
  610.     SHOW_EVENT    'c'    ; this almost always occurs in pairs, is this
  611.                 ; routine called twice WHILE one collision
  612.                 ; error lasts??? /Jan E LDC
  613.     add2    soft_tx_collisions,16
  614. tx_err_01:
  615.     call    count_out_err  ; only possible other hard error is FU, just
  616.                            ; count the hard error and skip the soft error
  617.     jmp     tx_err_done
  618.  
  619. ; Handle the tx soft errors and collisions
  620. ;
  621. ;  National DP8390 Datasheet Addendum June 1990 says that Carrier Sense Lost 
  622. ;  (CRS) and Non Deferred TX (DFR) are useless in some or all 8390s, that
  623. ;  leaves only out of window collision (OWC) and CD Heartbeat (CDH) as 
  624. ;  soft errors (I would hesitate to call collision an error of any kind).
  625. ;  With who knows how may MAUs out there with SQE either disabled or not
  626. ;  functional, I don't count CDs as errors either (If your MAU doesn't SQE
  627. ;  you would count CD errors on EVERY transmission.) That only leaves OWC
  628. ;  as a soft error.
  629.  
  630. tx_err_02:
  631.     test ah,ENTSR_OWC+ENTSR_COLL ; No soft errors or collisions?
  632.     jz    tx_err_done         ; return
  633.  
  634.     test ah,ENTSR_OWC    ; Out of window collision?
  635.     jz    tx_err_03    ; No, skip
  636.     SHOW_EVENT    'f'    ; this is not uncommon on a real net using
  637.                                 ; some WD cards, other WD cards on same net
  638.                 ; don't report any OWC!?? /Jan E LDC
  639.     add2    soft_tx_errors,1
  640.  
  641. ; Collison Counter
  642.     
  643. tx_err_03:
  644.     test ah,ENTSR_COLL    ; Enumerated Collisions?
  645.     jz    tx_err_done        ; No, return
  646.  
  647.     setport EN0_NCR        ; point at the collision counter
  648.     pause_
  649.     in    al,dx        ; get the count
  650.     and    al,0fh        ; clear the unused bits
  651.     xor    ah,ah        ; clear the high byte
  652.     add2    soft_tx_collisions,ax
  653.  
  654. tx_err_done:
  655.     mkle LE_TX_ERR, ax, 0, 0
  656.       ret
  657.  
  658.  
  659.     public    set_address
  660. set_address:
  661.     assume    ds:code
  662. ;enter with my_address,si -> Ethernet address, CX = length of address.
  663. ;exit with nc if okay, or cy, dh=error if any errors.
  664.     loadport
  665.     setport    EN_CCMD        ; Chip command register
  666.     pushf
  667.     cli            ; Protect from irq changing page bits
  668.     mov al,    ENC_NODMA+ENC_PAGE1    ;+ENC_STOP
  669.     out dx,    al        ; Switch to page one for writing eaddr
  670.     pause_
  671.     setport    EN1_PHYS    ; Where it goes in 8390
  672. set_8390_1:
  673.     lodsb
  674.     out    dx,al
  675.     pause_
  676.     inc    dx
  677.     loop    set_8390_1
  678.     loadport
  679.     setport    EN_CCMD        ; Chip command register
  680.     mov al,    ENC_NODMA+ENC_PAGE0    ;+ENC_STOP
  681.     out dx,    al        ; Restore to page zero
  682.     pause_
  683.     popf
  684.     clc
  685.     ret
  686.  
  687. ; Routines to set address filtering modes in the DS8390
  688. rcv_mode_1:     ; Turn off receiver
  689.     mov al,    ENRXCR_MON      ; Set to monitor for counts but accept none
  690.     jmp short rcv_mode_set
  691. rcv_mode_2:     ; Receive only packets to this interface
  692.     mov al, 0               ; Set for only our packets
  693.     jmp short rcv_mode_set
  694. rcv_mode_3:     ; Mode 2 plus broadcast packets (This is the default)
  695.     mov al,    ENRXCR_BCST     ; Set four ours plus broadcasts
  696.     jmp short rcv_mode_set
  697. rcv_mode_4:     ; Mode 3 plus selected multicast packets
  698.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  699.     mov     mcast_all_flag,0    ; need to do sw filter.
  700.     jmp short rcv_mode_set
  701. rcv_mode_5:     ; Mode 3 plus ALL multicast packets
  702.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  703.     mov     mcast_all_flag,1
  704.     jmp short rcv_mode_set
  705. rcv_mode_6:     ; Receive all packets (Promiscuous physical plus all multi)
  706.     mov al,    ENRXCR_BCST+ENRXCR_MULTI+ENRXCR_PROMP
  707.     mov     mcast_all_flag,1
  708. rcv_mode_set:
  709.     push    ax            ; Hold mode until masks are right
  710.     call    set_hw_multi        ; Set the multicast mask bits in chip
  711.     pop     ax
  712.     loadport
  713.     setport    EN0_RXCR        ; Set receiver to selected mode
  714.     pause_
  715.     out dx,    al
  716.     mov     rxcr_bits,al        ; Save a copy of what we set it to
  717.     ret
  718.  
  719.  
  720. ; Set the multicast filter mask bits in case promiscuous rcv wanted
  721. set_hw_multi:
  722.     push    cs
  723.     pop     ds
  724.     assume    ds:code
  725.     loadport
  726.     setport    EN_CCMD        ; Chip command register
  727.     pause_
  728.     mov cx,    8        ; Eight bytes of multicast filter
  729.     mov si, offset mcast_list_bits  ; Where bits are, if not all ones
  730.     cli            ; Protect from irq changing page bits
  731.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_STOP
  732.     out dx,    al        ; Switch to page one for writing eaddr
  733.     setport    EN1_MULT    ; Where it goes in 8390
  734.     pause_
  735.     mov al, mcast_all_flag  ; Want all ones or just selected bits?
  736.     or al,  al
  737.     je      set_mcast_2     ; Just selected ones
  738.     mov al,    0ffh        ; Ones for filter
  739. set_mcast_all:
  740.     out dx,    al        ; Write a mask byte
  741.     inc    dl        ; Step to next one
  742.     loop    set_mcast_all    ; ..
  743.     jmp short set_mcast_x
  744.  
  745. set_mcast_2:
  746.     lodsb                   ; Get a byte of mask bits
  747.     out dx,    al        ; Write a mask byte
  748.     inc    dl        ; Step to next I/O register
  749.     loop    set_mcast_2     ; ..
  750. set_mcast_x:
  751.     loadport
  752.     setport    EN_CCMD        ; Chip command register
  753.     pause_
  754.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  755.     out dx,    al        ; Restore to page zero
  756.     ret
  757.  
  758.  
  759.     public    reset_board
  760. reset_board:
  761.     assume ds:nothing
  762.     reset_8390
  763.     setport    EN_CCMD        ; Chip command reg
  764.     pause_
  765.     mov al,    ENC_STOP+ENC_NODMA
  766.     out dx,    al        ; Stop the DS8390
  767.  
  768. ; Wait 1.6ms for the NIC to stop transmitting or receiving a packet. National
  769. ; says monitoring the ISR RST bit is not reliable, so a wait of the maximum
  770. ; packet time (1.2ms) plus some padding is required.
  771.  
  772.     longpause
  773.     ret
  774.  
  775.     public    terminate
  776. terminate:
  777.     terminate_board
  778.     ret
  779.  
  780.     public    reset_interface
  781. reset_interface:
  782.     assume ds:code
  783.     call    reset_board
  784.     loadport        ; Base of I/O regs
  785.     setport    EN0_ISR        ; Interrupt status reg
  786.     pause_
  787.     mov al,    0ffh        ; Clear all pending interrupts
  788.     out dx,    al        ; ..
  789.     setport    EN0_IMR        ; Interrupt mask reg
  790.     pause_
  791.     xor al,    al        ; Turn off all enables
  792.     out dx,    al        ; ..
  793.     ret
  794.  
  795. ; Linkages to non-device-specific routines
  796. ;called when we want to determine what to do with a received packet.
  797. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  798. ;It returns with es:di = 0 if don't want this type or if no buffer available.
  799.     extrn    recv_find: near
  800.  
  801. ;called after we have copied the packet into the buffer.
  802. ;enter with ds:si ->the packet, cx = length of the packet.
  803.     extrn    recv_copy: near
  804.  
  805. ;call this routine to schedule a subroutine that gets run after the
  806. ;recv_isr.  This is done by stuffing routine's address in place
  807. ;of the recv_isr iret's address.  This routine should push the flags when it
  808. ;is entered, and should jump to recv_exiting_exit to leave.
  809. ;enter with ax = address of routine to run.
  810.     extrn    schedule_exiting: near
  811.  
  812. ;recv_exiting jumps here to exit, after pushing the flags.
  813.     extrn    recv_exiting_exit: near
  814.  
  815.     extrn    count_in_err: near
  816.     extrn    count_out_err: near
  817.  
  818.     public    recv
  819. recv:
  820. ;called from the recv isr.  All registers have been saved, and ds=cs.
  821. ;Actually, not just receive, but all interrupts come here.
  822. ;Upon exit, the interrupt will be acknowledged.
  823. ;ne1000 and ne2000 routines are identical to this point (except that ne2000
  824. ;  masks off interrupts).
  825.     assume    ds:code
  826.     mkle LE_RECV_E, 0, 0, 0
  827.  
  828. check_isr:            ; Was there an interrupt from this card?
  829.     loadport        ; Point at card's I/O port base
  830.     setport EN0_IMR        ; point at interrupt masks
  831.     pause_            ; switch off, this way we can
  832.     mov    al,0        ; leave the chip running.
  833.     out    dx,al        ; no interrupts please.
  834.     setport    EN0_ISR        ; Point at interrupt status register
  835.     pause_
  836.     in al,    dx        ; Get pending interrupts
  837.     and al,    ENISR_ALL    ; Any?
  838.     jnz    isr_test_overrun
  839.     mkle LE_RECV_X, 0, 0, 0
  840.     jmp    interrupt_done    ; Go if none
  841.  
  842. ;
  843. ; Revised receive overrun code which corresponds to the National DP8390
  844. ; Datasheet Addendum, June 1990.
  845. ;
  846. ; - gft - 910604
  847. ;
  848.  
  849. ; Test for receive overrun in value from NIC ISR register
  850.  
  851. isr_test_overrun:
  852.     test al,ENISR_OVER    ; Was there an overrun?
  853.     jnz    recv_overrun    ; Go if so.
  854.     jmp    recv_no_overrun    ; Go if not.
  855.  
  856. recv_overrun:
  857.   ifdef board_features
  858.     test    board_features, BF_NIC_690
  859.     jz    recv_overrun_2
  860.     mov    is_overrun_690, 1
  861.     jmp    recv_no_overrun
  862.  
  863. recv_overrun_2:
  864.   endif
  865.  
  866. ; Count these things
  867.  
  868.     add2    soft_rx_overruns,1
  869.  
  870. ; and log them
  871.     SHOW_EVENT    'd'
  872.     mkle LE_RX_OVR_E, 0, 0, 0
  873.  
  874. ; Get the command register TXP bit to test for incomplete transmission later
  875.  
  876.     loadport        ; Point at Chip's Command Reg
  877.      setport    EN_CCMD        ; ..
  878.     pause_
  879.     in     al, dx
  880.     mov     ah, al        ; Save CR contents in ah for now
  881.  
  882. ; Stop the NIC
  883.  
  884.     pause_
  885.     mov     al, ENC_STOP+ENC_NODMA
  886.     out     dx, al        ; Write "stop" to command register
  887.  
  888. ; Wait 1.6ms for the NIC to stop transmitting or receiving a packet. National
  889. ; says monitoring the ISR RST bit is not reliable, so a wait of the maximum
  890. ; packet time (1.2ms) plus some padding is required.
  891.  
  892.     longpause
  893.  
  894. ; Clear the remote byte count registers
  895.  
  896.     xor    al,al
  897.     setport    EN0_RCNTLO    ; Point at byte count regs
  898.     out    dx, al
  899.     setport EN0_RCNTHI
  900.     pause_
  901.     out    dx, al
  902.  
  903. ; check the saved state of the TXP bit in the command register
  904.  
  905.     mov    rcv_ovr_resend,al    ; clear the resend flag
  906.     test ah,ENC_TRANS    ; Was transmitter still running?
  907.     jz    rcv_ovr_loopback    ; Go if not running
  908.  
  909. ; Transmitter was running, see if it finished or died
  910.  
  911.     setport EN0_ISR        ; point at the NIC ISR
  912.     pause_
  913.     in    al,dx        ; and get it
  914.     test al,ENISR_TX+ENISR_TX_ERR    ; Did the transmitter finish?
  915.     jnz    rcv_ovr_loopback    ; one will be set if TX finished
  916.  
  917. ; Transmitter did not complete, remember to resend the packet later.
  918.  
  919.     mov    rcv_ovr_resend,ah    ; ah has at least ENC_TRANS set
  920.  
  921. ; Put the NIC chip into loopback so It won't keep trying to receive into
  922. ; a full ring
  923.  
  924. rcv_ovr_loopback:
  925.     loadport    ; resync setport
  926.      setport    EN0_TXCR    ; ..
  927.     mov al,    ENTXCR_LOOP    ; Put transmitter in loopback mode
  928.     pause_
  929.     out dx,    al        ; ..
  930.     setport    EN_CCMD        ; Point at Chip command reg
  931.     mov al,    ENC_START+ENC_NODMA
  932.     pause_
  933.     out dx,    al        ; Start the chip running again
  934.  
  935. ; Verify that there is really a packet to receive by fetching the current
  936. ; page pointer and comparing it to the next packet pointer.
  937.  
  938.     mov al, ENC_NODMA+ENC_PAGE1    ; Set page one
  939.     pause_
  940.     out dx,al
  941.     setport EN1_CURPAG    ; Get current page
  942.     pause_
  943.     in al,dx
  944.     pause_            ; Rewrite current page to fix SMC bug.
  945.     out dx,al
  946.     mov bl,al        ; save it
  947.     mov save_curr,al
  948.     setport    EN_CCMD        ;
  949.     mov al, ENC_NODMA+ENC_PAGE0
  950.     pause_
  951.     out dx,al        ; Back to page 0
  952.  
  953.     mov al, next_packet    ; get saved location for next packet
  954.  
  955.     cmp    al,bl        ; Check if buffer emptry
  956.     jne    rcv_ovr_rx_one  ; OK go get the NIC header
  957.  
  958. ; NO PACKET IN THE RING AFTER AN OVW INTERRUPT??? Can this ever happen?
  959. ; YES! if overrun happend between a receive interrupt and the when the
  960. ; current page register is read at the start of recv_frame.
  961. ; Count these things too.
  962.  
  963.     add2    soft_rx_over_nd,1
  964.  
  965.     jmp    rcv_ovr_empty
  966.  
  967.  
  968. ; Get the NIC header for the received packet, and check it
  969.  
  970. rcv_ovr_rx_one:
  971.     mov    ah,al        ; make a byte address. e.g. page
  972.     mov    bl,ah        ; and save in bl
  973.     mov    al,0        ; 46h becomes 4600h into buffer
  974.     mov    cx,RCV_HDR_SIZE    ; size of rcv_hdr
  975.     mov    di,offset rcv_hdr ;point to header
  976.     movseg    es,ds
  977.     call    block_input
  978.     mov al,    rcv_hdr+EN_RBUF_STAT    ; Get the buffer status byte
  979.     test al,ENRSR_RXOK    ; Is this frame any good?
  980.     jz    rcv_ovr_ng    ; Skip if not
  981.  
  982. ;
  983. ; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
  984. ; it doesn't hurt to range check the next packet pointer here.
  985. ;
  986.     mov al,    rcv_hdr+EN_RBUF_NXT_PG    ; Start of next frame
  987.     mov next_packet, al    ; Save next packet pointer
  988.     cmp     al,SM_RSTART_PG    ; Below around the bottom?
  989.     jb    rcv_ovr_ng    ; YES - out of range
  990.     cmp    al,sm_rstop_ptr ; Above the top?
  991.     jae    rcv_ovr_ng    ; YES - out of range
  992.  
  993. ; ok to call rcv_frm
  994.  
  995. ; This gets real tricky here. Because some wise user (like me) may attempt
  996. ; to call send_pkt from his receive interrupt service routine, you can't just
  997. ; blindly call rcv_frm from here because the NIC is now in LOOPBACK mode!
  998. ; to get around this problem I added a global flag that causes rcv_frm to
  999. ; make the first call to the users interrupt service routine, get a buffer,
  1000. ; fill the buffer, BUT defer the second call until later. If a second call
  1001. ; is required the flag will still be set after return from rcv_frm and you
  1002. ; can make the upcall after the NIC has been taken out of loopback and has
  1003. ; resent any required packet.
  1004.  
  1005.     mov    defer_upcall, 1    ; Defer upcalls until later. (may be cleared
  1006.                 ;  by rcv_frm)
  1007.      call    rcv_frm        ; Yes, go accept it
  1008.     jmp    rcv_ovr_ok
  1009.  
  1010. rcv_ovr_ng:
  1011.     or    byte ptr soft_rx_err_bits,al
  1012.     add2    soft_rx_errors,1
  1013.     mkle LE_RX_ERR, 0, 0, 0 ; Log error packet - gft - 910521
  1014. ;
  1015. ; HAD TO ADD ERROR RECOVERY HERE. TO BLINDLY PROCEED AND ASSUME THE NEXT
  1016. ; PACKET POINTR FROM THE NIC HEADER IS VALID IS INVITING DISASTER.
  1017. ;
  1018. ; Error recovery consists of killing and restarting the NIC. This drops all
  1019. ; the packets in the ring, but thats better than winding up in the weeds!
  1020. ;
  1021. ; - gft - 910611
  1022.  
  1023. ifdef err_stop
  1024.     call    rcv_mode_1    ; for debugging, stop on error
  1025.     jmp    check_isr    ; so we can dump the log
  1026. endif
  1027.  
  1028. ; NO! no longer in memory
  1029. ;       call    etopen_0        ; go back to the initial state
  1030. ;
  1031. ; Instead copy the last known current page pointer into the next packet pointer
  1032. ; which will result in skipping all the packets from the errored one to where
  1033. ; the NIC was storing them when we entered this ISR, but prevents us from
  1034. ; trying to follow totally bogus next packet pointers through the card RAM
  1035. ; space.
  1036. ;
  1037.         mov     al, save_curr   ; get the last known current page pointer
  1038.         mov     next_packet, al ; and use it as the next packet pointer
  1039.         jmp     check_isr       ; then go handle more interrupts
  1040.  
  1041. rcv_ovr_ok:
  1042. ; moved the next two instructions up to where I range check the
  1043. ; next packet pointer above - gft - 910611
  1044. ;    mov    al,rcv_hdr+EN_RBUF_NXT_PG ; Get pointer to next frame
  1045. ;    mov    next_packet, al ; save it in next_packet - gft - 910603
  1046.     mov    al,next_packet    ; Grap the next packet pointer
  1047.     dec    al        ; Back up one page
  1048.     cmp    al,SM_RSTART_PG    ; Did it wrap?
  1049.     jae    rcv_ovr_nwr2
  1050.     mov    al,sm_rstop_ptr    ; Yes, back to end of ring
  1051. rcv_ovr_empty:
  1052.     dec    al
  1053. rcv_ovr_nwr2:
  1054.     loadport        ; Point at boundary reg
  1055.     setport    EN0_BOUNDARY    ; ..
  1056.     pause_
  1057.     out dx,    al        ; Set the boundary
  1058. ; When we get here we have either removed one packet from the ring and updated
  1059. ; the boundary register, or determined that there really were no new packets
  1060. ; in the ring.
  1061.  
  1062. ; Clear the OVW bit in the ISR register.
  1063.  
  1064.     loadport        ; resync the setport macro
  1065.     setport EN0_ISR        ; point at the ISR 
  1066.     mov al,    ENISR_OVER    ; Clear the overrun interrupt bit
  1067.     pause_
  1068.     out dx,    al
  1069.  
  1070. ; Take the NIC out of loopback
  1071.  
  1072.     setport    EN0_TXCR    ; Back to TX control reg
  1073.     xor al,    al        ; Clear the loopback bit
  1074.     pause_
  1075.     out dx,    al        ; ..
  1076.  
  1077. ; Any incomplete transmission to resend?
  1078.  
  1079.     cmp rcv_ovr_resend,0
  1080.     jz  rcv_ovr_deferred    ; no, go check for deferred upcall
  1081.  
  1082. ; Yes, restart the transmission
  1083.  
  1084.     setport EN_CCMD    ; point at command register
  1085.     mov al,    ENC_TRANS+ENC_NODMA+ENC_START
  1086.     pause_
  1087.     out dx,    al        ; Start the transmitter
  1088.  
  1089. ; If an upcall was deferred, make it now
  1090.  
  1091. rcv_ovr_deferred:
  1092.     cmp    defer_upcall,0
  1093.     jz    rcv_ovr_done
  1094.     mov    si,defer_si        ; Recover pointer to destination
  1095.     mov    cx,defer_cx        ; And it's this long
  1096.     mov    ds,defer_ds        ; Tell client it's his source
  1097.     assume    ds:nothing
  1098.     call    recv_copy    ; Give it to him
  1099.     movseg    ds,cs
  1100.     assume    ds:code
  1101.  
  1102. ; log the end of overrun processing, with which flags were set
  1103.  
  1104. rcv_ovr_done:
  1105. ifdef debug
  1106.     mov     ax, WORD PTR rcv_ovr_resend
  1107.     mov     bx, WORD PTR defer_upcall
  1108.     mkle    LE_RX_OVR_X, ax, bx, 0
  1109. endif
  1110.  
  1111.     mov    defer_upcall,0    ; clear the defer upcall flag
  1112.  
  1113. ; finally go back and check for more interrupts
  1114.  
  1115.      jmp    check_isr    ; Done with the overrun case
  1116.  
  1117. ; End of new receive overrun code
  1118.  
  1119. recv_no_overrun:
  1120. ; Handle receive flags, normal and with error (but not overrun).
  1121.     test al,ENISR_RX+ENISR_RX_ERR    ; Frame received without overrun?
  1122.     jnz    recv_frame_0    ; Go if so.
  1123.  
  1124.   ifdef board_features
  1125.     cmp    is_overrun_690, 0
  1126.     jne    recv_overrun_11
  1127.     jmp    recv_no_frame    ; Go if not.
  1128. recv_overrun_11:
  1129.     jmp    recv_690_overrun
  1130.   else
  1131.     jmp    recv_no_frame    ; Go if not.
  1132.   endif
  1133.  
  1134. ;
  1135. ; Move the label recv_frame down to below where the interrupts are cleared.
  1136. ; This will cause the interrupts to be cleared only after being read in 
  1137. ; check_isr, instead of every time a packet is read from the ring. The way
  1138. ; it used to work was find a RX or RX_ERR interrupt, clear both, check for
  1139. ; packet really in ring (compare next packet pointer with current page reg)
  1140. ; read packet and loop back to clear both ints. When all packets read from
  1141. ; ring, loop back to check_isr. IF packets keep arriving as fast as or faster
  1142. ; than we can read them, we never get back to check_isr to see if any higher
  1143. ; priority interrupts occur (like OVW).
  1144. ;
  1145. ; The way it works now is find a RX or RX_ERR interrupt, clear both, check
  1146. ; for packet really in ring and remember the current page register. Read
  1147. ; packets from the ring until all packets received at the time the current
  1148. ; page register was last read have been received, (comparing next packet
  1149. ; pointer to the once read value of current page register). This eliminates
  1150. ; both the (possibly unnecessary) resetting of the interrupts and the 
  1151. ; page switch and current page register read on a per packet basis. This should
  1152. ; also eliminate possible problems with not doing the ring overflow processing
  1153. ; in heavy traffic referred to in my comments below.
  1154. ;
  1155. ;  - gft - 910611
  1156. ;
  1157. recv_frame_0:
  1158.  
  1159.     loadport        ; Point at Chip's Command Reg
  1160.     setport    EN0_ISR        ; Point at Interrupt status register
  1161.     pause_
  1162.     mov al,    ENISR_RX+ENISR_RX_ERR
  1163.     out dx,    al        ; Clear those requests
  1164.      setport    EN_CCMD        ; ..
  1165.     pause_
  1166.     cli
  1167.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_START
  1168.     out dx,    al        ; Switch to page 1 registers
  1169.     setport    EN1_CURPAG    ;Get current page of rcv ring
  1170.     pause_
  1171.     in al,    dx        ; ..
  1172. ;    mov ah,    al        ; Hold current page in AH
  1173.     mov save_curr,al    ; Hold last read current page register in 
  1174.                 ; memory instead - gft - 910611
  1175.      setport    EN_CCMD        ; Back to page zero registers
  1176.     pause_
  1177.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  1178.     out dx,    al        ; Switch back to page 0 registers
  1179.  
  1180. ; This becomes the loop back point to read packets from the ring.
  1181. ; now only loop back and read until those packets received at the time 
  1182. ; the current page register is read above have been read.
  1183. ; - gft - 910611
  1184.  
  1185. recv_frame:
  1186.     mov al, next_packet    ; Get saved pointer to next packet in ring
  1187. ;
  1188. ; change the next instruction to compare against the saved copy of the current
  1189. ; page register and only read from the ring what was received up until the 
  1190. ; last read from the current page register - gft - 910611
  1191. ;
  1192. ;    cmp al,    ah        ; Read all the frames?
  1193.     cmp al,    save_curr    ; Read all the frames?
  1194.     jne    recv_more_frames; hacked jump code for addition of mkle
  1195.                 ; macro below - gft -910521
  1196. ;    jmp    recv_frame_break    ; Finished them all
  1197. ;
  1198. ; changed jmp recv_frame_break to jmp check_isr after recv_frame_break was
  1199. ; determined to be superfluous. See comments at recv_frame_break below.
  1200. ; - gft - 910531
  1201. ;
  1202.   ifdef board_features
  1203.     cmp    is_overrun_690, 0
  1204.     je    recv_not_690_overrun
  1205.  
  1206. recv_690_overrun:
  1207.     mov    is_overrun_690, 0    ; clear overrun indicator
  1208.     loadport
  1209.     setport    EN0_BOUNDARY        ; rewrite bndry with itself
  1210.     in    al, dx
  1211.     pause_
  1212.     out    dx, al
  1213.  
  1214.     setport    EN0_ISR            ; Point at Interrupt status register
  1215.     pause_
  1216.     mov    al, ENISR_OVER        ; Clear overrun interrupt bit
  1217.     out    dx, al
  1218.     call    count_in_err        ; Count the anomaly
  1219.  
  1220. recv_not_690_overrun:
  1221.   endif
  1222.     jmp    check_isr    ; Finished all receives, check for more
  1223.                 ; interrupts.
  1224.  
  1225. recv_more_frames:
  1226.  
  1227.     mov    ah,al        ; make a byte address. E.G. page
  1228.     mov    al,0        ; 46h becomes 4600h into buffer
  1229.     mov    bl,ah
  1230.     mov    cx,RCV_HDR_SIZE
  1231.     mov    di,offset rcv_hdr
  1232.     movseg    es,ds
  1233.     call    block_input
  1234.     mov al,    rcv_hdr+EN_RBUF_STAT    ; Get the buffer status byte
  1235.     test al,ENRSR_RXOK    ; Good frame?
  1236.     jz    recv_err_no_rcv
  1237. ;
  1238. ; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
  1239. ; it doesn't hurt to range check the next packet pointer here.
  1240. ;
  1241.     mov al,    rcv_hdr+EN_RBUF_NXT_PG    ; Start of next frame
  1242.     mov next_packet, al    ; Save next packet pointer
  1243.     cmp     al,SM_RSTART_PG    ; Below around the bottom?
  1244.     jb    recv_err_no_rcv ; YES - out of range
  1245.     cmp    al,sm_rstop_ptr ; Above the top?
  1246.     jae    recv_err_no_rcv ; YES - out of range
  1247.  
  1248. ; ok to call rcv_frm
  1249.  
  1250.     call    rcv_frm        ; Yes, go accept it
  1251.     jmp    recv_no_rcv
  1252. recv_err_no_rcv:
  1253.     or    byte ptr soft_rx_err_bits,al
  1254.     add2    soft_rx_errors,1
  1255. ;
  1256. ; The code used to assume that after decoding the NIC header status
  1257. ; byte as a receive error, the status, and next packet pointer values
  1258. ; are actually valid. When using the NIC, this assumption may get one
  1259. ; up that proverbial creek without a paddle. It has been my experience that
  1260. ; IF bad status is read in the NIC header, the rest of the NIC header is
  1261. ; not to be trusted. More likely you read a NIC header from the middle of a
  1262. ; packet than actually receiving a frame, especially if the save error packet
  1263. ; bit (SEP) in the receive configuration register is NOT set (it's NOT set in
  1264. ; this driver).
  1265. ;
  1266. ; Error recovery consists of killing and restarting the NIC. This drops all
  1267. ; the packets in the ring, but thats better than winding up in the weeds!
  1268. ;
  1269. ; - gft - 910611
  1270.  
  1271. ifdef err_stop
  1272.     call    rcv_mode_1    ; for debugging, stop on error
  1273.     jmp    check_isr    ; so we can dump the log
  1274. endif
  1275.  
  1276. ; NO! no longer in memory
  1277. ;       call    etopen_0        ; go back to the initial state
  1278. ;
  1279. ; Instead copy the last known current page pointer into the next packet pointer
  1280. ; which will result in skipping all the packets from the errored one to where
  1281. ; the NIC was storing them when we entered this ISR, but prevents us from
  1282. ; trying to follow totally bogus next packet pointers through the card RAM
  1283. ; space.
  1284. ;
  1285.         mov     al, save_curr   ; get the last known current page pointer
  1286.         mov     next_packet, al ; and use it as the next packet pointer
  1287.         jmp     check_isr       ; then go handle more interrupts
  1288.  
  1289. recv_no_rcv:
  1290. ; moved the next two instructions up to where I range check the
  1291. ; next packet pointer above - gft - 910611
  1292. ;    mov al,    rcv_hdr+EN_RBUF_NXT_PG    ; Start of next frame
  1293. ;    mov next_packet, al    ; Save next packet pointer
  1294.     mov    al,next_packet    ; Grap the next packet pointer
  1295.     dec    al        ; Make previous page for new boundary
  1296.  
  1297. ; Here's another little bug, which was exposed when when I expanded the
  1298. ; recieve packet ring for HP 16 bit cards (from 06h-7fh to 06h-ffh).
  1299. ; The jge instruction is for SIGNED comparisons and failed when the next
  1300. ; packet pointer got into the range 81h-0feh. Changed the below jge to
  1301. ; a jae for unsigned comparsions. - gft - 910610
  1302. ; (Also scanned hppclan.asm and 8390.asm for improper use of signed 
  1303. ; comparisons and found no others.)
  1304.  
  1305.     cmp al,    SM_RSTART_PG    ; Wrap around the bottom?
  1306. ;    jge    rcv_nwrap4
  1307.     jae    rcv_nwrap4        ; - gft - 910610
  1308.     mov al,    sm_rstop_ptr    ; Yes
  1309.     dec al
  1310. rcv_nwrap4:
  1311.     loadport        ; Point at the Boundary Reg again
  1312.      setport    EN0_BOUNDARY    ; ..
  1313.     pause_
  1314.     out dx,    al        ; Set new boundary
  1315. ; This is real bizarre. The NIC DP8390 Datasheet Addendum, June 1990, states
  1316. ; that:
  1317. ;
  1318. ;    In heavily loaded networks which cause overflows of the Recieve Buffer
  1319. ;    Ring, the NIC may disable the local DMA and suspend further receptions
  1320. ;    even if the Boundary register is advanced beyond the Current register.
  1321. ;    In the event that the Network Interface Controller (DP8390 NIC) should
  1322. ;    encounter a receiver buffer overflow, it is necessary to implement the
  1323. ;    following routine. A receive buffer overflow is indicated by the NIC's
  1324. ;    assertion of the overflow bit (OVW) in the interrupt status register
  1325. ;    (ISR).
  1326. ;
  1327. ;    If this routine is not adhered to, the NIC may act in an unpredictable
  1328. ;    manner. It should also be noted that it is not permissible to service
  1329. ;    an overflow interrupt by continuing to empty packets from the receive
  1330. ;    buffer without implementing the prescribed overflow routine.
  1331. ;    ...
  1332. ;
  1333. ; The overflow routine is the one implemented at recv_overrun.
  1334. ;
  1335. ; The funny thing is that the way this code is written, in a heavily loaded
  1336. ; network, you could NEVER NOTICE THAT AN OVERRUN OCCURED. If the NIC does
  1337. ; NOT suspend further receptions even though the Boundary register is advanced
  1338. ; (like is says the NIC MAY do above), you will simply receive each frame,
  1339. ; advance the boundary pointer (allowing the NIC to receive another frame),
  1340. ; and jump from here back to recv_frame to read the next packet, NEVER CHECKING
  1341. ; ISR for OVW. If the NIC NEVER stops, and the network is heavily loaded
  1342. ; enough you could go round and round forever.
  1343. ;
  1344. ; So what's the problem you ask? If the NIC DOES stop receiving, you will
  1345. ; process every packet in the ring before you notice that there is an overrun!
  1346. ; Instead of dropping a few packets here and a few packets there you will drop
  1347. ; large blocks of packets because you have taken the time to empty the ring
  1348. ; completely before turning the NIC back on.
  1349. ;
  1350. ; The solution is to check here for an OVW after each pass and jump to
  1351. ; recv_overrun if required.
  1352. ;
  1353. ;    setport    EN0_ISR        ; Point at interrupt status register
  1354. ;    pause_
  1355. ;    in al,    dx        ; Get pending interrupts
  1356. ;ifdef debug
  1357. ;    mov log_isr,al
  1358. ;endif
  1359. ;    test al,ENISR_OVER    ; Was there an overrun?
  1360. ;    jz    recv_frame_loop    ; Go if not.
  1361. ;    jmp    recv_overrun    ; Go if so.
  1362. ;recv_frame_loop:
  1363. ;
  1364. ; But that's a performance hit and it may not be necessaary. I have not yet
  1365. ; been able to tell if the NIC is stopping (like National says it MAY do), or 
  1366. ; if it keeps on receiving as soon as the boundary pointer is advanced. It 
  1367. ; SEEMS to keep on working fine.
  1368. ;
  1369. ; Therefore I'm not going to put that overrun check in here and I'll
  1370. ; live with this routine as long as it seems to be working fine.
  1371. ;
  1372. ; One more thought, if this code is implemented, it shoud be moved to the
  1373. ; beginning of recv_frame before the RX interrupts are cleared. Recv_overrun
  1374. ; only receives ONE packet and jumps back to check_isr, and if you don't move 
  1375. ; this routine you could exit with packets in the ring and not know it because
  1376. ; you cleared the interrupt bits.
  1377. ;
  1378. ;  - gft - 910606
  1379. ;
  1380. ; New thoughts and fixes - gft - 910611
  1381. ; A compromise fix which also MINIMIZES NIC accesses is to remember the
  1382. ; contents of the current page register after entry to recv_frame and then
  1383. ; remove from the ring only those packets received at that point. Then go
  1384. ; back to check_isr and catch any new packets or receive overruns. See comments
  1385. ; at the start of recv_frame.
  1386. ;
  1387.     jmp    recv_frame    ; See if any more frames
  1388.  
  1389. ;
  1390. ; The next bit of code following recv_frame_break: is superfluous. 
  1391. ;   1. recv_frame_break: is not public, it can't be reached from outside.
  1392. ;   2. a grep of all the Clarkson packet driver collection reveals only
  1393. ;      one jump to recv_frame_break.
  1394. ;   3. Just prior to that jump, the command register was set to 
  1395. ;      ENC_NODMA+ENC_PAGE0+ENC_START, followed by a setport to EN0_BOUNDARY
  1396. ;      and a fetch of the boundry register.
  1397. ; Therefore I am commenting out the following bit of code, and changing the
  1398. ; jmp recv_frame_break (formerly je recv_frame_break) to a jmp check_isr.
  1399. ; - gft - 910531
  1400. ;
  1401. ;recv_frame_break:
  1402. ;    loadport        ; Point at Command register
  1403. ;     setport    EN_CCMD        ; ..
  1404. ;    pause_
  1405. ;    mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  1406. ;    out    dx,al
  1407. ;    jmp    check_isr    ; See if any other interrupts pending
  1408. ;
  1409.  
  1410. recv_no_frame:                ; Handle transmit flags.
  1411.     test al,ENISR_TX+ENISR_TX_ERR    ; Frame transmitted?
  1412.     jnz    isr_tx        ; Go if so.
  1413.     jmp    isr_no_tx    ; Go if not.
  1414. isr_tx:
  1415.     mov ah,    al        ; Hold interrupt status bits
  1416.     loadport        ; Point at Transmit Status Reg
  1417.      setport    EN0_TSR        ; ..
  1418.     pause_
  1419.     in al,    dx        ; ..
  1420.  
  1421. ; New TX interrupt acknowledge code follows:
  1422.  
  1423.     mov    ah,al        ; save the TSR state
  1424.  
  1425.     setport EN0_ISR        ; Point at the interrupt status register
  1426.     pause_
  1427.  
  1428. ; Since transmissions happen synchronously to this driver (even if as_send_pkt
  1429. ; is implemented, their still synchronous to the driver), only one of the two
  1430. ; possible TX interrupts may occur at any one time. Therefore it is OK to
  1431. ; zap both TX and TX_ERR bits in the interrupt status register here.
  1432.  
  1433.     mov    al,ENISR_TX+ENISR_TX_ERR ; clear either possible TX int bit
  1434.     out    dx,al
  1435.  
  1436.     test ah,ENTSR_COLL+ENTSR_COLL16+ENTSR_FU+ENTSR_OWC
  1437.     jz    isr_tx_done    ; No usefull errors, skip. See the called
  1438.                 ; routine for explanation of the selection
  1439.                 ; of TSR bits for consideration as errors.
  1440.     call    count_tx_err
  1441.  
  1442. isr_tx_done:
  1443. ; If TX queue and/or TX shared memory ring buffer were being
  1444. ; used, logic to step through them would go here.  However,
  1445. ; in this version, we just clear the flags for background to notice.
  1446.  
  1447.      jmp    check_isr    ; See if any other interrupts on
  1448.  
  1449. isr_no_tx:
  1450. ; Now check to see if any counters are getting full
  1451.     test al,ENISR_COUNTERS    ; Interrupt to handle counters?
  1452.     jnz    isr_stat    ; Go if so.
  1453.     jmp    isr_no_stat    ; Go if not.
  1454. isr_stat:
  1455. ; We have to read the counters to clear them and to clear the interrupt.
  1456. ; Version 1 of the PC/FTP driver spec doesn't give us
  1457. ; anything useful to do with the data, though.
  1458. ; Fix this up for V2 one of these days.
  1459.     loadport        ; Point at first counter
  1460.      setport    EN0_COUNTER0    ; ..
  1461.     pause_
  1462.     in al,    dx        ; Read the count, ignore it.
  1463.     setport    EN0_COUNTER1
  1464.     pause_
  1465.     in al,    dx        ; Read the count, ignore it.
  1466.     setport    EN0_COUNTER2
  1467.     pause_
  1468.     in al,    dx        ; Read the count, ignore it.
  1469.     setport    EN0_ISR        ; Clear the statistics completion flag
  1470.     pause_
  1471.     mov al,    ENISR_COUNTERS    ; ..
  1472.     out dx,    al        ; ..
  1473. isr_no_stat:
  1474.      jmp    check_isr    ; Anything else to do?
  1475.  
  1476. interrupt_done:
  1477.     loadport
  1478.     setport    EN0_IMR        ; Tell card it can cause these interrupts
  1479.     pause_
  1480.     mov al,    ENISR_ALL
  1481.     out dx,    al
  1482.     ret
  1483.  
  1484. ; Do the work of copying out a receive frame.
  1485. ; Called with bl/ the page number of the frame header in shared memory
  1486.  
  1487.     public    rcv_frm
  1488. rcv_frm:
  1489.     mkle LE_RCVFRM_E, 0, 0, 0
  1490.  
  1491. ; Set cx to length of this frame.
  1492.     mov ch,    rcv_hdr+EN_RBUF_SIZE_HI    ; Extract size of frame
  1493.     mov cl,    rcv_hdr+EN_RBUF_SIZE_LO    ; Extract size of frame
  1494.     sub cx,    EN_RBUF_NHDR        ; Less the header stuff
  1495. ; Set es:di to point to Ethernet type field.
  1496.     mov di,    offset rcv_hdr+EN_RBUF_NHDR+EADDR_LEN+EADDR_LEN
  1497.     push    bx            ; save page.
  1498.     push    cx            ; Save frame size
  1499.     push    es
  1500.     mov ax,    cs            ; Set ds = code
  1501.     mov ds,    ax
  1502.     mov es,ax
  1503.     assume    ds:code
  1504.  
  1505.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  1506.     mov    ax, es:[di]
  1507.     xchg    ah, al
  1508.     cmp     ax, 1500
  1509.     ja    BlueBookPacket
  1510.     inc    di            ;set di to 802.2 header
  1511.     inc    di
  1512.     mov    dl, IEEE8023
  1513. BlueBookPacket:
  1514.  
  1515.     call    recv_find        ; See if type and size are wanted
  1516.     pop    ds            ; RX page pointer in ds now
  1517.     assume    ds:nothing
  1518.     pop    cx
  1519.     pop    bx
  1520.     cld            ; Copies below are forward, please
  1521.     mov ax,    es        ; Did recv_find give us a null pointer?
  1522.     or ax,    di        ; ..
  1523.     je    rcv_no_copy    ; If null, don't copy the data
  1524.  
  1525.     push    cx        ; We will want the count and pointer
  1526.     push    es        ;  to hand to client after copying,
  1527.     push    di        ;  so save them at this point
  1528.     mov    ah,bl        ; set ax to page to start from
  1529.     mov    al,EN_RBUF_NHDR    ; skip the header stuff
  1530.     call    block_input
  1531. ;
  1532. ; Added defer upcall code here in support of new ring overrun code.
  1533. ; If defer_upcall is set, don't call recv_copy, just save si,ds,cx
  1534. ; and the receive ring overrun code will call recv_copy later.
  1535. ;  - gft - 910604
  1536. ;
  1537.     cmp    defer_upcall,0    ; is deferral required?
  1538.     jz    rcv_copy_ok    ; No, finish of the copy.
  1539.     pop    ax        ; Yes, save the parameters for recv_copy
  1540.     mov    defer_si,ax    ; to use later.
  1541.     pop    ax
  1542.     mov    defer_ds,ax
  1543.     pop    ax
  1544.     mov    defer_cx,ax
  1545.     jmp    rcv_copy_deferred
  1546.  
  1547. rcv_copy_ok:
  1548.     pop    si        ; Recover pointer to destination
  1549.     pop    ds        ; Tell client it's his source
  1550.     pop    cx        ; And it's this long
  1551.     assume    ds:nothing
  1552.     call    recv_copy    ; Give it to him
  1553. rcv_no_copy:
  1554.     movseg    ds,cs
  1555.     assume    ds:code
  1556.     mov    defer_upcall,0    ; clear the defer upcall flag - gft - 910604
  1557. rcv_copy_deferred:
  1558.     mkle LE_RCVFRM_X, 0, 0, 0
  1559.     ret            ; That's it for rcv_frm
  1560.  
  1561.     include    multicrc.asm
  1562.     include    timeout.asm
  1563.  
  1564.     public    timer_isr
  1565. timer_isr:
  1566. ;if the first instruction is an iret, then the timer is not hooked
  1567.     iret
  1568.  
  1569. ;any code after this will not be kept after initialization. Buffers
  1570. ;used by the program, if any, are allocated from the memory between
  1571. ;end_resident and end_free_mem.
  1572.     public end_resident,end_free_mem
  1573. end_resident    label    byte
  1574. end_free_mem    label    byte
  1575.  
  1576. ;standard EN0_DCFG contents:
  1577. endcfg    db    048h            ; Set burst mode, 8 deep FIFO
  1578.  
  1579. ; Called once to initialize the card
  1580.  
  1581.     public    etopen
  1582. etopen:                ; Initialize interface
  1583.  
  1584. ;Step 1. Reset and stop the 8390.
  1585.  
  1586.     call    reset_board
  1587.  
  1588. ;Step 2. Init the Data Config Reg.
  1589.  
  1590.     loadport
  1591.     mov    al,endcfg
  1592.     setport    EN0_DCFG
  1593.     pause_
  1594.     out    dx,al
  1595.  
  1596. ;Step 2a.  Config the Command register to page 0.
  1597.     loadport
  1598.     mov    al, ENC_PAGE0 + ENC_NODMA + ENC_STOP
  1599.     setport    EN_CCMD
  1600.     pause_
  1601.     out    dx,al
  1602.  
  1603. ;Step 3. Clear Remote Byte Count Regs.
  1604.  
  1605.     mov    al, 0
  1606.     setport    EN0_RCNTLO
  1607.     pause_
  1608.     out    dx,al
  1609.     setport    EN0_RCNTHI
  1610.     pause_
  1611.     out    dx,al
  1612.  
  1613. ;Step 4. Set receiver to monitor mode
  1614.  
  1615.     mov    al, ENRXCR_MON
  1616.     setport    EN0_RXCR
  1617.     pause_
  1618.     out    dx,al
  1619.  
  1620. ;Step 5. Place NIC into Loopback Mode 1.
  1621.  
  1622.     mov    al,ENTXCR_LOOP
  1623.     setport    EN0_TXCR
  1624.     pause_
  1625.     out    dx,al
  1626.  
  1627. ;Step 6. Do anything special that the card needs.  Read the Ethernet address
  1628. ;into rom_address.
  1629.  
  1630.     call    init_card        ;init the card as needed.
  1631.     jnc    etopen_1        ;go if it worked.
  1632.     ret
  1633. etopen_1:
  1634.  
  1635. ;Step 7. Re-init endcfg in case they put it into word mode.
  1636.  
  1637.     loadport
  1638.     mov    al,endcfg
  1639.     setport    EN0_DCFG
  1640.     pause_
  1641.     out    dx,al
  1642.  
  1643. ;Step 8. Init EN0_STARTPG to same value as EN0_BOUNDARY
  1644.  
  1645.     mov    al,SM_RSTART_PG
  1646.     setport    EN0_STARTPG
  1647.     pause_
  1648.     out    dx,al
  1649.   if 1    ;Paul Kranenburg suggests that this should be set to zero.
  1650.     mov    al,SM_RSTART_PG
  1651.   else
  1652.     mov    al,sm_rstop_ptr
  1653.     dec    al
  1654.   endif
  1655.     setport    EN0_BOUNDARY
  1656.     pause_
  1657.     out    dx,al
  1658.     mov    al,sm_rstop_ptr
  1659.     setport    EN0_STOPPG
  1660.     pause_
  1661.     out    dx,al
  1662.  
  1663. ;Step 9. Write 1's to all bits of EN0_ISR to clear pending interrupts.
  1664.  
  1665.     mov    al, 0ffh
  1666.     setport    EN0_ISR
  1667.     pause_
  1668.     out    dx,al
  1669.  
  1670. ;Step 10. Init EN0_IMR as desired.
  1671.  
  1672.     mov    al, ENISR_ALL
  1673.     setport    EN0_IMR
  1674.     pause_
  1675.     out    dx,al
  1676.  
  1677. ;Step 11. Init the Ethernet address and multicast filters.
  1678.  
  1679.     mov    si,offset rom_address
  1680.     mov    cx,EADDR_LEN
  1681.     call    set_address    ; Now set the address in the 8390 chip
  1682.     call    set_hw_multi  ; Put the right stuff into 8390's multicast masks
  1683.  
  1684. ;Step 12. Program EN_CCMD for page 1.
  1685.  
  1686.     loadport
  1687.     mov    al, ENC_PAGE1 + ENC_NODMA + ENC_STOP
  1688.     setport    EN_CCMD
  1689.     pause_
  1690.     out    dx,al
  1691.  
  1692. ;Step 13. Program the Current Page Register to same value as Boundary Pointer.
  1693.  
  1694. ; THIS IS WRONG WRONG WRONG inspite of some self-contradicting National
  1695. ; documentation. If the Current Page Register is initialized to the same
  1696. ; value as the Boundary Pointer, the first ever packet received will be lost or
  1697. ; trashed because the driver always expects packets to be received at Boundrary
  1698. ; pointer PLUS ONE! 
  1699.  
  1700.     mov    al,SM_RSTART_PG
  1701.     inc    al        ; To fix the bug! - gft - 910523
  1702.     setport    EN1_CURPAG
  1703.     pause_
  1704.     out    dx,al
  1705.     mov    save_curr,al    ; added in conjunction with fixes above
  1706.                 ; - gft - 910611
  1707.     mov    next_packet, al ; initialize next_packet to the value in
  1708.                 ; current - gft - 910603
  1709.  
  1710. ;Step 14. Program EN_CCMD back to page 0, and start it.
  1711.  
  1712.     mov    al, ENC_NODMA + ENC_START + ENC_PAGE0
  1713.     setport    EN_CCMD
  1714.     pause_
  1715.     out    dx,al
  1716.  
  1717.     mov    al, 0            ;set transmitter mode to normal.
  1718.     setport    EN0_TXCR
  1719.     pause_
  1720.     out    dx,al
  1721.  
  1722.   if 0
  1723.     mov    al, ENRXCR_BCST
  1724.     setport    EN0_RXCR
  1725.     pause_
  1726.     out    dx,al
  1727.   endif
  1728.  
  1729.     call    set_recv_isr    ; Put ourselves in interrupt chain
  1730.  
  1731.     mov    al, int_no        ; Get board's interrupt vector
  1732.     add    al, 8
  1733.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1734.     jb    set_int_num        ; No.
  1735.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1736. set_int_num:
  1737.     xor    ah, ah            ; Clear high byte
  1738.     mov    int_num, ax        ; Set parameter_list int num.
  1739.  
  1740.     clc                ; Say no error
  1741.     ret                ; Back to common code
  1742.  
  1743.