⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8390.asm

📁 RTL8019 Plug-And-Play Packet Driver.
💻 ASM
📖 第 1 页 / 共 4 页
字号:

; Get the command register TXP bit to test for incomplete transmission later

	loadport		; Point at Chip's Command Reg
 	setport	EN_CCMD		; ..
	pause_
	in 	al, dx
	mov 	ah, al		; Save CR contents in ah for now

; Stop the NIC

	pause_
	mov 	al, ENC_STOP+ENC_NODMA
	out 	dx, al		; Write "stop" to command register

; Wait 1.6ms for the NIC to stop transmitting or receiving a packet. National
; says monitoring the ISR RST bit is not reliable, so a wait of the maximum
; packet time (1.2ms) plus some padding is required.

	longpause

; Clear the remote byte count registers

	xor	al,al
	setport	EN0_RCNTLO	; Point at byte count regs
	out	dx, al
	setport EN0_RCNTHI
	pause_
	out	dx, al

; check the saved state of the TXP bit in the command register

	mov	rcv_ovr_resend,al	; clear the resend flag
	test ah,ENC_TRANS	; Was transmitter still running?
	jz	rcv_ovr_loopback	; Go if not running

; Transmitter was running, see if it finished or died

	setport EN0_ISR		; point at the NIC ISR
	pause_
	in	al,dx		; and get it
	test al,ENISR_TX+ENISR_TX_ERR	; Did the transmitter finish?
	jnz	rcv_ovr_loopback	; one will be set if TX finished

; Transmitter did not complete, remember to resend the packet later.

	mov	rcv_ovr_resend,ah	; ah has at least ENC_TRANS set

; Put the NIC chip into loopback so It won't keep trying to receive into
; a full ring

rcv_ovr_loopback:
	loadport	; resync setport
 	setport	EN0_TXCR	; ..
	mov al,	ENTXCR_LOOP	; Put transmitter in loopback mode
	pause_
	out dx,	al		; ..
	setport	EN_CCMD		; Point at Chip command reg
	mov al,	ENC_START+ENC_NODMA
	pause_
	out dx,	al		; Start the chip running again

; Verify that there is really a packet to receive by fetching the current
; page pointer and comparing it to the next packet pointer.

	mov al, ENC_NODMA+ENC_PAGE1	; Set page one
	pause_
	out dx,al
	setport EN1_CURPAG	; Get current page
	pause_
	in al,dx
	pause_			; Rewrite current page to fix SMC bug.
	out dx,al
	mov bl,al		; save it
	mov save_curr,al
	setport	EN_CCMD		;
	mov al, ENC_NODMA+ENC_PAGE0
	pause_
	out dx,al		; Back to page 0

	mov al, next_packet	; get saved location for next packet

	cmp	al,bl		; Check if buffer emptry
	jne	rcv_ovr_rx_one  ; OK go get the NIC header

; NO PACKET IN THE RING AFTER AN OVW INTERRUPT??? Can this ever happen?
; YES! if overrun happend between a receive interrupt and the when the
; current page register is read at the start of recv_frame.
; Count these things too.

	add2	soft_rx_over_nd,1

	jmp	rcv_ovr_empty


; Get the NIC header for the received packet, and check it

rcv_ovr_rx_one:
	mov	ah,al		; make a byte address. e.g. page
	mov	bl,ah		; and save in bl
	mov	al,0		; 46h becomes 4600h into buffer
	mov	cx,RCV_HDR_SIZE	; size of rcv_hdr
	mov	di,offset rcv_hdr ;point to header
	movseg	es,ds
	call	block_input
	mov al,	rcv_hdr+EN_RBUF_STAT	; Get the buffer status byte
	test al,ENRSR_RXOK	; Is this frame any good?
	jz	rcv_ovr_ng	; Skip if not

;
; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
; it doesn't hurt to range check the next packet pointer here.
;
	mov al,	rcv_hdr+EN_RBUF_NXT_PG	; Start of next frame
	mov next_packet, al	; Save next packet pointer
	cmp 	al,SM_RSTART_PG	; Below around the bottom?
	jb	rcv_ovr_ng	; YES - out of range
	cmp	al,sm_rstop_ptr ; Above the top?
	jae	rcv_ovr_ng	; YES - out of range

; ok to call rcv_frm

; This gets real tricky here. Because some wise user (like me) may attempt
; to call send_pkt from his receive interrupt service routine, you can't just
; blindly call rcv_frm from here because the NIC is now in LOOPBACK mode!
; to get around this problem I added a global flag that causes rcv_frm to
; make the first call to the users interrupt service routine, get a buffer,
; fill the buffer, BUT defer the second call until later. If a second call
; is required the flag will still be set after return from rcv_frm and you
; can make the upcall after the NIC has been taken out of loopback and has
; resent any required packet.

	mov	defer_upcall, 1	; Defer upcalls until later. (may be cleared
				;  by rcv_frm)
 	call	rcv_frm		; Yes, go accept it
	jmp	rcv_ovr_ok

rcv_ovr_ng:
	or	byte ptr soft_rx_err_bits,al
	add2	soft_rx_errors,1
	mkle LE_RX_ERR, 0, 0, 0 ; Log error packet - gft - 910521
;
; HAD TO ADD ERROR RECOVERY HERE. TO BLINDLY PROCEED AND ASSUME THE NEXT
; PACKET POINTR FROM THE NIC HEADER IS VALID IS INVITING DISASTER.
;
; Error recovery consists of killing and restarting the NIC. This drops all
; the packets in the ring, but thats better than winding up in the weeds!
;
; - gft - 910611

ifdef err_stop
	call	rcv_mode_1	; for debugging, stop on error
	jmp	check_isr	; so we can dump the log
endif

; NO! no longer in memory
;       call    etopen_0        ; go back to the initial state
;
; Instead copy the last known current page pointer into the next packet pointer
; which will result in skipping all the packets from the errored one to where
; the NIC was storing them when we entered this ISR, but prevents us from
; trying to follow totally bogus next packet pointers through the card RAM
; space.
;
        mov     al, save_curr   ; get the last known current page pointer
        mov     next_packet, al ; and use it as the next packet pointer
        jmp     check_isr       ; then go handle more interrupts

rcv_ovr_ok:
; moved the next two instructions up to where I range check the
; next packet pointer above - gft - 910611
;	mov	al,rcv_hdr+EN_RBUF_NXT_PG ; Get pointer to next frame
;	mov	next_packet, al ; save it in next_packet - gft - 910603
	mov	al,next_packet	; Grap the next packet pointer
	dec	al		; Back up one page
	cmp	al,SM_RSTART_PG	; Did it wrap?
	jae	rcv_ovr_nwr2
	mov	al,sm_rstop_ptr	; Yes, back to end of ring
rcv_ovr_empty:
	dec	al
rcv_ovr_nwr2:
	loadport		; Point at boundary reg
	setport	EN0_BOUNDARY	; ..
	pause_
	out dx,	al		; Set the boundary
; When we get here we have either removed one packet from the ring and updated
; the boundary register, or determined that there really were no new packets
; in the ring.

; Clear the OVW bit in the ISR register.

	loadport		; resync the setport macro
	setport EN0_ISR		; point at the ISR 
	mov al,	ENISR_OVER	; Clear the overrun interrupt bit
	pause_
	out dx,	al

; Take the NIC out of loopback

	setport	EN0_TXCR	; Back to TX control reg
	xor al,	al		; Clear the loopback bit
	pause_
	out dx,	al		; ..

; Any incomplete transmission to resend?

	cmp rcv_ovr_resend,0
	jz  rcv_ovr_deferred	; no, go check for deferred upcall

; Yes, restart the transmission

	setport EN_CCMD	; point at command register
	mov al,	ENC_TRANS+ENC_NODMA+ENC_START
	pause_
	out dx,	al		; Start the transmitter

; If an upcall was deferred, make it now

rcv_ovr_deferred:
	cmp	defer_upcall,0
	jz	rcv_ovr_done
	mov	si,defer_si		; Recover pointer to destination
	mov	cx,defer_cx		; And it's this long
	mov	ds,defer_ds		; Tell client it's his source
	assume	ds:nothing
	call	recv_copy	; Give it to him
	movseg	ds,cs
	assume	ds:code

; log the end of overrun processing, with which flags were set

rcv_ovr_done:
ifdef debug
	mov 	ax, WORD PTR rcv_ovr_resend
	mov 	bx, WORD PTR defer_upcall
	mkle	LE_RX_OVR_X, ax, bx, 0
endif

	mov	defer_upcall,0	; clear the defer upcall flag

; finally go back and check for more interrupts

 	jmp	check_isr	; Done with the overrun case

; End of new receive overrun code

recv_no_overrun:
; Handle receive flags, normal and with error (but not overrun).
	test al,ENISR_RX+ENISR_RX_ERR	; Frame received without overrun?
	jnz	recv_frame_0	; Go if so.

  ifdef board_features
	cmp	is_overrun_690, 0
	jne	recv_overrun_11
	jmp	recv_no_frame	; Go if not.
recv_overrun_11:
	jmp	recv_690_overrun
  else
	jmp	recv_no_frame	; Go if not.
  endif

;
; Move the label recv_frame down to below where the interrupts are cleared.
; This will cause the interrupts to be cleared only after being read in 
; check_isr, instead of every time a packet is read from the ring. The way
; it used to work was find a RX or RX_ERR interrupt, clear both, check for
; packet really in ring (compare next packet pointer with current page reg)
; read packet and loop back to clear both ints. When all packets read from
; ring, loop back to check_isr. IF packets keep arriving as fast as or faster
; than we can read them, we never get back to check_isr to see if any higher
; priority interrupts occur (like OVW).
;
; The way it works now is find a RX or RX_ERR interrupt, clear both, check
; for packet really in ring and remember the current page register. Read
; packets from the ring until all packets received at the time the current
; page register was last read have been received, (comparing next packet
; pointer to the once read value of current page register). This eliminates
; both the (possibly unnecessary) resetting of the interrupts and the 
; page switch and current page register read on a per packet basis. This should
; also eliminate possible problems with not doing the ring overflow processing
; in heavy traffic referred to in my comments below.
;
;  - gft - 910611
;
recv_frame_0:

	loadport		; Point at Chip's Command Reg
	setport	EN0_ISR		; Point at Interrupt status register
	pause_
	mov al,	ENISR_RX+ENISR_RX_ERR
	out dx,	al		; Clear those requests
 	setport	EN_CCMD		; ..
	pause_
	cli
	mov al,	ENC_NODMA+ENC_PAGE1+ENC_START
	out dx,	al		; Switch to page 1 registers
	setport	EN1_CURPAG	;Get current page of rcv ring
	pause_
	in al,	dx		; ..
;	mov ah,	al		; Hold current page in AH
	mov save_curr,al	; Hold last read current page register in 
				; memory instead - gft - 910611
 	setport	EN_CCMD		; Back to page zero registers
	pause_
	mov al,	ENC_NODMA+ENC_PAGE0+ENC_START
	out dx,	al		; Switch back to page 0 registers

; This becomes the loop back point to read packets from the ring.
; now only loop back and read until those packets received at the time 
; the current page register is read above have been read.
; - gft - 910611

recv_frame:
	mov al, next_packet	; Get saved pointer to next packet in ring
;
; change the next instruction to compare against the saved copy of the current
; page register and only read from the ring what was received up until the 
; last read from the current page register - gft - 910611
;
;	cmp al,	ah		; Read all the frames?
	cmp al,	save_curr	; Read all the frames?
	jne	recv_more_frames; hacked jump code for addition of mkle
				; macro below - gft -910521
;	jmp	recv_frame_break	; Finished them all
;
; changed jmp recv_frame_break to jmp check_isr after recv_frame_break was
; determined to be superfluous. See comments at recv_frame_break below.
; - gft - 910531
;
  ifdef board_features
	cmp	is_overrun_690, 0
	je	recv_not_690_overrun

recv_690_overrun:
	mov	is_overrun_690, 0	; clear overrun indicator
	loadport
	setport	EN0_BOUNDARY		; rewrite bndry with itself
	in	al, dx
	pause_
	out	dx, al

	setport	EN0_ISR			; Point at Interrupt status register
	pause_
	mov	al, ENISR_OVER		; Clear overrun interrupt bit
	out	dx, al
	call	count_in_err		; Count the anomaly

recv_not_690_overrun:
  endif
	jmp	check_isr	; Finished all receives, check for more
				; interrupts.

recv_more_frames:

	mov	ah,al		; make a byte address. E.G. page
	mov	al,0		; 46h becomes 4600h into buffer
	mov	bl,ah
	mov	cx,RCV_HDR_SIZE
	mov	di,offset rcv_hdr
	movseg	es,ds
	call	block_input
	mov al,	rcv_hdr+EN_RBUF_STAT	; Get the buffer status byte
	test al,ENRSR_RXOK	; Good frame?
	jz	recv_err_no_rcv
;
; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
; it doesn't hurt to range check the next packet pointer here.
;
	mov al,	rcv_hdr+EN_RBUF_NXT_PG	; Start of next frame
	mov next_packet, al	; Save next packet pointer
	cmp 	al,SM_RSTART_PG	; Below around the bottom?
	jb	recv_err_no_rcv ; YES - out of range
	cmp	al,sm_rstop_ptr ; Above the top?
	jae	recv_err_no_rcv ; YES - out of range

; ok to call rcv_frm

	call	rcv_frm		; Yes, go accept it
	jmp	recv_no_rcv
recv_err_no_rcv:
	or	byte ptr soft_rx_err_bits,al
	add2	soft_rx_errors,1
;
; The code used to assume that after decoding the NIC header status
; byte as a receive error, the status, and next packet pointer values
; are actually valid. When using the NIC, this assumption may get one
; up that proverbial creek without a paddle. It has been my experience that
; IF bad status is read in the NIC header, the rest of the NIC header is
; not to be trusted. More likely you read a NIC header from the middle of a
; packet than actually receiving a frame, especially if the save error packet
; bit (SEP) in the receive configuration register is NOT set (it's NOT set in
; this driver).
;
; Error recovery consists of killing and restarting the NIC. This drops all
; the packets in the ring, but thats better than winding up in the weeds!
;
; - gft - 910611

ifdef err_stop
	call	rcv_mode_1	; for debugging, stop on error
	jmp	check_isr	; so we can dump the log
endif

; NO! no longer in memory
;       call    etopen_0        ; go back to the initial state
;
; Instead copy the last known current page pointer into the next packet pointer
; which will result in skipping all the packets from the errored one to where
; the NIC was storing them when we entered this ISR, but prevents us from
; trying to follow totally bogus next packet pointers through the card RAM
; space.
;
        mov     al, save_curr   ; get the last known current page pointer
        mov     next_packet, al ; and use it as the next packet pointer
        jmp     check_isr       ; then go handle more interrupts

recv_no_rcv:
; moved the next two instructions up to where I range check the
; next packet pointer above - gft - 910611
;	mov al,	rcv_hdr+EN_RBUF_NXT_PG	; Start of next frame
;	mov next_packet, al	; Save next packet pointer
	mov	al,next_packet	; Grap the next packet pointer
	dec	al		; Make previous page for new boundary

; Here's another little bug, which was exposed when when I expanded the
; recieve packet ring for HP 16 bit cards (from 06h-7fh to 06h-ffh).
; The jge instruction is for SIGNED comparisons and failed when the next
; packet pointer got into the range 81h-0feh. Changed the below jge to
; a jae for unsigned comparsions. - gft - 910610
; (Also scanned hppclan.asm and 8390.asm for improper use of signed 
; comparisons and found no others.)

	cmp al,	SM_RSTART_PG	; Wrap around the bottom?
;	jge	rcv_nwrap4
	jae	rcv_nwrap4		; - gft - 910610
	mov al,	sm_rstop_ptr	; Yes

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -