Category : Network Files
Archive   : PKTD11B.ZIP
Filename : SMC_WD.ASM

 
Output of file : SMC_WD.ASM contained in archive : PKTD11B.ZIP
;History:500,1
version equ 7

include defs.asm

; The following people have contributed to this code: David Horne, Eric
; Henderson, Bob Clements, Reinhard Strebler, Jan Engvald LDC, and Paul
; Kranenberg.

; Copyright, 1988-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.

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

; Stuff specific to the Western Digital WD8003E Ethernet controller board
; C version by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package

; The EN registers - First, the board registers

EN_CMD equ 000h ; Board's command register
EN_REG1 equ 001h ; 8013 bus size register
EN_REG5 equ 005h ; New command register (REGISTER 5)
EN_SAPROM equ 008h ; Window on station addr prom
EN_REGE equ 00eh ; Board Id (code) byte

EN_OFF equ 10h

ENDCFG_BM8 equ 48h

include movemem.asm
include 8390.inc

; Board commands in EN_CMD
EN_RESET equ 080h ; Reset the board
EN_MEMEN equ 040h ; Enable the shared memory
EN_MEM_MASK equ 03fh ; B18-B13 of address of the shared memory

; Bits in REG1
ENR1_BUS16BIT equ 001h ; Bus is 16 bits

; Commands for REG5 register
ENR5_MEM16EN equ 080h ; Enable 16 bit memory access from bus (8013)
ENR5_LAN16EN equ 040h ; Enable 16 bit memory access from chip (8013)
ENR5_MEM_MASK equ 01fh ; B23-B19 of address of the memory (8013)
ENR5_LA19 equ 001h ; B19 of address of the memory (8013)
ENR5_EIL equ 004h ; Enable 8390 interrupts to bus (microchannel)

; Bits in the REGE register
ENRE_MICROCHANEL equ 080h ; Microchannel bus (vs. PC/AT)
ENRE_LARGERAM equ 040h ; Large RAM
ENRE_SOFTCONFIG equ 020h ; Soft config
ENRE_REVMASK equ 01eh ; Revision mask
ENRE_ETHERNET equ 001h ; Ethernet (vs. Starlan)

; Shared memory management parameters

SM_TSTART_PG equ 0 ; First page of TX buffer
SM_RSTART_PG equ 6 ; Starting page of ring
SM_RSTOP_PG equ 32 ; Last page +1 of ring

; End of WD8003E parameter definitions

board_features db 0 ; Board features
BF_MEM16EN equ 1 ; 16-bit board, enable 16-bit memory
BF_16K equ 2 ; Board has 16 KB or shared memory
BF_584 equ 4 ; Board has 584 interface chip
BF_NIC_690 equ 32 ; Board has 690 NIC chip

pause_ macro
; jmp $+2
;
; The reason for the pause_ macro is to establish a minimum time between
; accesses to the card hardware. The assumption is that the fetch and execution
; of the jmp $+2 instruction will provide this time. In a fast cache machine
; this may be a false assumption. In a fast cache machine, there may be
; NO REAL TIME DIFFERENCE between the two I/O instruction streams below:
;
; in al,dx in al,dx
; jmp $+2
; in al,dx in al,dx
;
; To establish a minimum delay, an I/O instruction must be used. A good rule of
; thumb is that ISA I/O instructions take ~1.0 microseconds and MCA I/O
; instructions take ~0.5 microseconds. Reading the NMI Status Register (0x61)
; is a good way to pause on all machines.
;
; The National 8390 Chip (NIC) requires 4 bus clocks between successive
; chip selects (National DP8390 Data Sheet Addendum, June 1990 -- it took them
; long enough to figure this out and tell everyone) or the NIC behaves badly.
; Therefor one I/O instruction should be inserted between each successive
; NIC I/O instruction that could occur 'back - to - back' on a fast cache
; machine.
; - gft - 910529
;
push ax
in al, 61h
pop ax
;
endm

reset_8390 macro
loadport ; First, pulse the board reset
setport EN_CMD
mov al,EN_RESET ;Turn on board reset bit
out dx,al
longpause
xor al,al ;Turn off board reset bit
out dx,al
setport EN_REG5
mov al,ENR5_EIL
test sys_features,SYS_MCA
jz reset_no_mc
out dx,al ; enable 8390 interrupts to bus
reset_no_mc:
endm


terminate_board macro
endm

; The following three values may be overridden from the command line.
; If they are omitted from the command line, these defaults are used.

public int_no, io_addr, mem_base
int_no db 3,0,0,0 ; Interrupt level
io_addr dw 0280h,0 ; I/O address for card (jumpers)
mem_base dw 0d000h,0 ; Shared memory addr (software)

public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK, IEEE8023, 0 ;from the packet spec
driver_type db 14 ;from the packet spec
driver_name db 'SMC_WD',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,

extrn sys_features: byte

block_output:
;enter with cx = byte count, ds:si = buffer location, ax = buffer address
assume ds:nothing
mov es,mem_base ; Set up ES:DI at the shared RAM
mov di,ax ; ..
; Can't use movemem which word aligns to the source, but needs to word
; align to the destination writing to WD8003ET/A. Fortunately works for
; all cards.
inc cx ; if odd bytes round up.
and cx,not 1
call rcopy_subr

clc
ret ; End of transmit-start routine

block_input:
;enter with cx = byte count, es:di = buffer location, ax = board address.
; Old version checked size, memory space, queue length here. Now done
; in higher level code.
; Set cx to length of this frame.
assume ds:nothing,es:nothing
push ds
mov ds,mem_base ; ds:si points at first byte to move
mov si,ax

cmp cx,GIANT
jbe rcv_size_ok ; is the size sane?
cmp ch,cl ; is it starlan bug (dup of low byte)
jne rcv_size_not_ok ; no.
;fix the starlan bug
mov ch,ds:[si+EN_RBUF_NXT_PG] ; Page after this frame
cmp ch,bl
ja rcv_frm_no_wrap
add ch,byte ptr cs:sm_rstop_ptr ; Wrap if needed
dec ch
rcv_frm_no_wrap:
sub ch,bl
dec ch
cmp cx,GIANT
jbe rcv_size_ok ; is the size sane?
rcv_size_not_ok:
mov cx,GIANT ; no, restore sanity.
rcv_size_ok:

add ax,cx ; Find the end of this frame.
cmp ah,byte ptr cs:sm_rstop_ptr ; Over the top of the ring?
jb rcopy_one_piece ; Go move it

rcopy_wrap:
; Copy in two pieces due to buffer wraparound.
mov ah,byte ptr cs:sm_rstop_ptr ; Compute length of first part
xor al,al
sub ax,si ; as all of the pages up to wrap point
sub cx,ax ; Move the rest in second part
push cx ; Save count of second part
mov cx,ax ; Count for first move
call rcopy_subr
mov si,SM_RSTART_PG*256 ; Offset to start of first receive page
pop cx ; Bytes left to move
rcopy_one_piece:
call rcopy_subr
pop ds
ret


rcopy_subr:
test board_features,BF_MEM16EN; Is this a WD8013?
je sm_wd8003 ; no, no need to enable 16-bit access.
loadport ; Base of device
setport EN_REG5 ; Enable 16-bit access
mov al,ENR5_MEM16EN+ENR5_LAN16EN+ENR5_LA19
out dx,al
call movemem ; Copy packet
mov al,ENR5_LAN16EN+ENR5_LA19 ; Disable 16-bit access to WD8013
out dx,al
ret
sm_wd8003:
call movemem ; Copy packet
ret


include 8390.asm

public usage_msg
usage_msg db "usage:",CR,LF
db " SMC_WD [options] [-o] ",CR,LF,'$'

public copyright_msg
copyright_msg db "Packet driver for SMC/WD/IBM Ethernet adapters, version "
db '0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,".",'0'+dp8390_version,CR,LF
db "Portions Copyright 1988, Robert C. Clements, K1BC",CR,LF
db "Portions Copyright 1992, 1993, Crynwr Software",CR,LF,'$'

not_our_msg label byte
db "The memory present at this address does not belong to WD/SMC/IBM",CR,LF,'$'
no_board_msg label byte
db "WD/SMC/IBM apparently not present at this memory address.",CR,LF,'$'
bad_cksum_msg label byte
db "WD/SMC/IBM not at this I/O address (or address PROM bad). Re-set parameters",CR,LF
db "with EZSETUP, or check jumpers.",CR,LF,'$'
bad_board_msg label byte
db "Suggested WD/SMC/IBM memory address is invalid.",CR,LF,'$'
occupied_msg label byte
db "Suggested WD/SMC/IBM memory address already occupied.",CR,LF,'$'
addr_bad_msg db "Memory address should be less than 65536.",CR,LF,'$'
using_16bits db "Accessing the board using 16 bits of data.",CR,LF,'$'
needs_16k_msg db "Please reconfigure the board to use 16K of RAM",CR,LF,'$'
int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
mem_base_name db "Memory address ",'$'
nic_name db "NIC ",'$'

occupied_switch db 0 ;if zero, don't use occupied test.
nic_number dw ?

extrn set_recv_isr: near
extrn skip_blanks: 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

;enter with dx:ax = number to print
extrn decout: near

;print a crlf.
extrn crlf: near

public parse_args
parse_args:
call skip_blanks
cmp al,'-' ;did they specify a switch?
jne not_switch
cmp byte ptr [si+1],'o' ;did they specify '-o'?
je got_occupied_switch
stc ;no, must be an error.
ret
got_occupied_switch:
mov occupied_switch,1
add si,2 ;skip past the switch's characters.
jmp parse_args ;go parse more arguments.
not_switch:
test sys_features,SYS_MCA
jnz do_mc_defaults
jmp just_parse_args
do_mc_defaults:

; channel selector resides at io 96h
; POS register base is at io 100h
; WD8003E ID is one of 6FC0h, 6FC1h or 6FC2h
; SMC ID is one of 61c8h or 61c9h.
; IBM Ethernet Adapter A is EFE5h

; search thro' the slots for a wd8003e card
mov cx, 8 ; for all channels(slots)

; channel select value for slots 0,1,2.. is 8,9,A etc
; start with slot 0, and then 7,6,5,4,3,2,1
get_05:
mov ax, cx ; channel number
or ax, 08h ; reg. select value
mov dx, 96h ; channel select register
out dx, al ; select channel

; read adapter id
mov dx, 101h
in al, dx ; adapter id - ms byte
mov ah, al
dec dx
in al, dx ; adapter id - ls byte

; Check if wd8003e
cmp ax, 06FC0h ;WD8003E/A or WD8003ET/A
je get_10
cmp ax, 06FC1h ;WD8003ST/A (Starlan)
je get_10
cmp ax, 06FC2h ;WD8003W/A
je get_10
;SMC's new IDs:
cmp ax, 061C8h ;WD8013EP/A
je get_20
cmp ax, 061C9h ;WD8013WP/A
je get_20
; Check if IBM Ethernet Adapter A
cmp ax, 0EFE5h ;long card
je get_12
cmp ax, 0EFD4h ;short card, BNC
je get_20
cmp ax, 0EFD5h ;short card, RJ_45
je get_20
loop get_05

mov dx,offset no_WD8003E_msg
mov etopen_diagn,37
stc
ret

no_WD8003E_msg:
db "WD/SMC/IBM board apparently not found.",CR,LF,'$'

int_xlate db 03,04,10,15

get_20:
jmp get_21

get_10:
; found our Adapter

; Get WD8003E I/O Address ( read POS Register 0 )
mov dx,102h
in al,dx
and ax,0F0h
jmp short get_17
get_12:
; Get long Ethernet Adapter/A I/O address
mov dx,102h
in al,dx
and ax,0FEh
get_17:
mov cl,4
shl ax,cl
mov io_addr,ax
; Get WD8003E shared RAM memory address (read POS Register 1 )
xor ax,ax
mov dx,103h
in al,dx
and al,0FCh
xchg al,ah
mov mem_base,ax
; Get WD8003E IRQ (read POS Register 3 )
xor ax,ax
mov dx,105h
in al,dx
and al,003h
mov bx,offset int_xlate
xlat
mov int_no,al
jmp short just_parse_args

int_xlate_20 db 03,04,10,14

get_21:
; Get short Ethernet Adapter/A I/O Address ( read POS Register 0 )
mov dx,102h
in al,dx
and ax,00F0h
or al,08h
xchg al,ah
mov io_addr,ax
; Get short Ethernet Adapter/A shared RAM memory address (read POS Register 1 )
mov dx,103h
in al,dx
test al,10000b
je get_21_needs_16k
and ax,0fh
shl al,1
or al,0c0h
xchg al,ah
mov mem_base,ax
; Get short Ethernet Adapter/A IRQ (read POS Register 3 )
xor ax,ax
mov dx,105h
in al,dx
shr al,1
shr al,1
and al,003h
mov bx,offset int_xlate_20
xlat
mov int_no,al

just_parse_args:
mov di,offset int_no
call get_number
mov di,offset io_addr
call get_number
mov di,offset mem_base
call get_number
clc
ret

get_21_needs_16k:
mov dx,offset needs_16k_msg
mov ah,9
int 21h
stc
ret

extrn etopen_diagn: byte
addr_not_avail:
mov dx,offset occupied_msg
mov etopen_diagn,34
stc
ret
bad_cksum:
mov dx,offset bad_cksum_msg
mov etopen_diagn,37
stc
ret
bad_memory:
mov dx,offset bad_board_msg
mov etopen_diagn,37
stc
ret
not_our_memory:
mov dx,offset not_our_msg
mov etopen_diagn,37
stc
ret
no_memory:
mov dx,offset no_board_msg
mov etopen_diagn,37
stc
ret

ENC_PAGE2 equ 080h ; select page 2 of chip registers
TCR_TST_690 equ 018h ; 690 xmit config test value

test_tcr:
;see if TXCR, when modified, also appears on page 2.
;enter with the bit value to test in cl.
loadport
setport EN_CCMD ; select page 0.
pause_
mov al, ENC_PAGE0 + ENC_NODMA + ENC_STOP
out dx,al

setport EN0_TXCR ; write test value to xmit
pause_
mov al,cl ; config register
out dx,al

setport EN_CCMD ; select page 2
pause_
mov al, ENC_PAGE2 + ENC_NODMA + ENC_STOP
out dx,al

setport EN0_TXCR ; read xmit config register
pause_
in al,dx
and al,TCR_TST_690
cmp al,cl
ret


init_card:
; Now get the board's physical address from on-board PROM into card_hw_addr
assume ds:code

mov nic_number, 8390 ; assume 8390

if 0 ;the following screws up on a 486/50, and the 690 support code doesn't
;seem to be really necessary anyway.
mov cl,0h
call test_tcr
jne check_690_1
mov cl,ENTXCR_ATD
call test_tcr
jne check_690_1
mov cl,ENTXCR_OFST
call test_tcr

jne check_690_1
mov cl,ENTXCR_ATD or ENTXCR_OFST
call test_tcr
je check_690_2

check_690_1:
or board_features, BF_NIC_690
mov nic_number, 690 ; yes, it's a 690
mov rcv_modes+2[4*2],0 ;nuke mode 4 -- the 690 has no hash tbl.

check_690_2:
loadport
setport EN_CCMD ; back to page 0
mov al, ENC_PAGE0 + ENC_NODMA + ENC_STOP
pause_
out dx, al

mov al, ENTXCR_LOOP ; back to loopback mode
setport EN0_TXCR
pause_
out dx, al
endif

test sys_features,SYS_MCA
jz etopen_no_mc
or board_features,BF_16K
or endcfg,ENDCFG_WTS
loadport
setport EN_REG5
mov al,ENR5_EIL
out dx,al ; enable 8390 interrupts to bus
jmp etopen_have_id
etopen_no_mc: ; Check for WD8013EBT
loadport ; WD8013EBT doesn't have register alaasing
setport EN_CMD ; Register 0 may be aliased to Register 8
mov bx, dx
setport EN_SAPROM
mov cx, EN_SAPROM-EN_CMD ; Check 8 bytes
alias_loop:
in al, dx ; Get one register
mov ah, al
xchg bx, dx ; Switch to other register
in al, dx ; Get other register
cmp al, ah ; Are they the same?
jne not_aliased ; Nope, not aliased
inc bx ; Increment register pair
inc dx
dec cx ; Decrement loop counter
jne alias_loop ; Finished?
jmp etopen_have_id ; Aliased; not WD8013EBT
not_aliased: ; Not aliased; Check for 16-bit board
loadport
setport EN_REG1 ; Bit 0 must be unmodifiable
in al, dx ; Get register 1
mov bl, al ; Store original value
xor al, ENR1_BUS16BIT ; Flip bit 0
out dx, al ; Write it back
and al, ENR1_BUS16BIT ; Throw other bits away
mov ah, al ; Store bit value
in al, dx ; Read register again
and al, ENR1_BUS16BIT ; Throw other bits away
cmp al, ah ; Was it modified?
jne board16bit ; No; board is a WD8013EBT !
mov al, bl ; Get original value
out dx, al ; Write it back
jmp etopen_have_id
board16bit: ; But is it plugged into a 16-bit slot?
and al, ENR1_BUS16BIT ; Throw other bits away
je etopen_have_id ; Nope; silly board installer!
mov dx,offset using_16bits
mov ah,9
int 21h
or board_features,BF_MEM16EN+BF_16K
or endcfg,ENDCFG_WTS
loadport
setport EN_REG5
mov al,ENR5_LAN16EN+ENR5_LA19 ; Write LA19 now, but not MEM16EN
out dx,al ; enable 8390 interrupts to bus

etopen_have_id:

loadport ; base of device
setport EN_SAPROM ; Where the address prom is
cld ; make sure string mode is right
movseg es,cs
mov di, offset rom_address
mov cx, EADDR_LEN ; Set count for loop
xor bx, bx ; Clear the addr ROM checksum
ini_addr_loop:
in al,dx ; Get a byte of address
stosb ; Feed it to caller
add bl,al ; Compute the checksum
inc dx ; Next byte at next I/O port
loop ini_addr_loop ; Loop over six bytes

in al, dx ; Get seventh byte
add bl, al ; Add it in
inc dx ; Step to eighth byte
in al, dx ; Get last byte
add bl, al ; Final checksum
cmp bl, 0ffh ; Correct?
je good_cksum
jmp bad_cksum ; No, board is not happy
good_cksum:

cmp mem_base.offs,0 ;low word of segment can't be zero.
je mem_base_bad
cmp mem_base.segm,0 ;high word of segment must be zero.
je mem_base_ok
mem_base_bad:
mov dx,offset addr_bad_msg
stc
ret
mem_base_ok:

; Check if the shared memory address range is available to us
mov bx,mem_base
cmp occupied_switch,0 ; did they insist?
jne no_lim_chk ; yes, don't check.
cmp bh,080h ; low limit is 8000
jae fr_8000
bad_memory_j_1:
jmp bad_memory
fr_8000:
cmp bh,0f0h ; upper limit is F000
jae bad_memory_j_1
test bx,01ffh ; must be on a 8 k boundary
jnz bad_memory_j_1
no_lim_chk:
mov di,8*1024/16 ; 8 kbyte
mov sm_rstop_ptr,32
test board_features,BF_16K
jz just_8k
test bx,03ffh ; must be on a 16K boundary
jnz bad_memory_j_1
mov di,16*1024/16 ; 16 kbytes
mov sm_rstop_ptr,64
just_8k:
cmp occupied_switch,0 ; did they insist?
jne is_avail ; yes, don't check.
call occupied_chk ; check if address range is available
jnc is_avail
jmp addr_not_avail ; we HAVE to have at least 8/16 kbyte
is_avail:
test board_features,BF_16K
jnz not_32k
mov di,32*1024/16 ; may be there is space for 32 kbyte
call occupied_chk
jc not_32k ; no, then don't try it later either
and bh,7
jnz not_32k ; must be on a 32k boundary
mov sm_rstop_ptr,128 ; yes, there is space for a WD8003EBT
not_32k:

; Turn on the shared memory block
loadport
setport EN_CMD ; Point at board command register
mov ax, mem_base ; Find where shared memory will be mapped
mov al, ah ; Shift to right location
shr al, 1 ; in the map control word
and al, EN_MEM_MASK ; Just these bits
or al, EN_MEMEN ; Command to turn on map
test sys_features,SYS_MCA
jz AT_card
mov al,EN_MEMEN ; membase handled different for MC card
AT_card:
out dx, al ; Create that memory

; Find how much memory this card has (without destroying other memory)
mov si,ax ; save bord command value
mov es,mem_base
mov bl,0FFH ; first try 32 kbyte (WD8003EBT)
mov bh,sm_rstop_ptr ; or what is available
dec bh
memloop:
dec bx ; use even address
cli ; disable interrupts
mov cx,es:[bx] ; save old memory contents
mov word ptr es:[bx],05A5Ah ; put testpattern
loadport
setport EN_CCMD ; drain the board bus for any
in al,dx ; capacitive memory
cmp word ptr es:[bx],05A5Ah ; any real memory there?
jne not_our_mem ; no
setport EN_CMD ; yes
mov ax,si
and al,not EN_MEMEN
out dx,al ; turn off our memory
jmp short $+2
or al,EN_MEMEN
cmp word ptr es:[bx],05A5Ah ; was it OUR memory?
out dx,al ; turn on our memory.
jmp short $+2
mov es:[bx],cx ; restore the original contents.
sti
jne our_mem ; yes, it wasn't there any more
not_our_mem: ; no, it was still there
shr bx,1 ; test if half as much memory
cmp bx,1FFFh ; down to 8 kbyte
jae memloop
jmp not_our_memory ; no memory at address mem_base
our_mem: ; it IS our memory!
inc bh
mov sm_rstop_ptr,bh ; # of 256 byte ring bufs + 1
mov ch,bh
xor cl,cl
mov ax,mem_base
call memory_test ; check all of that memory
je mem_ok
jmp no_memory
mem_ok:
clc
ret

public print_parameters
print_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 mem_base
mov dx,offset mem_base_name
call print_number

mov dx,offset nic_name ;print the number in decimal.
mov ah,9
int 21h
mov ax,nic_number
xor dx,dx
call decout
call crlf

ret

include memtest.asm
include occupied.asm

code ends

end


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