home *** CD-ROM | disk | FTP | other *** search
- page 54,132
- ; Packet driver for BICC Data Networks' ISOLINK 4110-2 ethernet
- ; controller, written by
- ; Rainer Toebbicke
- ; European Organisation of Nuclear Research (CERN)
- ; Geneva, Switzerland
- ; based on the "generic" packet driver by Russell Nelson.
-
- version equ 2 ;this is the minor version
-
- include defs.asm ;SEE ENCLOSED COPYRIGHT MESSAGE
-
- ; BICC ISOLINK card constants
-
-
-
- .286c ; we are at least on a 80286!
-
-
- code segment para public
- assume cs:code, ds:code
- public begin ;makes us appear in the link map
- begin equ $ ;used for alignment operations below
-
- ;Lance initialisation block, must be on word boundary
-
- ;
- ; Initialization Block Mode operation Bit Definitions.
- ;
- M_PROM equ 8000h ; Promiscuous Mode
- M_INTL equ 0040h ; Internal Loopback
- M_DRTY equ 0020h ; Disable Retry
- M_COLL equ 0010h ; Force Collision
- M_DTCR equ 0008h ; Disable Transmit CRC)
- M_LOOP equ 0004h ; Loopback
- M_DTX equ 0002h ; Disable the Transmitter
- M_DRX equ 0001h ; Disable the Reciever
-
- IBmode dw 00h ;mode word
- IBpadr db 6 dup (0) ;physical addr
- IBladrf db 8 dup (0ffh) ;logical addr filter
- IBrdraL dw 0 ;Receive Descr Ring ptr
- IBrdraH dw 0
- IBrdraHF equ byte ptr IBrdraH+1
- IBtdraL dw 0 ;Transmit Descr Ring ptr
- IBtdraH dw 0
- IBtdraHF equ byte ptr IBtdraH+1
-
-
- CSR0 equ 0
- c0_ERR equ 8000h
- c0_BABL equ 4000h
- c0_CERR equ 2000h
- c0_MISS equ 1000h
- c0_MERR equ 0800h
- c0_RINT equ 0400h
- c0_TINT equ 0200h
- c0_ErrClear equ c0_BABL+c0_CERR+c0_MISS+c0_MERR
-
- c0_IDON equ 0100h
- c0_INTR equ 0080h
- c0_INEA equ 0040h
- c0_RXON equ 0020h
- c0_TXON equ 0010h
- c0_TDMD equ 0008h
- c0_STOP equ 0004h
- c0_STRT equ 0002h
- c0_INIT equ 0001h
-
-
- CSR1 equ 1
- CSR2 equ 2
- CSR3 equ 3
-
-
-
- RD struc ;Receive descriptor
- RBadrL dw 0
- RBadrH dw 0
- RBbcnt dw 0 ;buffer size
- RBmcnt dw 0 ;packet size
- RD ends
-
- RBflags equ byte ptr RBadrH+1
- RBown equ 080h ;1=owned by Lance, 0=by host
- RBerr equ 040h ;error summary bit
- RBfram equ 020h
- RBoflo equ 010h
- RBcrc equ 008h
- RBbuff equ 004h
- RBstp equ 002h ;start of packet
- RBenp equ 001h ;end of packet
-
- TD struc ;Transmit descriptor
- TBadrL dw 0
- TBadrH dw 0
- TBbcnt dw 0 ;buffer size
- TBtdr dw 0 ;more flags
- TD ends
-
- TBflags equ byte ptr TBadrH+1
- TBown equ 080h ;1=owned by Lance, 0=by host
- TBerr equ 040h ;error summary bit
- TBstp equ 002h ;Start of packet
- TBenp equ 001h ;End of packet
- TBbcntF equ byte ptr TBbcnt+1
-
- gary db 0 ; DEBUG
- garycount db 0 ; DEBUG
-
- public int_no
- int_no dw 10,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 ;from the packet spec
- driver_type db 5 ;from the packet spec
- driver_name db 'ISOLINK',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
-
- public rcv_modes
- rcv_modes dw 7 ;number of receive modes in our table.
- dw 0
- dw rcv_mode_1
- dw 0
- dw rcv_mode_3
- dw 0,0
- dw rcv_mode_6
-
- rbfstart dw FirstDescr ;1st Rcv buffer descr
- rbfcurr dw ?
- tbfstart dw ? ;1st Xmit buffer descr
- tbfcurr dw ?
- tbfend dw ? ;end of Xmit buffers
-
- xmt_buffsz_r dw ? ;xmit buffer sizes
- xmt_buffsz_rn dw ? ;same, but times -1
- pklen dw ? ;length of packet
- pklen_rem dw ? ;remaining to be received
- rcv_csr0 dw ?
- rcvbuffp dd ?
-
-
- RAP dw 0 ;Register Address Port
- RDP dw 0 ;Register Data Port
-
- DMAPrt db 0,0,0,0 ;DMA port number.
-
- options db 0
- options_HMA equ 40h ;running in HMA
-
- word_16 dw 16
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Gary Spanswick - 3/5/90
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- CACPCtrl equ 90h ; Address of CACP control register
-
- DMACascade EQU 0D0H ; DMA Operates in Cascaded Mode
- DMAUnmask EQU 00H ; DMA Operation is to unmask
- DMAC1ModeReg EQU 0BH ; DMA Mode Register Address
- DMAC2ModeReg EQU 0D6H ; DMA Mode Register Address
- DMAC1MaskReg EQU 0AH ; DMA Mask Register Address
- DMAC2MaskReg EQU 0D4H ; DMA Mask Register Address
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- extrn count_out_err:near, count_in_err:near
-
-
- seg2lin proc near
- ; convert (ax:dx=offset:segment) to linear address (ax:dx=low:high)
- push bx
- push ax ;save offset
- mov ax,dx
- mul word_16 ;segment to linear address
- pop bx
- add ax,bx ;plus offset
- adc dx,0
- pop bx ;restore
- ret
- seg2lin endp
-
-
- lin2seg proc near
- ; convert linear addr (ax:dx=low:high) to (ax:dx=offset:segment)
- ; with minimal offset to avoid wrap-around problems
-
- ; the 80286 can address 0-10ffefh in real mode:
- cmp dl,010h ;over 1 Megabyte?
- je l2sHMA ;yes, segment is 0FFFFh
- push ax
- shr ax,4 ;convert to paragraphs
- shl dx,4+8
- or dx,ax ;segment ok
- pop ax
- and ax,0fh ;offset
- ret
-
-
- l2sHMA:
- ; effectively subtract 0ffff0h from the linear address to form the
- ; offset:
- mov dx,0ffffh ;this we know already
- sub ax,0fff0h ;only have to do low order word
- ret
- lin2seg endp
-
-
- ; write bx to Lance control & status reg [ax]
- wrcsr0 proc near
- xor ax,ax ;write to CSR0
- wrcsr: ;CSR in ax
- mov dx,RAP ;address CSR
- out dx,ax
- mov dx,RDP ;data port
- mov ax,bx
- out dx,ax
- ret
- wrcsr0 endp
-
-
- ; read Lance control reg [ax]
- rdcsr0 proc near
- xor ax,ax ;read CSR 0
- rdcsr: ;CSR in ax
- mov dx,RAP
- out dx,ax
- mov dx,RDP
- in ax,dx
-
- ret
- rdcsr0 endp
-
-
- rcv_nxt_d proc near
- ; release current and advance to next receive descriptor
- mov RBflags[bx],RBown ;give buffer to Lance
- add bx,8
- cmp bx,tbfstart ;end of ring?
- jb rcv_nxt_ok ;no...
- mov bx,rbfstart ;restart at first descriptor
- rcv_nxt_ok:
- mov rbfcurr,bx
- ret
- rcv_nxt_d endp
-
-
- xmt_nxt_d proc near
- xmt_nxt_d endp
-
-
- wait_own_0 proc near
- ; wait for "own" bit in descriptor [bx] to clear
- test TBflags[bx],TBown
- jnz wo_wait ;no, have to wait
- ret
-
- wo_wait:
- push cx ;save reg
- mov cx,0ffffh
- wo_lp1:
- test TBflags[bx],TBown
- jz wo_clear ;ok...
- loop wo_lp1
-
- wo_clear:
- pop cx
- ret
- wait_own_0 endp
-
-
- rcv_getaddr proc near
- ; obtain buffer addr from descriptor [bx]
- mov ax,RBadrL[bx]
- mov dx,RBadrH[bx]
- call lin2seg
- mov word ptr rcvbuffp,ax
- mov word ptr rcvbuffp+2,dx
- ret
- rcv_getaddr endp
-
- 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
-
-
- ErrExit proc near
- mov ah,9
- int 21h
- stc
- ret
- ErrExit endp
-
- LoadInitBlock proc near
- ; set initialisation block addr
- push ds
- pop dx
- mov ax,offset IBmode
- call seg2lin
- push dx ;don't loose it
- mov bx,ax
- mov ax,CSR1
- call wrcsr ;low order 16 bits of addr
- pop bx
- mov ax,CSR2
- call wrcsr ;high order bits
- ret
- LoadInitBlock endp
-
- InitLance proc near
- ; init the controller and wait for completion
- mov bx,c0_INIT
- call wrcsr0
-
- mov cx,-1 ;wait for completion
- eto_initlp:
- call rdcsr0
- test ax,c0_IDON ;done?
- jnz init_ok ;good!
- loop eto_initlp
-
- mov dx,offset init_errmsg
- call outofHMA ;get out of HMA
- call errexit
- init_ok:
- ret
- InitLance endp
-
-
- public send_pkt
- send_pkt proc near
- ;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
- push ds ;save packet segment
- push cs
- pop ds
- assume ds:code
-
- ; packet must be at least 64 bytes long (with fcs)...
-
- cmp cx, 82 ; DEBUG
- jb Fred1 ; DEBUG
- mov gary,1 ; DEBUG
- Fred1: ; DEBUG
-
- cmp gary,1
- jne fred2
- inc garycount
- fred2:
-
- cmp cx,RUNT
- jnl send_L_ok
- mov cl,RUNT
- send_L_ok:
-
- ; get next buffer descriptor
- mov bx,tbfcurr
- call wait_own_0 ;wait until it's free
-
- ; If the next buffer is big enough to hold the packet, we will
- ; copy the packet and send it out.
- ; Otherwise we send it from the user's buffer but then have to
- ; wait until it is sent out.
- ; This may speed up fast machines on the expense of some memory
-
- cmp cx,xmt_buffsz_r ;longer than our buffers?
- jng send_copy ;no, copy the packet
-
- send_user_buff: ;send from user's buffer
- mov ax,si ;input buffer addr
- pop dx ;segment
- call seg2lin ;convert to linear addr
- push TBadrL[bx] ;save original buffer address
- push TBadrH[bx] ;...
- mov TBadrL[bx],ax
- mov TBadrH[bx],dx
- jmp short send_send
-
- send_copy:
- mov ax,TBadrL[bx]
- mov dx,TBadrH[bx] ;buffer address
- call lin2seg ;convert to offset:segment
- mov es,dx
- mov di,ax
- pop ds ;restore packet segment
- assume ds:nothing
- push cx ;save length
- test cx,1 ;uneven length?
- jz send_even
- movsb
- send_even:
- shr cx,1 ;convert to words, can't be zero
- rep movsw ;copy buffer
- pop cx
- push cs
- pop ds ;restore ds
- assume ds:code
-
- send_send:
- neg cx ;length in two's complement
- mov TBbcnt[bx],cx
- or TBflags[bx],TBown+TBstp+TBenp
- push bx ;save ring entry address
- mov bx,c0_TDMD+c0_INEA
- call wrcsr0 ;start transmitter immediately
- pop bx ;restore ring entry addr
- xor al,al ;assume no error
- cmp cx,xmt_buffsz_rn ;was this a big buffer?
- jnl send_next ;no, all done
-
- call wait_own_0 ;wait for send ok
- mov al,TBflags[bx] ;save flags
- mov cx,xmt_buffsz_rn ;original buffer size negated
- pop TBadrH[bx]
- pop TBadrL[bx]
- mov TBbcnt[bx],cx
-
-
-
- ; advance to next transmit descriptor
- send_next:
- add bx,8
- cmp bx,tbfend ;end of ring?
- jb xmt_nxt_ok ;no...
- mov bx,tbfstart ;restart at first descriptor
- xmt_nxt_ok:
- mov tbfcurr,bx
-
- send_done:
- test al,TBerr ;were there problems?
- jnz send_err
- clc
- ret
-
- send_err:
- call count_out_err
- stc
- ret
- send_pkt endp
-
-
- 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
- jnb get_addr_ok ;buffer ok
- stc
- ret
-
- get_addr_ok:
- push si
- mov si,offset IBpadr
- rep movsb
- pop si
- mov cl,EADDR_LEN
- 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
- jnb set_addr_ok ;buffer ok
- mov dh,BAD_ADDRESS
- stc
- ret
-
- set_addr_ok:
- assume es:nothing
- clc
- ret
-
-
- reset_mode proc near
- ; stop and restart the receiver
- call reset_interface ;stop it
- mov bx,c0_INIT ;re-init
- call wrcsr0
- mov cx,-1 ;wait until done
- rm_lp:
- call rdcsr0
- test ax,c0_IDON ;ok?
- jnz rm_IDON ;yes...
- loop rm_lp ;else continue
-
- rm_IDON:
- mov bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON
- call wrcsr0 ;start the receiver
- ret
- reset_mode endp
-
-
- rcv_mode_1:
- mov IBmode,M_DRX or M_DTX
- jmp reset_mode
-
-
- rcv_mode_3:
- mov IBmode,0
- jmp reset_mode
-
- rcv_mode_6:
- mov IBmode,M_PROM
- jmp reset_mode
-
-
- public set_multicast_list
- set_multicast_list:
- ;enter with es:di ->list of multicast 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:
- call rcv_mode_1 ;don't receive any apckets.
-
- ;This routine will remove the (host) DMA controller from
- ;cascade mode of operation.
- mov al,DMAPrt
- or al,4
- cmp DMAPrt,4 ;If channel 5 or 6,
- ja terminate_16 ; use sixteen bit dma.
- terminate_8:
- out DMAC1MaskReg,al
- jmp short terminate_done
- terminate_16:
- out DMAC2MaskReg,al
- terminate_done:
- ret
-
-
- public get_multicast_list
- get_multicast_list:
- ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
- ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
- ;return cy, NO_MULTICAST if we don't implement multicast.
- mov dh,NO_MULTICAST
- stc
- ret
-
-
-
- public reset_interface
- reset_interface proc near
- ;reset the interface.
- assume ds:code
- mov bx,c0_STOP
- call wrcsr0
- ret
- reset_interface endp
-
-
- ;called when we want to determine what to do with a received packet.
- ;enter with cx = packet length, es:di -> packet type.
- 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
-
-
- public recv
- recv proc near
- ;called from the recv isr. All registers have been saved, and ds=cs.
- ;Upon exit, the interrupt will be acknowledged.
- assume ds:code
-
- call rdcsr0 ;obtain interrupting status
- and ax,0ffffh-c0_INEA ;disable interrupts
- ; mov RXStatus,Active ;Indicate receive is active
- mov bx,ax
- call wrcsr0 ;clear acknowledged i-sources
-
- mov rcv_csr0,bx ;save
- ; test bx,c0_ERR ;any errors?
- ; jz rcv_noerr ;no...
- ; ... errors checked on descriptor level
-
- rcv_noerr:
- test bx,c0_RINT ;received a packet
- jz rcv_norint
- call do_rcv ;process...
-
- rcv_norint:
-
- rcv_ret:
- mov bx,c0_INEA ;re-enable interrupts
- cli
- call wrcsr0
- ret
- recv endp
-
-
-
- do_rcv proc near
-
- mov bx,rbfcurr ;address descriptor
- rcv_lp:
- mov al,RBflags[bx]
- test al,RBown ;something in buffer?
- jz rcv_dobuf ;yes...
- ret ;else return
-
- rcv_dobuf:
- test al,RBerr ;any errors?
- jz rcv_good ;no...
- test al,RBoflo ;overflow bit set?
- jz rcv_err_1 ;no...
- test al,RBenp ;ghost overflow error?
- jnz rcv_good ;yes, ignore the error
-
- rcv_err_1:
-
- rcv_do_err:
- ; test al,RBoflo+RBbuff ;only count these
- ; jz rcv_next
-
- call count_in_err
-
- rcv_next:
- call rcv_nxt_d ;next descriptor
- jmp rcv_lp
-
- rcv_good:
- test al,RBstp ;packet starts here?
- jz rcv_do_err ;no, unrolling error chain,
- ;count when error flag appears
-
- rcv_good_stp:
- ; obtain packet length from last segment
- rcv_L_lp:
- test al,RBenp ;end of packet?
- jnz rcv_L_ok ;yes, get length
- add bx,8 ;to next descriptor
- cmp bx,tbfstart ;overrun?
- jb rcv_L_next ;no...
- mov bx,rbfstart
- rcv_L_next:
- cmp bx,rbfcurr ;make sure we don't loop!
- je rcv_L_ouch ;this is nonsense
- mov al,RBflags[bx] ;get flags
- test al,RBown+RBerr ;anything wrong with it?
- jz rcv_L_lp ;no, go ahead
- mov dl,al
- and dl,RBenp+RBoflo
- cmp dl,RBenp+RBoflo ;ghost overflow?
- je rcv_L_ok ;yes, let it go through
-
- rcv_L_ouch:
- mov bx,rbfcurr ;restore current
- jmp rcv_do_err ;give up
-
- rcv_L_ok:
- mov cx,RBmcnt[bx] ;message length
- sub cx,4 ;strip FCS
- mov bx,rbfcurr ;restore descriptor addr
- cmp cx,GIANT ;reasonable size?
- jg rcv_do_err ;rubbish!
- jcxz rcv_next ;nothing to do...
- mov pklen,cx ;save packet length
- mov pklen_rem,cx ;remains to be rcvd
-
- call rcv_getaddr
-
- mov di,ax
- mov es,dx
- add di,EADDR_LEN*2 ;point to type field
-
- 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:
-
- call recv_find ;want this packet?
-
- mov ax,es
- or ax,di
- mov bx,rbfcurr ;restore in case...
- jz rcv_next ;no buffer, give up
-
- push es
- push di
- rcv_seg_lp:
- ; the packet's segments are copied into the client's buffer.
- ; The calculated length did not include the 4 byte fcs. Care must
- ; be taken not to copy the fcs, which may (in the worst case) be
- ; part of the last two segments!
-
- test RBflags[bx],RBenp ;packet ends here?
- jz rcv_seg_l_buf ;no, use buffer size
- mov cx,pklen_rem ;remaining msg length
- or cx,cx ;still data?
- jle rcv_done ;no, just part of fcs
- jmp short rcv_seg_l_ok
-
- rcv_seg_l_buf:
- mov cx,RBbcnt[bx] ;buffer size
- neg cx ;it's in two's complement
- sub pklen_rem,cx ;correct remaining len
- jnl rcv_seg_l_ok ;use whole buffer
- ; the current buffer contains part of the fcs...
- add cx,pklen_rem ;use only data part
-
- rcv_seg_l_ok:
- lds si,rcvbuffp ;point to buffer
- assume ds:nothing
- test cl,1 ;prepare for movsw
- jz rcv_even
- movsb ;copy first byte
- rcv_even:
- shr cx,1
- jcxz rcv_moved
- rep movsw ;copy the packet
-
- rcv_moved:
- push cs
- pop ds
- assume ds:code
-
- test RBflags[bx],RBenp ;end of packet?
- jnz rcv_done ;yes...
-
- call rcv_nxt_d ;to next descriptor
- call rcv_getaddr ;next buffer addr
- jmp rcv_seg_lp
-
- rcv_done:
- mov cx,pklen
- pop si ;restore buffer addr
- pop ds
- assume ds:nothing
-
- call recv_copy ;wake up client
-
- push cs
- pop ds
- assume ds:code
-
- mov bx,rbfcurr ;current descriptor
- jmp rcv_next ;else do next descriptor
-
- do_rcv endp
-
-
- 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
-
-
- ; Most of the initialisation code is used only once and can be
- ; dicarded when init finishes, but not this:
- ; we formatted the buffer descriptors (a maximum space for
- ; that could be provided), but where could we place this code
- ; if buffers are allocated immediately afterwards?
- ; Too dangerous in the buffer area, since we will start the receiver now.
- ; Possible alternative: relocate to an address after the buffers, but
- ; since it's only a few bytes...
-
- eto_go:
- assume ds:code
- call wrcsr ;start the Lance
- pop dx ;get our ending paragraph
- mov ah,31h
- int 21h ;terminate, stay resident
-
-
- ; Provide maximum space for buffer descriptors before more
- ; discardable initialisation code starts, since the decriptors
- ; must be formatted. Buffers may follow immediately afterwards,
- ; but will not be used until the receiver is started.
-
- ; All resident code and data must be before this label!
- ; on quadword boundary...
- public buffers_start
- buffers_start db 0
-
- org begin+( (($-begin+7)/8)*8 )
- FirstDescr db ((128+128)*8) dup (0)
-
-
-
- public usage_msg
- usage_msg db "usage: ISOLINK [-n] [-d] [-w] <packet_int_no> <options>",CR,LF
- db "options: [defaults]",CR,LF
- db " /D<DMA channel #> [0]",CR,LF
- db " /I<hw-int-level> [10]",CR,LF
- db " /P<I/O port address> [(8)280]",CR,LF
- db " /R<# recv buffs> <recv buff size> [16 256]",CR,LF
- db " /T<# xmit buffs> <xmit buff size> [1 0]",CR,LF
- db " /X (requires himem.sys installed)",CR,LF
- db "$"
-
-
-
-
- public copyright_msg
- copyright_msg db "Packet driver for BICC 4110-2/3 ISOLAN controllers,"
- db "version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
- db "Written by R.Toebbicke, CERN, Switzerland",CR,LF
- db "* Copyright CERN, Geneva 1990 - Copyright and any other",CR,LF
- db "* appropriate legal protection of these computer programs",CR,LF
- db "* and associated documentation reserved in all countries",CR,LF
- db "* of the world.",CR,LF,'$'
-
-
-
- int_no_name db "Interrupt number $"
- BaseName db "I/O Port address $"
- BasePrt dw 08280h,0
- DMAName db "DMA channel number $"
-
- extrn our_isr: near, their_isr: dword
- extrn packet_int_no: byte
- extrn phd_environ: word
- extrn decout: near
-
- rcv_buffno dw 16,0
- rcv_buffnoname db "Number of receive buffers $"
- rcv_bufflog db 4
- rcv_buffsz dw 256,0
- rcv_buffszname db "Receive buffer size $"
- xmt_buffno dw 1,0
- xmt_buffnoname db "Number of transmit buffers $"
- xmt_bufflog db 0
- xmt_buffsz dw 0,0
- xmt_buffszname db "Transmit buffer size $"
-
- orgseg dw ?
-
- linaddrL dw 0
- linaddrH dw 0
-
- ; keep these two together!
- HMAaddr dw 00010h
- HMAaddrS dw 0FFFFh
-
- XMSctl dd ?
-
- PS2IO dw 08280h, 09250h, 0a390h, 0b1d0h
- PS2INT db 9, 10, 11, 15, 3, 4, 5, 0
-
-
- 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
-
- extrn skip_blanks: near
-
- argerr db "Error in options: '"
- argerrc db " "
- db "'.",CR,LF,"$"
-
- parse_err db 0
-
-
- public parse_args
- parse_args proc near
- ; If we run on a PS/2, read the default configuration from the POS regs
-
- test sys_features,MICROCHANNEL
- jnz do_mc_defaults
- jmp parse_args_l
- do_mc_defaults:
-
- mov bx,08h ;1st slot
- pa_slot_l:
- mov dx,96h
- mov ax,bx
- out dx,al ;put in setup mode
- mov dx,101h
- in al,dx
- xchg al,ah ;high id byte
- dec dx
- in al,dx ;low id byte
- cmp ax,0808h ;ISOLINK card?
- je pa_found_iso ;yes...
- inc bx ;next slot
- cmp bx,0fh ;too far?
- jna pa_slot_l ;no, try next
- mov dx,96h
- xor al,al
- out dx,al ;exit setup mode
- jmp parse_args_l
-
- pa_found_iso:
- mov dx,102h
- in al,dx ;get I/O address code
- xor ah,ah
- and al,6
- mov bx,ax
- mov ax,PS2IO[bx] ;I/O port address
- mov BasePrt,ax
-
- mov dx,104h
- in al,dx
- xor ah,ah
- shr al,5 ;isolate interrupt bits
- mov bx,ax
- mov al,PS2INT[bx] ;interrupt number
- mov int_no,ax
-
-
- parse_args_l:
- call skip_blanks
- cmp al,CR ;end of args?
- je pa_ret ;yes...
- cmp al,'/' ;option following?
- je pa_doopt ;yes
-
- pa_err:
- mov argerrc,al
- mov dx,offset argerr
-
- pa_err2:
- mov ah,9
- int 21h ;print error message
- mov parse_err,1 ;indicate error
- pa_ret:
- ret
-
- pa_doopt:
- inc si
- lodsb ;get option byte
- cmp al,'a' ;in lowercase range?
- jna pa_upper
- sub al,20h ;convert to uppercase
- pa_upper:
- cmp al,'I'
- je pa_doInt
- cmp al,'P'
- je pa_doPort
- cmp al,'D'
- je pa_doDMA
- cmp al,'R'
- je pa_doRcv
- cmp al,'T'
- je pa_doTrans
- cmp al,'X' ;into extended memory?
- je pa_doext
- jmp pa_err
-
- pa_doInt:
- mov di,offset int_no
- call get_number
- jmp parse_args_l
-
- pa_doPort:
- mov di,offset BasePrt
- call get_number
- jmp parse_args_l
-
- pa_doDMA:
- mov di,offset DMAPrt
- call get_number
- jmp parse_args_l
-
-
- pa_doRcv:
- mov di,offset rcv_buffno
- call get_number
-
- mov di,offset rcv_buffsz
- call get_number
- jmp parse_args_l
-
-
- pa_doTrans:
- mov di,offset xmt_buffno
- call get_number
-
- mov di,offset xmt_buffsz
- call get_number
- jmp parse_args_l
-
-
- pa_doext: ;set up for HMA
- or options,options_HMA ;indicate we want to run up there
- jmp parse_args_l
-
-
- parse_args endp
-
-
- public print_parameters
- print_parameters proc
- mov di,offset int_no
- mov dx,offset int_no_name
- call print_number
-
- mov di,offset BasePrt
- mov dx,offset BaseName
- call print_number
-
- mov di,offset DMAPrt
- mov dx,offset DMAName
- call print_number
-
- mov di,offset rcv_buffno
- mov dx,offset rcv_buffnoname
- call print_number
-
- mov di,offset rcv_buffsz
- mov dx,offset rcv_buffszname
- call print_number
-
- mov di,offset xmt_buffno
- mov dx,offset xmt_buffnoname
- call print_number
-
- mov di,offset xmt_buffsz
- mov dx,offset xmt_buffszname
- call print_number
-
- ret
-
- print_parameters endp
-
-
-
-
- inv_DMA db "Invalid DMA channel number.",CR,LF,"$"
- init_errmsg db "Lance initialisation failed.",CR,LF,"$"
- inv_buff db "Invalid buffer specification.",CR,LF,"$"
- HMAnoHIMEM db "HMA not available: HIMEM.SYS not installed.",CR,LF,"$"
- HMAnotavail db "HMA not available.",CR,LF,"$"
- HMAalloc db "Using extended memory (HMA).",CR,LF,"$"
- HMAtoobig db "Buffers exceed HMA size.",CR,LF,"$"
- HMAmsg_1 db "/X configured $"
- HMAmsg_2 db " receive buffers of length $"
- HMAmsg_3 db ".",CR,LF,"$"
-
- public etopen
- etopen proc near
- assume ds:code
-
- extrn flagbyte: byte
- or flagbyte,CALLED_ETOPEN
-
- test parse_err,0ffh ;any parsing error?
- jnz eto_errexit2 ;yes, give up
-
- cmp packet_int_no,0
- mov dx,offset usage_msg
- jz eto_errexit
-
-
-
- ; check DMA port
- mov al,DMAPrt
- or al,al
- jb eto_invalid_DMA ;should not be negative
- cmp al,7
- jna eto_DMA_ok
-
- eto_invalid_DMA:
- mov dx,offset inv_DMA
-
- eto_errexit:
- mov ah,9
- int 21h
- eto_errexit2:
- stc
- ret
-
- eto_DMA_ok:
- ; check receive buffers
- mov bx,rcv_buffno
- call do_power_of_2
- cmp ax,128
- jg eto_inv_Buff
- or ax,ax ;must have something!
- jz eto_inv_Buff
- mov rcv_bufflog,cl
- mov rcv_buffno,ax
-
- mov ax,rcv_buffsz ;check buffer size
- cmp ax,100 ;at least that big
- jg eto_rcvsz_1
- mov ax,100
- eto_rcvsz_1:
- cmp ax,GIANT+4 ;biggest packet plus fcs
- jl eto_rcvsz_2 ;does not exceed
- mov ax,GIANT+4 ;take maximum
- eto_rcvsz_2:
- mov rcv_buffsz,ax
-
- ; check transmit buffers
- mov bx,xmt_buffno
- call do_power_of_2
- or ax,ax ;must have something!
- jz eto_inv_Buff
- cmp ax,128
- jna eto_xmt_buffok
-
- eto_inv_Buff:
- mov dx,offset inv_Buff
- jmp eto_errexit
-
- eto_xmt_buffok:
- mov xmt_bufflog,cl
- mov xmt_buffno,ax
-
- mov ax,xmt_buffsz ;check buffer size
- cmp ax,RUNT ;at least that big
- jg eto_xmtsz_1
- mov ax,0 ;else don't use
- eto_xmtsz_1:
- cmp ax,GIANT ;biggest packet w/o fcs
- jl eto_xmtsz_2 ;does not exceed
- mov ax,GIANT ;take maximum
- eto_xmtsz_2:
- mov xmt_buffsz,ax
- mov xmt_buffsz_r,ax ;again for our resident part
- neg ax
- mov xmt_buffsz_rn,ax ;times -1 for resident part
-
- ; set RAP & RDP addresses
- mov ax,BasePrt
- add ax,0ch
- mov RDP,ax
- add ax,02h
- mov RAP,ax
-
-
- ; this code is from Russell Nelson's packet driver skeleton.
- ; Need it here, since we won't return from etopen: as soon as the
- ; receiver is started, this place may get clobbered with Ethernet packets
-
- mov ah,35h ;remember their packet interrupt.
- mov al,packet_int_no
- int 21h
- mov their_isr.offs,bx
- mov their_isr.segm,es
-
- mov ah,25h ;install our packet interrupt
- mov dx,offset our_isr
- int 21h
-
- call set_recv_isr ;intercept interrupts
-
-
- ; Now we decide whether we will run in the HMA (above 1 MB) before
- ; we do any calculations involving real addresses
-
- test options,options_HMA ;will we?
- jnz eto_tryHMA ;yes
- jmp eto_HMAok ;no...
-
- ; first check of HIMEM.SYS is installed and if we can globally
- ; enable the HMA
- eto_tryHMA:
- mov ax,4300h
- int 2Fh ; Is an XMS Driver installed?
- mov dx,offset HMAnoHIMEM ;error message in case...
- cmp al,80h
- jne eto_noHMA ;no...
- mov ax,4310h
- int 2fh ;obtain XMS control addr
- mov word ptr XMSctl,bx ;save entry point
- mov word ptr XMSctl+2,es
-
- mov dx,0ffffh ;allocate whole HMA
- mov ah,1
- call XMSctl
- mov dx,offset HMAnotavail ;error msg in case...
- cmp ax,1
- jne eto_noHMA ;not available
- mov ah,3 ;global enable A20 line
- call XMSctl
- cmp ax,1 ;ok?
- je eto_HMA_enabled
-
- eto_noHMA:
- mov ah,9
- int 21h ;error msg addr in dx!
- and options,not options_HMA ;turn off HMA bit
- jmp eto_HMAok ;continue as usual
-
- eto_HMA_enabled:
- ; mov dx,offset HMAalloc
- ; mov ah,9
- ; int 21h ;confirm
-
-
- ; maximize the receive buffer space to utilise the whole HMA:
- ; 1. calculate remaining space excluding receive buffers and descriptors
- ; 2. start with 128 receive buffers
- ; 3. calculate remaining space for buffers
- ; 4. divide by number of buffers to obtain (even) buffer size
- ; 5. if size inferior to defaulted or specified size half number
- ; of buffers and restart on step 2.
-
- mov bx,0fff0h ;total HMA size
- sub bx,offset FirstDescr ;minus resident code
-
- mov ax,xmt_buffsz ;xmit buffer size
- add ax,8 ;plus descriptor
- mul xmt_buffno ;=total xmit space
- or dx,dx ;not more than 64k!
- jnz try_err ;ooops
-
- sub bx,ax ;remaining space without recv
- jc try_err ;must be positive!
-
- mov cx,128 ;try 128 buffers
- try_lp:
- mov ax,cx ;number of buffers
- shl ax,3 ;8 bytes long
- sub ax,bx
- neg ax ;remaining space for buffers
-
- xor dx,dx ;accumulator extension
- div cx ;calculate buffer length
- and ax,0fffeh ;even length
- cmp ax,rcv_buffsz ;long enough?
- jnb try_ok ;yes...
- shr cx,1 ;else half number of buffers
- jnz try_lp ;and retry
-
- try_err:
- mov dx,offset HMAtoobig
- jmp eto_errexit
-
- try_ok:
- cmp ax,GIANT+4 ;maximum size
- jng try_ok_2 ;does not exceed
- mov ax,GIANT+4 ;else maximum length
- try_ok_2:
- mov rcv_buffno,cx
- mov rcv_buffsz,ax
- mov bx,cx
- call do_power_of_2 ;have to do it again
- mov rcv_bufflog,cl
-
-
-
- mov dx,offset HMAmsg_1
- mov ah,9
- int 21h
-
- mov ax,rcv_buffno
- xor dx,dx
- call decout
-
- mov dx,offset HMAmsg_2
- mov ah,9
- int 21h
-
- mov ax,rcv_buffsz
- xor dx,dx
- call decout
-
- mov dx,offset HMAmsg_3
- mov ah,9
- int 21h
-
-
- ; la demarche a suivre:
- ; we copy ourselves into the HMA completely, format all the
- ; descriptors, correct the interrupt addr and exit to DOS
-
- mov ax,cs
- mov orgseg,ax ;save original segment
- les di,dword ptr HMAaddr ;that's where we will be
- mov cx,offset end_code ;length(!) of code to be copied
- mov si,10h ;start at offset 10
- sub cx,si ;correct length
- rep movsb ;copy us
- push HMAaddrS ;our new segment
- ; careful: here comes a jump!
- call setcs ;we're in the HMA
- push cs
- pop ds ;our data as well
-
-
-
- eto_HMAok:
- ; get linear address for receive buffer descriptor start
- push ds
- mov ax,offset FirstDescr
- pop dx
- call seg2lin
-
- ; Store in Init Block
- mov IBrdraL,ax
- mov IBrdraH,dx
-
- ; calculate linear address of first buffer
- mov bx,offset FirstDescr
- mov rbfstart,bx
- mov rbfcurr,bx
-
- mov ax,rcv_buffno
- push ds
- pop dx
- add ax,xmt_buffno ;result is still in segment
- shl ax,3 ;times eight
- add ax,bx ;won't leave segment!
- call seg2lin ;convert to linear addr
- mov linaddrL,ax ;first available buffer addr
- mov linaddrH,dx
-
- ; format receive buffer descriptors
- mov si,rcv_buffsz ;buffer size
- mov cx,rcv_buffno ;number of buffers
- mov dl,RBown ;flags
- eto_rcvloop:
- call format_descr
- add bx,8
- loop eto_rcvloop
-
-
- ;set transmit descriptor ring address
- push ds
- mov ax,bx
- pop dx
- call seg2lin
- mov IBtdraL,ax
- mov IBtdraH,dx
-
- ; format transmit buffer descriptors
- mov tbfstart,bx ;remember start
- mov tbfcurr,bx
- mov dl,0 ;initial flags
- mov cx,xmt_buffno ;number of buffers
- mov si,xmt_buffsz ;buffer size
- eto_xmtloop:
- call format_descr
- add bx,8
- loop eto_xmtloop
- mov tbfend,bx ;remember end
-
-
- ; finish initialisation block
- mov al,rcv_bufflog ;# of rcv buffers
- shl al,5
- mov IBrdraHF,al
-
- mov al,xmt_bufflog ;# of xmt buffers
- shl al,5
- mov IBtdraHF,al
-
- ; copy Ethernet address out of ROM
- mov cx,EADDR_LEN
- push ds
- pop es
- mov di,offset IBpadr
- mov dx,BasePrt
- eto_addrloop:
- in ax,dx
- inc dx
- inc dx
- stosb
- loop eto_addrloop
-
- ; init DMA controller
- test sys_features,MICROCHANNEL ;running on a PS/2?
- jnz eto_DMA_done ;yes, no DMA
-
- cmp DMAPrt, 3 ; Which DMAC - 1 or 2 ?
- ja SetupDMAC2 ; DMAC 2
-
- mov dx,DMAC1ModeReg ;addr of mode reg 1
- mov al,DMAPrt ;DMA number
- or al,DMACascade ;or in mode reg bits
- out dx,al
- jmp $+2
- and al,3 ;leave only DMA channel #
- mov dx,DMAC1MaskReg ;mask register 1 addr
- out dx,al ;clear the DMA channel
- jmp eto_DMA_done
-
- SetupDMAC2:
- mov dx,DMAC2ModeReg ;addr of mode reg 2
- mov al,DMAPrt ;DMA number
- sub al, 4 ;Adjust DMA channel number
- or al,DMACascade ;or in mode reg bits
- out dx,al
- jmp $+2
- and al,3 ;leave only DMA channel #
- mov dx,DMAC2MaskReg ;mask register 2 addr
- out dx,al ;clear the DMA channel
- jmp eto_DMA_done
-
- eto_DMA_done:
-
- ; stop the Lance, sets required bits in CSR3 as well
- call reset_interface
-
- ; Give the LANCE the address of the initialisation block
- call LoadInitBlock
-
- ; init the controller and wait for completion
- call InitLance
-
- eto_init_ok:
- test options,options_HMA ;are we in HMA?
- jz eto_tsr ;no, use TSR code
- xor ax,ax
- ; correct the packet and hardware interrupt addresses
- mov es,ax
- xor bh,bh
- mov bl,packet_int_no
- shl bx,2 ;point to interrupt vector
- push cs
- pop es:[bx+2]
-
- mov bx,int_no ;card interrupt
- add bx,68h ;assume above 8
- cmp bx,8+68h ;is it?
- jnb eto_HMA_int_ok ;yes...
- sub bx,60h ;PS/2 can use interrupt < 8
- eto_HMA_int_ok:
- shl bx,2 ;point to interrupt vector
- push cs
- pop es:[bx+2]
-
- ; Now start the receiver and exit to DOS
- call outofHMA ;out of danger zone (buffers!)
- mov bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON ; ...SET...
- call wrcsr0 ; ...GO!
- int 20h ;exit...
-
-
- eto_tsr:
- ;calculate end of resident part (relative to pgm start)
- mov ax,linaddrL
- mov dx,linaddrH
- add ax,15 ;round to paragraph
- adc dl,0
- shr ax,4
- shl dl,4
- or ah,dl
- mov dx,ds ;minus pgm start addr
- sub ax,dx
- push ax ;save the address
-
-
- ; again some code from the packet driver skeleton...
-
- mov ah,49h ;free our environment, because
- mov es,phd_environ ; we won't need it.
- int 21h
-
- mov bx,1 ;get the stdout handle.
- mov ah,3eh ;close it in case they redirected it.
- int 21h
-
- ; call setup_isr ;Install LANCE lockup isr
-
- mov ax,csr0 ; READY...
- mov bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON ; ...SET...
- jmp eto_go ; ...GO!
- etopen endp
-
-
- do_power_of_2 proc near
- ; adjust bx to valid # of buffers.
- ; on exit: ax=fitting number, cx=log2(ax)
- mov cx,7 ;allow 7 shifts
- mov ax,bx
- dpw2_loop:
- cmp ax,1
- je dpw2_done
- shr ax,1
- loop dpw2_loop
- dpw2_done:
- mov ax,7
- sub ax,cx ;get number of shifts
- mov cx,ax
-
- mov ax,1
- jcxz dpw2_ret
- shl ax,cl
- dpw2_ret:
- ret
- do_power_of_2 endp
-
-
-
-
-
- format_descr proc near
- ; format buffer descriptor pointed to by [bx]
- ; si=buffer size, dl=flags
- push dx ;save flags
- mov ax,linaddrL ;next available buffer addr
- mov dx,linaddrH
- mov RBadrL[bx],ax ;buffer addr
- mov RBadrH[bx],dx
- add ax,si ;point to next available addr
- adc dx,0
- mov linaddrL,ax
- mov linaddrH,dx
- mov ax,si ;get buffer size
- ; or ah,0f0h ;reserved bits to 1
- neg ax ;two's complement
- mov RBbcnt[bx],ax
- pop dx ;restore flags
- mov RBflags[bx],dl
- ret
- format_descr endp
-
-
- outofHMA proc near ;leave the HMA
- test options,options_HMA ;are we in it?
- jz ooHret ;no...
- push orgseg
- call setcs
- push cs
- pop ds
- ooHret:
- ret
- outofHMA endp
-
-
- setcs proc near
- db 0cbh ;RET FAR (!)
- setcs endp
-
- disp_hex_num PROC NEAR
-
- push ax
- push bx
- push cx
- mov bx,ax
- mov cx,4
- start:
- push cx
- mov cl,4
- rol bx,cl
- push bx
- and bl,0fh
- mov al,bl
- cmp al,09
- jg letter
- digit:
- add al,48
- jmp print_num
- letter:
- add al,55
- print_num:
- mov ah,14
- int 10h
- pop bx
- pop cx
- loop start
-
- mov al,20h
- mov ah,14
- int 10h
-
- pop cx
- pop bx
- pop ax
-
- ret
-
- ; mov ax,4c00h ; Load DOS exit function
- ; int 21h ; call DOS
-
- disp_hex_num ENDP
-
- end_code equ $
-
- PUBLIC mc_end
- mc_end db 0
-
- code ends
- end
-
-
-