home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
packetdrivers.tar.gz
/
pd.tar
/
src
/
depca.asm
< prev
next >
Wrap
Assembly Source File
|
1995-06-25
|
24KB
|
1,067 lines
version equ 3
;History:685,1
; Copyright, 1991-1992, Russell Nelson, Crynwr Software
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, version 1.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
RBSA equ 0eh
;CSR bit definitions
CSR_RBT equ 100h
CSR_SHE equ 80h
CSR_SWAP32 equ 40h
CSR_BUF equ 20h
CSR_RBE equ 10h
CSR_DUM equ 08h ;for rev E. DEPCA compatability
CSR_IM equ 04h
CSR_IEN equ 02h
CSR_LED equ 01h
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 ;must be a power of two.
RECEIVE_BUF_COUNT equ 16 ;must be a power of two.
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 800h
receive_bufs equ 1000h
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
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 0 ;none at all.
dw 0 ;only ours.
dw rcv_mode_3 ;ours plus broadcast
dw 0 ;some multicasts
dw 0 ;all multicasts
dw rcv_mode_6 ;all packets
save_csr1 dw ?
save_csr2 dw ?
transmit_head dw transmit_dscps ;->next packet to be filled by host.
receive_head dw receive_dscps ;->next packet to be filled by LANCE.
ni_csr_value db CSR_SHE or CSR_DUM or CSR_IEN or CSR_SWAP32
translate_address dw ? ;->routine to translate the address.
;enter with ax = address.
;exit with di = translated address, RBI/NI_CSR set as needed.
;may trash dx.
assume ds:nothing
translate_64k:
mov di,ax
ret
translate_32k:
;move the window to the appropriate address.
mov di,ax
loadport
setport NI_CSR
mov al,ni_csr_value
test di,8000h
je translate_32k_1
and al,not CSR_SWAP32
translate_32k_1:
out dx,al
and di,7fffh ;only 32K of memory.
ret
translate_2k:
;move the window to the appropriate address.
loadport
setport RBI
shr ax,1 ;compute the 2K window.
shr ax,1 ;divide by 8
shr ax,1
mov al,ah ;divide by 256 (8*256 = 2K).
out dx,al
xor di,di
ret
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
mov es,base_addr
assume es:lance_seg
xor ax,ax ;go back to base window (if changed).
call translate_address
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_toobig:
mov dh,NO_SPACE
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.
call translate_address
shr cx,1
rep movsw
jnc send_pkt_3
movsb
send_pkt_3:
xor ax,ax
call translate_address
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 NI_CSR ;enable the rev. E DEPCA card.
mov al,CSR_DUM
out dx,al
setport EBASE ;is it in this port?
call detect_port
je detect_board_1 ;yup!
setport EBASE+1 ;look on the next port for rev. E
call detect_port
detect_board_1:
pushf ;preserve the result.
loadport
setport NI_CSR ;restore the NI_CSR contents.
mov al,ni_csr_value
out dx,al
popf
ret
depca_pattern db 0FFh, 00h, 55h, 0AAh, 0FFh, 00h, 55h, 0AAh
detect_port:
;enter with dx = port to read from, looking for depca_pattern.
;exit with zr if we found it, nz if not.
mov cx,32+8 ;do 32 reps, plus look at 8 to match.
mov di,0 ;start at the beginning of the string.
detect_port_1:
in al,dx ;input byte.
cmp al,depca_pattern[di] ;do they match?
jne detect_port_2 ;no, try again.
inc di ;yes, look at another character.
cmp di, 8 ;need to match eight chars.
jne short detect_port_3
ret
detect_port_2:
xor di,di ;start at the beginning of the pattern.
detect_port_3:
loop detect_port_1
or sp,sp ;return nz.
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:
movseg ds,cs
assume ds:code
ret
rcv_mode_1:
mov ax,M_DRX ;disable the receiver.
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:
mov es,base_addr
mov es:init_mode,ax
initialize:
loadport
mov ax,CSR0_STOP ;reset the INIT bit.
outport CSR0
mov ax,2 ;write the bus config register.
outport CSR3
mov ax,save_csr1 ;write the low word.
outport CSR1
mov ax,save_csr2 ;write the high word.
outport CSR2
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, 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 ;for some reason we can't do multi's.
stc
ret
public terminate
terminate:
call rcv_mode_1 ;don't receive any packets.
loadport ;disable the RAM, enable ROM.
setport NI_CSR
in al,dx
and al,not CSR_SHE
out dx,al
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
;call this routine to schedule a subroutine that gets run after the
;recv_isr. This is done by stuffing routine's address in place
;of the recv_isr iret's address. This routine should push the flags when it
;is entered, and should jump to recv_exiting_exit to leave.
;enter with ax = address of routine to run.
extrn schedule_exiting: near
;recv_exiting jumps here to exit, after pushing the flags.
extrn recv_exiting_exit: 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
xor ax,ax
call translate_address
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
sub cx,4 ;leave the CRC behind.
mov ax,lance_seg:[bx].rmd0 ;get the pointer into di.
call translate_address
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
shr cx,1
rep movsw
jnc rec_pkt_3
movsb
rec_pkt_3:
pop cx
pop si
pop ds
assume ds:nothing
call recv_copy
jmp short recv_free
recv_err:
call count_in_err
recv_free:
xor ax,ax
call translate_address
movseg ds,cs
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?
jne recv_free_1
jmp recv_own ;yes, go parse it.
recv_free_1:
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
include popf.asm
include timeout.asm
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. Buffers used by the program, if any,
;are allocated from the memory between end_resident and end_free_mem.
public end_resident,end_free_mem
end_resident label byte
end_free_mem label byte
public usage_msg
usage_msg db "usage: depca [options] <packet_int_no> <hardware_irq> <io_addr> <mem_addr>",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,'$'
mem_busy_msg db "Memory already present at your chosen address.",CR,LF,'$'
mem_bad_msg db "No DEPCA memory found at that memory address.",CR,LF,'$'
addr_bad_msg db "Memory address should be between 0x8000 and 0xdf80 inclusive,",CR,LF
db "and must be on a 2K boundary (increments of 0x80).",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet driver for a Digital Equipment Corporation DEPCA, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
db '$'
int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
base_addr_name db "Memory address ",'$'
memory_amount dw ? ;-> one of the following
have_64k db "Configured for 64K of memory",CR,LF,'$'
have_32k db "Configured for 32K of memory",CR,LF,'$'
have_2k db "Configured for 2K of memory",CR,LF,'$'
depca_signature db "DEPCA"
depca_signature_len equ $-depca_signature
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 dx -> name of word, di -> dword to print.
extrn print_number: near
;-> the assigned Ethernet address of the card.
extrn rom_address: byte
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.
stc
ret
find_board_found:
test base_addr.offs,007fh ;must be on at least a 2K boundary.
jne etopen_1
test base_addr.offs,8000h ;must be in upper 512K.
je etopen_1
cmp base_addr.segm,0 ;high word of segment must be zero.
je etopen_2
etopen_1:
mov dx,offset addr_bad_msg
stc
ret
etopen_2:
; now we detect whether we're set to 2K, 32K, or 64K.
pushf ;we're about to re-map the DEPCA
cli ; memory onto somewhere illicit.
;first, we see if the ROM is mappable in and out.
loadport ;disable the RAM, enable ROM.
setport NI_CSR
in al,dx
and al,not CSR_SHE
out dx,al
mov bx,base_addr ;get the segment of the ROM.
add bx,400h ;go up by 16K.
mov translate_address,offset translate_32k
mov memory_amount,offset have_32k
test al,CSR_BUF ;32k or 64k mode?
jne got_rom_address ;go if 32K.
and ni_csr_value,not CSR_SWAP32
mov al,ni_csr_value
and al,not CSR_SHE
out dx,al
mov translate_address,offset translate_64k
mov memory_amount,offset have_64k
add bx,800h ;up it by 32K more.
got_rom_address:
push bx
mov ax,bx
mov cx,4000h ;16K
call memory_test
pop bx
jz not_rom_address ;we found RAM there...
loadport
setport NI_CSR
in al,dx
or al,CSR_SHE ;enable the RAM.
out dx,al
push bx
mov ax,bx
mov cx,4000h ;there should be 16K of RAM there.
call memory_test
pop bx
je have_depca_mem ;there is -- we're cool.
mov es,bx
cmp word ptr es:[0],0aa55h ;is there a ROM there still?
jne not_rom_address
mov di,6 ;see if the DEPCA ROM signature is there.
mov si,offset depca_signature
mov cx,depca_signature_len
repe cmpsb
je have_depca_mem ;it is, we've got an old DEPCA.
not_rom_address:
;we got here because we decided that the ROM couldn't be mapped into memory.
mov translate_address,offset translate_2k
mov memory_amount,offset have_2k
and ni_csr_value,not CSR_SWAP32
loadport ;put our memory somewhere it can't be.
setport RBSA
mov ax,0f000h
out dx,ax
;make sure the memory *isn't* there.
mov bx,base_addr
mov di,2048 / 16
call occupied_chk
pushf
loadport ;the memory block is empty - put our
setport RBSA ; memory there.
mov ax,base_addr
out dx,ax
popf
jnc depca_mem_empty
popf
mov dx,offset mem_busy_msg
stc
ret
depca_mem_empty:
mov ax,base_addr ;now test our memory.
mov cx,2048
call memory_test
jz have_depca_mem
popf ;restore the original EI.
mov dx,offset mem_bad_msg
stc
ret
have_depca_mem:
popf ;restore the original EI.
movseg es,cs
mov di,offset rom_address
mov cx,EADDR_LEN
loadport ; Get our Ethernet address base.
setport EBASE
get_address_1:
in al,dx ; get a byte of the eprom address
stosb
loop get_address_1 ; go back for rest
mov si,offset rom_address ; copy it to the init table.
mov es,base_addr
mov di,offset init_addr
mov cx,EADDR_LEN
rep movsb
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
xor ax,ax
call translate_address
;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,800h
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,800h
loop setup_receive
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.
mov save_csr1,ax
mov save_csr2,dx
call rcv_mode_3
jnc init_ok
mov dx,offset bad_init_msg
stc
ret
init_ok:
;
; Now hook in our interrupt
;
call set_recv_isr
loadport
setport NI_CSR
mov al,ni_csr_value ;disable ROM, enable rev. E DEPCA,
; enable the interrupt line,
out dx,al
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
mov dx,memory_amount
mov ah,9
int 21h
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
include memtest.asm
include occupied.asm
code ends
end