; Driver for Ungermann-Bass NICps/2 Zypher interface
; Tim Krauskopf
;
;****************************************************************************
;* *
;* *
;* part of NCSA Telnet *
;* by Tim Krauskopf, VT100 by Gaige Paulsen, Tek by Aaron Contorer *
;* *
;* National Center for Supercomputing Applications *
;* 152 Computing Applications Building *
;* 605 E. Springfield Ave. *
;* Champaign, IL 61820 *
;* *
;* *
;****************************************************************************
TITLE NETSUPPORT -- LOW LEVEL DRIVERS FOR ETHERNET
;
; Tim Krauskopf
; National Center for Supercomputing Applications
; 9/1/87 Ungermann-Bass driver started, PC bus
; 12/28/87 UB NIC driver started, Zypher interface
;
;
;Microsoft EQU 1
;Lattice EQU 1
ifndef Microsoft
ifndef Lattice
if2
%out
%out ERROR: You have to specify "/DMicrosoft" OR "/DLattice" on the
%out MASM command line to determine the type of assembly.
%out
endif
end
endif
endif
NAME NET
ifdef Microsoft
X EQU 6
DOSSEG
.MODEL LARGE
else
INCLUDE DOS.MAC
SETX
endif
ifdef MSC6
INCLUDE NET\ENET\ZYPDEFS.INC
else
INCLUDE ZYPDEFS.INC
endif
;
;
; Data segment
;
ifdef Microsoft
;DGROUP group _DATA
;_DATA segment public 'DATA'
; assume DS:DGROUP
.data
else
DSEG
endif
;
; The pointers below are actually DWORDs but we access them two
; bytes at a time.
;
; STAT change to RSTAT because of name clash with MSC library routine
ifdef Microsoft
EXTRN _RSTAT:BYTE ; last status from read
EXTRN _BUFPT:WORD ; current buffer pointer
EXTRN _BUFORG:WORD ; pointer to beginning of buffer
EXTRN _BUFEND:WORD ; pointer to end of buffer
EXTRN _BUFREAD:WORD ; pointer to where program is reading
EXTRN _BUFBIG:WORD ; integer, how many bytes we have
EXTRN _BUFLIM:WORD ; integer, max bytes we can have
else
EXTRN RSTAT:BYTE ; last status from read
EXTRN BUFPT:WORD ; current buffer pointer
EXTRN BUFORG:WORD ; pointer to beginning of buffer
EXTRN BUFEND:WORD ; pointer to end of buffer
EXTRN BUFREAD:WORD ; pointer to where program is reading
EXTRN BUFBIG:WORD ; integer, how many bytes we have
EXTRN BUFLIM:WORD ; integer, max bytes we can have
endif
SAVECS DW 00H ; where to save the old interrupt ptr
SAVEIP DW 00H
LFPP DB 00h ; Full Page pointer
DEAF DB 00H ; when we can't handle any more packets
OFFS DW 00H ; how many times the handler was turned off
;
;
; Zypher definitions to work with
;
Init_ZCB LABEL WORD
db Initialize_Cmd
db 0 ; Status
db 0 ; Result
db 0 ; Report_Code
dw 0 ; Options
dd 0 ; Post_Routine
dw 2 dup (0)
dw 0 ; Modes
dw 1100 ; Max_Xmt_Length
dw 1 ; Num_Xmt_Buffers
dw 1514 ; Max_Rcv_Size
dw 12 ; Num_Rcv_Buffers
dw 0 ; Max_Multicast_Addresses
dw 7 dup (0) ; reserved
dw 0 ; Acquired Modes
dw 0 ; Acquired Max_Xmt_Length
dw 0 ; Acquired Num_Xmt_Buffers
dw 0 ; Acquired Max_Rcv_Size
dw 0 ; Acquired Num_Rcv_Buffers
dw 0 ; Acquired Max_Multicast_Addresses
dw 3 dup (0) ; reserved
Init2_ZCB LABEL WORD
db Initialize_Cmd
db 0 ; Status
db 0 ; Result
db 0 ; Report_Code
dw 0 ; Options
dd 0 ; Post_Routine
dw 2 dup (0)
dw 0 ; Modes
dw 1100 ; Max_Xmt_Length
dw 1 ; Num_Xmt_Buffers
dw 1514 ; Max_Rcv_Size
dw 12 ; Num_Rcv_Buffers
dw 0 ; Max_Multicast_Addresses
dw 7 dup (0) ; reserved
dw 0 ; Acquired Modes
dw 0 ; Acquired Max_Xmt_Length
dw 0 ; Acquired Num_Xmt_Buffers
dw 0 ; Acquired Max_Rcv_Size
dw 0 ; Acquired Num_Rcv_Buffers
dw 0 ; Acquired Max_Multicast_Addresses
dw 3 dup (0) ; reserved
Stat_ZCB LABEL WORD
db Status_Cmd
db 0 ; Status
db 0 ; Result
db 0 ; Report_Code
dw 0 ; Options
dd 0 ; Post_Routine
dw 2 dup (0)
dw 0 ; state
dw 0 ; modes
dw 0 ; Max_Xmt_Length
dw 0 ; Act Num_Xmt_Buffers
dw 0 ; Act Max_Rcv_Size
dw 0 ; Act Num_Rcv_Buffers
db 6 dup (0) ; unique ID
dw 0,0 ; total xmts
dw 0,0 ; total rcvs
dw 0,0 ; CRC errors
dw 0,0 ; ALN errors
dw 0,0 ; RSC errors
dw 0,0 ; OVR errors
dw 12 dup (0) ; reserved
Xmt_ZCB LABEL WORD
db Transmit_Cmd
db 0 ; Status
db 0 ; Result
db 0 ; Report_Code
dw 0 ; Options
dd 0
dw 2 dup (0)
dw 0 ; Xmt_Length
dw 0,0 ; Xmt_Buffer
dw 0 ; hardware status
db 0,0 ; Xmt_Bfr_ID and an unused byte
dw 0,0 ; Xmt_Bfr_Address (on-card transmit buffer address)
Cancel_ZCB LABEL WORD
db Cancel_Receives_Cmd
db 0 ; Status
db 0 ; Result
db 0 ; Report_Code
dw 0 ; Options
dd 0 ; Post_Routine
dw 2 dup (0)
Recv_ZCB LABEL WORD
db Receive_Cmd
db 0 ; Status
db 0 ; Result
db 0 ; Report_Code
dw 0 ; Options
dd 0
dw 2 dup (0)
; db SIZE ZCB_Header dup (0)
;ZCB_Rcv_Mode db 0
db 0
;ZCB_Rcv_Status db 0
db 0
;ZCB_Rcv_Buffer_Size dw 0 ; Size of user's buffer.
dw 1514 ; always this much room
;ZCB_Rcv_Buffer_Address dd 0 ; Address of user's buffer.
dd 0
;ZCB_Rcv_Data_Length dw 0 ; Bytes copied to user's buffer.
dw 0
;ZCB_Rcv_Frame_Count dw 0 ; Count of as-yet-uncopied bytes left;
dw 0
; in frame.
;ZCB_Rcv_Hdwr_Status dw 0 ; Status reported by 82586.
dw 0
;ZCB_Rcv_Frame_ID dw 0 ; Frame ID for "incremental mode".
dw 0
;ZCB_Rcv_Bfr_Ptr dw 0,0 ; Address of next as-yet-uncopied byte
dw 0,0
; of frame in on-card receive buffer.
;ZCB_Rcv_Bfr_Count dw 0 ; Count of as-yet-uncopied bytes in
dw 0
; current on-card receive buffer.
;ZCB_Rcv_Descriptor dw 0,0 ; Address of 82586 RBD (Receive Buffer
dw 0,0
; Descriptor) for current on-card
; receive buffer.
ifdef Microsoft
;_DATA ends
else
ENDDS
endif
;
;
;
; The subroutines to call from C
;
ifdef Microsoft
;_TEXT segment public 'CODE'
; assume CS:_TEXT
.code
PUBLIC _U2RECV,_U2ETOPEN,_U2ETCLOSE,_U2GETADDR
PUBLIC _U2XMIT,_U2ETUPDATE
else
PSEG
PUBLIC U2RECV,U2ETOPEN,U2ETCLOSE,U2GETADDR
PUBLIC U2XMIT,U2ETUPDATE
endif
ZYP_Entry LABEL DWORD
dw 0, 0D000h
;******************************************************************
; ETOPEN
; Initialize the Ethernet board, set receive type.
;
; usage: etopen(s,irq,addr,ioaddr)
; char s[6]; ethernet address
; int irq,addr,ioaddr;
; interrupt number, base mem address and
; i/o address to use
;
;
ifdef Microsoft
_U2ETOPEN PROC FAR
else
U2ETOPEN PROC FAR
endif
PUSH BP
MOV BP,SP
PUSH SI
PUSH DI
push es
push ds
mov ax,ds
mov es,ax ; set to base address for NCB
;
; Set base address for board into ZYP_Entry
;
mov ax,[X+BP+6] ; base address for board as installed
mov word ptr cs:[ZYP_Entry+2],ax ; store
;
; try shutting the board down first
;
; MOV BX,offset Cancel_ZCB
; CALL ZYP_Entry
;closeit:
; CMP [BX].ZCB_Status,0FFh
; JE closeit
;
; now reopen it
;
MOV BX,offset Init2_ZCB
CALL ZYP_Entry
Init_wait:
CMP [BX].ZCB_Status,0FFh
JE Init_wait
;
; call ZYP receive
;
mov bx,offset Recv_ZCB
ifdef Microsoft
mov ax,word ptr [_BUFPT+2] ; where packet should arrive
else
mov ax,word ptr [BUFPT+2] ; where packet should arrive
endif
ifdef Microsoft
mov di,word ptr [_BUFPT]
else
mov di,word ptr [BUFPT]
endif
inc di
inc di
; address of packet into NCB
mov word ptr [bx].ZCB_Rcv_Buffer_Address,di
mov word ptr [bx].ZCB_Rcv_Buffer_Address+2,ax
CALL ZYP_Entry
xor ax,ax
getout:
pop ds
POP ES
POP DI
POP SI
POP BP
RET
ifdef Microsoft
_U2ETOPEN ENDP
else
U2ETOPEN ENDP
endif
;
;
;*******************************************************************
; GETADDR
; get the Ethernet address off of the board
;
; usage: getaddr(s,address,ioaddr);
; char s[6]; will get six bytes from the PROM
; int address;
; int ioaddr; mem address and ioaddress to use
;
;
ifdef Microsoft
_U2GETADDR PROC FAR
else
U2GETADDR PROC FAR
endif
PUSH BP
MOV BP,SP
PUSH SI
PUSH DI
PUSH ES ; save mine
push ds
mov ax,ds
mov es,ax
;
; Set base address for board into ZYP_Entry
;
mov ax,[X+BP+4] ; base address for board as installed
mov word ptr cs:[ZYP_Entry+2],ax ; store
;
;
MOV BX,offset Init_ZCB
CALL ZYP_Entry
ifdef OLD_WAY
Init_wt:
CMP [BX].ZCB_Status,0FFh
JE Init_wt
else
MOV AX,0
Init_wt:
INC AX
CMP AX,0ffh
JE getaddr_timeout
CMP [BX].ZCB_Status,0FFh
JE Init_wt
getaddr_timeout:
endif
; CMP [BX].ZCB_Result,Initialization_Complete
; JNE oh_well
MOV BX,offset Stat_ZCB
CALL ZYP_Entry
addr_wait:
CMP [BX].ZCB_Status,0FFh
JE addr_wait
CMP [BX].ZCB_Result,Status_Complete
JE get_addr
oh_well:
mov ax,-1
jmp SHORT nomore
get_addr:
MOV AX,[BP+X+2] ; get new one
MOV ES,AX ; set new one
MOV DI,[BP+X] ; get pointer, es:di is ready
MOV SI,BX
add si,ZCB_Stat_Unique_ID
;
mov cx,3
CLD
rep movsw ; copy address
xor ax,ax
nomore:
pop ds
POP ES
POP DI
POP SI
POP BP
RET
ifdef Microsoft
_U2GETADDR ENDP
else
U2GETADDR ENDP
endif
;
;***********************************************************************
; ETCLOSE
; shut it down
;
ifdef Microsoft
_U2ETCLOSE PROC FAR
else
U2ETCLOSE PROC FAR
endif
push bp
push si
push di
push es
push ds
mov ax,ds
mov es,ax
MOV BX,offset Cancel_ZCB
CALL ZYP_Entry
canwait:
CMP [BX].ZCB_Status,0FFh
JE canwait
pop ds
pop es
pop di
pop si
pop bp
RET
ifdef Microsoft
_U2ETCLOSE ENDP
else
U2ETCLOSE ENDP
endif
;
;
;************************************************************************
; XMIT
; send a packet to Ethernet
; Is not interrupt driven, just call it when you need it.
;
; usage: xmit(packet,count)
; char *packet;
; int count;
;
; Takes a packet raw, Ethernet packets start with destination address,
; and puts it out onto the wire. Count is the length of packet < 2048
;
; checks for packets under the Ethernet size limit of 60 and handles them
;
ifdef Microsoft
_U2XMIT PROC FAR
else
U2XMIT PROC FAR
endif
PUSH BP
MOV BP,SP
PUSH SI
PUSH DI
push es
push ds
MOV CX,[BP+X+2] ; ds for buffer
MOV SI,[BP+X] ; offset for buffer
MOV AX,[BP+X+4] ; count of bytes
cmp ax,1100
jle oklen
mov ax,1100 ; maximum for me
oklen:
;
; place into Xmit parms
;
MOV BX,offset Xmt_ZCB ; Start the 1st transmit, using
mov word ptr [bx].ZCB_Xmt_Data_Address,si
mov word ptr [bx].ZCB_Xmt_Data_Address+2,CX
mov [bx].ZCB_Xmt_Data_Length,ax
mov ax,ds
mov es,ax ; base for ZCB block
CALL ZYP_Entry
ifdef OLD_WAY
waitstat:
CMP [BX].ZCB_Status,0FFh
JE waitstat
else
MOV AX,0
waitstat:
INC AX
CMP AX,0ffh
JE timeout
CMP [BX].ZCB_Status,0FFh
JE waitstat
timeout:
endif
xor ax,ax
; CMP [BX].ZCB_Result,Initialization_Complete
; JE xmitok
; mov al,[BX].ZCB_Result
xmitok:
pop ds
pop es
POP DI
POP SI
POP BP
RET
ifdef Microsoft
_U2XMIT ENDP
else
U2XMIT ENDP
endif
;
;
;***********************************************************************
; Receive
; This is a CPU hook for boards that must be polled before we can
; deliver packets into the receive buffer. (i.e. no interrupts used)
;
; usage: recv();
;
;
ifdef Microsoft
_U2RECV proc far
else
U2RECV proc far
endif
push bp
PUSH SI
PUSH DI
push es
push ds
;
mov bx,offset Recv_ZCB
CMP [BX].ZCB_Status,0FFh ; status byte for outstanding read request
JNE newpkt
;
; no packet yet, skip
;
pop ds
pop es
POP DI
POP SI
pop bp
ret ; no packet arrival yet
newpkt:
mov dx,[bx].ZCB_Rcv_Data_Length ; length of recieved packet
ifdef Microsoft
MOV aX,word ptr [_BUFPT+2] ; buffer's ds
else
MOV aX,word ptr [BUFPT+2] ; buffer's ds
endif
ifdef Microsoft
mov bx,word ptr [_BUFPT] ; get where size field for this packet goes
else
mov bx,word ptr [BUFPT] ; get where size field for this packet goes
endif
mov es,ax
mov es:[bx],dx ; put the accumulated size there
add bx,dx ; add length to bufpt
inc bx
inc bx
ifdef Microsoft
MOV word ptr [_BUFPT],bx ; it is here, now
else
MOV word ptr [BUFPT],bx ; it is here, now
endif
ifdef Microsoft
MOV AX,word ptr [_BUFBIG] ; total amount of stuff in buffer
else
MOV AX,word ptr [BUFBIG] ; total amount of stuff in buffer
endif
ADD AX,DX ; add in size of this packet
INC AX
INC AX ; to cover the length value
ifdef Microsoft
MOV word ptr [_BUFBIG],AX ; after adding in current packet size
else
MOV word ptr [BUFBIG],AX ; after adding in current packet size
endif
;
; set up to read the next packet from the net
;
ifdef Microsoft
MOV aX,word ptr [_BUFPT+2] ; buffer's ds
else
MOV aX,word ptr [BUFPT+2] ; buffer's ds
endif
ifdef Microsoft
MOV DI,word ptr [_BUFPT] ; where buffer is
else
MOV DI,word ptr [BUFPT] ; where buffer is
endif
mov es,ax
;
; check for buffer overrun or catching up with reader
;
; implicit 64K max buffer, should stop before 64K anyway
;
ifdef Microsoft
MOV AX,_BUFBIG ; how much stuff is in buffer
else
MOV AX,BUFBIG ; how much stuff is in buffer
endif
ifdef Microsoft
MOV BX,_BUFLIM ; what is our size limit?
else
MOV BX,BUFLIM ; what is our size limit?
endif
CMP AX,BX
JNA ISROOM ; we are ok
;
; no room at the Inn.
;
JMP SHORT ENDINT ; can't do much, we lose packets until restarted
;
; wrap pointer around at end, we know that we have room
;
ISROOM:
ifdef Microsoft
MOV DX,word ptr [_BUFEND] ; right before 2K safety area
else
MOV DX,word ptr [BUFEND] ; right before 2K safety area
endif
CMP DX,DI ; see if pointer is over limit
JA OKAYREAD ; we are not at wrap-around
ifdef Microsoft
MOV AX,word ptr [_BUFORG] ; wrap to here
else
MOV AX,word ptr [BUFORG] ; wrap to here
endif
ifdef Microsoft
MOV word ptr [_BUFPT],AX ; wrap-around
else
MOV word ptr [BUFPT],AX ; wrap-around
endif
MOV DI,AX ; di also
;
; here, DI contains where we want to put the packet.
;
OKAYREAD:
inc di
inc di ; leave space for length of packet
;
;
; call receive again
;
mov bx,offset Recv_ZCB
; address of packet into NCB
mov word ptr [bx].ZCB_Rcv_Buffer_Address,di
mov word ptr [bx].ZCB_Rcv_Buffer_Address+2,es
mov ax,ds
mov es,ax
CALL ZYP_Entry
STOPINT:
ENDINT:
pop ds
pop es
POP DI
POP SI
POP BP
RET
ifdef Microsoft
_U2RECV ENDP
else
U2RECV ENDP
endif
;
;*************************************************************************
; ETUPDATE
; update pointers and/or restart receiver when read routine has
; already removed the current packet
;
ifdef Microsoft
_U2ETUPDATE PROC FAR
else
U2ETUPDATE PROC FAR
endif
PUSH ES
ifdef Microsoft
MOV AX,word ptr [_BUFPT+2] ; establish data segment to buffer
else
MOV AX,word ptr [BUFPT+2] ; establish data segment to buffer
endif
MOV ES,AX ; put that in es
;
ifdef Microsoft
MOV BX,word ptr [_BUFREAD] ; where read pointer is now
else
MOV BX,word ptr [BUFREAD] ; where read pointer is now
endif
MOV DX,ES:[BX] ; get size of this packet
INC DX
INC DX ; TWO MORE FOR LENGTH VALUE
ADD BX,DX ; increment bufread by size of packet
ifdef Microsoft
MOV CX,word ptr [_BUFEND] ; right before 2K safety area
else
MOV CX,word ptr [BUFEND] ; right before 2K safety area
endif
CMP BX,CX ; see if pointer is over limit
JB NOWRAPRD ; we are not at wrap-around
ifdef Microsoft
MOV BX,_BUFORG ; wrap to here
else
MOV BX,BUFORG ; wrap to here
endif
NOWRAPRD:
ifdef Microsoft
MOV _BUFREAD,BX ; buffer pointer has been updated
else
MOV BUFREAD,BX ; buffer pointer has been updated
endif
;
; DECREMENT TOTAL BUFFER SIZE
;
CLI ; keep interrupt handler from bothering dec
ifdef Microsoft
MOV CX,_BUFBIG ; size before removing packet
else
MOV CX,BUFBIG ; size before removing packet
endif
SUB CX,DX ; remove size of current packet
ifdef Microsoft
MOV _BUFBIG,CX ; put it back
else
MOV BUFBIG,CX ; put it back
endif
STI
;
; IF RECEIVER IS ON, THEN CHECKING BUFLIM IS UNNECESSARY.
;
MOV AL,DEAF ; is the receiver turned off?
OR AL,AL ; 0 = reading, 1 = deaf
JZ ALIVE
;
; CHECK FOR ROOM IN THE BUFFER, IF THERE IS, TURN ON RECEIVER
;
ifdef Microsoft
MOV AX,_BUFLIM ; what is our limit?
else
MOV AX,BUFLIM ; what is our limit?
endif
CMP CX,AX ; compare to limit
JA ALIVE ; not really alive, but can't turn on yet
XOR AL,AL
MOV DEAF,AL ; reset flag
INC OFFS ; keep count how many times this happened
ALIVE:
POP ES
RET
ifdef Microsoft
_U2ETUPDATE ENDP
else
U2ETUPDATE ENDP
endif
;
ifdef Microsoft
;_TEXT ends
else
ENDPS
endif
END