home *** CD-ROM | disk | FTP | other *** search
- version equ 1
-
- ;History:525,47 0
-
- ; Copyright, 1990-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.
-
-
- include defs.asm
-
- ;some generic information about buffer lengths, etc
- XMITBUF_LEN equ 800h ;Transmit buffer length
- RPAGE_LEN equ 128 ;receive page is 128 bytes
- NUM_RPAGES equ 96 ;There are 96 receive pages
- NUM_XBUFS equ 2 ;Number of xmit buffers
- NUM_XBUFS_MASK equ 1
-
- ub_seg segment at 0
-
- org 10h
- eaddr_rom db 6 dup(?) ;Has serial # in 3 & 4th bytes
-
- org 2080h
- tsa_msb db ? ;transmitter start address, high order 4
- ;bits on write, start send on read
- tsa_lsb db ? ;Transmitter start address, least
- ;significant byte on write, clear PAV
- ;on read
-
- ;Control / status register (CSR)
-
- csr db ? ;Control on write, status on read port
-
- ;Command bits
- TxRdyIntEn equ 080h ;allow TxRdy interrupts
- PAVIntEn equ 040h ;Allow PAV to gen. intr.
- SFTInt equ 020h ;generate an interrupt reg.
- TimIntEn equ 010h ;allow Time interrupt req.
- ;status bits
- NTxRdyInt equ 080h ;Not req. TxRdy inter.
- NPAVInt equ 040h ;Not req. Pav intr.
- NSFTInt equ 020h ;Not req. SFTInt inter.
- NTimInt equ 010h ;Not req. timer inter.
- NRINT equ 008h ;Not req. recv inter.
- NTINT equ 004h ;Not req. xmit inter.
- TPOK equ 002h ;Packet okay of some type
- TXDONE equ 001h ;Transmit done
-
- ;Page pointer register definitions
-
- ffp label byte ;ffp - first free page register
- epp label byte ;epp - empty page pointer register
- pp db ? ;ffp on write/epp on read
-
-
- ;ffp bits
- NIC_IE equ 080h ;NIC interrupts enable
-
- ;epp bits
- PAV equ 080h ;Page available
- RPAGE_BITS equ 07fh
-
-
- org 2100h
- page_ram db NUM_RPAGES dup(?);Receiver buffer pages
-
- org 2180h
- tstatus db ? ;Transmitter status 80
-
- ;Transmit status bits - EDLC
- TX_READY equ 080h ;
- TX_BUSY equ 040h ;Carrier detect
- TX_TPR equ 020h ;Self received packet sent
- TX_SHORTED equ 010h ;Carrier lost
- TX_UF equ 008h ;Underflow
- TX_COL equ 004h ;Collision
- TX_C16 equ 002h ;16 collisions
- TX_PE equ 001h ;Parity error
-
- TXERRMASK equ TX_PE or TX_C16 or TX_COL or TX_UF or TX_SHORTED or TX_BUSY
-
- tmask db ? ;Transmitter mask 81
- rstatus db ? ;Receiver status
- rmask db ? ;Receiver mask 83
- tmode db ? ;Transmitter mode 84
- rmode db ? ;Receiver mode 85
- reset db ? ;Reset line - high on bit 7, 86
- tdrlsb db ? ;TDR lsb 87
- eaddr_ram db 6 dup(?) ;current Ethernet address.
- db ? ;Reserved 8e
- tdrmsb db ? ;TDR msb 8f
-
- org 4000h
- receive_buf label byte
-
- org 7000h
- transmit_buf_1 label byte
-
- org 7800h
- transmit_buf_2 label byte
-
- ub_seg ends
-
- code segment word public
- assume cs:code, ds:code
-
- public int_no
- int_no db 3,0,0,0 ;must be four bytes long for get_number.
- base_addr dw 0d000h,0
-
- public driver_class, driver_type, driver_name, driver_function, parameter_list
- driver_class db BLUEBOOK, IEEE8023, 0 ;from the packet spec
- driver_type db 8 ;from the packet spec
- driver_name db 'PC-NIC',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
-
- current_page db 0 ;current receiver page
-
- active_buffer dw transmit_buf_1
- inactive_buffer dw transmit_buf_2
-
- include movemem.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
-
- mov es,base_addr
- assume es:ub_seg
-
- cmp cx,GIANT ; Is this packet too large?
- ja send_pkt_toobig
-
- cmp cx,RUNT ; minimum length for Ether
- jnb oklen
- mov cx,RUNT ; make sure size at least RUNT
- oklen:
-
- mov di,XMITBUF_LEN ;compute where we're going to
- sub di,cx ; be putting the packet.
-
- ;games above ensure that the last byte of data to go out is at the
- ;end of the ub xmit buffer, pos is really the offset from the
- ;start of that buffer
-
- mov ax,active_buffer ;swap the buffer pointers.
- xchg ax,inactive_buffer
- mov active_buffer,ax
- add di,ax
- push di
- call movemem
- pop di
-
- ;Wait for previous packet to finish first
- ;could do this with interrupts, etc, but with only 2 xmit buffers
- ;doesn't seem worth the effort
-
- send_pkt_1:
- mov al,csr
- and al,TPOK or TXDONE
- cmp al,TPOK or TXDONE
- jne send_pkt_1
-
- mov al,tstatus ;get xmiter status ...
- mov tstatus,0fh ;... and clear status bits
-
- test al,TXERRMASK ;any errors?
- je send_pkt_2
- call count_out_err ;yes, count them.
- send_pkt_2:
-
- ;all done above, we can play with TSA now!
- ;give offset
-
- mov ax,di
- mov tsa_lsb,al
- mov tsa_msb,ah
-
- cmp al,tsa_msb ;Start the send in action (SIDEEFFECT)
-
- clc
- ret
- send_pkt_toobig:
- mov dh,NO_SPACE
- stc
- 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:code
- 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:
-
- mov es,base_addr
- mov di,offset eaddr_ram
- rep movsb
- ; call initialize ;initialize with our new address.
-
- set_address_okay:
- mov cx,EADDR_LEN ;return their address length.
- clc
- set_address_done:
- ret
-
-
- ; 0 - accept no packets
- rcv_mode_1:
- mov es,base_addr
- assume es:ub_seg
-
- mov rmode,0
- ret
-
- rcv_mode_3:
- ; 1 - accept node id packets, multicasts which match first three
- ; bytes of node id, and broadcasts
- mov es,base_addr
- assume es:ub_seg
-
- mov rmode,1
- ret
-
- ; 2 - accept node id packets, all multicasts and broadcasts
- rcv_mode_5:
- mov es,base_addr
- assume es:ub_seg
-
- mov rmode,2
- ret
-
- ; 3 - take all, promiscous
- rcv_mode_6:
- mov es,base_addr
- assume es:ub_seg
-
- mov rmode,3
- 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:
- mov es,base_addr
- assume es:ub_seg
-
- mov ffp,0 ;set ffp to zero - disabling PAV
- mov csr,0 ;Turn off interrupt masks here and ...
- mov tmask,0 ;reset edlc interrupt masks
- mov rmask,0
- mov reset,80h ;Turn on reset line
-
- ret
-
- public reset_interface
- reset_interface:
- ;reset the interface.
- assume ds:code
- 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
-
- 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
-
- mov es,base_addr
- assume es:ub_seg
-
- recv_3:
- test epp,PAV
- jne recv_4
- jmp recv_2 ;yes.
- recv_4:
-
- ;checking against epp is a pain actually...
- xor cx,cx ;start with zero length
- mov bl,current_page ;get the first page.
- xor bh,bh
- mov dx,bx ;remember the first page.
- count_pages_1:
- mov al,page_ram[bx] ;Get page descriptor
- and al,RPAGE_BITS ;Only page offset bits PLEASE
- inc al ;Add 1 to offset to make length
- xor ah,ah
- add cx,ax ;Add in current page length
-
- mov al,page_ram[bx] ;Get page descriptor
- inc bx ;go to the next page
- cmp bx,NUM_RPAGES ;wrap around if necessary.
- jb count_pages_2
- xor bx,bx
- count_pages_2:
-
- test al,80h ;End page?
- je count_pages_1 ;yes, go add this one's length.
-
- mov current_page,bl
-
- mov ax,dx ;multiply dx by RPAGE_LEN.
- xchg ah,al
- ror ax,1
- mov di,ax
- add di,offset receive_buf ;get the starting address.
- add di,EADDR_LEN+EADDR_LEN ;skip the ethernet addreses and
- ; point to the packet type.
- push bx
- push cx
- push dx
-
- 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 ;look up our type.
- assume es:nothing
- pop dx
- pop cx
- pop bx
-
- mov ax,es ;is this pointer null?
- or ax,di
- je just_discard ;yes - just free the frame.
-
- push cx
- push di
- push es
-
- cmp dx,bx ;did we wrap around (first >last?)
- jbe no_wrap ;no, just do one move.
-
- ;we wrapped around the buffer, so we have to move in two halves.
- ;move the first part.
- mov ax,dx ;multiply dx by RPAGE_LEN.
- xchg ah,al
- ror ax,1
- mov si,ax
- add si,offset receive_buf ;get the starting address.
-
- mov ax,NUM_RPAGES ;Compute the number of pages to move.
- sub ax,dx
- xchg ah,al ;convert to pages (*RPAGE_LEN).
- ror ax,1
- cmp cx,ax ;are we moving less than that?
- jbe no_wrap ;yes, just move it.
- sub cx,ax ;reduce the total count by this count.
- push cx ;preserve the second part's count
- mov cx,ax ;get the first part's count.
-
- push ds
- mov ds,base_addr
- assume ds:nothing
- call movemem
- assume ds:code
- pop ds
-
- pop cx ;get back the count
-
- xor dx,dx
-
- no_wrap:
- mov ax,dx ;multiply dx by 128.
- xchg ah,al
- ror ax,1
- mov si,ax
- add si,offset receive_buf
- mov ds,base_addr
- assume ds:nothing
- call movemem
- assume ds:code
-
- pop ds
- pop si
- pop cx
- call recv_copy
- push cs
- pop ds
-
- just_discard:
- mov es,base_addr
- assume es:ub_seg
- mov al,epp ;Any more packets left?
- and al,RPAGE_BITS
- cmp al,current_page
- je recv_5
- jmp recv_3
- recv_5:
-
- cmp al,tsa_lsb ;Clearing pav bit (SIDEEFFECT)
-
- recv_2:
-
- ;Ack the interrupt by turning bit on and off
- mov al,current_page ;Set first free page pointer
- mov ffp,al
- or al,NIC_IE ;set interrupt bit, was off
- mov ffp,al
- recv_1:
- 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
-
-
- 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: ubnic [options] <packet_int_no> <int_no> <base_addr>",CR,LF,'$'
-
- public copyright_msg
- copyright_msg db "Packet driver for the UB PC/NIC, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
- db '$'
-
- int_no_name db "Interrupt number ",'$'
- base_addr_name db "Memory address ",'$'
-
- extrn set_recv_isr: near
-
- ;enter with si -> argument string, di -> wword to store.
- ;if there is no number, don't change the number.
- extrn get_number: near
-
- ;enter with si -> argument string, di -> wword 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 base_addr
- call get_number
- clc
- ret
-
-
- public etopen
- etopen:
- cli
-
- cmp base_addr,-1 ;did they ask for auto-configure?
- jne no_auto_config
-
- mov bx,8000h ;yes, they *could* address it there.
- auto_config_1:
- mov es,bx
- assume es:ub_seg
- cmp word ptr es:eaddr_rom[0],00h + 0ddh * 256
- jne auto_config_2
- cmp byte ptr es:eaddr_rom[2],01h
- je auto_config_3
- auto_config_2:
- add bx,800h ;move up by 32K
- jnc auto_config_1 ;go if we didn't overflow.
- sti
- stc ;say that we couldn't init.
- ret
-
- auto_config_3:
- mov base_addr,bx ;remember where we found it.
- mov base_addr+2,0 ;and nuke the rest of the -1.
-
- no_auto_config:
- mov es,base_addr
- assume es:ub_seg
-
- mov reset,80h ;Turn on reset line to tie down NIC
- mov rmode,0 ;no packets for now
- mov tmode,0 ;Turn on loopback
-
- mov al,epp ;start ffp at epp - eliminates bogus ....
- and al,07fh
- mov current_page,al ;... packets if we've been started before
- mov ffp,al ;Make sure interrupt enable is dead
-
- cmp al,tsa_lsb ;Clearing pav bit (SIDEEFFECT)
-
- mov tstatus, 0fh ;Clear xmit status bits
- mov tmask,0 ;No xmit intrs
- mov rmask,0 ;'Packet okay' only?
- mov rstatus,0ffh ;Clear receiver status bits
-
- movseg ds,es
- mov di,offset rom_address
- push ds
- mov ds,base_addr
- mov si,offset eaddr_rom
- repmov EADDR_LEN
- pop ds
-
- mov si,offset rom_address
- mov cx,EADDR_LEN
- call set_address
-
- ;Since first packet will get sent no matter what we do, let's make it
- ;something everyone (include me) will ignore
- ;set length to zero
-
- mov tsa_lsb,0ffh ;Get last 8 bits
- mov tsa_msb,0fh ;and top 4 bits
-
- mov reset,0 ;Clear reset - expect packet to go
- ;Wait for packet to go!
- etopen_1:
- mov al,csr
- and al,TPOK or TXDONE
- cmp al,TPOK or TXDONE
- jne etopen_1
-
- mov tstatus,0fh ;clear xmiter status
- mov tmode,0ah ;Clear loopbk, set parity enable
-
- mov csr,0 ;make sure this interrupt was off first
- mov csr,PAVIntEn ;Page frame available interrupt only
- mov al,current_page ;Set first free page register ...
- or al,NIC_IE
- mov ffp,al ;... and make sure interrupts enabled
-
- mov al,epp ;get epp again
- test al,PAV
- je etopen_2
- cmp al,tsa_lsb ;Try clearing pav bit (SIDEEFFECT)
- etopen_2:
-
- ;enable receiving now
- ; 1 - accept node id packets, multicasts which match first three
- ; bytes of node id, and broadcasts
- mov rmode,1
-
- ;
- ; Now hook in our interrupt
- ;
- call set_recv_isr
-
- sti
-
- 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.
-
- ;if all is okay,
- mov dx,offset end_resident
- clc
- ret
- ;if we got an error,
- stc
- 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 base_addr
- mov dx,offset base_addr_name
- call print_number
- ret
-
- code ends
-
- end
-