Category : Network Files
Archive   : PKTD11A.ZIP
Filename : 3C509.ASM

 
Output of file : 3C509.ASM contained in archive : PKTD11A.ZIP
version equ 0
;History:1145,1

.286

; 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.

;-------------------------------------------------------------------------
; vA 4/3/93 Hacks for multiple ISA board support added, IJW @ Leeds Univ.
; vB 10/3/93 Added checks for legal packet size in rx, ijw.
;-------------------------------------------------------------------------

include defs.asm

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

;----------------------------------------------------------------------------;
; ;
; This source file is the property of 3Com Corporation and may not be ;
; copied or distributed in any isomorphic form without an appropriate ;
; prior licensing arrangement with 3Com Corporation. ;
; ;
; Copyright (c) 1988 3Com Corporation ;
; ;
;------ Equates -------------------------------------------------------------;
;
; Command code masks
;
CMD_CMDMASK equ 0F800h ; command bits
CMD_ARGMASK equ 007FFh ; argument bits
;
; Command codes, word form
;
CMD_GLOBALRESET equ 00000b shl 11 ; global reset
CMD_SELECTWINDOW equ 00001B shl 11 ; select register window
CMD_STARTINTXCVR equ 00010b shl 11 ; start internal transciver
CMD_RXDISABLE equ 00011b shl 11 ; rx disable
CMD_RXENABLE equ 00100b shl 11 ; rx enable
CMD_RXRESET equ 00101b shl 11 ; rx reset
CMD_RXDISCARD equ 01000b shl 11 ; rx discard top packet
CMD_TXENABLE equ 01001b shl 11 ; tx enable
CMD_TXDISABLE equ 01010b shl 11 ; tx disable
CMD_TXRESET equ 01011b shl 11 ; tx reset
CMD_REQUESTINT equ 01100b shl 11 ; request interrupt
CMD_ACKNOWLEDGE equ 01101b shl 11 ; acknowledge interrupt
CMD_SETINTMASK equ 01110b shl 11 ; set interrupt mask
CMD_SETRZMASK equ 01111b shl 11 ; set read zero mask
CMD_SETRXFILTER equ 10000b shl 11 ; set rx filter
CMD_SETRXEARLY equ 10001b shl 11 ; set rx early threshold
CMD_SETTXAVAILABLE equ 10010b shl 11 ; set tx available threshold
CMD_SETTXSTART equ 10011b shl 11 ; set tx start threshold
CMD_STATSENABLE equ 10101b shl 11 ; statistics enable
CMD_STATSDISABLE equ 10110b shl 11 ; statistics disable
CMD_STOPINTXCVR equ 10111b shl 11 ; start internal transciver
;
; Command codes, hibyte form (commands without operands only)
;
CMDH_STARTINTXCVR equ CMD_STARTINTXCVR shr 8
CMDH_RXDISABLE equ CMD_RXDISABLE shr 8
CMDH_RXENABLE equ CMD_RXENABLE shr 8
CMDH_RXDISCARD equ CMD_RXDISCARD shr 8
CMDH_TXENABLE equ CMD_TXENABLE shr 8
CMDH_TXDISABLE equ CMD_TXDISABLE shr 8
CMDH_REQUESTINT equ CMD_REQUESTINT shr 8
CMDH_STATSENABLE equ CMD_STATSENABLE shr 8
CMDH_STATSDISABLE equ CMD_STATSDISABLE shr 8
CMDH_STOPINTXCVR equ CMD_STOPINTXCVR shr 8
;
; Status register bits (INT for interrupt sources, ST for the rest)
;
INT_LATCH equ 00001h ; interrupt latch
INT_ADAPTERFAIL equ 00002h ; adapter failure
INT_TXCOMPLETE equ 00004h ; tx complete
INT_TXAVAILABLE equ 00008h ; tx available
INT_RXCOMPLETE equ 00010h ; rx complete
INT_RXEARLY equ 00020h ; rx early
INT_REQUESTED equ 00040h ; interrupt requested
INT_UPDATESTATS equ 00080h ; update statistics
ST_FAILED equ 00800h ; command failed
ST_BUSY equ 01000h ; command busy
ST_WINDOW equ 0E000h ; window bits (13-15)

STH_FAILED equ ST_FAILED shr 8
STH_BUSY equ ST_BUSY shr 8
STH_WINDOW equ ST_WINDOW shr 8

;
; RxStatus register bits
;
RXS_INCOMPLETE equ 8000h ; not completely received
RXS_ERROR equ 4000h ; error in packet
RXS_LENGTH equ 07FFh ; bytes in RxFIFO
RXS_ERRTYPE equ 3800h ; Rx error type, bit 13-11
RXS_OVERRUN equ 0000h ; overrun error
RXS_OVERSIZE equ 0800h ; oversize packet error
RXS_DRIBBLE equ 1000h ; dribble bit (not an error)
RXS_RUNT equ 1800h ; runt packet error
RXS_CRC equ 2800h ; CRC error
RXS_FRAMING equ 2000h ; framing error

RXSH_INCOMPLETE equ RXS_INCOMPLETE shr 8
RXSH_ERROR equ RXS_ERROR shr 8
RXSH_ERRTYPE equ RXS_ERRTYPE shr 8
RXSH_OVERRUN equ RXS_OVERRUN shr 8
RXSH_DRIBBLE equ RXS_DRIBBLE shr 8
RXSH_CRC equ RXS_CRC shr 8
RXSH_RUNT equ RXS_RUNT shr 8
RXSH_OVERSIZE equ RXS_OVERSIZE shr 8
RXSH_FRAMING equ RXS_FRAMING shr 8
;
; TxStatus register bits
;
TXS_COMPLETE equ 80h ; tx completed
TXS_INTREQUESTED equ 40h ; interrupt on successfull tx
TXS_ERRTYPE equ 38h ; error bits
TXS_JABBERERROR equ 20h ; jabber error
TXS_UNDERRUN equ 10h ; tx underrun error
TXS_MAXCOLLISIONS equ 08h ; max collisions error
TXS_STATUSOVERFLOW equ 04h ; TX status stack is full
;
; Window Numbers
;
WNO_SETUP equ 0 ; setup/configuration
WNO_OPERATING equ 1 ; operating set
WNO_STATIONADDRESS equ 2 ; station address setup/read
WNO_FIFO equ 3 ; FIFO management
WNO_DIAGNOSTICS equ 4 ; diagnostics
WNO_READABLE equ 5 ; registers set by commands
WNO_STATISTICS equ 6 ; statistics
;
; Port offsets, Window 1 (WNO_OPERATING)
;
PORT_CmdStatus equ 0Eh ; command/status
PORT_TxFree equ 0Ch ; free transmit bytes
PORT_TxStatus equ 0Bh ; transmit status (byte)
PORT_Timer equ 0Ah ; latency timer (byte)
PORT_RxStatus equ 08h ; receive status
PORT_RxFIFO equ 00h ; RxFIFO read
PORT_TxFIFO equ 00h ; TxFIFO write
;
; Port offsets, Window 0 (WNO_SETUP)
;
PORT_EEData equ 0Ch ; EEProm data register
PORT_EECmd equ 0Ah ; EEProm command register
PORT_CfgResource equ 08h ; resource configuration
PORT_CfgAddress equ 06h ; address configuration
PORT_CfgControl equ 04h ; configuration control
PORT_ProductID equ 02h ; product id (EISA)
PORT_Manufacturer equ 00h ; Manufacturer code (EISA)
;
; Port offsets, Window 2 (WNO_STATIONADDRESS)
;
PORT_SA0_1 equ 00h ; station address bytes 0,1
PORT_SA2_3 equ 02h ; station address bytes 2,3
PORT_SA4_5 equ 04h ; station address bytes 4,5
;
; Port offsets, Window 3 (WNO_FIFO)
;
PORT_ALT_TxFree equ 0Ch ; free transmit bytes (dup)
PORT_RxFree equ 0Ah ; free receive bytes
;
; Port offsets, Window 4 (WNO_DIAGNOSTICS)
;
PORT_MediaStatus equ 0Ah ; media type/status
PORT_SlingshotStatus equ 08h ; Slingshot status
PORT_NetDiagnostic equ 06h ; net diagnostic
PORT_FIFODiagnostic equ 04h ; FIFO diagnostic
PORT_HostDiagnostic equ 02h ; host diagnostic
PORT_TxDiagnostic equ 00h ; tx diagnostic
;
; Port offsets, Window 5 (WNO_READABLE)
;
PORT_RZMask equ 0Ch ; read zero mask
PORT_IntMask equ 0Ah ; interrupt mask
PORT_RxFilter equ 08h ; receive filter
PORT_RxEarly equ 06h ; rx early threshold
PORT_TxAvailable equ 02h ; tx available threshold
PORT_TxStart equ 00h ; tx start threshold
;
; Port offsets, Window 6 (WNO_STATISTICS)
;
PORT_TXBYTES equ 0Ch ; tx bytes ok
PORT_RXBYTES equ 0Ah ; rx bytes ok
PORT_TXDEFER equ 08h ; tx frames deferred (byte)
PORT_RXFRAMES equ 07h ; rx frames ok (byte)
PORT_TXFRAMES equ 06h ; tx frames ok (byte)
PORT_RXDISCARDED equ 05h ; rx frames discarded (byte)
PORT_TXLATE equ 04h ; tx frames late coll. (byte)
PORT_TXSINGLE equ 03h ; tx frames one coll. (byte)
PORT_TXMULTIPLE equ 02h ; tx frames mult. coll. (byte)
PORT_TXNOCD equ 01h ; tx frames no CDheartbt (byte)
PORT_TXCARRIERLOST equ 00h ; tx frames carrier lost (byte)
;
; Various command arguments
;
INT_ALLDISABLED equ 00000000000b ; all interrupts disabled
INT_ALLENABLED equ 00011111110b ; all interrupts enabled

FILTER_INDIVIDUAL equ 0001b ; individual address
FILTER_MULTICAST equ 0010b ; multicast/group addresses
FILTER_BROADCAST equ 0100b ; broadcast address
FILTER_PROMISCUOUS equ 1000b ; promiscuous mode

RXEARLY_DISABLED equ 2032 ; RxEarly to disable

TXAVAIL_DISABLED equ 2040 ; TxAvailable to disable
TXAVAIL_MIN equ 4

TXSTART_DISABLED equ 2040 ; TxStart to disable
TXSTART_MIN equ 0
TXSTART_MAX equ TXSTART_DISABLED

RXLENGTH_MAX equ 1792 ; maximum rxlength
;
; Transmit Preamble
;
PREAMBLESIZE equ 4 ; transmit preamble size
TXP_INTONSUCCESS equ 8000h ; interrupt on successful tx
;
; Bits in various diagnostics registers
;
MEDIA_TP equ 8000h ; TP transciever
MEDIA_BNC equ 4000h ; Thinnet transciever
MEDIA_INTENDEC equ 2000h ; internal encoder/decoder
MEDIA_SQE equ 1000h ; SQE present
MEDIA_LBEAT equ 0800h ; link beat ok (TP)
MEDIA_POLARITY equ 0400h ; polarity (TP)
MEDIA_JABBER equ 0200h ; jabber (TP)
MEDIA_UNSQUELCH equ 0100h ; unsquelch (TP)
MEDIA_LBEATENABLE equ 0080h ; link beat enable (TP)
MEDIA_JABBERENABLE equ 0040h ; jabber enable (TP)
MEDIA_CRS equ 0020h ; carrier sense
MEDIA_COLLISION equ 0010h ; collision
MEDIA_SQEENABLE equ 0008h ; enable SQE statistics

NETD_EXTLOOPBACK equ 8000h ; TP external loopback
NETD_ENDECLOOPBACK equ 4000h ; ENDEC loopback
NETD_CORELOOPBACK equ 2000h ; ethernet core loopback
NETD_FIFOLOOPBACK equ 1000h ; FIFO loopback
NETD_TXENABLED equ 0800h ; tx enabled
NETD_RXENABLED equ 0400h ; rx enabled
NETD_TXTRANSMITTING equ 0200h ; tx transmitting
NETD_TXRESETREQD equ 0100h ; tx reset required

FIFOD_RXRECEIVING equ 8000h ; rx receiveing
FIFOD_RXUNDERRUN equ 2000h ; rx underrun
FIFOD_RXSTATUSOVER equ 1000h ; rx status overrun
FIFOD_RXOVERRUN equ 0800h ; rx overrun
FIFOD_TXOVERRUN equ 0400h ; tx overrun
FIFOD_BISTRESULTS equ 00FFh ; BIST results (mask)

SLING_TXUNDERRUN equ 2000h ; Slingshot TxUnderrun bit
;
; board identification codes, byte swapped in Rev 0
;
EISA_MANUFACTURER_ID equ 06D50h ; EISA manufacturer code
ISA_PRODUCT_ID equ 09050h ; Product ID for ISA board
PRODUCT_ID_MASK equ 0F0FFh ; Mask off revision nibble
;
; EEProm access
;
EE_BUSY equ 8000h ; EEProm busy bit in EECmd
EE_TCOM_NODE_ADDR_WORD0 equ 00h
EE_TCOM_NODE_ADDR_WORD1 equ 01h
EE_TCOM_NODE_ADDR_WORD2 equ 02h
EE_VULCAN_PROD_ID equ 03h
EE_MANUFACTURING_DATA equ 04h
EE_SERIAL_NUMBER_WORD0 equ 05h
EE_SERIAL_NUMBER_WORD1 equ 06h
EE_MANUFACTURER_CODE equ 07h
EE_ADDR_CONFIGURATION equ 08h
EE_RESOURCE_CONFIGURATION equ 09h
EE_OEM_NODE_ADDR_WORD0 equ 0Ah
EE_OEM_NODE_ADDR_WORD1 equ 0Bh
EE_OEM_NODE_ADDR_WORD2 equ 0Ch
EE_SOFTWARE_CONFIG_INFO equ 0Dh
EE_CWORD equ 0Eh
;
; contention logic
;
READ_EEPROM equ 080h
ID_GLOBAL_RESET equ 0C0h
SET_TAG_REGISTER equ 0D0h
TEST_TAG_REGISTER equ 0D8h
ACTIVATE_AND_SET_IO equ 0E0h
ACTIVATE_VULCAN equ 0FFh
;
; Resource Configuration Register bits
;
RCONFIG_IRQ equ 0F000h
;
; Address Configuration Register bits
;
ACONFIG_XCVR equ 0C000h
ACONFIG_IOBASE equ 0001Fh

IOBASE_EISA equ 0001Fh

TP_XCVR equ 00000h
BNC_XCVR equ 0C000h
AUI_XCVR equ 04000h

MIN_IO_BASE_ADDR equ 200h
MAX_IO_BASE_ADDR equ 3F0h
REGISTER_SET_SIZE equ 10h
;
; Software Configuration Register bits
;
SW_OPTIMIZE equ 0030h
SW_MAXCLI equ 3F00h
SW_LINKBEAT equ 4000h
;
; Possibilities for SW_OPTIMIZE
;
OPTIMIZE_DOS_CLIENT equ 0010h
OPTIMIZE_WINDOWS_CLIENT equ 0020h
OPTIMIZE_SERVER equ 0030h
;
; Configuration Control Register bits
;
ENABLE_ADAPTER equ 01h

setwin macro win
setport PORT_CmdStatus
mov ax,CMD_SELECTWINDOW+win
out dx,ax
endm

extrn is_eisa: byte ;=0 if ISA, =1 if EISA
extrn is_186: byte ;=0 if 808[68], =1 if 80[1234]86.
extrn is_386: byte ;=0 if 80[12]8[68], =1 if 80[34]86.

public int_no, io_addr
int_no db 0,0,0,0 ;must be four bytes long for get_number.
io_addr dw 0,0 ;must be four bytes long for get_number.

public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK,IEEE8023,0 ;null terminated list of classes.
driver_type db 94 ;assigned by FTP Software,
driver_name db '3c509',0 ;name of the driver.
driver_function db 2
parameter_list label byte
db 1 ;major rev of packet driver specification
db 9 ;minor rev of packet driver specification
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 rcv_mode_2
dw rcv_mode_3
dw 0 ;haven't set up perfect filtering yet.
dw rcv_mode_5
dw rcv_mode_6

include timeout.asm

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 es:di->upcall routine, (0:0) if no upcall is desired.
; (only if the high-performance bit is set in driver_function)
;enter with ds:si -> packet, cx = packet length.
;if we're a high-performance driver, es:di -> upcall.
;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

loadport
setport PORT_TxStatus ;get the previous transmit status.
in al,dx
setport PORT_CmdStatus
test al,TXS_UNDERRUN or TXS_JABBERERROR ;do we need to reset transmitter?
je send_pkt_0
push ax
mov ax,CMD_TXRESET
out dx,ax
pop ax
send_pkt_0:

test al,TXS_ERRTYPE ;any errors?
je send_pkt_3 ;no.
call count_out_err ;yes, count it.
mov ax,CMD_TXENABLE ;yes, re-enable the transmitter.
out dx,ax
send_pkt_3:

mov bx,cx ;round BX up to dword boundary.
add bx,3
and bx,not 3

setport PORT_TxFree ;wait for enough bytes in transmit buffer.
mov ax,18
call set_timeout
send_pkt_1:
in ax,dx
cmp ax,bx
jae send_pkt_2
call do_timeout
jne send_pkt_1
mov dh,CANT_SEND ;timed out, can't send.
stc
ret
send_pkt_toobig:
mov dh,NO_SPACE
stc
ret
send_pkt_2:

setport PORT_TxFIFO
mov ax,cx ;output the count
out dx,ax ; (no interrupt requested)
out dx,ax ;output the second reserved word.
mov cx,bx ;output the rest of the packet.

cmp is_386,0 ;can we output dwords?
jne send_pkt_7 ;yes.
shr cx,1 ;output 16 bits at a time.
rep outsw
jmp short send_pkt_6
send_pkt_7:
.386
shr cx,2 ;already rounded up.
rep outsd ;output 32 bits at a time.
.286
send_pkt_6:

clc
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:

loadport
setwin WNO_STATIONADDRESS
setport PORT_SA0_1
set_address_1:
lodsb
out dx,al
inc dx
loop set_address_1
set_address_okay:
mov cx,EADDR_LEN ;return their address length.
clc
set_address_done:
push cs
pop ds
assume ds:code
loadport
setwin WNO_OPERATING
ret


;skip past the following two bytes while destroying BX.
skip2 macro
db 0bbh ;opcode of "mov bx,0000"
endm

rcv_mode_1:
mov al,0 ;receive nothing
skip2
rcv_mode_2:
mov al,1 ;receive individual address
skip2
rcv_mode_3:
mov al,5 ;receive individual address+broadcast
skip2
rcv_mode_5:
mov al,3 ;receive individual address+group addr(multicast)
skip2
rcv_mode_6:
mov al,8 ;receive all packets.
mov ah,CMD_SETRXFILTER shr 8 ;set receive filter
loadport
setport PORT_CmdStatus
out dx,ax
ret


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


public terminate
terminate:
loadport
setport PORT_CmdStatus
mov ax,CMD_GLOBALRESET
out dx,ax
ret


public reset_interface
reset_interface:
;reset the interface.
assume ds:code
ret


;decide if we know this packet's type.
;enter with es:di -> packet type, dl = packet class.
;exit with nc if we know it, cy if not.
extrn recv_locate: near

;do the first upcall, get a pointer to the packet.
;enter with cx = packet length.
;exit with cx = packet length, es:di -> buffer for the packet.
extrn recv_found: near

;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

ether_buff db EADDR_LEN dup(?)
db EADDR_LEN dup(?)
ether_type db 8 dup(?)
ETHER_BUFF_LEN equ $ - ether_buff
.erre (ETHER_BUFF_LEN and 3) eq 0 ;must be an even # of dwords.

early_bytes dw 0 ;the early byte gets the worm.


read_header:
;enter with dx -> PORT_RxFIFO
;exit with es:di -> packet type.

mov ax,ds
mov es,ax
mov di,offset ether_buff
mov cx,ETHER_BUFF_LEN/4
repinsd:
shl cx,1 ;*** this gets changed into "rep insd"
rep insw ;*** "nop" on a 386 or 486.

mov di,offset ether_type

mov dl, BLUEBOOK ;assume bluebook Ethernet.
mov ax, es:[di]
xchg ah, al
cmp ax, 1500
ja read_header_1
inc di ;set di to 802.2 header
inc di
mov dl, IEEE8023
read_header_1:
ret


public recv
recv:
;called from the recv isr. All registers have been saved, ds=cs,
;our interrupt has been acknowledged, and our interrupts have been
;masked at the interrupt controller.
assume ds:code
recv_another:
loadport
setport PORT_CmdStatus
in ax,dx ;did we get a packet?
or ax,CMD_ACKNOWLEDGE
out dx,ax
setport PORT_RxStatus
test al,INT_RXCOMPLETE
jne recv_complete
test al,INT_RXEARLY ;are we getting it early?
jne recv_early
jmp recv_exit ;no.
recv_early:
in ax,dx ;get the amount we can read.
and ax,RXS_LENGTH
cmp ax,ETHER_BUFF_LEN ;do we have enough to read early?
jb recv_early_1 ;no, give up.

mov early_bytes,ETHER_BUFF_LEN

setport PORT_RxFIFO
call read_header
call recv_locate ;see if this is a type we want.
jnc recv_early_1 ;it is, just exit.
jmp recv_discard ;it isn't.

recv_early_1:
jmp recv_exit

;yes, this is dead code. It's only in here to ensure that the setport macro
;has the right value.
setport PORT_RxStatus
recv_complete:
in ax,dx ;get the size.
test ax,RXS_ERROR ;any errors?
je recv_complete_2 ;no, it's fine.

and ax,RXS_ERRTYPE ;get just the error type bits.
cmp ax,RXS_DRIBBLE ;dribble is just a warning.
jne recv_complete_1

recv_err:
call count_in_err
jmp recv_discard

recv_complete_1:
in ax,dx ;get the size again.
recv_complete_2:
;Put it on the receive queue
and ax,RXS_LENGTH
mov cx,ax

cmp early_bytes,0 ;did we read the header in already?
jne recv_complete_3 ;yes, we've already got it.

cmp cx,RUNT ;check legal packet size
jb recv_err
cmp cx,GIANT
ja recv_err

push cx
setport PORT_RxFIFO
call read_header
pop cx

push cx
call recv_find
pop cx
jmp short recv_complete_4

recv_complete_3:
add cx,early_bytes ;add in the early bytes we got.

cmp cx,RUNT ;check legal packet size
jb recv_err
cmp cx,GIANT
ja recv_err

push cx
call recv_found ;do the first upcall.
pop cx

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

push es ;remember where the buffer pointer is.
push di

mov bx,cx ;save the count.
mov cx,ETHER_BUFF_LEN/2 ;move the data over.
mov si,offset ether_buff
rep movsw

loadport ;restore the I/O port.
setport PORT_RxFIFO
mov cx,bx ;restore the count.
sub cx,ETHER_BUFF_LEN ;but leave off what we've already copied.

cmp is_386,0
jne io_input_386
io_input_286:
push cx
shr cx,1
rep insw
pop cx
jnc io_input_286_1 ;go if the count was even.
insb ;get that last byte.
in al,dx ;and get the pad byte.
test cx,2 ;even number of words?
jne io_input_done ;no.
in ax,dx ;yes, get the pad word.
jmp short io_input_done
io_input_286_1:
test cx,2 ;odd number of words?
je io_input_done ;no.
in ax,dx ;yes, get the pad word.
jmp short io_input_done

io_input_386:
.386
push eax
push cx ;first, get all the full words.
shr cx,2
rep insd
pop cx
test cx,3 ;even number of dwords?
je io_input_386_one_byte ;yes.
in eax,dx ;no, get the partial word.
test cx,2 ;a full word to be stored?
je io_input_386_one_word
stosw ;yes, store it,
shr eax,16 ;and move over by a word.
io_input_386_one_word:

test cx,1 ;a full byte to be stored?
je io_input_386_one_byte
stosb ;yes, store it.
io_input_386_one_byte:
pop eax
.286

io_input_done:

mov cx,bx ;restore the count.
pop si
pop ds
assume ds:nothing
call recv_copy ;tell them that we copied it.

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

recv_discard:
loadport
setport PORT_CmdStatus
mov ax,CMD_RXDISCARD
out dx,ax

recv_discard_1:
in ax,dx ;wait for the command to finish.
test ax,ST_BUSY
jne recv_discard_1

mov early_bytes,0

jmp recv_another
recv_exit:
ret


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: 3c509 [options] "
db "[id_port]|[io_port]|[board_num]",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet driver for a 3c509, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
db "Portions Copyright 1992, Crynwr Software",CR,LF,'$'
needs_186_msg db "Needs a 186 or higher-numbered processor",CR,LF,'$'
no_isa_msg db CR,LF
db "No 3c509 found. Use a different id_port value. Default is 0x110.",CR,LF,'$'
reading_msg db "Reading EEPROM.",'$'

multiple_msg db "Multiple 3C509s found, specify i/o port",CR,LF,'$'
wrong_port_msg db "No 3C509 board found at specified i/o port",CR,LF,'$'
eisa_in_isa_msg db "EISA configured board in ISA slot",CR,LF,'$'

int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
aui_xcvr_msg db "Using AUI transceiver",CR,LF,'$'
bnc_xcvr_msg db "Using BNC (10Base2) transceiver",CR,LF,'$'
tp_xcvr_msg db "Using Twisted Pair (10BaseT) transceiver",CR,LF,'$'
id_port_name db "ID port ",'$'

;called when you're ready to receive interrupts.
extrn set_recv_isr: 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 -> argument string, di -> dword to print.
extrn print_number: near

;-> the unique Ethernet address of the card. Filled in by the etopen routine.
extrn rom_address: byte

;-> current address. Normally the same as rom_address, unless changed
;by the set_address() call.
extrn my_address: byte

address_configuration dw ?
resource_configuration dw ?

is_10base2 db 0
is_10baseT db 0

id_port dw 110h,0
scratch dw 0,0 ;for multi-board support
board_number db 0

;print the character in al.
extrn chrout: near

;print a crlf
extrn crlf: near

;parse_args is called with si -> first parameter (CR if none).
public parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
mov di,offset scratch
call get_number ;also returns number in bx:cx
jc pa_ok
cmp cx,15 ;board or slot?
ja pa_id
mov board_number,cl
jmp parse_args
pa_id:
cmp cx,200h ;id-port (100-1f0) or io-port (200-3e0) ?
jae pa_io
cmp cx,100h
jb pa_bad
and cx,1F0h
mov id_port,cx
jmp parse_args
pa_io:
cmp cx,3E0h
ja pa_bad ; bad value
and cx,3F0h
mov io_addr,cx
jmp parse_args ; get another arg
pa_ok:
clc
ret
pa_bad:
stc
ret


public etopen
etopen:
;initialize the driver. Fill in rom_address with the assigned address of
;the board. Exit with nc if all went well, or cy, dx -> $ terminated error msg.
;if all is okay,
cmp is_186,0 ;this version requires a 186 or better.
jne etopen_1
mov dx,offset needs_186_msg
stc
ret
etopen_1:

cmp is_386,0 ;can we do a real insd?
je etopen_2
;overlay the repinsd routine with a real "rep insd;nop"
mov word ptr repinsd+0,066h+0f3h*256
mov word ptr repinsd+2,06dh+090h*256
etopen_2:

cmp is_eisa,0
jne etopen_eisa
jmp etopen_isa
etopen_eisa:
mov cx,0fh
eisa_search:
mov dx,cx ;move it into the first nibble.
shl dx,12
or dx,0c80h
in ax,dx ;look for the manufacturer's ID
cmp ax,EISA_MANUFACTURER_ID
jne eisa_search_1
inc dx
inc dx
in ax,dx ;look for the product ID
and ax,PRODUCT_ID_MASK
cmp ax,ISA_PRODUCT_ID
je eisa_found
eisa_search_1:
loop eisa_search
jmp etopen_isa ;;; if it's not EISA-configured, try ISA.

eisa_found:
and dx,0f000h
mov io_addr,dx

loadport
setwin WNO_SETUP

setport PORT_CfgAddress
in ax,dx
mov address_configuration,ax

setport PORT_CfgResource
in ax,dx
mov resource_configuration,ax

setport PORT_EECmd
mov si,offset read_ee_eisa
call read_eaddr

jmp have_configuration

;---------------------------------------------------------------------------
; etopen_ISA for multiple 3c509 boards, added 3/93, IJW.
;
etopen_isa:
and id_port,01F0h
mov dx,id_port
xor bl,bl

isa_1:
cli
call write_id_pat
or bl,bl ; first board?
jnz isa_2
mov al,SET_TAG_REGISTER
out dx,al
isa_2:
mov al,EE_MANUFACTURER_CODE
call read_ee_isa
cmp ax,EISA_MANUFACTURER_ID ; board here ?
jne isa_3 ; no

mov al,EE_OEM_NODE_ADDR_WORD0 ; must read the address..
call read_ee_isa ; else it don't work ?!
mov al,EE_OEM_NODE_ADDR_WORD1 ; address[1]
call read_ee_isa ; address[2]
mov al,EE_OEM_NODE_ADDR_WORD2
call read_ee_isa ; address[3]

inc bl ;count up a board.
mov al,bl
or al,SET_TAG_REGISTER
out dx,al
xor al,al
out dx,al ; reset
sti
jmp isa_1 ; see if any more boards

isa_3:
xor al,al
out dx,al ; reset
sti
or bl,bl ; found any boards ?
jnz isa_4

not_found_isa:
mov dx,offset no_isa_msg
stc
ret
isa_multiple:
mov dx,offset multiple_msg
stc
ret

isa_4:
xor bl,bl
isa_5:
cli
call write_id_pat
inc bl
mov al,bl
add al,TEST_TAG_REGISTER
out dx,al ; select the board
mov al,SET_TAG_REGISTER
out dx,al
mov al,EE_MANUFACTURER_CODE
call read_ee_isa
cmp ax,EISA_MANUFACTURER_ID ; board here ?
jne isa_8

cmp io_addr,0 ; did user give an io_address ?
je isa_6 ; no
mov al,EE_ADDR_CONFIGURATION
call read_ee_isa
and ax,1Fh ; make real io-address
shl ax,4
add ax,MIN_IO_BASE_ADDR
cmp ax,io_addr ; this board ?
jne isa_7 ; no

isa_6:
cmp board_number,0
jne isa_multiple
mov board_number,bl

isa_7:
mov al,bl
add al,set_tag_register ; D0
out dx,al
xor al,al ; reset
out dx,al
sti
jmp isa_5 ; find the next board

isa_8:
sti
cmp board_number,0 ; found the board?
jne isa_9 ; yes
mov dx,offset wrong_port_msg
stc
ret

isa_9:
cli
call write_id_pat
mov al,TEST_TAG_REGISTER
add al,board_number
out dx,al
mov al,SET_TAG_REGISTER
out dx,al
mov al,EE_ADDR_CONFIGURATION
call read_ee_isa
mov address_configuration,ax
cmp io_addr,0 ; know the base address?
jne isa_10 ; yes
and ax,1Fh
shl ax,4
add ax,min_io_base_addr ; make realworld io addr
mov io_addr,ax

isa_10:
mov al,EE_RESOURCE_CONFIGURATION
call read_ee_isa
mov resource_configuration,ax

mov si,offset read_ee_isa
call read_eaddr

mov al,SET_TAG_REGISTER
or al,board_number
out dx,al
sti

cmp io_addr,3F0h
jne isa_start
mov dx,offset eisa_in_isa_msg
stc
ret

isa_start:
mov al,ACTIVATE_VULCAN
out dx,al

have_configuration:
mov ax,address_configuration
and ax,BNC_XCVR or TP_XCVR or AUI_XCVR ;include all the bits.
cmp ax,BNC_XCVR ;does it match BNC?
jne not_10base2
inc is_10base2
not_10base2:
cmp ax,TP_XCVR ;does it match TP?
jne not_10baseT
inc is_10baseT
not_10baseT:

mov bx,resource_configuration
mov cl,12 ;move it over where we need it.
shr bx,cl
mov int_no,bl

loadport
setwin WNO_DIAGNOSTICS
setport PORT_MediaStatus
in ax,dx
or ax,MEDIA_LBEATENABLE or MEDIA_JABBERENABLE
out dx,ax

setwin WNO_SETUP ;select Window 0

mov ax,CMD_TXENABLE ;Enable the transmitter
out dx,ax

mov ax,CMD_RXENABLE ;Enable the receiver
out dx,ax

;Enable RX Complete interrupts
mov ax,CMD_SETINTMASK + INT_RXCOMPLETE + INT_RXEARLY
out dx,ax

mov ax,CMD_SETRZMASK + 0feh ;Enable all the status bits.
out dx,ax

mov ax,CMD_SETTXSTART + 0 ;start transmitting after this many bytes.
out dx,ax

mov ax,CMD_SETRXEARLY + 0 ;receive after this many bytes.
out dx,ax

cmp is_10base2,0 ;coax?
je not_10base2_1 ;no.
mov ax,CMD_STARTINTXCVR ;start internal transciever
out dx,ax
call delay_27_5ms
not_10base2_1:

setport PORT_CfgControl ;position to the CCR
mov al,ENABLE_ADAPTER ;Enable the adapter.
out dx,al

call rcv_mode_3

mov si,offset rom_address ;set our address.
mov cx,EADDR_LEN
call set_address_4
;sets the window to WNO_OPERATING.

call set_recv_isr

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.

clc
ret
;if we got an error,
stc
ret


write_id_pat:
;write the 3c509 ID pattern to the ID port.
;enter with dx=id_port
xor al,al
out dx,al ;select the ID port.
out dx,al ;reset hardware pattern generator
mov cx,0ffh
mov al,0ffh
write_id_pat_1:
out dx,al ;keep writing matching values...
shl al,1
jnc write_id_pat_2
xor al,0cfh
write_id_pat_2:
loop write_id_pat_1
ret

read_eaddr:
;enter with dx = eeprom register, si -> routine to read eeprom.
push cs
pop es
mov di,offset rom_address

mov al,EE_TCOM_NODE_ADDR_WORD0 ;read the Ethernet address.
call si
xchg ah,al
stosw
mov al,EE_TCOM_NODE_ADDR_WORD1
call si
xchg ah,al
stosw
mov al,EE_TCOM_NODE_ADDR_WORD2
call si
xchg ah,al
stosw
ret


read_ee_eisa:
;enter with al = EEPROM address to read, dx = PORT_EECmd
;exit with ax = data.
or al,READ_EEPROM
out dx,al
read_ee_eisa_1:
in ax,dx
test ax,EE_BUSY
jnz read_ee_eisa_1
add dx,PORT_EEData - PORT_EECmd ;move to data register.
in ax,dx
add dx,PORT_EECmd - PORT_EEData ;move back to command register.
ret


read_ee_isa:
;enter with al = EEPROM address to read, dx = address of ID port.
;exit with ax = data, cx = 0.
push bx
or al,READ_EEPROM
out dx,al
;wait 400 us here.
call delay_27_5ms
mov cx,16
read_ee_isa_1:
in al,dx
shr al,1 ;put it into the carry.
rcl bx,1 ;shift it into bx.
loop read_ee_isa_1
mov ax,bx
pop bx
ret


delay_27_5ms:
;delay one timeout period, which is 27.5 ms.
mov ax,1
delay:
;delay AX timeout periods, each of which is 27.5 ms.
call set_timeout
delay_1:
call do_timeout
jnz delay_1
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 dx,offset aui_xcvr_msg
cmp is_10base2,0 ;coax?
je print_parameters_1
mov dx,offset bnc_xcvr_msg
print_parameters_1:
cmp is_10baseT,0 ;tp?
je print_parameters_2
mov dx,offset tp_xcvr_msg
print_parameters_2:
mov ah,9
int 21h
mov di,offset id_port
mov dx,offset id_port_name
call print_number
ret

code ends

end


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