Category : Network Files
Archive   : PKTD11A.ZIP
Filename : DE600.ASM

 
Output of file : DE600.ASM contained in archive : PKTD11A.ZIP
PAGE ,132
.286c
version equ 1

include defs.asm ;SEE ENCLOSED COPYRIGHT MESSAGE

;/* PC/FTP Packet Driver source, conforming to version 1.09 of the spec
;* Portions (C) Copyright 1990 D-Link, Inc.
;*
;* Permission is granted to any individual or institution to use, copy,
;* modify, or redistribute this software and its documentation provided
;* this notice and the copyright notices are retained. This software may
;* not be distributed for profit, either in original form or in derivative
;* works. D-Link, inc. makes no representations about the suitability
;* of this software for any purpose. D-LINK GIVES NO WARRANTY,
;* EITHER EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION
;* PROVIDED, INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY
;* AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
;*/

BIT0 EQU 01H
BIT1 EQU 02H
BIT2 EQU 04H
BIT3 EQU 08H
BIT4 EQU 10H
BIT5 EQU 20H
BIT6 EQU 40H
BIT7 EQU 80H

code segment byte public
assume cs:code, ds:code

; DE-600's I/O port Table
DAT equ 0
STAT equ 1
CMD equ 2

; DE-600's DATA port Command
WRITE equ 0004h ;write memory
READ equ 0104h ;read memory
STATUS equ 0204h ;read status register
COMMAND equ 0304h ;write command register
NUL_CMD equ 0ch ;null command
RX_LEN equ 0504h ;read Rx packet length
TX_ADR equ 0604h ;write Tx address
RW_ADR equ 0704h ;write memory address

;< COMMAND bits 7-0 >
RXEN equ 08h ; bit 3
TXEN equ 04h ; bit 2
LOOPBACK equ 0Ch ; RXEN=1, TXEN=1
RX_NONE equ 00h ; M1=0, M0=0 (bit 1,0)
RX_ALL equ 01h ; M1=0, M0=1
RX_BP equ 02h ; M1=1, M0=0
RX_MBP equ 03h ; M1=1, M0=1
RESET equ 80h ; set bit 7 high
STOP_RESET equ 00h ; set bit 7 low
; bit 6 -- IRQ inverse
; bit 5,4 -- Rx Page Number ( RA12=1, RA11=0 or 1 )

;< TX_ADR bit 7, bit 4 >
; bit 7 -- Tx Page Number ( TA11=0 or 1 )
; bit 4 -- Tx Page Number ( TA12=0 )
PAGE0 equ 00h
PAGE1 equ 08h
PAGE2 equ 10h
PAGE3 equ 18h

;< RW_ADR bit 7, bit 5,4 >
; bit 7 -- RW Page Number ( H11 =? )
; bit 4 -- RW Page Number ( H12 =? )
; bit 5 -- Address Maping ( HA13=0 => Memory, HA13=1 => Node Number )
HA13 equ 020h

; DE-600's CMD port Command
SLT_NIC equ 004h ;select Network Interface Card
SLT_PRN equ 01Ch ;select Printer
NML_PRN equ 0ECh ;normal Printer situation
IRQEN equ 010h ;enable IRQ line

; DE-600's STAT port bits 7-4
RXBUSY equ 80h
GOOD equ 40h
RESET_FLAG equ 20h
T16 equ 10h
TXBUSY equ 08h

BFRSIZ equ 2048 ;number of bytes in a buffer
PRNTABADD equ 408h ;DOS printer table address
RX_MIN_LEN equ 18 ;= EADDR_LEN + EADDR_LEN + TYPE_LEN + CRC

write_sub_delay macro reg
mov al,reg ;output the low nibble.
shl al,cl ;cl must be four.
or al,ch
xor al,08h ;raise the write line.
out dx,al
call delay

xor al,08h ;lower the write line
out dx,al
call delay

mov al,reg ;output the high nibble.
and al,not 0fh ;get us some zero bits.
or al,ch
out dx,al ;(write line is low).
call delay

xor al,08h ;raise the write line.
out dx,al
endm

write_sub_fast macro reg
mov al,reg ;output the low nibble.
shl al,cl ;cl must be four.
or al,ch
out dx,al

mov al,reg ;output the high nibble.
and al,not 0fh ;get us some zero bits.
or al,ch
xor al,08h ;raise the write line.
out dx,al ;(write line is low).
endm

write_sub_slow macro reg
mov al,reg ;output the low nibble.
shl al,cl ;cl must be four.
or al,ch
out dx,al
call delay

mov al,reg ;output the high nibble.
and al,not 0fh ;get us some zero bits.
or al,ch
xor al,08h ;raise the write line.
out dx,al ;(write line is low).
endm

read_sub_fast macro reg
setport DAT
mov al,ch
out dx,al
pause

setport STAT
in al,dx
mov reg,al
setport DAT
mov al,ch
xor al,08h
out dx,al
pause

setport STAT
in al,dx
shr reg,cl
and al,0f0h
or reg,al
endm


read_sub_slow macro reg
setport DAT
mov al,ch
out dx,al
call delay

setport STAT
in al,dx
mov reg,al
setport DAT
mov al,ch
xor al,08h
out dx,al
call delay

setport STAT
in al,dx
shr reg,cl
and al,0f0h
or reg,al
endm


read_sub_delay macro reg, first
setport DAT
mov al,ch
if first
xor al,08h
endif
out dx,al
call delay

if first
xor al,08h
out dx,al
call delay
endif

setport STAT
in al,dx
mov reg,al
setport DAT
mov al,ch
xor al,08h
out dx,al
call delay

setport STAT
in al,dx
shr reg,cl
and al,0f0h
or reg,al
endm


pause macro
jmp $+2
endm

public int_no
int_no db 7,0,0,0 ; IRQ interrupt number
io_addr dw 03bch,0 ; I/O address for card (jumpers)

public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK, IEEE8023, 0 ;from the packet spec
driver_type db 31 ;from the packet spec
driver_name db 'DE600',0 ;name of the driver
driver_function db 2
parameter_list label byte
db 1 ;major rev of packet driver
db 9 ;minor rev of packet driver
db 14 ;length of parameter list
db EADDR_LEN ;length of MAC-layer address
dw GIANT ;MTU, including MAC headers
dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
dw 0 ;(# of back-to-back MTU rcvs) - 1
dw 0 ;(# of successive xmits) - 1
int_num dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,

public rcv_modes
rcv_modes dw 7 ;number of receive modes in our table.
dw 0 ;There is no mode zero
dw rcv_mode_1
dw 0
dw rcv_mode_3
dw 0
dw rcv_mode_5
dw rcv_mode_6

CurTxPage db 08h ;the BL value when OUT DATA,TX_ADR
CurRxPage db 20h ;the BL value when OUT DATA,COMMAND
TxStartAdd dw ?
RxStartAdd dw ?
InitRxTxReg dw ?
RxPktLen dw ?
TxPktLen dw ?
Mode_RxPg db ?
Mode db RX_BP
IRQinverse db 0 ; = 40h for XT printer adapter
NICstatus db 0
In_ISR db 0
In_Tx db 0
printer dw 408h
PS2 db 0

our_type dw ?,?


public bad_command_intercept
bad_command_intercept:
;called with ah=command, unknown to the skeleton.
;exit with nc if okay, cy, dh=error if not.
mov dh,BAD_COMMAND
stc
ret

public as_send_pkt
; The Asynchronous Transmit Packet routine.
; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
; interrupts possibly enabled.
; Exit with nc if ok, or else cy if error, dh set to error number.
; es:di and interrupt enable flag preserved on exit.
as_send_pkt:
ret

public drop_pkt
; Drop a packet from the queue.
; Enter with es:di -> iocb.
drop_pkt:
assume ds:nothing
ret

public xmit
; Process a transmit interrupt with the least possible latency to achieve
; back-to-back packet transmissions.
; May only use ax and dx.
xmit:
assume ds:nothing
ret


public send_pkt
send_pkt:
;enter with ds:si -> packet, cx = packet length.
;exit with nc if ok, or else cy if error, dh set to error number.
assume ds:nothing
cmp cx,GIANT ; Is this packet too large?
ja send_pkt_toobig

;select DE-600
mov al,SLT_NIC
;*** CMD sub ***
loadport
setport CMD
out dx,al
;*** End CMD sub ***
mov In_Tx,1
call delay

cmp cx,RUNT ; minimum length for Ether
jae LengthOK
mov cx,RUNT ; make sure size at least RUNT
LengthOK:
inc cx
and cx,not 1

mov di,cx
;change Tx page to another free buffer
xor CurTxPage,08h

mov bx,offset send_pkt_pointer
jmp cs:[bx]

send_pkt_toobig:
mov dh,NO_SPACE
stc
ret

send_pkt_pointer dw offset send_pkt0

send_pkt0:
;set Tx Pointer for moving packet
mov ax,BFRSIZ
sub ax,cx ;AX = the pointer to TX
or ah,CurTxPage
mov TxStartAdd,ax ;save Current Tx Packet Start Address
mov bx,ax ;write memory address
mov cx,RW_ADR
setport DAT
write_sub_fast bl
write_sub_fast bh
cld
mov cx,WRITE ;write packet into memory
mov ah,ch
xor ah,08h
write_mem:
lodsb
mov bl,al
shl al,cl
or al,ch
out dx,al

mov al,bl
and al,0f0h
or al,ah
dec di
out dx,al
jnz write_mem

mov cx,4000h
setport STAT
wait_Tx_idle:
in al,dx
test al,TXBUSY ; Is the previous Tx successful ?
jz command_to_Tx ; Yes, TXBUSY is low. Then could Tx next packet.
loop wait_Tx_idle

command_to_Tx:
;set Tx Pointer at beginning of packet
mov bx,TxStartAdd
mov cx,TX_ADR
loadport
setport DAT
write_sub_fast bl
write_sub_fast bh

;Enable interrupt and start Tx
mov bl,Mode_RxPg
mov cx,COMMAND
write_sub_fast bl
or bl,TXEN
write_sub_fast bl

Exit_Send_Packet:
mov In_Tx,0

cmp In_ISR,0
jne using_NIC_now
mov al,SLT_PRN
loadport
setport CMD
out dx,al

cmp PS2,0
jnz using_NIC_now
setport STAT
in al,dx

and al,40h
xor al,IRQinverse
jz using_NIC_now
call trigger_int
using_NIC_now:
clc
ret


send_pkt1:
;set Tx Pointer for moving packet
mov ax,BFRSIZ
sub ax,cx ;AX = the pointer to TX
or ah,CurTxPage
mov TxStartAdd,ax ;save Current Tx Packet Start Address
mov bx,ax ;write memory address
mov cx,RW_ADR
loadport
setport DAT
write_sub_slow bl
call delay
write_sub_slow bh

cld
mov cx,WRITE ;write packet into memory
mov ah,ch
xor ah,08h
write_mem1:
lodsb
mov bl,al
shl al,cl
or al,ch
out dx,al
call delay

mov al,bl
and al,0f0h
or al,ah
dec di
out dx,al
call delay
jnz write_mem1

mov cx,4000h
setport STAT
wait_Tx_idle1:
in al,dx
test al,TXBUSY ; Is the previous Tx successful ?
jz command_to_Tx1 ; Yes, TXBUSY is low. Then could Tx next packet.
loop wait_Tx_idle1

command_to_Tx1:
;set Tx Pointer at beginning of packet
mov bx,TxStartAdd
mov cx,TX_ADR
loadport
setport DAT
write_sub_slow bl
call delay
write_sub_slow bh
call delay

;Enable interrupt and start Tx
mov bl,Mode_RxPg
mov cx,COMMAND
write_sub_slow bl
call delay
or bl,TXEN
write_sub_slow bl
jmp Exit_Send_Packet


send_pkt2:
;set Tx Pointer for moving packet
mov ax,BFRSIZ
sub ax,cx ;AX = the pointer to TX
or ah,CurTxPage
mov TxStartAdd,ax ;save Current Tx Packet Start Address
mov bx,ax ;write memory address
mov cx,RW_ADR
loadport
setport DAT
write_sub_delay bl
call delay
write_sub_delay bh
cld
mov cx,WRITE ;write packet into memory
write_mem2:
lodsb
mov bl,al ;except for this line,
shl al,cl ; it's write_sub_delay
or al,ch
xor al,08h
out dx,al
call delay

xor al,08h
out dx,al
call delay

mov al,bl
and al,0f0h
or al,ch
out dx,al
call delay

xor al,08h
out dx,al
call delay
dec di
jnz write_mem2

mov cx,4000h
setport STAT
wait_Tx_idle2:
in al,dx
test al,TXBUSY ; Is the previous Tx successful ?
jz command_to_Tx2 ; Yes, TXBUSY is low. Then could Tx next packet.
loop wait_Tx_idle2

command_to_Tx2:
;set Tx Pointer at beginning of packet
mov bx,TxStartAdd
mov cx,TX_ADR
loadport
setport DAT
write_sub_delay bl
call delay
write_sub_delay bh
call delay

;Enable interrupt and start Tx
mov bl,Mode_RxPg
mov cx,COMMAND
write_sub_delay bl
call delay
or bl,TXEN
write_sub_delay bl
jmp Exit_Send_Packet


trigger_int:
mov al,SLT_NIC
call CMD_sub

mov bl,Mode_RxPg
xor bl,BIT6
mov cx,COMMAND
call Write_sub

mov al,SLT_PRN
call CMD_sub

call delay
call delay

mov al,SLT_NIC
call CMD_sub

mov bl,Mode_RxPg
mov cx,COMMAND
call Write_sub
ret


rcv_mode_1:
mov cl,RX_NONE
jmp short set_RXCR
rcv_mode_3:
mov cl,RX_BP
jmp short set_RxCR
rcv_mode_5:
mov cl,RX_MBP
jmp short set_RxCR
rcv_mode_6:
mov cl,RX_ALL
set_RxCR:
mov Mode,cl
mov bl,cl
or bl,CurRxPage ; Add original Rx Page
mov Mode_RxPg,bl ; Save Rx Mode & Rx Page
;select DE-600
loadport
setport CMD
in al,dx
pause
test al,BIT4
jz in_IC_mode
;not active, we have to put a wrapper around it.
mov al,int_no
call maskint

mov al,SLT_NIC ;turn on the NIC.
call CMD_sub
call in_IC_mode ;now we're in the right mode.
mov al,SLT_PRN ;turn on the PRN.
call CMD_sub

mov al,int_no
call unmaskint
ret

in_IC_mode:
mov cx,COMMAND ; Set new Rx Mode
call Write_sub
ret


extrn maskint : near
extrn unmaskint : near

public set_address
set_address:
;Set Ethernet address on controller
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
;
assume ds:nothing
cmp cx,EADDR_LEN ;make sure that we have enough room.
je can_set_address
mov dh,BAD_ADDRESS
stc
jmp set_address_none

;select DE-600
can_set_address:
loadport
setport CMD
in al,dx
push ax
test al,BIT4
jz IC_mode

mov al,int_no
call maskint
mov al,SLT_NIC
call CMD_sub
IC_mode:
mov cx,RW_ADR
xor bl,bl
call Write_sub
or bl,HA13
call Write_sub

cld
mov bp,cs
mov es,bp

mov di,EADDR_LEN
mov cx,WRITE
set_our_address:
lodsb
mov bl,al
call Write_sub
dec di
jnz set_our_address

pop ax
test al,BIT4
jz IC_mode1

mov al,SLT_PRN
call CMD_sub
mov al,int_no
call unmaskint
IC_mode1:
clc
set_address_none:
push cs
pop ds
assume ds:code
ret


public set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, ax = number of addresses,
; cx = number of bytes.
;return nc if we set all of them, or cy,dh=error if we didn't.
mov dh,NO_MULTICAST
stc
ret


public terminate
terminate:
ret


public reset_interface
reset_interface:
mov al,int_no
call maskint
;select DE-600

mov al,SLT_NIC
call CMD_sub

; Pulse IE_RESET
mov bl,RESET
mov cx,COMMAND
call Write_sub
mov bl,STOP_RESET
call Write_sub

; Initialize Rx buffer pointer, and start receive
mov bl,Mode_RxPg
mov cx,COMMAND
call Write_sub
or bl,RXEN
call Write_sub

; Enable Printer Adapter IRQ line
mov al,SLT_PRN
call CMD_sub

mov al,int_no
call unmaskint
ret


assume ds:nothing
Write_sub:
loadport
setport DAT
write_sub_delay bl
ret

Read_sub:
loadport
setport DAT
mov al,ch
xor al,08h
out dx,al
call delay

xor al,08h
out dx,al
call delay

setport STAT
in al,dx
mov bl,al
test ch,BIT1
jz not_READ_STATUS
dec dx
mov al,NUL_CMD
xor al,08h
out dx,al
call delay

xor al,08h
out dx,al
jmp short End_read
not_READ_STATUS:
setport DAT
mov al,ch
xor al,08h
out dx,al
call delay

setport STAT
in al,dx
shr bl,cl
and al,0f0h
or bl,al
End_read:
ret

CMD_sub:
loadport
setport CMD
out dx,al
ret

delay:
nop ; pointer 0
nop ; 1
nop ; 2
nop ; 3
nop ; 4
nop ; 5
nop ; 6
nop ; 7
nop ; 8
nop ; 9
ret

;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.
extrn recv_find: near

;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
extrn recv_copy: near

extrn count_in_err: near
extrn count_out_err: near

recv_pointer dw offset recv0

public recv
recv:
;called from the recv isr. All registers have been saved, and ds=cs.
;Upon exit, the interrupt will be acknowledged.
assume ds:code
;select DE-600
mov al,SLT_NIC
;*** CMD sub ***
loadport
setport CMD
out dx,al
;*** End CMD sub ***
;set watch dog
mov In_ISR,1
call delay

;Check the interrupt source, Rx or Tx ?
mov cx,STATUS ; Read NIC Status Register
;*** Read sub ***
setport DAT
mov al,ch
out dx,al
pause
setport STAT
in al,dx
;*** End Read sub ***

jmp recv_pointer

recv0:
mov NICstatus,al ; save NIC status
setport DAT
test al,GOOD ; Is Rx generating interrupt ?
mov al,NUL_CMD
out dx,al
jnz Rx_Good_Pkt ; Yes, take care of this situation.
mov al,NICstatus
test al,RXBUSY
jz Enable_Rx
jmp CheckTx

Enable_Rx:
;change Rx page & enable NIC to Rx
mov bl,Mode_RxPg
mov cx,COMMAND
setport DAT
write_sub_fast bl
or bl,RXEN
write_sub_fast bl
jmp CheckTx

Rx_Good_Pkt:
;Put it on the receive queue
mov cx,RX_LEN ; read Rx Packet Length
loadport
read_sub_fast bl
read_sub_fast bh

sub bx,4 ;subtrate 4 CRC Byte Count
mov RxPktLen,bx ;save Rx Packet Length

;change Rx page & enable NIC to Rx
xor Mode_RxPg,10h
mov bl,Mode_RxPg
mov cx,COMMAND
setport DAT
write_sub_fast bl
or bl,RXEN
write_sub_fast bl
xor bx,bx
mov bh,CurRxPage ;BL = Current Rx Page
xor CurRxPage,10h ;change to next page for Rx
shr bx,1 ;shift BX to real memory address
mov RxStartAdd,bx ;save just Rx Packet Start Address

add bx,EADDR_LEN+EADDR_LEN ;seek to the TYPE word
mov cx,RW_ADR
write_sub_fast bl
write_sub_fast bh
pause
mov cx,READ ;read the TYPE word
read_sub_fast bl
read_sub_fast bh

mov our_type,bx ;save the TYPE word

mov cx,READ ;read the TYPE word
read_sub_fast bl
read_sub_fast bh

mov our_type[2],bx ;save the TYPE word

mov ax,ds
mov es,ax
mov di,offset our_type
mov cx,RxPktLen

mov dl, BLUEBOOK ;assume bluebook Ethernet.
mov ax, es:[di]
xchg ah, al
cmp ax, 1500
ja BlueBookPacket
inc di ;set di to 802.2 header
inc di
mov dl, IEEE8023
BlueBookPacket:
call recv_find ;request a Rx buffer to store Rx data

mov ax,es ;is this pointer null?
or ax,di
jnz find_buffer
jmp short CheckTx ;yes - just free the frame.
find_buffer:
push es
push di ;remember where the buffer pointer is.
assume ds:nothing
mov bx,RxStartAdd
mov cx,RW_ADR
loadport
setport DAT
write_sub_fast bl
write_sub_fast bh

cld
mov bp,RxPktLen ;CX = the byte count of Rx Packet
setport STAT
mov cx,READ
mov ah,ch
xor ah,08h
read_mem:
setport DAT
mov al,ch ;output our read request.
out dx,al
pause

setport STAT
in al,dx ;input four bits into bl.
mov bl,al
setport DAT ;now output the inverse read request.
mov al,ah
out dx,al
pause

setport STAT
in al,dx ;input the high four bits.
shr bl,cl
and al,0f0h
or al,bl ;combine the two nibbles.
stosb
dec bp
jnz read_mem

RxCopy_CheckTx:
pop si
pop ds
mov cx,RxPktLen

call recv_copy ;tell them that we copied it.

mov ax,cs ;restore our ds.
mov ds,ax
assume ds:code

CheckTx:
test NICstatus,T16 ; Is pending a Tx Packet ?
jz return ; No, then return.
; Yes, send this packet.
;set Tx Pointer at beginning of packet
mov bx,TxStartAdd
mov cx,TX_ADR
call Write_sub
xchg bh,bl
call Write_sub

;Enable interrupt and start Tx
mov bl,Mode_RxPg
mov cx,COMMAND
call Write_sub
or bl,TXEN
call Write_sub
return:
mov al,SLT_PRN
;*** CMD sub ***
loadport
setport CMD
out dx,al
;*** End CMD sub ***

cmp PS2,0
jnz Rx_another_pkt
setport STAT
in al,dx
and al,40h
xor al,IRQinverse
jz Rx_another_pkt
call trigger_int
Rx_another_pkt:
mov In_ISR,0
ret


recv1:
assume ds:code
mov NICstatus,al ; save NIC status
loadport
setport DAT
test al,GOOD ; Is Rx generating interrupt ?
mov al,NUL_CMD
out dx,al
jnz Rx_Good_Pkt1 ; Yes, take care of this situation.
mov al,NICstatus
test al,RXBUSY
jz Enable_Rx1
jmp CheckTx ; No, go to check Tx.

Enable_Rx1:
;change Rx page & enable NIC to Rx
mov bl,Mode_RxPg
mov cx,COMMAND
setport DAT
write_sub_slow bl
call delay
or bl,RXEN
write_sub_slow bl
jmp CheckTx

Rx_Good_Pkt1:
;Put it on the receive queue
mov cx,RX_LEN ; read Rx Packet Length
loadport
read_sub_slow bl
read_sub_slow bh

sub bx,4 ;subtrate 4 CRC Byte Count
mov RxPktLen,bx ;save Rx Packet Length

;change Rx page & enable NIC to Rx
xor Mode_RxPg,10h
mov bl,Mode_RxPg
mov cx,COMMAND
setport DAT
write_sub_slow bl
call delay
or bl,RXEN
write_sub_slow bl
call delay
xor bx,bx
mov bh,CurRxPage ;BL = Current Rx Page
xor CurRxPage,10h ;change to next page for Rx
shr bx,1 ;shift BX to real memory address
mov RxStartAdd,bx ;save just Rx Packet Start Address

add bx,EADDR_LEN+EADDR_LEN ;seek to the TYPE word
mov cx,RW_ADR
write_sub_slow bl
call delay
write_sub_slow bh
call delay
mov cx,READ ;read the TYPE word

read_sub_slow bl
read_sub_slow bh

mov our_type,bx ;save the TYPE word

mov ax,ds
mov es,ax
mov di,offset our_type
mov cx,RxPktLen

call recv_find ;request a Rx buffer to store Rx data

mov ax,es ;is this pointer null?
or ax,di
jnz find_buffer1
jmp CheckTx ;yes - just free the frame.
find_buffer1:
push es
push di ;remember where the buffer pointer is.
assume ds:nothing
mov bx,RxStartAdd
mov cx,RW_ADR
loadport
setport DAT
write_sub_slow bl
call delay
write_sub_slow bh
call delay

cld
mov bp,RxPktLen ;CX = the byte count of Rx Packet
setport STAT
mov cx,READ
mov ah,ch
xor ah,08h
read_mem1:
dec dx
mov al,ch
out dx,al
call delay

inc dx
in al,dx
mov bl,al
dec dx
mov al,ah
out dx,al
call delay

inc dx
in al,dx
shr bl,cl
and al,0f0h
or al,bl
stosb
dec bp
jnz read_mem1
jmp RxCopy_CheckTx


recv2:
assume ds:code
mov NICstatus,al ; save NIC status
loadport
setport DAT
test al,GOOD ; Is Rx generating interrupt ?
mov al,NUL_CMD
out dx,al
jnz Rx_Good_Pkt2 ; Yes, take care of this situation.
mov al,NICstatus
test al,RXBUSY
jz Enable_Rx2
jmp CheckTx ; No, go to check Tx.

Enable_Rx2:
;change Rx page & enable NIC to Rx
mov bl,Mode_RxPg
mov cx,COMMAND
setport DAT
write_sub_delay bl
call delay
or bl,RXEN
if 0
write_sub_delay bl
else
mov al,bl
shl al,cl
or al,ch
xor al,08h
out dx,al
call delay

xor al,08h
out dx,al
call delay

mov al,bl
and al,0f0h
or al,ch
xor al,08h
out dx,al
endif
jmp CheckTx

Rx_Good_Pkt2:
;Put it on the receive queue
mov cx,RX_LEN ; read Rx Packet Length
loadport

read_sub_delay bl, 1
read_sub_delay bh, 0

sub bx,4 ;subtrate 4 CRC Byte Count
mov RxPktLen,bx ;save Rx Packet Length

;change Rx page & enable NIC to Rx
xor Mode_RxPg,10h
mov bl,Mode_RxPg
mov cx,COMMAND
setport DAT
write_sub_delay bl
call delay
or bl,RXEN
write_sub_delay bl
call delay

xor bx,bx
mov bh,CurRxPage ;BL = Current Rx Page
xor CurRxPage,10h ;change to next page for Rx
shr bx,1 ;shift BX to real memory address
mov RxStartAdd,bx ;save just Rx Packet Start Address

add bx,EADDR_LEN+EADDR_LEN ;seek to the TYPE word
mov cx,RW_ADR
write_sub_delay bl
call delay
write_sub_delay bh
call delay

mov cx,READ ;read the TYPE word

read_sub_delay bl, 1
read_sub_delay bh, 0
mov our_type,bx ;save the TYPE word

mov ax,ds
mov es,ax
mov di,offset our_type
mov cx,RxPktLen

call recv_find ;request a Rx buffer to store Rx data

mov ax,es ;is this pointer null?
or ax,di
jnz find_buffer2
jmp CheckTx ;yes - just free the frame.
find_buffer2:
push es
push di ;remember where the buffer pointer is.
assume ds:nothing
mov bx,RxStartAdd
mov cx,RW_ADR
loadport
setport DAT
write_sub_delay bl
call delay
write_sub_delay bh
call delay

cld
mov bp,RxPktLen ;CX = the byte count of Rx Packet
setport STAT
mov cx,READ
mov ah,ch
xor ah,08h
read_mem2:
dec dx
mov al,ch
out dx,al
call delay

inc dx
in al,dx
mov bl,al
dec dx
mov al,ah
out dx,al
call delay

inc dx
in al,dx
shr bl,cl
and al,0f0h
or al,bl
stosb
dec bp
jnz read_mem2
jmp RxCopy_CheckTx


public end_resident,end_free_mem
end_resident label byte
end_free_mem label byte
public timer_isr
timer_isr:
;if the first instruction is an iret, then the timer is not hooked
iret

;any code after this will not be kept after initialization.

public usage_msg
usage_msg db "usage: DE600 [options] ",CR,LF,'$'

public copyright_msg
copyright_msg db "Packet driver for the D-Link DE-600, "
db "version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF,'$'
db "Portions Copyright 1988, Robert C. Clements, K1BC"
db CR,LF,'$'

CableErr db "Bad cable connection.",07,CR,LF,'$'
mem_error_msg db "Adapter memory buffer failure, or bad printer "
db "port connection.",07,CR,LF,'$'
irq_error_msg db "IRQ unavailable, please check other hardware in "
db "computer.",07,CR,LF,'$'
no_NIC_err db "Adapter not found, or AC adapter power is off.",07,CR,LF,'$'

extrn set_recv_isr: near

;enter with si -> argument string, di -> word to store.
;if there is no number, don't change the number.
extrn get_number: near

;enter with dx -> name of word, di -> dword to print.
extrn print_number: near

;-> the assigned Ethernet address of the card.
extrn rom_address: byte

assume ds:code
public parse_args
parse_args:
ret


public print_parameters
print_parameters:
ret

cable_err:
mov dx,offset CableErr
stc
ret
IRQ_error:
mov dx,offset irq_error_msg
stc
ret
no_our_NIC:
mov dx,offset no_NIC_err
stc
ret

public etopen
etopen:
; Initialize the Ethernet board.
call check_PS2

xor ax,ax
mov es,ax
mov si,PRNTABADD-2 ; point to printer table at low memory
next_prn_port:
add si,2
mov bx,es:[si] ; get LPTx's I/O Base
or bx,bx ; Does LPTx really exist ?
jz Chk_out_of_range
mov io_addr,bx ; save the I/O Base number
mov printer,si ; memorize it's LPTx now
call Check_DE600 ; Yes, BX = I/O Base, then check.
jnc IO_good ; If carry flag is clear, so go to
mov al,NML_PRN
call CMD_sub
Chk_out_of_range:
cmp si,PRNTABADD+6 ; We still miss our card from LPT1 to
jb next_prn_port
jmp short no_our_NIC ; We still miss our card from LPT1 to
; LPT4. We give it up.
IO_good:
; Copy our Ethernet address from PROM into DE600.
push ds
pop es
mov di,offset rom_address
mov cx,RW_ADR
xor bl,bl
call Write_sub
or bl,HA13
call Write_sub

cld
mov bp,EADDR_LEN
mov cx,READ
get_our_address:
call Read_sub
mov al,bl
stosb
dec bp
jnz get_our_address

mov si,offset rom_address ;make sure it's got the right magic
cmp word ptr es:[si],0de00h ; number.
jne no_our_NIC
cmp byte ptr es:[si+2],15h
jne no_our_NIC

mov word ptr es:[si],8000h ;now modify it to the address assigned
mov byte ptr es:[si+2],0c8h ; by Xerox.
and byte ptr es:[si+3],0fh
or byte ptr es:[si+3],070h

mov cx,EADDR_LEN
call set_address

; Check DE600's IRQ enviroment
call Check_IRQ
cmp bx,1
je cable_OK
jmp cable_err

cable_OK:
mov bx,offset delay
mov byte ptr [bx],0c3h ; ret

; test 8 KBytes memory
;********** write mode 1 *************
mov cx,700h
mov al,PAGE3
call Write_LoopBack_Data
xor bx,bx
mov si,bx
write_next_page:
call Tx_Data
push bx
mov cx,RW_ADR
loadport
setport DAT
write_sub_fast bl
write_sub_fast bh

mov bx,si
mov bp,800h
mov cx,WRITE
mov ah,ch
xor ah,08h
wr_this_page:
mov al,bl
shl al,cl
or al,ch
out dx,al
mov al,bl
and al,0f0h
or al,ah
out dx,al
inc bl
dec bp
jnz wr_this_page
inc si
pop bx
add bx,800h
cmp bx,1800h
ja read_memory
jmp short write_next_page

;************ read mode 1 ************
read_memory:
loadport
setport DAT
xor bx,bx
mov si,bx
read_next_page:
push bx
mov cx,RW_ADR
write_sub_fast bl
write_sub_fast bh

mov bx,si
mov bp,800h
mov cx,READ
mov ah,ch
xor ah,08h
rd_this_page:
mov al,ch
out dx,al
pause
inc dx
in al,dx
mov bh,al
dec dx
mov al,ah
out dx,al
pause
inc dx
in al,dx
shr bh,cl
and al,0f0h
or bh,al
cmp bh,bl
jne memory_test
dec dx
inc bl
dec bp
jnz rd_this_page
inc si
pop bx
add bx,800h
cmp bx,1800h
ja mem_is_OK
push si
push bx
mov cx,700h
mov al,PAGE0
call Write_LoopBack_Data
call Tx_Data
pop bx
pop si
jmp short read_next_page
mem_is_OK:
jmp mem_OK

;************ write mode 2 ***************
memory_test:
pop ax
memory_test1:
mov cx,700h
mov al,PAGE3
call Write_LoopBack_Data
xor bx,bx
mov si,bx
write_next_page1:
call Tx_Data
push bx
mov cx,RW_ADR
loadport
setport DAT
write_sub_slow bl
call delay
write_sub_slow bh
call delay

mov bx,si
mov bp,800h
mov cx,WRITE
mov ah,ch
xor ah,08h
wr_this_page1:
mov al,bl
shl al,cl
or al,ch
out dx,al
call delay

mov al,bl
and al,0f0h
or al,ah
out dx,al
call delay
inc bl
dec bp
jnz wr_this_page1
inc si
pop bx
add bx,800h
cmp bx,1800h
ja read_memory1
jmp short write_next_page1

;************* read mode 2 **************
read_memory1:
loadport
setport DAT
xor bx,bx
mov si,bx
read_next_page1:
push bx
mov cx,RW_ADR
write_sub_slow bl
call delay
write_sub_slow bh
call delay

mov bx,si
mov bp,800h
mov cx,READ
mov ah,ch
xor ah,08h
rd_this_page1:
mov al,ch
out dx,al
call delay

inc dx
in al,dx
mov bh,al
dec dx
mov al,ah
out dx,al
call delay

inc dx
in al,dx
shr bh,cl
and al,0f0h
or bh,al
cmp bh,bl
jne memory_test2
dec dx
inc bl
dec bp
jnz rd_this_page1
inc si
pop bx
add bx,800h
cmp bx,1800h
ja mem_is_OK1
push si
push bx
mov cx,700h
mov al,PAGE0
call Write_LoopBack_Data
call Tx_Data
pop bx
pop si
jmp read_next_page1
mem_is_OK1:
jmp mem_OK1

;************* write mode 3 ***************
memory_test2:
pop ax
memory_test3:
mov cx,700h
mov al,PAGE3
call Write_LoopBack_Data
xor bx,bx
mov si,bx
write_next_page3:
call Tx_Data
push bx
mov cx,RW_ADR
loadport
setport DAT
write_sub_delay bl
call delay
write_sub_delay bh
call delay

mov bx,si
mov bp,800h
mov cx,WRITE
wr_this_page3:
mov al,bl
shl al,cl
or al,ch
xor al,08h
out dx,al
call delay

xor al,08h
out dx,al
call delay

mov al,bl
and al,0f0h
or al,ch
out dx,al
call delay

xor al,08h
out dx,al
call delay
inc bl
dec bp
jnz wr_this_page3
inc si
pop bx
add bx,800h
cmp bx,1800h
ja read_memory3
jmp write_next_page3

;************* read mode 3 ***************
read_memory3:
loadport
setport DAT
xor bx,bx
mov si,bx
read_next_page3:
push bx
mov cx,RW_ADR
write_sub_delay bl
call delay
write_sub_delay bh

call delay

mov bx,si
mov bp,800h
mov cx,READ
mov ah,ch
xor ah,08h

mov al,ch
xor al,08h
out dx,al
call delay
rd_this_page3:
mov al,ch
out dx,al
call delay

setport STAT
in al,dx
mov bh,al
setport DAT
mov al,ah
out dx,al
call delay

setport STAT
in al,dx
shr bh,cl
and al,0f0h
or bh,al
cmp bh,bl
jne mem_err
setport DAT
inc bl
dec bp
jnz rd_this_page3
inc si
pop bx
add bx,800h
cmp bx,1800h
ja mem_OK2
push si
push bx
mov cx,700h
mov al,PAGE0
call Write_LoopBack_Data
call Tx_Data
pop bx
pop si
jmp read_next_page3

pointer dw 0

mem_err:
pop bx
cmp pointer,9 ;too slow? Must not be working.
ja mem_real_err
mov bx,offset delay ;append another NOP and RET in.
add bx,pointer
mov [bx],0c390h
inc pointer ;slow it down a little more and try
jmp memory_test3 ; again.
mem_real_err:
mov dx,offset mem_error_msg
stc
ret

change_routine:
mov ax,offset recv1
mov recv_pointer,ax
mov ax,offset send_pkt1
mov send_pkt_pointer,ax
ret

change_routine2:
mov ax,offset recv2
mov recv_pointer,ax
mov ax,offset send_pkt2
mov send_pkt_pointer,ax
ret

;********** memory test passed ****************
mem_OK1:
call change_routine
jmp short mem_OK
mem_OK2:
call change_routine2
mem_OK:
call speed_test

push es
xor ax,ax
mov es,ax
mov si,printer
mov word ptr es:[si],ax ; Zero-out Printer Port
pop es

; Initialize Rx buffer pointer, and start receive
mov bl,Mode
or bl,IRQinverse
or bl,CurRXPage
mov Mode_RxPg,bl
mov cx,COMMAND
call Write_sub
or bl,RXEN
call Write_sub

; Put our Receive routine in interrupt chain
call set_recv_isr

; We didn't need to enable the receive & transmit interrupts, they were
; set by hardware already. (accept GOOD, SUC & T16 to generate interrupt)

; Enable Printer Adapter IRQ line
mov al,SLT_PRN
call CMD_sub

clc
ret


;*********** sub-routine *************
; Check DE-600 routine
Check_DE600:
mov al,SLT_NIC
call CMD_sub
call delay

loadport
setport DAT
mov al,NUL_CMD
out dx,al
call delay

mov bl,RESET
mov cx,COMMAND
call Write_sub
call delay
mov bl,STOP_RESET
call Write_sub
call delay

mov cx,STATUS
call Read_sub
test bl,0f0h
jz Check_OK
stc
ret
Check_OK:
clc
ret

OldIRQ5 dd 0
OldIRQ7 dd 0

NewIRQ5:
push ax
push bx
push cx
push dx
push ds
mov al,20h
out 20h,al
mov ax,cs
mov ds,ax
cmp LB,0
jz DisCare_IRQ5
mov bh,5
call Clear_int
DisCare_IRQ5:
pop ds
pop dx
pop cx
pop bx
pop ax
iret

NewIRQ7:
push ax
push bx
push cx
push dx
push ds
mov al,20h
out 20h,al
mov ax,cs
mov ds,ax
cmp LB,0
jz DisCare_IRQ7
mov bh,7
call Clear_int
DisCare_IRQ7:
pop ds
pop dx
pop cx
pop bx
pop ax
iret

replace_IRQ5_7:
xor cx,cx
mov es,cx
mov di,034h
mov ax,es:[di] ;save old interrupt vector
mov word ptr OldIRQ5,ax
mov ax,es:[di]+2
mov word ptr OldIRQ5+2,ax
mov ax,offset NewIRQ5
stosw
mov ax,cs
stosw

mov di,03ch
mov ax,es:[di] ;save old interrupt vector
mov word ptr OldIRQ7,ax
mov ax,es:[di]+2
mov word ptr OldIRQ7+2,ax
mov ax,offset NewIRQ7
stosw
mov ax,cs
stosw

in al,21h
mov intmask,al
pause
pause
and al,5fh
out 21h,al
ret

intmask db 0
INT_come db 0
T16_flag db 0
LB db 0

restore_IRQ5_7:
xor cx,cx
mov es,cx
mov di,034h
mov ax,word ptr OldIRQ5
mov es:[di],ax ;save old interrupt vector
mov ax,word ptr OldIRQ5+2
mov es:[di]+2,ax

mov di,03ch
mov ax,word ptr OldIRQ7
mov es:[di],ax ;save old interrupt vector
mov ax,word ptr OldIRQ7+2
mov es:[di]+2,ax

mov al,intmask
out 21h,al
ret

Write_LoopBack_Data:
mov si,offset rom_address
mov di,si
;set Tx Pointer for moving packet
mov bx,BFRSIZ
sub bx,cx ;CX= Packet Length
or bh,al ;AL= Page Number
mov TxStartAdd,bx ;BX= the pointer to TX
mov cx,RW_ADR ;write memory address
call Write_sub
mov bl,bh
call Write_sub
cld
loadport
setport DAT
mov bp,12
mov cx,WRITE
write_our_node_ID:
lodsb
mov bl,al
call Write_sub
cmp bp,7
jne not_second_ID
mov si,di
not_second_ID:
dec bp
jnz write_our_node_ID
ret

Tx_Data:
;Check TXIDLE, if high then wait for previous Tx end, if low then Tx it
mov cx,800h ; Avoid infinite loop
loadport
setport STAT
wait_Txidle0:
in al,dx
test al,TXBUSY ; Is the previous Tx successful ?
jz Tx_next0 ; Yes, TXBUSY is low. Then could Tx next packet.
loop wait_Txidle0
Tx_next0:
;set Tx Pointer at beginning of packet
push bx
mov cx,TX_ADR
mov bx,TxStartAdd
call Write_sub
mov bl,bh
call Write_sub
;Enable interrupt and start Tx
mov cx,COMMAND
mov bl,RX_NONE
call Write_sub
or bl,TXEN
call Write_sub
pop bx
ret

LoopBack_Tx:
;set Tx Pointer at beginning of packet
mov bx,TxStartAdd
mov cx,TX_ADR
call Write_sub
mov bl,bh
call Write_sub
;Enable interrupt and start Tx
mov bl,RX_BP
or bl,IRQinverse
mov cx,COMMAND
call Write_sub
or bl,LOOPBACK
call Write_sub

mov LB,1
mov al,SLT_PRN
call CMD_sub

xor bx,bx
mov cx,8000h
wait_int:
cmp INT_come,0
jz have_T16
mov bx,1
jmp short exit_LoopBack
have_T16:
cmp T16_flag,0
jz still_wait
mov bx,-1
jmp short exit_LoopBack
still_wait:
loop wait_int

exit_LoopBack:
mov LB,0
mov al,SLT_NIC
call CMD_sub

push bx
mov cx,STATUS
call Read_sub
pop bx
ret

Clear_int:
mov al,SLT_NIC
call CMD_sub
pause
mov cx,STATUS
call Read_sub

mov T16_flag,0
test bl,GOOD ; Is Rx generating interrupt ?
jz chk_T16
mov INT_come,1
mov int_no,bh
jmp short exit_Clear_int
chk_T16:
test bl,T16 ; Is pending a Tx Packet ?
jz exit_Clear_int
mov T16_flag,1
exit_Clear_int:
ret

Check_IRQ:
call replace_IRQ5_7
sti
mov cx,RUNT
mov al,PAGE0
call Write_LoopBack_Data
call LoopBack_Tx ; check IRQ= 7 or 5 but IRQ not inverse
cmp bx,0
jnz IRQ_OK

;Check TXIDLE, if high then wait for previous Tx end, if low then Tx it
mov cx,800h ; Avoid infinite loop
loadport
setport STAT
wait_Txidle:
in al,dx
test al,TXBUSY ; Is the previous Tx successful ?
jz Tx_next ; Yes, TXBUSY is low. Then could Tx next packet.
loop wait_Txidle
Tx_next:
mov IRQinverse,40h ; check IRQ= 7 or 5 but IRQ inverse
mov PS2,0
call LoopBack_Tx
IRQ_OK:
cli
call restore_IRQ5_7
ret

check_PS2:
mov ax,0c400h
int 15h
jc not_PS2
mov PS2,1
not_PS2:
ret

speed_test:
xor ax,ax
mov es,ax
mov si,20h
mov ax, es:[si]
mov cs:old_int8, ax
mov ax, es:[si+2]
mov cs:old_int8[2], ax
cli
mov ax,offset new_int8
mov es:[si],ax
mov es:[si+2],cs
sti

next_test1:
mov ticks_start,0
next_test:
cmp ticks_start,0
jz next_test
mov ticks,0
xor bx,bx
loop_again:
mov cx,6
loop $
cmp ticks,2
jae End_count
inc bx
jmp short loop_again

End_count:
cli
xor ax,ax
mov es,ax
mov si,20h
mov ax,old_int8
mov es:[si],ax
mov ax,old_int8[2]
mov es:[si+2],ax
sti
cmp bx,0a000h
jb low_speed
mov ax,offset recv1 ; special for high speed EISA
mov recv_pointer,ax
low_speed:
ret

ticks_start db 0
ticks db 0
old_int8 dw ?
dw ?
new_int8:
inc ticks
inc ticks_start
jmp dword ptr cs:old_int8

code ends
end


  3 Responses to “Category : Network Files
Archive   : PKTD11A.ZIP
Filename : DE600.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/