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

📄 head.asm

📁 dos下的网卡驱动程序。支持一般通用网卡
💻 ASM
📖 第 1 页 / 共 3 页
字号:
count_in_err:
	assume	ds:nothing
	add2	errors_in,1
	ret

	public	count_out_err
count_out_err:
	assume	ds:nothing
	add2	errors_out,1
	ret

recv_isr_frame	struc
recv_isr_ds	dw	?
recv_isr_dx	dw	?
recv_isr_ax	dw	?
recv_isr_ip	dw	?
recv_isr_cs	dw	?
recv_isr_f	dw	?
recv_isr_frame	ends

;
; I have had a problem with some hardware which under extreme LAN loading
; conditions will re-enter the recv_isr. Since the 8259 interrupts for
; the card are masked off, and the card's interrupt mask register is 
; cleared (in 8390.asm at least) disabling the card from interrupting, this
; is clearly a hardware problem. Due to the low frequencey of occurance, and
; extreme conditions under which this happens, it is not lilely to be fixed
; in hardware any time soon, plus retrofitting of hardware in the field will
; not happen. To protect the driver from the adverse effects of this I am
; adding a simple re-entrancy trap here.  - gft - 910617
;

in_recv_isr	db 	0	; flag to trap re-entrancy

recv_isr:
	cmp	in_recv_isr, 0
	jne	recv_iret

	mov	in_recv_isr, 1

; I realize this re-entrancy trap is not perfect, you could be re-entered
; anytime before the above instruction. However since the stacks have not
; been swapped re-entrancy here will only appear to be a spurious interrupt.
; - gft - 910617

; In order to achieve back-to-back packet transmissions, we handle the
; latency-critical portion of transmit interrupts first.  The xmit
; interrupt routine should only start the next transmission, but do
; no other work.  It may only touch ax and dx (the only register necessary
; for doing "out" instructions) unless it first pushes any other registers
; itself.
	PUSH_16_32	ax
	PUSH_16_32	dx
	call	xmit
	jc	not_our_interrupt

; Now switch stacks, push remaining registers, and do remaining interrupt work.
	push	ds
	mov	ax,cs			;ds = cs.
	mov	ds,ax
	assume	ds:cgroup

	mov	savesp,sp
	mov	sp,offset cgroup:our_stack
	mov	savess,ss

	mov	ss,ax
	cld

	PUSH_16_32	bx
	PUSH_16_32	cx
	PUSH_16_32	si
	PUSH_16_32	di
	PUSH_16_32	bp
	push		es

; The following comment is wrong in that we now do a specific EOI command,
; and because we don't enable interrupts (even though we should).

; Chips & Technologies 8259 clone chip seems to be very broken.  If you
; send it a Non Specific EOI command, it clears all In Service Register
; bits instead of just the one with the highest priority (as the Intel
; chip does and clones should do).  This bug causes our interrupt
; routine to be reentered if: 1. we reenable processor interrupts;
; 2. we reenable device interrupts; 3. a timer or other higher priority
; device interrupt now comes in; 4. the new interrupting device uses
; a Non Specific EOI; 5. our device interrupts again.  Because of
; this bug, we now completely mask our interrupts around the call
; to "recv", the real device interrupt handler.  This allows us
; to send an EOI instruction to the 8259 early, before we actually
; reenable device interrupts.  Since the interrupt is masked, we
; are still guaranteed not to get another interrupt from our device
; until the interrupt handler returns.  This has another benefit:
; we now no longer prevent other devices from interrupting while our
; interrupt handler is running.  This is especially useful if we have
; other (multiple) packet drivers trying to do low-latency transmits.
	mov	al,int_no	; Disable further device interrupts
	call	maskint

; The following is from Bill Rust, <wjr@ftp.com>
; this code dismisses the interrupt at the 8259. if the interrupt number
;  is > 8 then it requires fondling two PICs instead of just one.
	mov	al, int_no	; get hardware int #
	cmp	al, 8		; see if its on secondary PIC
	jg	recv_isr_4
	add	al, 60h		; make specific EOI dismissal
	out	20h, al
	jmp	short recv_isr_3	; all done
recv_isr_4:
	add	al,60h - 8	; make specific EOI (# between 9 & 15).
	out	0a0h,al		; Secondary 8259 (PC/AT only)
	mov	al,62h		; Acknowledge on primary 8259.
	out	20h,al
recv_isr_3:

;	sti				; Interrupts are now completely safe
	call	recv

	cli				;interrupts *must* be off between
					;here and the stack restore, because
					;if we have one of our interrupts
					;pending, we would trash our stack.

	mov	al,int_no	; Now reenable device interrupts
	call	unmaskint

	pop			es
	POP_16_32	bp
	POP_16_32	di
	POP_16_32	si
	POP_16_32	cx
	POP_16_32	bx

	mov	ss,savess
	mov	sp,savesp

	pop			ds
	assume	ds:nothing
;IBM has a situation where:
; 1) Serial interrupt IRQ4 or IRQ3 occurs
; 2) Network interrupt occurs in the middle.
; 3) Network interrupt completes and issues EOI
; 4) Network interrupt falls through to default handler.
; 5) Default handler assumes there is no interrupt handler
;    and masks off the current (IRQ4 or IRQ3) interrupt.  Bad!
;To fix this problem, we are simply going to iret if we serviced our interrupt.
	POP_16_32	dx
	POP_16_32	ax
	mov	in_recv_isr, 0	; clear the re-entrancy flag - gft - 901617
	iret
not_our_interrupt:
	POP_16_32	dx
	POP_16_32	ax
	mov	in_recv_isr, 0	; clear the re-entrancy flag - gft - 901617
recv_iret:
	jmp	their_recv_isr

recv_exiting_flag	db	0	;nonzero if recv_exiting will be run.
recv_exiting_addr	dd	?

	public	schedule_exiting
schedule_exiting:
;call this routine to schedule a subroutine that gets run after the
;recv_isr.  This is done by stuffing routine's address in place
;of the recv_isr iret's address.  This routine should push the flags when it
;is entered, and should jump to recv_exiting_exit to leave.
;enter with ax = address of routine to run.
	cmp	recv_exiting_flag,0	;is it already scheduled?
	jne	schedule_exiting_1	;yes, don't do it again!
	inc	recv_exiting_flag	;set the flag.
	les	di,savespss		;make es:di -> their stack.
	xchg	ax,es:[di].recv_isr_ip	;stuff our routine's address in,
	mov	recv_exiting_addr.offs,ax	;and save the original address.
	mov	ax,cs
	xchg	ax,es:[di].recv_isr_cs
	mov	recv_exiting_addr.segm,ax
schedule_exiting_1:
	ret

	public	recv_exiting_exit
recv_exiting_exit:
;recv_exiting jumps here to exit, after pushing the flags.
	cli				;protect the following semaphore.
	mov	recv_exiting_flag,0
	push	recv_exiting_addr.segm
	push	recv_exiting_addr.offs
	iret


	public	maskint
maskint:
	or	al,al			;are they using a hardware interrupt?
	je	maskint_1		;no, don't mask off the timer!

	assume	ds:cgroup
	mov	dx,21h			;assume the master 8259.
	cmp	al,8			;using the slave 8259 on an AT?
	jb	mask_not_irq2
	mov	dx,0a1h			;go disable it on slave 8259
	sub	al,8
mask_not_irq2:
	mov	cl,al

	in	al,dx			;disable them on the correct 8259.
	mov	ah,1			;set the bit.
	shl	ah,cl
	or	al,ah
;
; 500ns Stall required here, per INTEL documentation for eisa machines
; - gft - 910617
;
	push	ax
	in	al,61h	; 1.5 - 3 uS should be plenty
	in	al,61h
	in	al,61h
	pop	ax
	out	dx,al
maskint_1:
	ret


	public	unmaskint
unmaskint:
;exit with cl = 0 if the interrupt had been enabled.
	assume	ds:cgroup
	mov	dx,21h			;assume the master 8259.
	mov	cl,al
	cmp	cl,8			;using the slave 8259 on an AT?
	jb	unmask_not_irq2		;no
	in	al,dx			;get master mask
	push	ax
	in	al,61h			;wait lots of time.
	in	al,61h
	in	al,61h
	pop	ax
	and	al,not (1 shl 2)	; and clear slave cascade bit in mask
	out	dx,al			;set new master mask (enable slave int)
;
; 500ns Stall required here, per INTEL documentation for eisa machines
; - gft - 910617
;
	push	ax
	in	al,61h	; 1.5 - 3 uS should be plenty
	in	al,61h
	in	al,61h
	pop	ax
	mov	dx,0a1h			;go enable int on slave 8259
	sub	cl,8
unmask_not_irq2:

	in	al,dx			;enable interrupts on the correct 8259.
	mov	ah,1			;clear the bit.
	shl	ah,cl
	mov	cl,al			;remember the original mask.
	and	cl,ah
	not	ah
	and	al,ah
;
; 500ns Stall required here, per INTEL documentation for eisa machines
; - gft - 910617
;
	push	ax
	in	al,61h	; 1.5 - 3 uS should be plenty
	in	al,61h
	in	al,61h
	pop	ax
	out	dx,al

	ret


	public	recv_locate
recv_locate:
;called when we want to determine what to do with a received packet.
;enter with es:di -> packet type, dl = packet class.
;exit with cy if the packet is not desired, or nc if we know its type.
	assume	ds:cgroup, es:nothing

; If -n option take IEEE 802.3 encapsulated packets that could be Novell IPX 
; and make them Ethernet encapsulated Novell IPX packets (for PDSHELL).
	test	flagbyte,N_OPTION
	jz	not_n_op

; Make IEEE 802.3-like packets that could be Novell IPX into BlueBook class
; Novell type 8137 packets.
	cmp	dl,IEEE8023		;Is this an IEEE 802.3 packet?
	jne	recv_not_802_3		;no
	cmp	word ptr es:[di],0ffffh	;if this word not ffff
	jne	recv_not_8137		;  then not Novell
	sub	di,2			; back it up to the 8137 word.
	mov	es:[di],3781h		; fake as Novell protocol (8137)
	mov	dl,BLUEBOOK
	jmp	short recv_not_8137
recv_not_802_3:
; Convert incoming Ethernet type 8137 IPX packets to type 8138, as with -n in 
; effect we can't send type 8137, and it will only confuse Netware.
	cmp	dl,BLUEBOOK		;Is this a BLUEBOOK packet?
	jne	recv_not_8137		;no, don't change it.
	cmp	word ptr es:[di],3781h	;Is it an 8137 packet?
	jne	recv_not_8137		;no, don't change it.
	mov	es:[di],word ptr 3881h	;yes, mung it slightly.
recv_not_8137:
not_n_op:

	mov	bx,offset cgroup:handles
recv_find_1:
	cmp	[bx].in_use,0		;is this handle in use?
	je	recv_find_2		;no - don't check the type.

	mov	ax,[bx].receiver.offs	;do they have a receiver?
	or	ax,[bx].receiver.segm
	je	recv_find_2		;no - they're not serious about it.

;per request by the UK people, we match on IEEE 802.3 classes, then types.
;for all others, we match on type, then class.  This lets their software work
;without breaking BLUEBOOK type length=0 clients.
	cmp	[bx].class,IEEE8023	;is this an IEEE 802.3 handle
	jne	recv_find_7		;no.
	cmp	dl,IEEE8023		;is the packet also IEEE 802.3?
	jne	recv_find_2		;no, give up on it now.
recv_find_7:

	mov	cx,[bx].packet_type_len	;compare the packets.
	lea	si,[bx].packet_type
	jcxz	recv_find_3		;if cx is zero, they want them all.

	cmp	[bx].class, dl		;is this the right class?
	jne	recv_find_2		;no- don't bother

	push	di
	repe	cmpsb
	pop	di
	je	recv_find_3		;we've got it!
recv_find_2:
	add	bx,(size per_handle)	;go to the next handle.
	cmp	bx,offset cgroup:end_handles
	jb	recv_find_1

	add2	packets_dropped,1	;count it as dropped.
	stc
	ret
recv_find_3:
	mov	found_handle,bx		;remember what our handle was.
	clc
	ret


	public	recv_find, recv_found
recv_find:
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type, dl = packet class.
;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
;  to be filled by the driver.
	assume	ds:cgroup, es:nothing
	push	cx			;preserve packet length.
	call	recv_locate		;search for the packet type.
	pop	cx
	jc	recv_find_5		;we didn't find it -- discard it.
;
recv_found:
;called to do the first upcall.
;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
;  to be filled by the driver.

	add2	packets_in,1
	add2	bytes_in,cx		;add up the received bytes.

	mov	bx,found_handle
	les	di,[bx].receiver	;remember the receiver upcall.
	mov	receive_ptr.offs,di
	mov	receive_ptr.segm,es

	test	flagbyte,W_OPTION	;did they select the Windows option?
	je	recv_find_6		;no, don't check for the upcall.

; does the receiver signature match whats currently in memory?  if not,
; jump to fake return
	push	si
	push	cx
	lea	si,[bx].receiver_sig
	mov	cx,8/2
	repe	cmpsw
	pop	cx
	pop	si
	je	recv_find_6
recv_find_5:
	xor	di,di			;"return" a null pointer.
	mov	es,di
	ret
recv_find_6:

	mov	ax,0			;allocate request.
	stc				;with stc, flags must be an odd number
	push	ax			; save a number that cant be flags
	pushf				;save flags in case iret used.
	call	receive_ptr		;ask the client for a buffer.
	; on return, flags should be at top of stack. if an IRET has been used,
	; then 0 will be at the top of the stack
	pop	bx
	cmp	bx,0
	je	recv_find_4		;0 is at top of stack
	add	sp,2
recv_find_4:
	ret


	public	recv_copy
recv_copy:
;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
;preserve bx.
	assume	ds:nothing, es:nothing

	push	bx
	mov	bx,found_handle
	mov	ax,1			;store request.
	clc				;with clc, flags must be an even number
	push	ax			; save a number that can't be flags
	pushf				;save flags incase iret used.
	call	receive_ptr		;ask the client for a buffer.
	pop	bx
	cmp	bx,1			;if this is a 1, IRET was used.
	je	recv_copy_1
	pop	bx
recv_copy_1:
	pop	bx
	ret

	public	send_queue
send_queue:
; Queue an iocb.
; Enter with es:di -> iocb, interrupts disabled.
; Destroys ds:si.
	assume	ds:nothing, es:nothing
	mov	es:[di].next.offs,0	; Zero next offset
	mov	es:[di].next.segm,0	; Zero next segment
	mov	si,send_head.offs	; Queue empty?
	or	si,send_head.segm
	jnz	sq_notempty		; No
	mov	send_head.offs,di	; Set head offset
	mov	send_head.segm,es	; Set head segment
	jmp	short sq_settail
sq_notempty:				; Queue is not empty
	lds	si,send_tail		; Get tail segment:offset
	mov	ds:[si].next.offs,di	; Set next offset
	mov	ds:[si].next.segm,es	; Set next segment
sq_settail:
	mov	send_tail.offs,di	; Set tail offset
	mov	send_tail.segm,es	; Set tail segment
	ret


	public	send_dequeue
send_dequeue:
; Dequeue an iocb and possibly call its upcall.
; Enter with device or processor interrupts disabled, ah = return code.
; Exits with es:di -> iocb; destroys ds:si, ax, bx, cx, dx, bp.
	assume	ds:nothing, es:nothing
	les	di,send_head		; Get head segment:offset
	lds	si,es:[di].next		; Get next segment:offset
	mov	send_head.offs, si	; Set head offset
	mov	send_head.segm, ds	; Set head segment
	or	es:flags[di], DONE	; Mark done
	mov	es:ret_code[di], ah	; Set retcode
	test	es:[di].flags,CALLME	; Does he want an upcall?
	je	send_dequeue_1		; No.
	push	es			; Push iocb segment
	push	di			;  and offset
	clc				; Clear carry.
	mov	ax,1			; Push a number that cant be flags.
	push	ax
	pushf				; Save flags in case iret used.
	call	es:[di].upcall		; Call the client.
	pop	ax			; Pop first word.
	cmp	ax,1			; If this is a 1, IRET was used.
	je	send_dequeue_2		; Far return used.
	add	sp,2			; Pop flags.
send_dequeue_2:
	pop	di			; Pop iocb segment
	pop	es			;  and offset
send_dequeue_1:
	ret


code	ends

_text	segment para public 'code'
_text	ends

init	segment para public 'code'
init	ends

	end	start

⌨️ 快捷键说明

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