Category : Network Files
Archive   : TCP_SRC.ZIP
Filename : DEPCA.ASM

 
Output of file : DEPCA.ASM contained in archive : TCP_SRC.ZIP
version equ 0

include defs.asm

NI_CSR equ 0
RBI equ 2
DATA_REG equ 4
ADDR_REG equ 6
CSR0 equ 0
CSR1 equ 1
CSR2 equ 2
CSR3 equ 3
EBASE equ 0ch

outport macro reg
push ax
setport ADDR_REG
mov ax,reg
out dx,ax
in ax,dx ;always follow a write by a read

setport DATA_REG
pop ax
out dx,ax
in ax,dx ;always follow a write by a read

endm


;
; Control and Status Register 0 (CSR0) bit definitions
;
CSR0_ERR equ 8000h ; Error summary
CSR0_BABL equ 4000h ; Babble transmitter timeout error
CSR0_CERR equ 2000h ; Collision Error
CSR0_MISS equ 1000h ; Missed packet
CSR0_MERR equ 0800h ; Memory Error
CSR0_RINT equ 0400h ; Reciever Interrupt
CSR0_TINT equ 0200h ; Transmit Interrupt
CSR0_IDON equ 0100h ; Initialization Done
CSR0_INTR equ 0080h ; Interrupt Flag
CSR0_INEA equ 0040h ; Interrupt Enable
CSR0_RXON equ 0020h ; Receiver on
CSR0_TXON equ 0010h ; Transmitter on
CSR0_TDMD equ 0008h ; Transmit Demand
CSR0_STOP equ 0004h ; Stop
CSR0_STRT equ 0002h ; Start
CSR0_INIT equ 0001h ; Initialize

;
; Initialization Block Mode operation Bit Definitions.
;
M_PROM equ 8000h ; Promiscuous Mode
M_INTL equ 0040h ; Internal Loopback
M_DRTY equ 0020h ; Disable Retry
M_COLL equ 0010h ; Force Collision
M_DTCR equ 0008h ; Disable Transmit CRC)
M_LOOP equ 0004h ; Loopback
M_DTX equ 0002h ; Disable the Transmitter
M_DRX equ 0001h ; Disable the Reciever


;
; Receive message descriptor bit definitions.
;
RCV_OWN equ 8000h ; owner bit 0 = host, 1 = lance
RCV_ERR equ 4000h ; Error Summary
RCV_FRAM equ 2000h ; Framing Error
RCV_OFLO equ 1000h ; Overflow Error
RCV_CRC equ 0800h ; CRC Error
RCV_BUF_ERR equ 0400h ; Buffer Error
RCV_START equ 0200h ; Start of Packet
RCV_END equ 0100h ; End of Packet


;
; Transmit message descriptor bit definitions.
;
XMIT_OWN equ 8000h ; owner bit 0 = host, 1 = lance
XMIT_ERR equ 4000h ; Error Summary
XMIT_RETRY equ 1000h ; more the 1 retry needed to Xmit
XMIT_1_RETRY equ 0800h ; one retry needed to Xmit
XMIT_DEF equ 0400h ; Deferred
XMIT_START equ 0200h ; Start of Packet
XMIT_END equ 0100h ; End of Packet

;
; Miscellaneous Equates
;

TRANSMIT_BUF_COUNT equ 1
RECEIVE_BUF_COUNT equ 8
TRANSMIT_BUF_SIZE equ 1518
RECEIVE_BUF_SIZE equ 1518

;
; Receive Message Descriptor
;
rcv_msg_dscp struc
rmd0 dw ? ; Rec. Buffer Lo-Address
rmd1 dw ? ; Status bits / Hi-Address
rmd2 dw ? ; Buff Byte-length (2's Comp)
rmd3 dw ? ; Receive message length
rcv_msg_dscp ends


;
; Transmit Message Descriptor
;
xmit_msg_dscp struc
tmd0 dw ? ; Xmit Buffer Lo-Address
tmd1 dw ? ; Status bits / Hi-Address
tmd2 dw ? ; Buff Byte-length (2's Comp)
tmd3 dw ? ; Buffer Status bits & TDR value
xmit_msg_dscp ends

lance_seg segment at 0

;
;the LANCE requires that the descriptor pointers be on a qword boundary.
;
align 8

transmit_dscps xmit_msg_dscp TRANSMIT_BUF_COUNT dup(<>)
receive_dscps rcv_msg_dscp RECEIVE_BUF_COUNT dup(<>)

;
; LANCE Initialization Block
;
align 2
init_block label byte
init_mode dw 0
init_addr db EADDR_LEN dup(?) ; Our Ethernet address
init_filter db 8 dup(0) ;Multicast filter.
init_receive dw ?,? ;Receive Ring Pointer.
init_transmit dw ?,? ;Transmit Ring Pointer.

transmit_bufs equ $
receive_bufs equ transmit_bufs + TRANSMIT_BUF_COUNT * TRANSMIT_BUF_SIZE

lance_seg ends

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

public int_no
int_no db 2,0,0,0 ;must be four bytes long for get_number.
io_addr dw -1,-1
base_addr dw -1,-1
depca_pattern db 0FFh, 00h, 55h, 0AAh, 0FFh, 00h, 55h, 0AAh

public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK, IEEE8023, 0 ;from the packet spec
driver_type db 66 ;from the packet spec
driver_name db 'DEPCA',0 ;name of the driver.
driver_function db 2 ;basic, extended
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 RECEIVE_BUF_COUNT-1 ;(# of back-to-back MTU rcvs) - 1
dw TRANSMIT_BUF_COUNT-1 ;(# 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 ;only ours.
dw rcv_mode_3 ;ours plus broadcast
dw 0 ;some multicasts
dw rcv_mode_5 ;all multicasts
dw rcv_mode_6 ;all packets

transmit_head dw transmit_dscps ;->next packet to be filled by host.
receive_head dw receive_dscps ;->next packet to be filled by LANCE.

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
mov es,base_addr
assume es:lance_seg

xor bx,bx

mov ax,18
call set_timeout
send_pkt_1:
test transmit_dscps[bx].tmd1,XMIT_OWN ;Did the lance chip give it back?
je send_pkt_2
call do_timeout
jne send_pkt_1
mov dh,CANT_SEND
stc
ret
send_pkt_2:
;reset error indications.
and transmit_dscps[bx].tmd1,not (XMIT_ERR or XMIT_DEF or XMIT_1_RETRY or XMIT_RETRY) ;Did the lance chip give it back?
mov transmit_dscps[bx].tmd3,0 ;reset all error bits.

mov ax,cx ;store the count.
cmp ax,RUNT ; minimum length for Ether
ja oklen
mov ax,RUNT ; make sure size at least RUNT
oklen:
neg ax
mov transmit_dscps[bx].tmd2,ax ;store the negative of the cnt.

mov ax,transmit_dscps[bx].tmd0 ;store the packet.
mov dx,transmit_dscps[bx].tmd1
call phys_to_segmoffs
assume es:nothing
rep movsb

mov es,base_addr
assume es:lance_seg
or transmit_dscps[bx].tmd1,XMIT_OWN ;give it to the lance chip.

;Inform LANCE that it should poll for a packet.
loadport
mov ax,CSR0_INEA or CSR0_TDMD
outport CSR0
clc
ret


detect_board:
;test to see if a board is located at io_addr.
;setup to read first byte of ethernet address rom when successful.
;return nz if not.
assume cs:code, ds:code

loadport
setport EBASE
mov si, offset depca_pattern
lodsb ;get first char of test pattern
mov ah,al ;move string byte to ah
mov di,0
mov cx,32 ;do 32 reps
detect_board_1:
in al,dx ;input byte
cmp ah,al
jne detect_board_2
lodsb ;get next char
mov ah,al
inc di
cmp di, 8 ;need to match eight chars
je detect_board_done
detect_board_2:
loop detect_board_1
or sp,sp ;guaranteed to be nonzero.
detect_board_done:
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.
;exit with nc, cx = actual size of address, or cy if buffer not big enough.
assume ds:code, es:nothing
cmp cx,EADDR_LEN ;make sure that we have enough room.
jb get_address_2
push di
call detect_board
pop di
mov cx,EADDR_LEN
loadport ; Get our Ethernet address base.
setport EBASE+1
cld
get_address_1:
in al,dx ; get a byte of the eprom address
stosb
loop get_address_1 ; go back for rest
mov cx,EADDR_LEN
clc
ret
get_address_2:
stc
ret


public set_address
set_address:
;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 ;ensure that their address is okay.
je set_address_4
mov dh,BAD_ADDRESS
stc
jmp short set_address_done
set_address_4:

mov es,base_addr
mov di,offset init_addr
rep movsb
call initialize ;initialize with our new address.

set_address_okay:
mov cx,EADDR_LEN ;return their address length.
clc
set_address_done:
push cs
pop ds
assume ds:code
ret


rcv_mode_1:
mov ax,M_DRX or M_DTX ;disable the receiver and transmitter.
jmp initialize_nomulti
rcv_mode_3:
xor ax,ax ;don't accept any multicast frames.
call initialize_multi
mov ax,0 ;non-promiscuous mode
jmp short initialize_nomulti
rcv_mode_5:
mov ax,-1 ;accept any multicast frames.
call initialize_multi
mov ax,0 ;non-promiscuous mode
jmp short initialize_nomulti
rcv_mode_6:
mov ax,M_PROM ;promiscuous mode
initialize_nomulti:
initialize:
mov es,base_addr
mov es:init_mode,ax

loadport
mov ax,CSR0_STOP ;reset the INIT bit.
outport CSR0

mov ax,CSR0_INEA or CSR0_STRT or CSR0_INIT ;reinit and restart.
outport CSR0

setport DATA_REG

mov ax,36 ;wait one second for the board
call set_timeout ; to timeout.
initialize_1:
in ax,dx
test ax,CSR0_IDON
jne initialize_2
call do_timeout
jne initialize_1
stc
ret
initialize_2:
clc
ret


initialize_multi:
;enter with ax = value for all multicast hash bits.
mov es,base_addr
mov di,offset init_filter
mov cx,8/2
rep stosw
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 ;for some reason we can't do multi's.
stc
ret


public terminate
terminate:
call rcv_mode_1 ;don't receive any apckets.

ret

public reset_interface
reset_interface:
;reset the interface.
assume ds:code
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

LANCE_ISR_ACKNOWLEDGE equ (CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)

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

loadport
setport ADDR_REG
mov ax,CSR0
out dx,ax
in ax,dx
setport DATA_REG
in ax,dx
mov bx,ax ;make a copy.

; Acknowledge the Interrupt from the controller, but disable further
; controller Interrupts until we service the current interrupt.
;
;(CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
;
and ax,not LANCE_ISR_ACKNOWLEDGE
out dx,ax
in ax,dx ; follow all writes by a read

test bx,CSR0_RINT ;receive interrupt?
jne recv_RINT ;yes.
jmp recv_done ;no, we're done.
recv_RINT:

mov es,base_addr
assume es:lance_seg
mov bx,receive_head

recv_search:
test lance_seg:[bx].rmd1,RCV_OWN ;do we own this buffer?
je recv_own ;yes - process it.
call inc_recv_ring ;go to the next one.
cmp bx,receive_head ;did we get back to the beginning?
jne recv_search ;not yet.
jmp recv_done ;yes -- spurious interrupt!
recv_own:
test lance_seg:[bx].rmd1,RCV_ERR ;Any errors in this buffer?
jne recv_err ;yes -- ignore this packet.

mov cx,lance_seg:[bx].rmd3
and cx,0fffh ;strip off the reserved bits

mov ax,lance_seg:[bx].rmd0 ;fetch the packet.
mov dx,lance_seg:[bx].rmd1
call phys_to_segmoffs
assume es:nothing

push es
push di
push bx

add di,EADDR_LEN+EADDR_LEN ;skip the ethernet addreses and
; point to the packet type.
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:
push cx
call recv_find
pop cx

pop bx
pop si
pop ds
assume ds:nothing, es:nothing

mov ax,es ;is this pointer null?
or ax,di
je recv_free ;yes - just free the frame.

push es
push di
push cx
rep movsb
pop cx
pop si
pop ds
assume ds:nothing

call recv_copy

jmp short recv_free

recv_err:
call count_in_err
recv_free:
push cs
pop ds
assume ds:code
mov es,base_addr
assume es:lance_seg

;clear any error bits.
and lance_seg:[bx].rmd1,not (RCV_ERR or RCV_FRAM or RCV_OFLO or RCV_CRC or RCV_BUF_ERR)
or lance_seg:[bx].rmd1,RCV_OWN ;give it back to the lance.
call inc_recv_ring ;go to the next one.
test lance_seg:[bx].rmd1,RCV_OWN ;Do we own this one?
je recv_own
mov receive_head,bx ;remember where the next one starts.
recv_done:
loadport ;enable interrupts again.
setport DATA_REG
mov ax,CSR0_INEA
out dx,ax

ret


inc_recv_ring:
;advance bx to the next receive ring descriptor.
assume ds:nothing
add bx,(size rcv_msg_dscp)
cmp bx,offset receive_dscps + RECEIVE_BUF_COUNT * (size rcv_msg_dscp)
jb inc_recv_ring_1
mov bx,offset receive_dscps
inc_recv_ring_1:
ret


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


phys_to_segmoffs:
;enter with dx:ax as the physical address of the buffer,
;exit with es:di -> buffer.
assume ds:nothing
if 0
shl dx,16-4 ;move the upper four bits into position.
mov di,ax ;now get the low 12 bits of the segment.
shr di,4
or dx,di ;combine them.
mov es,dx
mov di,ax
and di,0fh ;now compute the offset.
else
mov es,base_addr
mov di,ax
endif
ret

include timeout.asm

end_resident label byte

public usage_msg
usage_msg db "usage: depca [-n] [-d] [-w] ",CR,LF,'$'
no_board_msg db "No DEPCA detected.",CR,LF,'$'
io_addr_funny_msg label byte
db "No DEPCA detected, continuing anyway.",CR,LF,'$'
bad_reset_msg db "Unable to reset the DEPCA.",CR,LF,'$'
bad_init_msg db "Unable to initialize the DEPCA.",CR,LF,'$'

public copyright_msg
copyright_msg db "Packet driver for a Digital Equipment Corporation DEPCA, version ",'0'+majver,".",'0'+version,CR,LF
db '$'

int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
base_addr_name db "Memory address ",'$'

extrn set_recv_isr: near
extrn maskint: near

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

;enter with si -> argument string, di -> dword to print.
extrn print_number: near

public parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
assume ds:code
mov di,offset int_no
call get_number
mov di,offset io_addr
call get_number
mov di,offset base_addr
call get_number
clc
ret


public etopen
etopen:
assume ds:code

cmp io_addr,-1 ;Did they ask for auto-detect?
je find_board

call detect_board ;no, just verify its existance.
je find_board_found

mov dx,offset io_addr_funny_msg
mov ah,9
int 21h

jmp find_board_found

find_board:
mov io_addr,300h ;Search for the Ethernet address at 300h
mov io_addr+2,0
call detect_board
je find_board_found
mov io_addr,200h ;Search at 200h
call detect_board
je find_board_found

mov dx,offset no_board_msg ;Tell them that we can't find it.
mov ah,9
int 21h

stc
ret
find_board_found:

mov al, int_no ; Get board's interrupt vector
add al, 8
cmp al, 8+8 ; Is it a slave 8259 interrupt?
jb set_int_num ; No.
add al, 70h - 8 - 8 ; Map it to the real interrupt.
set_int_num:
xor ah, ah ; Clear high byte
mov int_num, ax ; Set parameter_list int num.

mov al,int_no
call maskint ;disable these interrupts.

loadport
mov ax,CSR0_STOP ;reset the INIT bit.
outport CSR0

;set up transmit descriptor ring.
mov es,base_addr
assume es:lance_seg
mov cx,TRANSMIT_BUF_COUNT
mov bx,offset transmit_dscps
mov di,offset transmit_bufs
setup_transmit:
call segmoffs_to_phys

or dx,XMIT_START or XMIT_END
mov lance_seg:[bx].tmd0,ax ;points to the buffer.
mov lance_seg:[bx].tmd1,dx

add bx,(size xmit_msg_dscp)
add di,TRANSMIT_BUF_SIZE
loop setup_transmit

;set up receive descriptor ring.
mov cx,RECEIVE_BUF_COUNT
mov bx,offset receive_dscps
mov di,offset receive_bufs
setup_receive:
call segmoffs_to_phys

or dx,RCV_OWN
mov lance_seg:[bx].rmd0,ax ;points to the buffer.
mov lance_seg:[bx].rmd1,dx

mov lance_seg:[bx].rmd2,-RECEIVE_BUF_SIZE
mov lance_seg:[bx].rmd3,0

add bx,(size rcv_msg_dscp)
add di,RECEIVE_BUF_SIZE
loop setup_receive

;initialize the board.
mov cx,EADDR_LEN ;get our address.
mov di,offset init_addr
call get_address

mov cx,RECEIVE_BUF_COUNT
call compute_log2

mov di,offset receive_dscps
call segmoffs_to_phys
or dx,cx ;include the buffer size bits.
mov init_receive[0],ax
mov init_receive[2],dx

mov cx,TRANSMIT_BUF_COUNT
call compute_log2

mov di,offset transmit_dscps
call segmoffs_to_phys
or dx,cx ;include the buffer size bits.
mov init_transmit[0],ax
mov init_transmit[2],dx

mov di,offset init_block ;now tell the board where the init
call segmoffs_to_phys ; block is.

push dx
push ax

loadport
mov ax,2 ;write the bus config register.
outport CSR3

pop ax ;write the low word.
outport CSR1

pop ax ;write the high word.
outport CSR2

xor ax,ax ;don't accept any multicast frames.
call initialize_multi
mov ax,0 ;non-promiscuous mode
call initialize
jnc init_ok

mov dx,offset bad_init_msg
mov ah,9
int 21h

stc
ret

init_ok:
;
; Now hook in our interrupt
;
call set_recv_isr

loadport
setport NI_CSR
mov al,82h ;disable ROM, enable the interrupt line
out dx,al

mov dx,offset end_resident
clc
ret

public print_parameters
print_parameters:
;echo our command-line parameters
mov di,offset int_no
mov dx,offset int_no_name
call print_number
mov di,offset io_addr
mov dx,offset io_addr_name
call print_number
mov di,offset base_addr
mov dx,offset base_addr_name
call print_number
ret

compute_log2:
;enter with cx = number of buffers.
;exit with cx = log2(number of buffers) << 13.
mov ax,-1
compute_log2_1:
inc ax
shr cx,1
jne compute_log2_1
mov cl,13
shl ax,cl
mov cx,ax
ret


segmoffs_to_phys:
;enter with es:di -> buffer.
;exit with dx:ax as the physical address of the buffer,

if 0 ; The DEPCA doesn't use system memory, it uses its own.
mov dx,es ;get the high 4 bits of the segment,
shr dx,16-4
mov ax,es ;and the low 12 bits of the segment.
shl ax,4
add ax,di ;add in the offset.
adc dx,0
else
xor dx,dx ;the offset is the only part of the
mov ax,di ; address.
endif
ret


code ends

end


  3 Responses to “Category : Network Files
Archive   : TCP_SRC.ZIP
Filename : DEPCA.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/