home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Stars of Shareware: Programmierung
/
SOURCE.mdf
/
programm
/
msdos
/
asm
/
drivers3
/
de600.asm
< prev
next >
Wrap
Assembly Source File
|
1992-03-05
|
45KB
|
2,153 lines
PAGE ,132
.286c
version equ 0
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 ?,?
our_address db EADDR_LEN + EADDR_LEN dup(0) ;temporarily hold our address
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
;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_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
public get_address
get_address:
;get the address of the interface.
;enter with es:di -> place to get the address, cx = size of address buffer.
assume ds:code
cmp cx,EADDR_LEN ;make sure that we have enough room.
jb cant_get_address
;select DE-600
cld
mov si,offset our_address
rep movsb
mov cx,EADDR_LEN
clc
ret
cant_get_address:
stc
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 bp,si
mov cx,EADDR_LEN
mov di,offset our_address
rep movsb
mov si,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, cx = number of addresses.
;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 recv_exiting
recv_exiting:
;called from the recv isr after interrupts have been acknowledged.
;Only ds and ax have been saved.
assume ds:nothing
ret
public end_resident
end_resident label byte
;any code after this will not be kept after initialization.
public usage_msg
usage_msg db "usage: DE600PD <packet_int_no>",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
assume ds:code
public parse_args
parse_args:
ret
public print_parameters
print_parameters:
ret
cable_err:
mov dx,offset CableErr
jmp short show_msg
IRQ_error:
mov dx,offset irq_error_msg
jmp short show_msg
no_our_NIC:
mov dx,offset no_NIC_err
jmp short show_msg
mem_error:
mov dx,offset mem_error_msg
show_msg:
mov ah,9
int 21h
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 our_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 our_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:
jmp mem_error
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
mov dx,offset end_resident
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 our_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