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

 
Output of file : 3C501.ASM contained in archive : PKTD11A.ZIP
version equ 2

include defs.asm

;Ported from Phil Karn's ec.c, a C-language driver for the 3COM 3C501
;by Russell Nelson. Any bugs are due to Russell Nelson.
;* Updated to version 1.08 Feb. 17, 1989.

; 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 word public
assume cs:code, ds:code

;The various IE command registers
EDLC_ADDR equ 00h ;EDLC station address, 6 bytes
EDLC_RCV equ 06h ;EDLC receive csr
EDLC_XMT equ 07h ;EDLC transmit csr
IE_GP equ 08h ;GP pointer
IE_RP equ 0ah ;Receive buffer pointer
IE_SAPROM equ 0ch ;window on station addr prom
IE_CSR equ 0eh ;IE command/status
IE_BFR equ 0fh ;window on packet buffer

;Bits in EDLC_RCV, interrupt enable on write, status when read
EDLC_NONE equ 000h ;match mode in bits 5-6, write only
EDLC_ALL equ 040h ;promiscuous receive, write only
EDLC_BROAD equ 080h ;station address plus broadcast
EDLC_MULTI equ 0c0h ;station address plus multicast

EDLC_STALE equ 80h ;receive CSR status previously read
EDLC_GOOD equ 20h ;well formed packets only
EDLC_ANY equ 10h ;any packet, even those with errors
EDLC_SHORT equ 08h ;short frame
EDLC_DRIBBLE equ 04h ;dribble error
EDLC_FCS equ 02h ;CRC error
EDLC_OVER equ 01h ;data overflow

EDLC_RERROR equ EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
EDLC_RMASK equ EDLC_GOOD or EDLC_ANY or EDLC_RERROR

;bits in EDLC_XMT, interrupt enable on write, status when read
EDLC_IDLE equ 08h ;transmit idle
EDLC_16 equ 04h ;packet experienced 16 collisions
EDLC_JAM equ 02h ;packet experienced a collision
EDLC_UNDER equ 01h ;data underflow

;bits in IE_CSR
IE_RESET equ 80h ;reset the controller (wo)
IE_XMTBSY equ 80h ;Transmitter busy (ro)
IE_RIDE equ 40h ;request interrupt/DMA enable (rw)
IE_DMA equ 20h ;DMA request (rw)
IE_EDMA equ 10h ;DMA done (ro)

IE_BUFCTL equ 0ch ;mask for buffer control field (rw)
IE_LOOP equ 0ch ;2 bit field in bits 2,3, loopback
IE_RCVEDLC equ 08h ;gives buffer to receiver
IE_XMTEDLC equ 04h ;gives buffer to transmit
IE_SYSBFR equ 00h ;gives buffer to processor

IE_CRC equ 01h ;causes CRC error on transmit (wo)
IE_RCVBSY equ 01h ;receive in progress (ro)

BFRSIZ equ 2048 ;number of bytes in a buffer

public int_no
int_no db 3,0,0,0 ; interrupt number.
io_addr dw 0300h,0 ; I/O address for card (jumpers)

public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK, IEEE8023, 0 ;from the packet spec
driver_type db 1 ;from the packet spec
driver_name db '3C501',0 ;name of the driver.
driver_function db 2
parameter_list label byte
db 1 ;major rev of packet driver
db 9 ;minor rev of packet driver
db 14 ;length of parameter list
db EADDR_LEN ;length of MAC-layer address
dw GIANT ;MTU, including MAC headers
dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
dw 0 ;(# of back-to-back MTU rcvs) - 1
dw 0 ;(# of successive xmits) - 1
int_num dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,

public rcv_modes
rcv_modes dw 7 ;number of receive modes in our table.
dw 0 ;There is no mode zero
dw rcv_mode_1
dw 0 ;don't want to bother.
dw rcv_mode_3
dw 0 ;haven't set up perfect filtering yet.
dw rcv_mode_5
dw rcv_mode_6

ipkt_size dw ?
opkt_size dw ?

extrn is_186: byte ;=0 if 808[68], =1 if 80[123]86.
our_type dw ?,?

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

cmp cx,RUNT ; minimum length for Ether
jae oklen
mov cx,RUNT ; make sure size at least RUNT
oklen:
inc cx ;round size up to next even number.
and cx,not 1

;Wait for transmitter ready, if necessary. IE_XMTBSY is valid
;only in the transmit mode, hence the initial check.

loadport
setport IE_CSR
in al,dx
and al,IE_BUFCTL
cmp al,IE_XMTEDLC
jne send_pkt_2

mov bx,20000 ;try this many times.
send_pkt_3:
in al,dx ;if not busy, exit.
and al,IE_XMTBSY
je send_pkt_2
dec bx
jne send_pkt_3
mov dh,CANT_SEND ;timed out, can't send.
stc
ret
send_pkt_toobig:
mov dh,NO_SPACE
stc
ret
send_pkt_2:

;Get control of the board buffer and disable receiver
mov al,IE_RIDE or IE_SYSBFR
setport IE_CSR
out dx,al

;Point GP at beginning of packet
mov ax,BFRSIZ
sub ax,cx
setport IE_GP
out dx,ax

setport IE_BFR

mov opkt_size,cx ; opkt_size = cx;
call repoutsb

;Start transmitter
;Point GP at beginning of packet
mov ax,BFRSIZ
sub ax,opkt_size
setport IE_GP
out dx,ax

mov al,IE_RIDE or IE_XMTEDLC
setport IE_CSR
out dx,al

if 1
mov bx,20000 ;try this many times.
send_pkt_4:
in al,dx ;if not busy, exit.
and al,IE_XMTBSY
je send_pkt_5
dec bx
jne send_pkt_4
mov dh,CANT_SEND ;timed out, can't send.
stc
ret
send_pkt_5:

endif

clc
ret


;Set Ethernet address on controller
public set_address
set_address:
assume ds:nothing
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
;
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
setport EDLC_ADDR
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:
movseg ds,cs
assume ds:code
ret


rcv_mode_1:
;Set up the receiver interrupts and flush status
mov al,EDLC_NONE
loadport
setport EDLC_RCV
out dx,al
in al,dx ;flush status.

ret


rcv_mode_3:
;Set up the receiver interrupts and flush status
mov al,EDLC_BROAD or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
loadport
setport EDLC_RCV
out dx,al
in al,dx ;flush status.

ret


rcv_mode_5:
;Set up the receiver interrupts and flush status
mov al,EDLC_MULTI or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
loadport
setport EDLC_RCV
out dx,al
in al,dx ;flush status.

ret


rcv_mode_6:
;Set up the receiver interrupts and flush status
mov al,EDLC_ALL or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
loadport
setport EDLC_RCV
out dx,al
in al,dx ;flush status.

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:
;Pulse IE_RESET
mov al,IE_RESET
loadport
setport IE_CSR
out dx,al
mov al,0
out dx,al

ret

public reset_interface
reset_interface:
;reset the interface.
;we don't do anything.
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

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

;Check for transmit jam

loadport
setport IE_CSR
in al,dx
and al,IE_XMTBSY
jne recv_isr_1

setport EDLC_XMT
in al,dx
test al,EDLC_16
je recv_isr_2
;ecp->estats.jam16++;
call rcv_fixup
jmp short recv_isr_3
recv_isr_2:
test al,EDLC_JAM
je recv_isr_3
;Crank counter back to beginning and restart transmit
;ecp->estats.jam++;
mov al,IE_RIDE or IE_SYSBFR
setport IE_CSR
out dx,al

mov ax,BFRSIZ
sub ax,opkt_size
setport IE_GP
out dx,ax

mov al,IE_RIDE or IE_XMTEDLC
setport IE_CSR
out dx,al

recv_isr_3:

recv_isr_1:
loadport
setport EDLC_RCV
in al,dx
test al,EDLC_STALE
jne recv_isr_4_j_1
test al,EDLC_OVER
je recv_isr_5
;ecp->estats.over++;
call rcv_fixup
jmp recv_isr_1
recv_isr_5:
test al,EDLC_SHORT or EDLC_FCS or EDLC_DRIBBLE
je recv_isr_6
;ecp->estats.bad++;
call rcv_fixup
jmp recv_isr_1
recv_isr_4_j_1:
jmp recv_isr_4
recv_isr_6:
test al,EDLC_ANY
je recv_isr_4_j_1
;Get control of the buffer
mov al,IE_RIDE or IE_SYSBFR
setport IE_CSR
out dx,al

setport IE_RP
in ax,dx ;get the size.
mov ipkt_size,ax
cmp ax,RUNT ;less than RUNT?
jb recv_isr_7 ;yes.
cmp ax,GIANT ;greater than GIANT?
jbe recv_isr_8 ;no.
recv_isr_7:
call count_in_err
;ecp->estats.bad++;
jmp recv_isr_9
recv_isr_8:
;Put it on the receive queue

mov ax,EADDR_LEN+EADDR_LEN ;seek to the type word.
setport IE_GP
out dx,ax

setport IE_BFR
in al,dx ;read the type word out of the board.
mov ah,al
in al,dx
xchg al,ah ;should be in network byte order.
mov our_type,ax
in al,dx ;read the type word out of the board.
mov ah,al
in al,dx
xchg al,ah ;should be in network byte order.
mov our_type+2,ax

movseg es,ds ;look up our type.
mov di,offset our_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:

mov cx,ipkt_size
call recv_find

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

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

xor ax,ax ;seek to the beginning again.
loadport
setport IE_GP
out dx,ax

mov cx,ipkt_size
setport IE_BFR

call repinsb

pop si
pop ds
assume ds:nothing
mov cx,ipkt_size
call recv_copy ;tell them that we copied it.

movseg ds,cs
assume ds:code

recv_isr_9:
mov al,IE_RIDE or IE_RCVEDLC
loadport
setport IE_CSR
out dx,al
xor al,al
setport IE_RP
out dx,al
recv_isr_4:
;Clear any spurious interrupts
loadport
setport EDLC_RCV
in al,dx

setport EDLC_XMT
in al,dx

ret


rcv_fixup:
call count_out_err

mov al,IE_RIDE or IE_SYSBFR
loadport
setport IE_CSR
out dx,al

mov al,IE_RIDE or IE_RCVEDLC
setport IE_CSR
out dx,al

mov al,0
setport IE_RP
out dx,al

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: 3C501 [options] ",CR,LF,'$'

public copyright_msg
copyright_msg db "Packet driver for the 3COM 3C501, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
db "Portions Copyright 1988 Phil Karn",CR,LF,'$'

no_3c501_msg db "No 3C501 found at that address.",CR,LF,'$'
ether_bdcst db 6 dup(-1) ;ethernet broadcast address.

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

extrn set_recv_isr: near

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

;enter with dx -> name of word, di -> dword to print.
extrn print_number: near

;-> 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.
mov di,offset int_no
call get_number
mov di,offset io_addr
call get_number
clc
ret


public etopen
etopen:
; Initialize the Ethernet board, set receive type.
;
; check for correct EPROM location
;
;Pulse IE_RESET
mov al,IE_RESET
loadport
setport IE_CSR
out dx,al

call set_recv_isr

movseg es,ds
mov di,offset rom_address
mov cx,EADDR_LEN
xor bx,bx
get_address_1:
mov ax,bx
loadport
setport IE_GP
out dx,ax

setport IE_SAPROM
in al,dx
stosb
inc bx
loop get_address_1

;See if there really is a 3c501 there.
mov cx,EADDR_LEN
mov si,offset rom_address
mov di,offset ether_bdcst
repe cmpsb
jne have_3c501 ;not broadcast address -- must be real.
mov dx,offset no_3c501_msg
stc
ret
have_3c501:

mov si,offset rom_address
mov cx,EADDR_LEN
call set_address

;Enable DMA/interrupt request, gain control of buffer
mov al,IE_RIDE or IE_SYSBFR
loadport
setport IE_CSR
out dx,al

;Enable transmit interrupts
mov al,EDLC_16 or EDLC_JAM
setport EDLC_XMT
out dx,al

;Set up the receiver interrupts and flush status
mov al,EDLC_MULTI or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
setport EDLC_RCV
out dx,al
in al,dx ;flush status.

;Start receiver
mov ax,0 ;Reset read pointer
setport IE_RP
out dx,ax
mov al,IE_RIDE or IE_RCVEDLC
setport IE_CSR
out dx,al

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

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
ret


code ends

end


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