home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
lan
/
driver6s
/
ne1000.asm
< prev
next >
Wrap
Assembly Source File
|
1990-03-15
|
25KB
|
1,007 lines
; Packet driver for Novell's NE1000
; Written by:
; Eric Henderson
; Brigham Young University
;
; Based on the "generic" packet driver by Russell Nelson with help
; from the western digital pd by Russell Nelson.
; 80[123]86 processor support lifted from 3com driver by permission
; from Russell Nelson
;
; Portions (C) Copyright 1989 BYU
version equ 2
include defs.asm
code segment byte public
assume cs:code, ds:code
;*****************************************************************************
;
; NE1000 controller board offsets
; IO port definition (BASE in io_addr)
;*****************************************************************************
ADDROM EQU 10h ; LAN Address ROM
RACK EQU 10h ; NE1000 Port Window (?)
NERESET EQU 1fh ; Issue a read for reset
; 8390 LAN Controller (page0) register offset for read and write
CMDR EQU 00h ; command register for read & write
CLDA0 EQU 01h ; current local dma addr 0 for read
PSTART EQU 01h ; page start register for write
CLDA1 EQU 02h ; current local dma addr 1 for read
PSTOP EQU 02h ; page stop register for write
BNRY EQU 03h ; boundary reg for rd and wr
TSR EQU 04h ; tx status reg for rd
TPSR EQU 04h ; tx start page start reg for wr
NCR EQU 05h ; number of collision reg for rd
TBCR0 EQU 05h ; tx byte count 0 reg for wr
FIFO EQU 06h ; FIFO for rd
TBCR1 EQU 06h ; tx byte count 1 reg for wr
ISR EQU 07h ; interrupt status reg for rd and wr
CRDA0 EQU 08h ; current remote dma address 0 for rd
RSAR0 EQU 08h ; remote start address reg 0 for wr
CRDA1 EQU 09h ; current remote dma address 1 for rd
RSAR1 EQU 09h ; remote start address reg 1 for wr
RBCR0 EQU 0Ah ; remote byte count reg 0 for wr
RBCR1 EQU 0Bh ; remote byte count reg 1 for wr
RSR EQU 0Ch ; rx status reg for rd
RCRWD EQU 0Ch ; rx configuration reg for wr
CNTR0 EQU 0Dh ; tally cnt 0 for frm alg err for rd
TCR EQU 0Dh ; tx configuration reg for wr
CNTR1 EQU 0Eh ; tally cnt 1 for crc err for rd
DCR EQU 0Eh ; data configuration reg for wr
CNTR2 EQU 0Fh ; tally cnt 2 for missed pkt for rd
IMR EQU 0Fh ; interrupt mask reg for wr
; 8390 LAN Controller (page1) register offset for read and write
PAR0 EQU 01h ; physical addr reg 0 for rd and wr
PAR1 EQU 02h ; physical addr reg 1 for rd and wr
PAR2 EQU 03h ; physical addr reg 2 for rd and wr
PAR3 EQU 04h ; physical addr reg 3 for rd and wr
PAR4 EQU 05h ; physical addr reg 4 for rd and wr
PAR5 EQU 06h ; physical addr reg 5 for rd and wr
CURR EQU 07h ; current page reg for rd and wr
MAR0 EQU 08h ; multicast addr reg 0 fro rd and WR
MAR1 EQU 09h ; multicast addr reg 1 fro rd and WR
MAR2 EQU 0Ah ; multicast addr reg 2 fro rd and WR
MAR3 EQU 0Bh ; multicast addr reg 3 fro rd and WR
MAR4 EQU 0Ch ; multicast addr reg 4 fro rd and WR
MAR5 EQU 0Dh ; multicast addr reg 5 fro rd and WR
MAR6 EQU 0Eh ; multicast addr reg 6 fro rd and WR
MAR7 EQU 0Fh ; multicast addr reg 7 fro rd and WR
;***********************************************************************
;
; 8003 control register operations
;***********************************************************************
MSK_RESET EQU 80h ; reset LAN controller
MSK_ENASH EQU 40h ; enable PC access to shared mem
MSK_DECOD EQU 3Fh ; ???? memory decode bits, corresponding
; to SA 18-13. SA 19 assumed to be 1
;***********************************************************************
;
; 8390 CMDR MASK
;***********************************************************************
MSK_STP EQU 01h ; software reset, take 8390 off line
MSK_STA EQU 02h ; activate the 8390 NIC
MSK_TXP EQU 26h ; initial txing of a frm (With DMA)
MSK_RD2 EQU 20h ; abort remote DMA
MSK_PG0 EQU 00h ; select register page 0
MSK_PG1 EQU 40h ; select register page 1
MSK_PG2 EQU 80h ; select register page 2
MSK_DMA_RD EQU 0ah ; start DMA read
MSK_DMA_WR EQU 12h ; start DMA write
;***********************************************************************
;
; 8390 ISR & IMR MASK
;***********************************************************************
MSK_PRX EQU 01h ; rx with no error
MSK_PTX EQU 02h ; tx with no error
MSK_RXE EQU 04h ; rx with error
MSK_TXE EQU 08h ; tx with error
MSK_OVW EQU 10h ; overwrite warning
MSK_CNT EQU 20h ; MSB of one of the tally counters is set
MSK_RDC EQU 40h ; remote dma completed
MSK_RST EQU 80h ; reset state indicator
UnmaskByte equ 1fh
InterruptMask equ 0fh
;***********************************************************************
;
; 8390 DCR MASK
;***********************************************************************
MSK_WTS EQU 01h ; word transfer mode selection
MSK_BOS EQU 02h ; byte order selection
MSK_LAS EQU 04h ; long addr selection
MSK_BMS EQU 08h ; burst mode selection
MSK_ARM EQU 10h ; atuoinitialize remote
MSK_FT00 EQU 00h ; burst lrngth selection
MSK_FT01 EQU 20h ; burst lrngth selection
MSK_FT10 EQU 40h ; burst lrngth selection
MSK_FT11 EQU 60h ; burst lrngth selection
;***********************************************************************
;
; 8390 RCR MASK
;***********************************************************************
MSK_SEP EQU 01h ; save error pkts
MSK_AR EQU 02h ; accept runt pkt
MSK_AB EQU 04h ; accept broadcast
MSK_AM EQU 08h ; accept multicast
MSK_PRO EQU 10h ; promiscuous physical
; accept all pkt with physical adr
MSK_MON EQU 20h ; monitor mode
;***********************************************************************
;
; 8390 TCR MASK
;***********************************************************************
MSK_CRC EQU 01h ; inhibit CRC, do not append crc
MSK_LB01 EQU 06h ; encoded loopback control
MSK_ATD EQU 08h ; auto tx disable
MSK_OFST EQU 10h ; collision offset enable
;***********************************************************************
;
; 8390 RSR MASK
;***********************************************************************
SMK_PRX EQU 01h ; rx without error
SMK_CRC EQU 02h ; CRC error
SMK_FAE EQU 04h ; frame alignment error
SMK_FO EQU 08h ; FIFO overrun
SMK_MPA EQU 10h ; missed pkt
SMK_PHY EQU 20h ; physical/multicase address
SMK_DIS EQU 40h ; receiver disable. set in monitor mode
SMK_DEF EQU 80h ; deferring
;***********************************************************************
;
; 8390 TSR MASK
;***********************************************************************
SMK_PTX EQU 01h ; tx without error
SMK_DFR EQU 02h ; non deferred tx
SMK_COL EQU 04h ; tx collided
SMK_ABT EQU 08h ; tx aboort because of excessive collisions
SMK_CRS EQU 10h ; carrier sense lost
SMK_FU EQU 20h ; FIFO underrun
SMK_CDH EQU 40h ; collision detect heartbeat
SMK_OWC EQU 80h ; out of window collision
;***********************************************************************
;
; on board memory constant definition
;***********************************************************************
; for rcv buff ring of onboard mem
START_PG EQU 26h ; start at page 26
STOP_PG EQU 40h ; end at page 40
; for tx buff of shr mem
TB_SIZE EQU 1 ; number of tb buff in shr mem
TB_PGNO EQU 6 ; number of pages in one tb buff
public int_no, io_addr
int_no db 3,0,0,0 ;must be four bytes long for get_number.
io_addr dw 0300h,0 ; I/O address for card (jumpers)
my_eaddr db 6 dup(?) ; 6 byte LAN address
m_channel dw 0 ; micro channel flag
is_186 db 0 ;=0 if 808[68], =1 if 80[123]86.
rd_NE MACRO port
mov DX, CS:io_addr
add DX, port ; DX contains address of port
in AL, DX ; AL contains data read from port
ENDM
wr_NE MACRO port
mov DX, CS:io_addr
add DX, port ; DX contains address of port
out DX, AL ; AL contains data to be written to port
ENDM
ReceiveHeaderStructure struc
RReceiveStatus db ?
RNextBuffer db ?
RByteCount dw ?
RDestinationAddress db 6 dup(?)
RSourceAddress db 6 dup(?)
RPacketLength dw ?
RChecksum dw ?
RRPacketLength dw ?
RTranControl db ?
RHPacketType db ?
RDestinationNet db 4 dup(?)
RDestinationNode db 6 dup(?)
RDestinationSocket dw ?
ReceiveHeaderStructure ends
ReceiveHeader ReceiveHeaderStructure <>
BLUEBOOK equ 1
IEEE8023 equ 11h
public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK, 0 ;from the packet spec
driver_type dw 53 ;Wild card matches any type
driver_name db 'NE1000',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
dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,
public rcv_modes
rcv_modes dw 4 ;number of receive modes in our table.
dw 0,0,0,rcv_mode_3
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
; get txblk length
inc cx
and cl, 0feh
cmp CX, RUNT
jnb length_ok
mov cx, RUNT
length_ok:
cmp cx, GIANT
jbe length1_ok
mov dh, NO_SPACE
stc
jmp count_out_err
length1_ok:
;new stuff
mov AX, CX
wr_NE TBCR0 ; Transmit byte count
mov al, ah
wr_NE TBCR1
mov al, 0
wr_NE RSAR0
mov al, 20h
wr_NE RSAR1
mov ax, cx
wr_NE RBCR0 ; Remote byte count
mov al, ah
wr_NE RBCR1
; Clear out DMA complete interrupt
mov al, MSK_PG0
wr_NE CMDR
mov al, 40h
wr_NE ISR
mov al, MSK_DMA_WR
wr_NE CMDR
mov DX, CS:io_addr
add DX, RACK ; DX has address NE1000 Port window (?)
cmp is_186,0 ; Can we use rep outsb?
je out86 ; no - have to do it slowly.
db 0f3h, 06eh ;masm 4.0 doesn't grok "rep outsb"
jmp short ocnteven
out86:
test si,1 ; (buf & 1) ?
jz obufeven ; no
lodsb ; al = *si++;
out dx,al ; out(dx,al);
dec cx ; cx--;
obufeven:
mov di,cx ; save for later test
shr cx,1 ; cx = cnt >> 1; (convert to word count)
; Do the bulk of the buffer, a word at a time
jcxz onobuf ; if(cx != 0){
xb: lodsw ; do { ax = *si++; (si is word pointer)
out dx,al ; out(dx,lowbyte(ax));
mov al,ah
out dx,al ; out(dx,hibyte(ax));
loop xb ; } while(--cx != 0); }
; now check for odd trailing byte
onobuf: shr di,1 ; if (di & 1)
jnc ocnteven
lodsb ; out(dx,*si++);
out dx,al
ocnteven:
mov cx, 1000h ; Prevent infinite loop
WaitForDMAComplete:
rd_NE ISR
test al, 40h
jnz DMAComplete
loop WaitForDMAComplete
DMAComplete:
mov al, MSK_TXP
wr_NE CMDR
clc
exit_now:
ret
public get_address
get_address:
;get the address of the interface.
;enter with es:di -> place to get the address, cx = size of address buffer.
;exit with nc, cx = actual size of address, or cy if buffer not big enough.
assume ds:code
cmp cx, EADDR_LEN ; Caller wants a reasonable length?
jb get_addr_x ; No, fail.
mov cx, EADDR_LEN ; Yes. Set count for loop
mov si, offset cs:my_eaddr
cld ; Make sure string mode is right
rep movsb
mov cx, EADDR_LEN ; Tell caller how many bytes we fed him
clc ; Carry off says success
ret
get_addr_x:
stc ; Tell caller our addr is too big for him
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.
;This proc will set the first CX bytes of the ethernet address, leaving
; the rest unchanged.
assume ds:nothing
cmp cx, 6
jbe set1
mov dh, BAD_ADDRESS
stc
ret
set1:
push es
push di
mov di, offset my_eaddr
mov ax, cs
mov es, ax
mov al, 61h
wr_NE CMDR
mov DX, CS:io_addr
add DX, PAR0 ; DX has address 8390 Phys Address Reg
AddressToChip1:
lodsb
out dx, al
mov es:[di], al
inc di
inc dx
nop
nop
nop
nop
loop AddressToChip1
pop di
pop es
mov al, 21h
wr_NE CMDR
clc
ret
rcv_mode_3:
;receive mode 3 is the only one we support, so we don't have to do anything.
ret
public set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, cx = number of addresses.
;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:
ret
public reset_interface
reset_interface:
;reset the interface.
assume ds:code
mov al, MSK_STP + MSK_RD2
wr_NE CMDR
mov al, 0ffh ; Clear all pending interrupts
wr_NE ISR
xor al, al ; Turn off all enables
wr_NE IMR
rd_NE NERESET ; Hard reset NE1000
wr_NE NERESET
ret
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type.
;It returns with es:di = 0 if don't want this type or if no buffer available.
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
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.
;Actually, not just receive, but all interrupts come here.
;Upon exit, the interrupt will be acknowledged.
assume ds:code
; read irq status register
rd_isr:
rd_NE ISR ; read isr into AL
and AL, 3Fh ; check bit0-bit5, if all 1's no irq
cmp AL, 0 ; if any irq
jne tst_ovw ; some irq
ret ; no more irq, exit
; process OVW (OVW = 1)
; may report error here
tst_ovw:
test AL, MSK_OVW ; if OVW irq
jnz prcs_ov ; OVW (OVW = 1)
jmp test_rx ; no OVW (OVW = 0)
; **************************************************************
; follow the DP8390 datasheet addendum to handle the buff ring overflow
prcs_ov:
; 1. issue a STOP mode command
mov AL, MSK_STP + MSK_RD2
wr_NE CMDR
jmp $+2
; 6. remove one packet from the ring
rd_NE BNRY ; BNRY in AL
add AL, 1 ; start page of frm in AL
cmp AL, STOP_PG ; check boundary
jne get1
mov AL, START_PG
; ring not empty
get1:
mov BH, AL ; BX has the rx_frm pointer
mov al, SIZE ReceiveHeader
wr_NE RBCR0
xor al, al
jmp $+2
wr_NE RBCR1
jmp $+2
wr_NE RSAR0
mov al, bh
wr_NE RSAR1
mov al, MSK_DMA_RD
wr_NE CMDR
mov DX, CS:io_addr
add DX, RACK ; DX has address NE1000 Port window (?)
mov di, OFFSET ReceiveHeader
mov ax, cs
mov es, ax
mov cx, SIZE ReceiveHeader
Receive1:
in al, dx
stosb
loop Receive1
SkipReceive1:
mov bx, offset ReceiveHeader
mov AL, CS:[BX] ; AL has the status byte
test AL, SMK_PRX ; if rx good
jz fd_bnr ; rx error, drop frm by forward bnry
; good frm, call _rcv_frm
call _rcv_frm
fd_bnr: ;drop frm by forward BNRY
mov al, cs:ReceiveHeader.RNextBuffer ; al = next pointer
sub AL, 1 ; new BNRY in AL
cmp AL, START_PG ; check boundary
jae wrbnr ; unsigned arithmetic
mov AL, STOP_PG ;
dec AL ;
wrbnr:
wr_NE BNRY
jmp $+2 ;
; 2. clear the remote byte count registers (RBCR0,RBCR1)
xor AL, AL
wr_NE RBCR0
jmp $+2 ;
wr_NE RBCR1
jmp $+2 ;
; 3. poll the ISR for the RST bit
plisr:
rd_NE ISR
jmp $+2 ;
test AL, MSK_RST
jz plisr ; keep polling until the RST bit set
; 4. place the NIC in loopback mode (mode 1 or 2) by writing 02 or 04 to TCR
mov AL, 02h ; put it in mode 2 (internal loopback)
wr_NE TCR
jmp $+2 ;
; 5. issue start mode command
mov AL, MSK_STA + MSK_RD2
wr_NE CMDR
jmp $+2 ;
; 7. out from loopback mode by writing 00 to TCR
xor AL, AL
wr_NE TCR ; normal operation configuration
jmp $+2 ;
; clear OVW in ISR
mov AL, MSK_OVW
wr_NE ISR ; clear OVW
call count_in_err ; increment overflow counter
jmp rd_isr ; back to the top
; end of the modification
; *****************************************************
;
;process PRX and RXE
;
test_rx:
test AL, MSK_PRX
jnz prcs_rx ; PRX = 1
test AL, MSK_RXE
jnz prcs_rxe ; RXE = 1
jmp test_tx
prcs_rxe:
call count_in_err
prcs_rx:
mov AL, MSK_PG1 + MSK_RD2 ; read CURR reg
wr_NE CMDR
jmp $+2
rd_NE CURR
jmp $+2
mov BL, AL ; CURR in BL
mov AL, MSK_PG0 + MSK_RD2 ; read BNRY reg
wr_NE CMDR
jmp $+2
rd_NE BNRY ; BNRY in AL
add AL, 1 ; start page of frm in AL
cmp AL, STOP_PG ; check boundary
jne go_cmp
mov AL, START_PG ;
go_cmp:
cmp AL, BL
je end_rx ; buff ring empty
; Ring Not Empty
wr_NE RSAR1
jmp $+2
xor al, al
jmp $+2
wr_NE RBCR1
jmp $+2
wr_NE RSAR0
mov al, SIZE ReceiveHeader
wr_NE RBCR0
mov al, MSK_DMA_RD
wr_NE CMDR
mov DX, CS:io_addr
add DX, RACK ; DX has address NE1000 Port window (?)
mov di, OFFSET ReceiveHeader
mov ax, cs
mov es, ax
mov cx, SIZE ReceiveHeader
Receive2:
in al, dx
stosb
loop Receive2
SkipReceive2:
mov bx, offset ReceiveHeader
mov AL, CS:[BX] ; AL has the status byte
test AL, SMK_PRX ; if rx good
jz fd_bnry ; rx error, drop frm by forward bnry
; good frm, call _rcv_frm
call _rcv_frm
fd_bnry: ; drop frm by forward BNRY
mov al, CS:ReceiveHeader.RNextBuffer ; al = next pointer
sub AL, 1 ; new BNRY in AL
cmp AL, START_PG ; check boundary
jae wrbnry ; unsigned arithmetic
mov AL, STOP_PG ;
dec AL ;
wrbnry:
wr_NE BNRY
jmp prcs_rx
; clear PRX, RXE, OVW in ISR
end_rx:
mov AL, MSK_OVW + MSK_RXE + MSK_PRX
wr_NE ISR ; clear OVW, RXE, PRX
jmp rd_isr ; back to the top
;process PTX and TXE
test_tx:
test AL, MSK_PTX
jnz prc_ptx ; PTX = 1
test AL, MSK_TXE
jnz prc_txe ; TXE = 1
jmp test_cnt
; process tx good, update txok, lostcrs, collsn
prc_ptx: ; tx good
rd_NE TSR
test AL, SMK_CRS ; is crs set in TSR
jz nocrs ; no
nocrs:
rd_NE NCR ; read number of collision in AL
mov AL, MSK_PTX
wr_NE ISR ; clear PTX
jmp rd_isr
; process tx error, update .txbad .underrun
prc_txe: ; tx bad
call count_out_err
rd_NE TSR
test AL, SMK_FU ; it fu set in TSR
jz nofu ; no
nofu:
mov AL, MSK_TXE
wr_NE ISR ; clear PTX
jmp rd_isr
; process counter overflow, update .algerr .crcerr .???(missed pkt)
test_cnt:
test AL, MSK_CNT
jnz prc_cnt ; yes, process cnt
jmp rd_isr ; no CNT irq, back to the top
; process CNT
prc_cnt:
mov AL, MSK_CNT
wr_NE ISR ; clear CNT
jmp rd_isr ; back to the top
; End of RECV
_rcv_frm:
; read byte count
mov cx, cs:ReceiveHeader.RByteCount ; Extract size of frame
cmp CX, 5dch
jna rxlen_ok
jmp rcv_ret
rxlen_ok:
sub CX, 4 ; 4 control bytes
mov AX, cs
mov ES, AX
mov di, offset cs:ReceiveHeader.RPacketLength
push cx ; Save frame size
push es
mov ax, cs ; Set ds = code
mov ds, ax
assume ds:code
call recv_find ; See if type and size are wanted
; CX = packet length
; ES:DI = packet type
pop ds ; RX page pointer in ds now
assume ds:nothing
pop cx
cld ; Copies below are forward
mov ax, es ; Did recv_find give us a null pointer?
or ax, di ; ..
je no_buff ; If null, don't copy the data
has_buf:
;Tell DMA to copy the whole packet for us
mov ax, 4
wr_NE RSAR0 ; Don't copy 4 8390 control bytes
mov ax, cx ; CX has byte count
wr_NE RBCR0 ; LSB first
mov al, ah
wr_NE RBCR1 ; Now MSB
mov al, MSK_DMA_RD ; Issue DMA read command
wr_NE CMDR
; copy from NE1000 on board memory using the window RACK
; use IN and stosb to do the copy, IN -> AX -> ES:DI (CX has byte count)
copynow:
push cx ; We will want the count and pointer
push es ; to hand to client after copying,
push di ; so save them at this point
mov DX, CS:io_addr
add DX, RACK ; DX has address NE1000 Port window (?)
cmp is_186,0 ; Can we use rep insb?
je in86 ; no - have to do it slowly.
db 0f3h, 06ch ;masm 4.0 doesn't grok "rep insb"
jmp short icnteven
in86:
; If buffer doesn't begin on a word boundary, get the first byte
test di,1 ; if(buf & 1){
jz ibufeven ;
in al,dx ; al = in(dx);
stosb ; *di++ = al
dec cx ; cx--;
ibufeven:
mov si,cx ; size = cx;
shr cx,1 ; cx = cnt >> 1; (convert to word count)
; Do the bulk of the buffer, a word at a time
jcxz inobuf ; if(cx != 0){
rb: in al,dx ; do { al = in(dx);
mov ah,al
in al,dx ; ah = in(dx);
xchg al,ah
stosw ; *si++ = ax; (di is word pointer)
loop rb ; } while(--cx != 0);
; now check for odd trailing byte
inobuf: shr si,1
jnc icnteven
in al,dx
stosb ; *di++ = al
icnteven:
call_rc:
pop si ; Recover pointer to destination
pop ds ; Tell client it's his source
pop cx ; And it's this long
assume ds:nothing
call recv_copy ; Give it to him
jmp short rcv_ret
; no system buff availble to hold rx frm
no_buff:
rcv_ret:
push cs ; Put ds back in code space
pop ds ; ..
assume ds:code
ret
public recv_exiting
recv_exiting:
;called from the recv isr after interrupts have been acknowledged.
;Only ds and ax have been saved.
assume ds:nothing
ret
;any code after this will not be kept after initialization.
end_resident label byte
public usage_msg
usage_msg db "usage: NE1000 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet driver for NE1000, version "
db '0'+majver,".",'0'+version,CR,LF
db "Portions Copyright 1989, Eric Henderson, BYU",CR,LF,'$'
int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
no_board_msg:
db "NE1000 apparently not present at this IO address.",CR,LF,'$'
HardwareFailure:
db "The NE1000 is not responding.",CR,LF,'$'
using_186_msg db "Using 80[123]86 I/O instructions.",CR,LF,'$'
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
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
extrn etopen_diagn: byte
BoardNotResponding:
mov dx, offset HardwareFailure
mov etopen_diagn, 35
jmp short error_wrt
bad_cksum:
no_memory:
mov dx,offset no_board_msg
mov etopen_diagn,37
error_wrt:
mov ah,9
int 21h
stc
ret
public etopen
etopen:
;if all is okay,
; reset NE1000 board
rd_NE NERESET
wr_NE NERESET
mov al, 21h
wr_NE CMDR
; Test to see if we're OK
rd_NE CMDR
cmp al, 21h
je WeBeOK
jmp BoardNotResponding
WeBeOK:
mov al, 0
wr_NE DCR
mov al, 60h
wr_NE TPSR
mov al, 0
wr_NE TCR
mov al, 20h
wr_NE RCRWD
mov al, 4
wr_NE PSTART
mov al, 4
wr_NE BNRY
mov al, 0ffh
wr_NE PSTOP
mov al, 3ch
wr_NE TBCR0
mov al, 0
wr_NE TBCR1
mov al, 0ffh
wr_NE ISR
mov al, 61h
wr_NE CMDR
mov al, 4
wr_NE CURR
mov al, 22h
wr_NE CMDR
; Test to see if we're still OK
rd_NE CMDR
cmp al, 22h
je WeBeStillOK
jmp BoardNotResponding
WeBeStillOK:
; set up my_eaddr from addr ROM
mov al, 21h
wr_NE CMDR
mov al, 6
wr_NE RBCR0
mov al, 0
wr_NE RBCR1
wr_NE RSAR0
wr_NE RSAR1
mov al, MSK_DMA_RD
wr_NE CMDR
mov DX, CS:io_addr
add DX, RACK ; DX has address NE1000 Port window (?)
mov di, OFFSET my_eaddr
mov ax, cs
mov es, ax
mov cx, 6
GetEnetAddress:
in al, dx
stosb
loop GetEnetAddress
mov ax, cs
mov ds, ax
mov si, OFFSET my_eaddr
mov cx, 6
call set_address
mov al, 21h
wr_NE CMDR
mov al, START_PG
jmp $+2
wr_NE PSTART
jmp $+2
wr_NE BNRY
mov al, STOP_PG
jmp $+2
wr_NE PSTOP
mov al, 61h
jmp $+2
wr_NE CMDR
mov al, START_PG + 1
jmp $+2
wr_NE CURR
mov al, 21h
jmp $+2
wr_NE CMDR
mov al, 48h
jmp $+2
wr_NE DCR
mov al, 0
jmp $+2
wr_NE TCR
mov al, MSK_RXE
jmp $+2
wr_NE RCRWD
mov al, 0ffh
jmp $+2
wr_NE ISR
mov al, UnmaskByte
jmp $+2
wr_NE InterruptMask
;Determine the processor type. The 8088 and 8086 will actually shift ax
;over by 33 bits, while the 80[123]86 use a shift count mod 32.
mov cl,33
mov ax,0ffffh
shl ax,cl
jz not_186
mov is_186,1
mov dx,offset using_186_msg
mov ah,9
int 21h
not_186:
call set_recv_isr ; Put ourselves in interrupt chain
mov al, 22h
jmp $+2
wr_NE CMDR
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 end_resident
clc
ret
code ends
end