;****************************************************************************
;
;       The information contained in this file is confidential and 
;       proprietary to Standard Microsystems Corporation.  No part
;       of this file may be reproduced or distributed, in any form
;       or by any means for any purpose, without the express written
;       permission of Standard Microsystems Corporation.
;
; File:         ETH_PCM.ASM
;
; Description:	LMI lower routine assembly source file for all SMC PCM Cards.
;		Original development done by Mike Steiger.
;
;
;********************
;* Revision History *
;********************
;
; $Log:   K:\sweng\src\lmetha\vcs\eth_pcm.avm  $
;  
;     Rev 1.27   05 May 1995 14:43:40   STEIGER
;  Added time delay near the end of LM_Open_Adapter so the link
;  integrity bit data is stabilized before reading. This is necessary
;  to fix the IBM Socket Services bug reported by Tech Support.
;  
;     Rev 1.26   07 Jun 1994 14:06:16   WOOD_R
;  
;     Rev 1.25   07 Jun 1994 09:01:32   mike
;  Changed LM_Close_Adapter so PERM_CLOSE will work even with the card removed.
;  
;     Rev 1.24   20 May 1994 15:22:16   steiger
;  Changed upper range check on rx frame size (in NIC header) from 1536 bytes
;  to 2560 bytes. This was done so the driver will accept > 2KB frames that
;  are sent by Novell's silly test program.
;  
;     Rev 1.23   10 May 1994 11:22:00   wood_r
;  Added file banner
;
; Changes:	Added two tests at the top of the event polling loop in
;		LM_Service_Events that validate data read from the NIC.
;		The first test checks the validity of the 690 command
;		register data (REG_CMD), the second checks the interrupt
;		status register data validity. If either is invalid,
;		LM_Service_Events returns HARDWARE_FAILED.  This was done
;		to detect when the PCMCIA card has been removed.  In the
;		receive handler (HandlePRX:), the packet size and next packet
;		pointer data read from the NIC header in shared memory are
;		also range checked with the same return code (HARDWARE_FAILED)
;		if not in range. This was done to further enhance the
;		driver's ability to detect a removed card. All of this is
;		necessary because some systems (most notably Toshiba) process
;		the false interrupt that is generated when the card is
;		removed from the socket before the card removal interrupt
;		that is generated by the socket controller (i.e. Intel 365).
;
;
;+!/? ***********************************************************************

ifndef   EZSTART
include         ETH_RTNS.INC
include         GETCNFG.INC
include	        ezstart.inc
include		PCMCIA.INC
include		bicnic.inc
include         LMSTRUCT.INC
endif

db		'@(#) LM_8016_s2.1_v2.02',0,'$'

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       LM_Service_Events       Interrupt event handling routine.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ASM_PCM_PROC    LM_Service_Events

			push    bx
			push	cx
			push    dx
			push	di
			push	si
			push    ds
			push    es
			pushf

CheckNextInt:
			cmp	ds:[bp].adapter_status, OPEN
			je	ProcessEvents
			jmp	ServEvDone
ProcessEvents:
			mov	es, word ptr ds:[bp].ram_access+2
			or	byte ptr es:[REG_OFFSET+REG_MSR], 02h		; Wake up NIC
			jmp	$+2
			mov	byte ptr es:[REG_OFFSET+REG_CMD], 0
			jmp	$+2
			mov	al, es:[REG_OFFSET+REG_CMD]
			and	al, not CMD_TXP
			or	al, al
			jz	CardIsProbablyInserted

CardIsProbablyRemoved:
			mov	ax, HARDWARE_FAILED
			jmp	NotMyInt

CardIsProbablyInserted:
			mov	al, es:[REG_OFFSET+REG_ISR]
			or      al, al
			jnz     StartIntCheck
			jmp     NotNICInterrupt ; If no NIC int, check hw int

StartIntCheck:		cmp	al, 0FFh
			je	CardIsProbablyRemoved

			mov     ds:[bp].servicing_ints, 1
			test    al, ISR_PTX         ; Was packet xmitted?
			jz      CheckOVW        ; If not, check ring overflow
			jmp     HandlePTX

CheckOVW:               test    al, ISR_OVW         ; Is ring overflowing?
			jz      CheckPktRec     ; If not, check packet received
			jmp     HandleOVW

CheckPktRec:            test    al, ISR_PRX         ; Was packet received?
			jz      CheckRxErr      ; If not, check receive error
			jmp     HandlePRX

CheckRxErr:             test    al, ISR_RXE         ; Is there a receive error?
			jz      CheckTxErr      ; If not, check transmit error
			jmp     HandleRXE

CheckTxErr:             test    al, ISR_TXE	; Is there a transmit error?
			jz      CheckCntrs 	; If not, update counters.
			jmp     HandleTXE 	

CheckCntrs:		test	al, ISR_CNT
	     		jnz	DoCounters
			jmp     NotNICInterrupt ; If no NIC int, check hw int
;			jmp	ServEvDone

DoCounters:		mov	al, ISR_CNT
			mov	es:[REG_OFFSET+REG_ISR], al
			call	UpdateCounters
			jmp     CheckNextInt
	   
;---------------------- Handle Packet Received
HandlePRX:              
			mov	es, word ptr ds:[bp].ram_access.2

CheckForReceive:	mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_RD2+CMD_PAGE1
			jmp	$+2
			mov	ah, es:[REG_OFFSET+REG_CURR]	; AH == CURR
			jmp	$+2
			mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_RD2	; Select page 0
			jmp	$+2
			mov	al, es:[REG_OFFSET+REG_BNRY]	; Get Boundary Ptr
			inc     al                      ; AL == BNRY+1

			cmp     ds:[bp].pstop_hold, al
			jne     not_end_of_buf
			mov     al, ds:[bp].pstart_hold

not_end_of_buf:         cmp     al, ah                  ; If BNRY+1 == CURR,
			jne     RingNotEmpty            ; ring is empty
			jmp     ReceiveDone
RingNotEmpty:
			mov     ah, ds:[bp].local_nxtpkt_ptr
			xor     al, al
;			sub	ax, SHMEM_NIC_OFFSET
			mov     si, ax			; SI == ptr to packet
			mov     cx, es:[si+2]		; Get packet length
			mov     bx, es:[si]		; Get rx stat in BL,
							; next pkt in BH.
			cmp	cx, 2560		; Qualify value read from
			jna	RxSizeInRange		; memory - card may have been
			mov	ax, HARDWARE_FAILED	; removed ...
			jmp	NotMyInt
RxSizeInRange:
			cmp     bh, ds:[bp].pstop_hold  ; Qualify value read from
			jb      ptr_ok			; memory - card may have been
			mov	ax, HARDWARE_FAILED	; removed ...
			jmp	NotMyInt

;			sub     bh, ds:[bp].pstop_hold	; ?? No correction necessary - if
;			add     bh, ds:[bp].pstart_hold	; NIC's value is out of range,
							; we're dead anyway.

ptr_ok:
			push    es
			push	bx
			test	bl, RSR_DFR
			jz	SkipDeferringCnt
			mov	bx, word ptr ds:[bp].ptr_tx_deferred
			or	bx, word ptr ds:[bp].ptr_tx_deferred+2
			jz	SkipDeferringCnt
			les     bx, ds:[bp].ptr_tx_deferred
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
			
SkipDeferringCnt:	pop	bx
			pop     es
			test    bl, RSR_PHY
			jz      PhysicalAdd
			test	ds:[bp].receive_mask, ACCEPT_MULTI_PROM
			jnz	PhysicalAdd	; If Promiscuous multicast
ifdef	LARGE
			call    far ptr CheckMultiAdd	; mode, skip address check.
else
			call    CheckMultiAdd	; mode, skip address check.
endif
			cmp     ax, SUCCESS
			jne     DumpPacket

;---------------------- Process packet
PhysicalAdd:
			add     si, NIC_HEADER_SIZE
			sub	cx, CRC_SIZE
			call    UM_Receive_Packet
DumpPacket:
			mov     ds:[bp].local_nxtpkt_ptr, bh

;---------------------- Update BNRY
			mov	es, word ptr ds:[bp].ram_access.2
			dec     bh
			cmp     bh, ds:[bp].pstart_hold
			jnb     bnry_ok
			mov     bh, ds:[bp].pstop_hold
			dec     bh
bnry_ok:
			mov	es:[REG_OFFSET+REG_BNRY], bh
			cmp     ax, EVENTS_DISABLED     ; This ret code set
							; only by
							; UM_Receive_Packet.
			jne     NearCheckForReceive
			jmp     ServEvDone
NearCheckForReceive:    jmp     CheckForReceive
ReceiveDone:		mov	byte ptr es:[REG_OFFSET+REG_ISR], ISR_PRX
			jmp	$+2

;---------------------- Check ring to see if it is still empty...
			mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_RD2+CMD_PAGE1
			jmp	$+2
			mov	ah, es:[REG_OFFSET+REG_CURR]
			jmp	$+2

			mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_RD2
			jmp	$+2
			mov	al, es:[REG_OFFSET+REG_BNRY]
			inc     al                      ; AL == BNRY+1

			cmp     ds:[bp].pstop_hold, al
			jne     not_at_end_of_buf
			mov     al, ds:[bp].pstart_hold

not_at_end_of_buf:      cmp     al, ah                  ; If BNRY+1 == CURR,
			je      RingEmpty               ; ring is empty
			jmp     RingNotEmpty
RingEmpty:
			cmp     ds:[bp].ring_ovw, 1
			jnz     NearCheckNextInt

			mov	byte ptr es:[REG_OFFSET+REG_ISR], ISR_OVW
			jmp	$+2
			mov     ds:[bp].ring_ovw, 0
			mov	al, es:[REG_OFFSET+REG_BNRY]
			jmp     $+2
			jmp     $+2
			mov	es:[REG_OFFSET+REG_BNRY], al

NearCheckNextInt:       jmp     CheckNextInt

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;---------------------- Handle Transmit Error
HandleTXE:
			mov	byte ptr es:[REG_OFFSET+REG_ISR], ISR_TXE
			jmp	$+2
			mov	al, es:[REG_OFFSET+REG_TSR]
			test    al, TSR_ABT         ; Check max collisions
			jz      AssumeUnderrun  ; 
			mov     ax, MAX_COLLISIONS ; UM_Send_Complete status

;---------------------- Update MAX_COLLISIONS counter
			mov	bx, word ptr ds:[bp].ptr_tx_max_collisions
			or	bx, word ptr ds:[bp].ptr_tx_max_collisions+2
			jnz	IncMaxCollisions
			jmp	TransmitErrorDone			  
IncMaxCollisions:
			push    es
			les     bx, ds:[bp].ptr_tx_max_collisions
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
			pop     es
			jmp     TransmitErrorDone

;---------------------- Assume FIFO underrun
AssumeUnderrun:         mov     ax, FIFO_UNDERRUN

;---------------------- Update FIFO_UNDERRUN counter

			mov	bx, word ptr ds:[bp].ptr_tx_underruns
			or	bx, word ptr ds:[bp].ptr_tx_underruns+2
			jnz	IncTxUnderruns
			jmp	TransmitErrorDone
IncTxUnderruns:
			push    es
			les     bx, ds:[bp].ptr_tx_underruns
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
			pop     es
			jmp     TransmitErrorDone

;---------------------- Handle Successful Packet Transmit
HandlePTX:
			push    es
			mov	byte ptr es:[REG_OFFSET+REG_ISR], ISR_PTX
			jmp	$+2
			mov	al, es:[REG_OFFSET+REG_TSR]
			test	al, TSR_COL
ifdef	EZSTART
			jnz	GetCollisionCount
			push	ax
			mov	al, 0
			call	UpdateCollisionTable
			pop	ax
			jmp	CheckCRS
else
			jz	CheckCRS
endif
GetCollisionCount:
			push	ax
			xor	ax, ax
			mov	al, es:[REG_OFFSET+REG_NCR]
ifdef	EZSTART
			call	UpdateCollisionTable
endif
			mov	bx, word ptr ds:[bp].ptr_tx_total_collisions
			or	bx, word ptr ds:[bp].ptr_tx_total_collisions+2
			jz	ContinueCollisionCount
			les     bx, ds:[bp].ptr_tx_total_collisions
			add     word ptr es:[bx], ax
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
ContinueCollisionCount:
			cmp	al, 1
			pop	ax
			jg	IncMultCollisions	
			mov	bx, word ptr ds:[bp].ptr_tx_one_collision
			or	bx, word ptr ds:[bp].ptr_tx_one_collision+2
			jz	CheckCRS
			les     bx, ds:[bp].ptr_tx_one_collision
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
			jmp	CheckCRS
IncMultCollisions:
			mov	bx, word ptr ds:[bp].ptr_tx_mult_collisions
			or	bx, word ptr ds:[bp].ptr_tx_mult_collisions+2
			jz	CheckCRS
			les     bx, ds:[bp].ptr_tx_mult_collisions
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
CheckCRS:
			test	al, TSR_CRS
			jz	CheckCDH
			mov	bx, word ptr ds:[bp].ptr_tx_carrier_lost
			or	bx, word ptr ds:[bp].ptr_tx_carrier_lost+2
			jz	CheckCDH
			les     bx, ds:[bp].ptr_tx_carrier_lost
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
CheckCDH:
			test	al, TSR_CDH
			jz	CheckOWC
			mov	bx, word ptr ds:[bp].ptr_tx_CD_heartbeat
			or	bx, word ptr ds:[bp].ptr_tx_CD_heartbeat+2
			jz	CheckOWC
			les     bx, ds:[bp].ptr_tx_CD_heartbeat
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
CheckOWC:
			test	al, TSR_OWC
			jz	XmitErrorCheckDone
			mov	bx, word ptr ds:[bp].ptr_tx_ow_collision
			or	bx, word ptr ds:[bp].ptr_tx_ow_collision+2
			jz	XmitErrorCheckDone
			les     bx, ds:[bp].ptr_tx_ow_collision
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
XmitErrorCheckDone:
			pop	es
			mov     ax, SUCCESS     ; Set UM_Send_Complete status

;---------------------- Call upper MAC layer
TransmitErrorDone:
			push	ax
                        mov	al, ds:[bp].tx_head
			inc	al
			cmp	al, byte ptr ds:[bp].num_of_tx_buffs
			jne	tx_head_ok
			xor     al, al
tx_head_ok:
			mov	ds:[bp].tx_head, al
			dec	ds:[bp].tx_count
			je	NoXmitsPending
IFDEF LARGE
ifdef	EZSTART
        		call	far ptr PCM_SendPacket
else
        		call	far ptr SendPacket
endif
ELSE
        		call	SendPacket
ENDIF

NoXmitsPending:         pop     ax                      ; Restore status
			call    UM_Send_Complete
			cmp     ax, EVENTS_DISABLED     ; If events dis.,
			jne     PTXCheckNextInt         ; Stop all processing
							; and return.
			jmp     ServEvDone
PTXCheckNextInt:        jmp     CheckNextInt

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;---------------------- Handle Receive Error
HandleRXE:              
			mov	byte ptr es:[REG_OFFSET+REG_ISR], ISR_RXE
			jmp	$+2
			mov	al, es:[REG_OFFSET+REG_RSR]
			test    al, RSR_CRC
			jz      CheckFAE

;---------------------- Update CRC Error Counter
			push    es
			push    ax
			xor     ax, ax
			mov	al, es:[REG_OFFSET+REG_CNTR1]
			mov	bx, word ptr ds:[bp].ptr_rx_CRC_errors
			or	bx, word ptr ds:[bp].ptr_rx_CRC_errors+2
			jz	SkipCrcErrors
			les     bx, ds:[bp].ptr_rx_CRC_errors
			add     es:[bx], ax
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
SkipCrcErrors:		pop     ax
			pop     es

CheckFAE:               test    al, RSR_FAE
			jz      CheckFO

;---------------------- Update Frame Alignment Error Counter
			push    es
			push    ax
			xor     ax, ax
			mov	al, es:[REG_OFFSET+REG_CNTR0]
			mov	bx, word ptr ds:[bp].ptr_rx_align_errors
			or	bx, word ptr ds:[bp].ptr_rx_align_errors+2
			jz	SkipRxAlign
			les     bx, ds:[bp].ptr_rx_align_errors
			add     es:[bx], ax
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
SkipRxAlign:
			pop     ax
			pop     es

CheckFO:                test    al, RSR_FO
			jz      CheckMPA

;---------------------- Update Rx Overrrun Error Counter
			push    es
			mov	bx, word ptr ds:[bp].ptr_rx_overruns
			or	bx, word ptr ds:[bp].ptr_rx_overruns+2
			jz	SkipRxOvrns
			les     bx, ds:[bp].ptr_rx_overruns
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
SkipRxOvrns:		pop     es

CheckMPA:               test    al, RSR_MPA
			jz      RXErrorDone

;---------------------- Update Lost Packets Counter
			push    es
			push    ax
			xor     ax, ax
			mov	al, es:[REG_OFFSET+REG_CNTR2]
			mov	bx, word ptr ds:[bp].ptr_rx_lost_pkts
			or	bx, word ptr ds:[bp].ptr_rx_lost_pkts+2
			jz	SkipLostPkts
			les     bx, ds:[bp].ptr_rx_lost_pkts
			add     es:[bx], ax
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
SkipLostPkts:		pop     ax
			pop     es

RXErrorDone:		test    ds:[bp].receive_mask, ACCEPT_ERR_PACKETS
			jz	DontGetBadPackets
			jmp	HandlePRX
DontGetBadPackets:	jmp     CheckNextInt

;---------------------- Handle Ring Overwrite
HandleOVW:
			mov	bx, word ptr ds:[bp].ptr_ring_OVW
			or	bx, word ptr ds:[bp].ptr_ring_OVW+2
			jz	OvwCntrPtrZero

			push	es
			les     bx, ds:[bp].ptr_ring_OVW
			add     word ptr es:[bx], 1
ifndef	COUNTER16
			adc     word ptr es:[bx+2], 0
endif
			pop	es

OvwCntrPtrZero:		mov     ds:[bp].ring_ovw, 1
			jmp     HandlePRX
NotNICInterrupt:
			cli
			mov     ax, NOT_MY_INTERRUPT
			cmp     ds:[bp].hdw_int, 0
			jne     IsHardwareInt
			cmp     ds:[bp].servicing_ints, 0
			je      NotMyInt
			mov     ds:[bp].servicing_ints, 0
			jmp     ServEvDone

IsHardwareInt:          mov     ds:[bp].hdw_int, 0
			and	byte ptr es:[REG_OFFSET+REG_MSR], 0FEh
			call    UM_Interrupt

ServEvDone:             mov     ax, SUCCESS

NotMyInt:
;			and	byte ptr es:[REG_OFFSET+REG_MSR], 0FCh		; Put NIC to sleep.
			popf
			pop     es
			pop     ds
			pop	si
			pop	di
			pop     dx
			pop	cx
			pop     bx
			ret

ASM_PCM_PROC_END    LM_Service_Events

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       LM_Receive_Copy Copies data from adapter shared RAM to
;                               a Data buffer structure.
;
;       Entry:              CX  == bytes to move
;                           AX  == Offset in shared RAM
;               ES:SI  == Pointer to data buffer structure
;               DS:BP  == Pointer to adapter structure
;
;       Return:             AX == Return code. High 16 bits of EAX
;                                 altered if CODE386 is defined.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ASM_PCM_PROC    LM_Receive_Copy

		push    bp                      ; Save regs
		push    ds
		push    es
		push    si
		push    di
		push    bx
		push    cx
		push    dx

		mov     bh, ds:[bp].local_nxtpkt_ptr
		mov     bl, NIC_HEADER_SIZE
		add     bx, ax			; Add in offset in AX.

		cld                             ;make sure we increment

;		sub	bx, SHMEM_NIC_OFFSET
; Save offset of pkt in shared memory.

		cmp	bh, ds:[bp].pstop_hold
		jb	PktOffsetOk
		sub	bh, ds:[bp].pstop_hold
		add	bh, ds:[bp].pstart_hold
PktOffsetOk:
		mov     ds:[bp].packet_offset, bx

		mov     dx, es:[si].fragment_count      ; Get # of frags in DX
		lea     bx, es:[si].fragment_list       ; ES:BX = 1st frag str.
		xor     ah, ah

		mov     ds:[bp].byte_cnt, cx            ; Save total byte cnt.
fragment_loop2:
		cmp     ds:[bp].byte_cnt, 0
		jg      move_more
		jmp     no_more_frags2
move_more:      push    es
		push    bx
		mov     cx, es:[bx].fragment_length
		jcxz	NearZeroLenFrag
		cmp     ds:[bp].byte_cnt, cx
						; Subtract this fragment's
						; count from total count.
		ja      count_ok                ; If fragment byte count is >
		mov     cx, ds:[bp].byte_cnt    ; remaining byte count (last
						; fragment) use byte count,
						; else use fragment count.

count_ok:       sub     ds:[bp].byte_cnt, cx
		push    ax                      ; save AX for later
		mov     ah, ds:[bp].pstop_hold
		xor     al, al                  ; Subtract
;		sub	ax, SHMEM_NIC_OFFSET
		sub     ax, cx                  ; this count from pstop
						; If current ptr is >=, ring is
						; wrapped.
		cmp     ds:[bp].packet_offset, ax
		jna     no_ring_wrap            ;
		mov     ds:[bp].wr_frag_cnt, cx ; save fragment count
		mov     ch, ds:[bp].pstop_hold
		xor     cl, cl
;		sub	cx, SHMEM_NIC_OFFSET
; calculate leftover count
		sub     cx, ds:[bp].packet_offset
		sub     ds:[bp].wr_frag_cnt, cx ; Save for later.
no_ring_wrap:
		pop     ax
		les     di, es:[bx].fragment_ptr ; ES == far ptr to fragment.
continue_copy:
		or      ah, ah
		jz      no_leftover2
		mov     bx, ds:[bp].leftover_data
		mov     byte ptr es:[di], bh

		inc     di
		jcxz	DecWrFragCnt1
		dec     cx	
		jmp	no_leftover2
NearZeroLenFrag:
		jmp	ZeroLenFrag
DecWrFragCnt1:	dec	ds:[bp].wr_frag_cnt
no_leftover2:
		push    si
		push    ds
		mov     si, ds:[bp].packet_offset
		test	si, 1
		jz	EvenPtr

		mov	bx, word ptr ds:[bp].ram_access.2
		mov     ds, bx
		mov	bx, ds:[si-1]
		mov	es:[di], bh
		pop	ds	  	; Restore DS:BP ptr to adap struc
		push	ds		; Push back on stack
		inc	si
		inc	di
		mov	bx, si
;		add	bx, SHMEM_NIC_OFFSET
		cmp	bh, ds:[bp].pstop_hold
		jne	PtrOK
		xor	bx, bx
		mov	bh, ds:[bp].pstart_hold
		mov	si, bx
;		sub	si, SHMEM_NIC_OFFSET
PtrOK:		jcxz	DecWrFragCnt2
		dec     cx	    
		jmp	EvenPtr
DecWrFragCnt2:	dec	ds:[bp].wr_frag_cnt
	    	
EvenPtr:	push    ax
		push    cx

		mov     ax, word ptr ds:[bp].ram_access.2
		mov     ds, ax
		pop     cx
		pop     ax

		shr     cx, 1
		jz      short_frag2
ifdef	KLUDGE_PATCH
		push	ax
KludgeRecLoop:
		lodsw
		nop
		nop
		stosw
		loop	KludgeRecLoop
		pop	ax
else
		rep     movsw
endif
short_frag2:
		jnc     show_no_leftover2
		mov     bx, word ptr ds:[si]
		inc     si
		inc     si
		mov     byte ptr es:[di], bl
		inc     di
		mov     ah, 0ffh
		jmp     short check_for_more_frags2
show_no_leftover2:
		xor     ah, ah
check_for_more_frags2:
		pop     ds
		mov     ds:[bp].leftover_data, bx
		mov     ds:[bp].packet_offset, si
		pop     si
		cmp     ds:[bp].wr_frag_cnt, 0
		je      ring_not_wrapped
		mov     cx, ds:[bp].wr_frag_cnt ; Get byte count of wrapped
		mov     ds:[bp].wr_frag_cnt, 0  ; data starting at pstart and
						; clear wrapped frag count.
		push    ax                      ; save AX
		mov     ah, ds:[bp].pstart_hold
		xor     al, al                  ; Get pstart in SI. Pstart_hold
;		sub	ax, SHMEM_NIC_OFFSET
		mov     ds:[bp].packet_offset, ax       ; is bits 8-15. 
		pop     ax
		jmp     continue_copy           ; Finish copying to this frag.
ring_not_wrapped:
;		mov     ds:[bp].leftover_data, bx
ZeroLenFrag:
		pop     bx
		pop     es
		add     bx, size FragmentStructure
		dec     dx                      ; Decrement fragment count.
		jz      no_more_frags2
		jmp     fragment_loop2
no_more_frags2:
		mov	ax, SUCCESS
		cmp     ds:[bp].byte_cnt, 0
		je      byte_count_ok
		mov     ax, OUT_OF_RESOURCES
byte_count_ok:
		pop     dx                      ; restore regs.
		pop     cx
		pop     bx
		pop     di
		pop     si
		pop     es
		pop     ds
		pop     bp
		ret

ASM_PCM_PROC_END    LM_Receive_Copy

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       LM_Close_Adapter        Closes adapter whose adapter structure is
;                               indicated by DS:BP.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ASM_PCM_PROC    LM_Close_Adapter

		push	cx
		push    dx
		push	si
		push	es

		mov     es, word ptr ds:[bp].ram_access+2
		or	byte ptr es:[REG_OFFSET+REG_MSR], 02h		; Wake up NIC.

ifndef	EZSTART
		cmp     ds:[bp].adapter_status, NOT_INITIALIZED
		jne	StatusOK
		mov	ax, ADAPTER_NOT_INITIALIZED
		jmp	NoStatusChange
endif

StatusOK:	mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_STP+CMD_RD2
		mov	cx, -1
		jmp	$+2

LM_CA_wait:	test	byte ptr es:[REG_OFFSET+REG_ISR], ISR_RST
		jmp	$+2
		jnz	LM_CA_NIC_Reset
		loop	LM_CA_wait

LM_CA_NIC_Reset:
		and	byte ptr es:[REG_OFFSET+REG_MSR], 0FCh	; Put NIC to sleep . . .
		jmp	$+2
		test	ds:[bp].adapter_flags, PERM_CLOSE
		jz	TemporaryClose

		push	es	; Save shared memory segment/selector.

; ES:SI & DS:SI -> adapter structure for AdjustResInfo and RelPcm* calls below.

		mov	si, bp
		push	ds
		pop	es

		cmp	ds:[bp].adapter_status, CARD_REMOVED
		jne	DontAddResource

; If card was inserted the first time, add the resources that were used
; before releasing the configuration. If resources that were removed when
; the card was de-inserted are not added to card sevices resource list, they
; are gone forever (or until the machine is rebooted). Normally, we would not
; get here if the card was never inserted, but for the sake of robustness (and
; mis-behaved UMACs, we'll check it nonetheless.

		test	ds:[bp].pcm_card_flags, INSERTED
		jz	DontAddResource

		mov	al, ADD_RESOURCE
		call	AdjustResInfo

DontAddResource:
		call	RelPcmCfg
		call	RelPcmIrq
		call	RelPcmShMem
ifdef	LARGE
		call	far ptr DeRegPcmClient
else
		call	DeRegPcmClient
endif
		pop	es	; Restore shared memory segment/selector.

		and	ds:[bp].adapter_flags, not PERM_CLOSE

TemporaryClose:
		mov     ds:[bp].adapter_status, CLOSED
	       	call	UM_Status_Change
		and	byte ptr es:[REG_OFFSET+REG_SSR], not SSR_BNC	; Turn off BNC
LM_Close_Exit:
	       	mov     ax, SUCCESS             ; Set return code

NoStatusChange:	pop	es
		pop	si
		pop     dx
		pop	cx
		ret
ASM_PCM_PROC_END    LM_Close_Adapter

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       LM_Open_Adapter		Opens adapter whose adapter structure is
;                               indicated by DS:BP.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ASM_PCM_PROC    LM_Open_Adapter

		push    cx
		push    dx
		push	es

		mov     es, word ptr ds:[bp].ram_access+2
		or	byte ptr es:[REG_OFFSET+REG_MSR], 02h		; Wake up NIC.
		cmp     ds:[bp].adapter_status, NOT_INITIALIZED
		jne	CheckStat01
		mov	ax, ADAPTER_NOT_INITIALIZED
		jmp	LM_OADone
CheckStat01:	cmp     ds:[bp].adapter_status, INITIALIZED
	    	je      OKToOpen
		cmp     ds:[bp].adapter_status, OPEN
		je      AlreadyOpen
DoInit:
ifdef   EZSTART
		call	far ptr ETH_LM_Initialize_Adapter
else
ifdef	LARGE
		call	far ptr LM_Initialize_Adapter
else
		call	LM_Initialize_Adapter
endif
endif
		cmp	ax, SUCCESS
		je	OKToOpen
		mov	ax, OPEN_FAILED
		mov	ds:[bp].adapter_status, FAILED
		jmp	LM_OADone
OKToOpen:
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_STA+CMD_RD2
		mov     al, 0
		mov     cx, ds:[bp].mode_bits
		test    cx, MANUAL_CRC
		jz      OpenAdap01
		mov     al, TCR_CRC
OpenAdap01:	mov	es:[REG_OFFSET+REG_TCR], al
		mov     ds:[bp].adapter_status, OPEN
		call	UM_Status_Change
AlreadyOpen:	mov     ax, SUCCESS             ; Set return code

LM_OADone:

;;; Create a time delay for IBM DOS socket services to get a clue ...

                mov     cx, 0FFFFh
                push    ax              ; Save return code
LazyLoop:
                mov     dx, 0a1h
                in      al, dx
                in      al, dx
                in      al, dx
                in      al, dx
                in      al, dx
                loop    LazyLoop
                pop     ax              ; Restore return code

;;; After the delay, check the link integrity bit ...

		test	byte ptr es:[REG_OFFSET+REG_SSR], SSR_NLNK
		jz	LM_OA_Exit
		or	byte ptr es:[REG_OFFSET+REG_SSR], SSR_BNC	; Turn on BNC xceiver.
		
LM_OA_Exit:
;		and	byte ptr es:[REG_OFFSET+REG_MSR], 0FCh		; Put NIC to sleep.
		pop	es
		pop     dx
		pop     cx
		ret
ASM_PCM_PROC_END    LM_Open_Adapter

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       LM_Interrupt_Req        Generates a hardware interrupt from the
;                               adapter indicated by DS:BP.
;
;       Entry:  DS:BP	Pointer to adapter structure
;
;       Exit:   AX	SUCCESS
;			OUT_OF_RESOURCES If adapter has been disabled
;					 by LM_Disable_Adapter.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ASM_PCM_PROC    LM_Interrupt_Req

		push    dx
		push	es
		pushf
		cli                     ; Disable ints
		mov     es, word ptr ds:[bp].ram_access+2
		or	byte ptr es:[REG_OFFSET+REG_MSR], 02h		; Wake up NIC.
		mov     ds:[bp].int_bit, 0
		mov     ds:[bp].int_port, 0
		mov     ds:[bp].hdw_int, 0

		test	ds:[bp].adapter_flags, ADAPTER_DISABLED
		jnz	LM_Int_Disabled
		or	byte ptr es:[REG_OFFSET+REG_MSR], 01h
		mov     ds:[bp].hdw_int, 1
LM_Int_Enabled:
		mov     ax, SUCCESS
		jmp     IntReqDone
LM_Int_Disabled:
		mov	ax, OUT_OF_RESOURCES
		jmp	IntReqDone
IntReqDone:
;		and	byte ptr es:[REG_OFFSET+REG_MSR], 0FDh		; Put NIC to sleep.
		popf
		pop	es
		pop     dx
		ret

ASM_PCM_PROC_END    LM_Interrupt_Req

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;	UpdateCounters	Updates error counters to reflect current
;				NIC stats.
;
;	Entry:	DS:BP	Pointer to Adapter Structure.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
UpdateCounters	proc	near
		push	dx
		push	es
		push	bx
		xor	ax, ax

		mov     es, word ptr ds:[bp].ram_access+2
		mov	al, es:[REG_OFFSET+REG_CNTR0]

		mov	bx, word ptr ds:[bp].ptr_rx_align_errors
		or	bx, word ptr ds:[bp].ptr_rx_align_errors+2
		jz	RXA0
		les	bx, ds:[bp].ptr_rx_align_errors
		add	es:[bx], ax
ifndef	COUNTER16
		adc	word ptr es:[bx], 0
endif
		mov     es, word ptr ds:[bp].ram_access+2
		mov	al, es:[REG_OFFSET+REG_CNTR1]
RXA0:
		mov	bx, word ptr ds:[bp].ptr_rx_CRC_errors
		or	bx, word ptr ds:[bp].ptr_rx_CRC_errors+2
		jz	CRC0
		les	bx, ds:[bp].ptr_rx_CRC_errors
		add	es:[bx], ax
ifndef	COUNTER16
		adc	word ptr es:[bx], 0
endif
		mov     es, word ptr ds:[bp].ram_access+2
		mov	al, es:[REG_OFFSET+REG_CNTR2]

CRC0:		mov	bx, word ptr ds:[bp].ptr_rx_lost_pkts
		or	bx, word ptr ds:[bp].ptr_rx_lost_pkts+2
		jz	RxLP
		les	bx, ds:[bp].ptr_rx_lost_pkts
		add	es:[bx], ax
ifndef	COUNTER16
		adc	word ptr es:[bx], 0
endif
RxLP:		mov	ax, SUCCESS
		pop	bx
		pop	es
		pop	dx
		ret
UpdateCounters	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       load_node_address       Loads node address into adapter structure
;                               indicated by DS:BP
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ASM_PCM_PROC            load_node_address
		push    cx
		push	di
		push	si
		push	es
		mov     es, word ptr ds:[bp].ram_access+2

		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_STP+CMD_RD2+CMD_PAGE1
		lea	si, ds:[bp].node_address
		mov	di, REG_OFFSET+REG_PAR0
		mov	cx, 6
		repz	movsb
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_STP+CMD_RD2+CMD_PAGE0
NodeAddDone:
		pop	es
		pop	si
		pop	di
		pop     cx
		mov     ax, SUCCESS
		ret
ASM_PCM_PROC_END        load_node_address

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       enable_NIC_irq  Enables irq on 583 or 584-based adapter whose adapter
;                       structure is indicated by DS:BP
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ASM_PCM_PROC    enable_NIC_irq

		push    es
		mov     es, word ptr ds:[bp].ram_access+2
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_RD2
		jmp	$+2
		mov	al, ds:[bp].imr_hold
		mov	byte ptr es:[REG_OFFSET+REG_IMR], al
		mov     ax, SUCCESS		; return SUCCESS
		pop     es			; Restore regs
		ret

ASM_PCM_PROC_END enable_NIC_irq

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       disable_NIC_irq Disables IRQ on 58x-based adapter whose adapter
;                       structure is indicated by DS:BP
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ASM_PCM_PROC disable_NIC_irq
		push    es
		mov     es, word ptr ds:[bp].ram_access+2
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_RD2
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_IMR], 0
		mov     ax, SUCCESS		; return SUCCESS
		pop     es			; Restore regs
		ret

ASM_PCM_PROC_END disable_NIC_irq

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       init_nic        Initializes NIC on adapter whose adapter
;                       structure is indicated by DS:BP.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ASM_PCM_PROC    init_nic
		push    bx
		push    cx
		push    dx
		push    si                      ; Save regs used
		push	es

		mov     es, word ptr ds:[bp].ram_access+2

		or	byte ptr es:[REG_OFFSET+REG_MSR], 02h
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_STP+CMD_RD2
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_RBCR0], 0
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_RBCR1], 0
		jmp	$+2
		mov	cx, -1
init_nic_wait:
		test	byte ptr es:[REG_OFFSET+REG_ISR], ISR_RST
		jmp	$+2
		jnz	init_NIC_Reset
		loop	init_nic_wait
init_NIC_Reset:
		mov	byte ptr es:[REG_OFFSET+REG_DCR], DCR_FT1+DCR_LS+DCR_WTS

ifdef   EZSTART
		call    far ptr ETH_LM_Change_Receive_Mask
else
ifdef	LARGE
		call    far ptr LM_Change_Receive_Mask
else
		call    LM_Change_Receive_Mask
endif
endif

		mov	byte ptr es:[REG_OFFSET+REG_TCR], TCR_LB1
		mov     al, ds:[bp].tx_pstop
		mov     ds:[bp].pstart_hold, al
		mov	byte ptr es:[REG_OFFSET+REG_PSTART], al
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_BNRY], al

		mov     ax, ds:[bp].ram_size
		mov	ah, al
		shl     ah, 1
		shl     ah, 1           ; Multiply by 4 to get pstop_hold

		xor	al, al
;		add	ax, SHMEM_NIC_OFFSET
;		jnz	DontDecPstop
;		dec	ah
;DontDecPstop:
		mov     ds:[bp].pstop_hold, ah
		mov	byte ptr es:[REG_OFFSET+REG_PSTOP], ah
		jmp	$+2
		
		mov	byte ptr es:[REG_OFFSET+REG_ISR], 0FFh
		jmp	$+2

	;	mov     al, IMR_PRXE+IMR_PTXE+IMR_RXEE+IMR_TXEE+IMR_OVWE
	;	jmp	$+2
		mov     al, ds:[bp].imr_hold
		mov	byte ptr es:[REG_OFFSET+REG_IMR], al
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_STP+CMD_RD2+CMD_PAGE1
		
		push    bp              ; Load Physical Address regs
		mov     cx, 6
		mov	bx, REG_OFFSET+REG_PAR0
GetTheNodeAddress:
		mov     al, ds:[bp].node_address
		mov	es:[bx], al
		inc     bp
		inc     bx
		loop    GetTheNodeAddress
		pop     bp

;		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_PAGE0
;		jmp	$+2
		mov     al, ds:[bp].pstart_hold
		inc     al
		mov     ds:[bp].local_nxtpkt_ptr, al
		mov	byte ptr es:[REG_OFFSET+REG_CURR], al
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_STP+CMD_RD2
		mov     ds:[bp].tx_pend, 0

		pop	es
		pop     si                      ; Restore regs used
		pop     dx
		pop     cx
		pop     bx
		mov     ax, SUCCESS
		ret                     ; Return to caller
ASM_PCM_PROC_END    init_nic
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       reset_nic       Resets the NIC on the adapter whose adapter structure
;                       is indicated by DS:BP.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ASM_PCM_PROC            reset_nic

		push	es
		push	cx
		mov     es, word ptr ds:[bp].ram_access+2

		mov	al, es:[REG_OFFSET+REG_MSR]
		jmp	$+2
; Set reset bit
		or	byte ptr es:[REG_OFFSET+REG_MSR], MSR_RST

; Mask original data and write back after delay.

		and	al, 06h
		push	ax
		mov	cx, 1000h	; Delay count

; Time delay to create decent pulse width.
ResetNicPulseLoop:
		inc	ax
		push	ax
		pop	ax
		loop	ResetNicPulseLoop

		pop	ax
		mov	es:[REG_OFFSET+REG_MSR], al

; Time delay to allow 690 to recover. Hardware has cap on reset line.
		mov	cx, 1000h

ResetNicDelayLoop:
		inc	ax
		push	ax
		pop	ax
		loop	ResetNicDelayLoop

		mov     ax, SUCCESS
		pop	cx
		pop	es
		ret
ASM_PCM_PROC_END        reset_nic

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       set_MARs        Sets all 8 NIC Multicast Address Registers (REG_MAR0-7)
;                       to value in BL. All regs preserved, no return code.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ASM_PCM_PROC            set_MARs
		push    ax
		push    cx
		push    di
		push	es

		mov     es, word ptr ds:[bp].ram_access+2
		mov	bh, es:[REG_OFFSET+REG_CMD]
		jmp	$+2
		and     bh, CMD_PS0+CMD_PS1		; Save original page in BH
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_RD2+CMD_PAGE1	; Select page 1
		mov	di, REG_MAR0+REG_OFFSET
		mov     cx, 8
		mov	al, bl
		repz	stosb
		mov	es:[REG_OFFSET+REG_CMD], bh

		pop	es
		pop     di
		pop     cx
		pop     ax
		ret

ASM_PCM_PROC_END        set_MARs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       SendPacket      Sends packet of at offset 
;                       ds:[bp].tx_buffer in shared memory.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ASM_PCM_PROC            SendPacket
		push    ax
		push    bx
		push	cx
		push    si
		push	es

		mov     es, word ptr ds:[bp].ram_access+2
 		or	byte ptr es:[REG_OFFSET+REG_MSR], 02h		; Wake up NIC.
		jmp	$+2
		test	byte ptr es:[REG_OFFSET+REG_CMD], CMD_TXP
		jnz     NicPending
		xor     ax, ax                  ; get tx_buffer offset
		mov	al, ds:[bp].tx_head
		shl     ax, 1
		shl     ax, 1
		mov     si, ax
		mov	cx, word ptr ds:[bp+si].tx_buffer+2				
		mov	ax, word ptr ds:[bp+si].tx_buffer				
		mov	es:[REG_OFFSET+REG_TPSR], ah
		jmp	$+2
		mov	es:[REG_OFFSET+REG_TBCR0], cl
		jmp	$+2
		mov	es:[REG_OFFSET+REG_TBCR1], ch
		jmp	$+2
		mov	byte ptr es:[REG_OFFSET+REG_CMD], CMD_TXP
		clc
SendPacketDone:
		pop	es
		pop     si
		pop	cx
		pop     bx
		pop     ax
		ret

NicPending:	stc
		jmp     SendPacketDone

ASM_PCM_PROC_END        SendPacket



IFNDEF EZSTART

enable_59x_irq	proc	near
		ret
enable_59x_irq	endp

enable_585_irq	proc	near
		ret
enable_585_irq	endp

disable_59x_irq	proc	near
		ret
disable_59x_irq	endp

disable_585_irq	proc	near
		ret
disable_585_irq	endp

enable_ram	proc	near
		ret
enable_ram	endp

disable_ram	proc	near
		ret
disable_ram	endp
ENDIF


