home *** CD-ROM | disk | FTP | other *** search
- ;History:426,1
- version equ 5
-
- include defs.asm
-
- ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec,
- ;* for the 3-Com 3C503 interface card.
- ;* Robert C Clements, K1BC, 14 February, 1989
- ;* Portions (C) Copyright 1988, 1989 Robert C Clements
- ;*
- ; 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.
-
- ;* Change history:
- ;* Updated to driver spec version 1.08 Feb. 17, 1989 by Russell Nelson.
- ;* Changes 27 Jul 89 by Bob Clements (/Rcc)
- ;* Added Thick versus Thin Ethernet switch 27 Jul 89 by Bob Clements (/Rcc)
- ;* Added call to memory_test.
- ;* Added rcv_mode logic. Started, but didn't finish, multicast logic.
- ;* Fixed get_address to return current, not PROM, address.
- ;* Minor races fixed.
-
- comment /
- From: "James A. Harvey" <IJAH400@indyvax.iupui.edu>
- Subject: Patches for 6.x packet drivers; lockup problem fixed!
-
- Now for the best part, the lockup problem fix. I think this may be one that
- I keep hearing about that for most people the machine locks up for a minute
- on startup, but then continues. For me it was worse because it appears that
- the "recovery" time is only short on heavily loaded networks. The lockup is
- caused by the "first page for RX" being set improperly in etopen; I finally
- figured it out by looking at code from other drivers that used the DS8390
- chip. One must switch to the page 1 command registers first.
- /
-
-
- code segment word public
- assume cs:code, ds:code
-
- ; Stuff specific to the 3-Com 3C503 Ethernet controller board
- ; WD version in C by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
- ; 3Com version based on WD8003E version in .ASM, also by Bob Clements, dated
- ; 19 August 1988. The WD and 3Com cards both use the National DS8390.
-
- ; Symbol prefix "EN" is for Ethernet, National chip
- ; Symbol prefix "E33" is for _E_thernet, _3_Com 50_3_
- ; Symbol prefix "E33G" is for registers in the Gate array ASIC.
-
- ; The E33 registers - For the ASIC on the 3C503 card:
- ; Offsets from the board's base address, which can be set by
- ; jumpers to be one of the following 8 values (hex):
- ; 350, 330, 310, 300, 2E0, 2A0, 280, 250
- ; Factory default address is 300H.
- ; The card occupies a block of 16 I/O addresses.
- ; It also occupies 16 addresses at base+400 through base+40F.
- ; These high-addressed registers are in the ASIC.
- ; Recall that the normal PC I/O decoding is only 10 bits. The 11'th
- ; bit (400H) can be used on the same card for additional registers.
- ; This offset requires word, not byte, arithmetic
- ; on the DX register for the setport macro. Current SETPORT is OK.
-
- ; The card can also be jumpered to have the shared memory disabled
- ; or enabled at one of four addresses: C8000, CC000, D8000 or DC000.
- ; This version of the driver REQUIRES the shared memory to be
- ; enabled somewhere.
- ; The card can be operated using direct I/O instructions or by
- ; using the PC's DMA channels instead of the shared memory, but
- ; I haven't included the code for those other two methods.
- ; They would be needed in a system where all four possible addresses
- ; for the shared memory are in use by other devices. /Rcc
-
- ; Blocks of I/O addresses:
-
- E33GA equ 400h ; Registers in the gate array.
- E33_SAPROM equ 000h ; Window on station addr prom (if
- ; E33G_CNTRL bits 3,2 = 0,1
-
- ; These appear at Base+0 through Base+0F when bits 3,2 of
- ; E33G_CNTRL are 0,0.
-
- EN_OFF equ 0h
-
- ENDCFG_BM8 equ 48h
-
- include 8390.inc
-
- ; Registers in the 3-Com custom Gate Array
-
- E33G_STARTPG equ E33GA+00h ; Start page, must match EN0_STARTPG
- E33G_STOPPG equ E33GA+01h ; Stop page, must match EN0_STOPPG
- E33G_NBURST equ E33GA+02h ; Size of DMA burst before relinquishing bus
- E33G_IOBASE equ E33GA+03h ; Bit coded: where I/O regs are jumpered.
- ; (Which you have to know already to read it)
- E33G_ROMBASE equ E33GA+04h ; Bit coded: Where/whether EEPROM&DPRAM exist
- E33G_GACFR equ E33GA+05h ; Config/setup bits for the ASIC GA
- E33G_CNTRL equ E33GA+06h ; Board's main control register
- E33G_STATUS equ E33GA+07h ; Status on completions.
- E33G_IDCFR equ E33GA+08h ; Interrupt/DMA config register
- ; (Which IRQ to assert, DMA chan to use)
- E33G_DMAAH equ E33GA+09h ; High byte of DMA address reg
- E33G_DMAAL equ E33GA+0ah ; Low byte of DMA address reg
- E33G_VP2 equ E33GA+0bh ; Vector pointer - for clearing RAM select
- E33G_VP1 equ E33GA+0ch ; on a system reset, to re-enable EPROM.
- E33G_VP0 equ E33GA+0dh ; 3Com says set this to Ctrl-Alt-Del handler
- E33G_FIFOH equ E33GA+0eh ; FIFO for programmed I/O data moves ...
- E33G_FIFOL equ E33GA+0fh ; .. low byte of above.
-
- ; Bits in E33G_CNTRL register:
-
- ECNTRL_RESET equ 001h ; Software reset of the ASIC and 8390
- ECNTRL_THIN equ 002h ; Onboard thin-net xcvr enable
- ECNTRL_SAPROM equ 004h ; Map the station address prom
- ECNTRL_DBLBFR equ 020h ; FIFO configuration bit
- ECNTRL_OUTPUT equ 040h ; PC-to-3C503 direction if 1
- ECNTRL_INPUT equ 000h ; PC-to-3C503 direction if 0
- ECNTRL_START equ 080h ; Start the DMA logic
-
- ; Bits in E33G_STATUS register:
-
- ESTAT_DPRDY equ 080h ; Data port (of FIFO) ready
- ESTAT_UFLW equ 040h ; Tried to read FIFO when it was empty
- ESTAT_OFLW equ 020h ; Tried to write FIFO when it was full
- ESTAT_DTC equ 010h ; Terminal Count from PC bus DMA logic
- ESTAT_DIP equ 008h ; DMA In Progress
-
- ; Bits in E33G_GACFR register:
-
- EGACFR_NORM equ 049h ; Enable 8K shared mem, no DMA TC int
- EGACFR_IRQOFF equ 0c9h ; Above, and disable 8390 IRQ line
-
- ; Shared memory management parameters
-
- SM_TSTART_PG equ 020h ; First page of TX buffer
- SM_RSTART_PG equ 026h ; Starting page of RX ring
- SM_RSTOP_PG equ 040h ; Last page +1 of RX ring
-
- ; End of 3C503 parameter definitions
-
- pause_ macro
- jmp $+2
- endm
-
- longpause macro
- push cx
- mov cx,0
- loop $
- pop cx
- endm
-
- ram_enable macro
- setport E33G_GACFR ; Make sure gate array is set up and
- mov al, EGACFR_NORM ; the RAM is enabled (not EPROM)
- out dx, al ; ..
- endm
-
-
- reset_8390 macro
- loadport ; First, pulse the board reset
- setport E33G_CNTRL
- mov al,thin_bit ; Thick or thin cable bit
- or al,ECNTRL_RESET
- out dx,al ; Turn on board reset bit
- mov al,thin_bit ; Thick or thin cable bit
- out dx,al ; Turn off board reset bit
- call do_reset
- loadport
- endm
-
- terminate_board macro
- endm
-
- ; The following three values may be overridden from the command line.
- ; If they are omitted from the command line, these defaults are used.
- ; The shared memory base is set by a jumper. We read it from the
- ; card and set up accordingly.
-
- public int_no, io_addr, thin_not_thick
- int_no db 2,0,0,0 ; Interrupt level
- io_addr dw 0300h,0 ; I/O address for card (jumpers)
- thin_not_thick dw 1,0 ; Non-zero means thin net
- public mem_base
- mem_base dw 00000h,0 ; Shared memory addr (jumpers)
- ; (Not changeable by software in 3C503) ; (0 if disabled by jumpers)
- thin_bit db ECNTRL_THIN ; Default to thin cable
-
- public driver_class, driver_type, driver_name, driver_function, parameter_list
- driver_class db BLUEBOOK, IEEE8023, 0 ;from the packet spec
- driver_type db 12 ;from the packet spec
- driver_name db '3C503',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,
-
- is_186 db 0
-
- include movemem.asm
-
- block_output:
- ;enter with cx = byte count, ds:si = buffer location, ax = buffer address
- assume ds:nothing
- cmp mem_base,0 ;memory or I/O?
- je block_o ;I/O.
- mov es,mem_base ; Set up ES:DI at the shared RAM
- mov di,ax ; ..
- loadport ; Set up for address of TX buffer.
- ram_enable ; Make sure the RAM is actually there.
- call movemem
- clc
- ret
-
- block_o:
- loadport
- setport E33G_DMAAL
- out dx,al
- setport E33G_DMAAH
- mov al,ah
- out dx,al
-
- setport E33G_CNTRL
- mov al,thin_bit
- or al,ECNTRL_OUTPUT or ECNTRL_START ;start dma, write to board.
- out dx,al
-
- cmp is_186,0
- je block_o_88
-
- .286
- setport E33G_STATUS
- block_o_186_0:
- jcxz block_o_2 ;if there is none, exit.
- in al,dx ;wait for the FIFO to be ready.
- test al,ESTAT_DPRDY
- je block_o_186_0
- setport E33G_FIFOH ;now get ready to read data.
- cmp cx,8 ;do we have eight more to do?
- jb block_o_186_1 ;no, do them one by one.
- outsw ;yes, output eight all at once.
- outsw
- outsw
- outsw
- sub cx,8 ;reduce the count by what we write.
- setport E33G_STATUS ;go back to the status bit.
- jmp block_o_186_0
- block_o_186_1:
- rep outsb ;output less than 8 bytes.
- jmp short block_o_2
- .8086
-
-
- block_o_88:
- loadport
- setport E33G_STATUS
- block_o_88_0:
- jcxz block_o_2 ;if there is none, exit.
- in al,dx ;wait for the FIFO to be ready.
- test al,ESTAT_DPRDY
- je block_o_88_0
- setport E33G_FIFOH ;now get ready to read data.
- cmp cx,8 ;do we have eight more to do?
- jb block_o_88_1 ;no, do them one by one.
- lodsw ;yes, output eight all at once.
- out dx,ax
- lodsw
- out dx,ax
- lodsw
- out dx,ax
- lodsw
- out dx,ax
- sub cx,8 ;reduce the count by what we write.
- setport E33G_STATUS ;go back to the status bit.
- jmp block_o_88_0
- block_o_88_1:
- lodsb ;output less than 8 bytes.
- out dx,al
- loop block_o_88_1
- block_o_2:
- loadport
- setport E33G_CNTRL
- mov al,thin_bit ;stop dma.
- out dx,al
- ret
-
-
- block_input:
- ;enter with cx = byte count, es:di = buffer location, ax = board address.
- cmp mem_base,0 ; memory or I/O
- je block_i ; I/O
- push ds
- assume ds:nothing
- mov ds,mem_base ; ds:si points at first byte to move
- mov si,ax
-
- add ax,cx ; Find the end of this frame.
- cmp ah,byte ptr cs:sm_rstop_ptr ; Over the top of the ring?
- jb rcopy_one_piece ; Go move it
-
- rcopy_wrap:
- ; Copy in two pieces due to buffer wraparound.
- mov ah,byte ptr cs:sm_rstop_ptr ; Compute length of first part
- xor al,al
- sub ax,si ; as all of the pages up to wrap point
- sub cx,ax ; Move the rest in second part
- push cx ; Save count of second part
- mov cx,ax ; Count for first move
- call rcopy_subr
- mov si,SM_RSTART_PG*256 ; Offset to start of first receive page
- pop cx ; Bytes left to move
- rcopy_one_piece:
- call rcopy_subr
- pop ds
- ret
-
-
- rcopy_subr:
- shr cx,1 ; convert byte count to word count
- rep movsw
- jnc rcv_wrap_even ; odd byte left over?
- lodsw ; yes, word fetch
- stosb ; and byte store
- rcv_wrap_even:
- ret
-
- block_i:
- assume ds:code
- loadport
- setport E33G_DMAAL
- out dx,al
- setport E33G_DMAAH
- mov al,ah
- out dx,al
-
- setport E33G_CNTRL
- mov al,thin_bit
- or al,ECNTRL_INPUT or ECNTRL_START ;start dma, read from board.
- out dx,al
-
- cmp is_186,0
- je block_i_88
-
- .286
- setport E33G_STATUS
- block_i_186_0:
- jcxz block_i_2 ;if there is none, exit.
- in al,dx ;wait for the FIFO to be ready.
- test al,ESTAT_DPRDY
- je block_i_186_0
- setport E33G_FIFOH ;now get ready to read data.
- cmp cx,8 ;do we have eight more to do?
- jb block_i_186_1 ;no, do them one by one.
- insw ;yes, input eight all at once.
- insw
- insw
- insw
- sub cx,8 ;reduce the count by what we read.
- setport E33G_STATUS ;go back to the status bit.
- jmp block_i_186_0
- block_i_186_1:
- rep insb ;input less than 8 bytes.
- jmp short block_i_2
- .8086
-
-
- block_i_88:
- loadport
- setport E33G_STATUS
- block_i_88_0:
- jcxz block_i_2 ;if there is none, exit.
- in al,dx ;wait for the FIFO to be ready.
- test al,ESTAT_DPRDY
- je block_i_88_0
- setport E33G_FIFOH ;now get ready to read data.
- cmp cx,8 ;do we have eight more to do?
- jb block_i_88_1 ;no, do them one by one.
- in ax,dx ;yes, input eight all at once.
- stosw
- in ax,dx
- stosw
- in ax,dx
- stosw
- in ax,dx
- stosw
- sub cx,8 ;reduce the count by what we write.
- setport E33G_STATUS ;go back to the status bit.
- jmp block_i_88_0
- block_i_88_1:
- in al,dx ;input less than 8 bytes.
- stosb
- loop block_i_88_1
- block_i_2:
- loadport
- setport E33G_CNTRL
- mov al,thin_bit ;stop dma.
- out dx,al
- ret
-
-
-
- include 8390.asm
-
- public usage_msg
- usage_msg db "usage: 3C503 [-n] [-d] [-w] <packet_int_no> <int_level(2-5)> <io_addr> <thin_net_flag>",CR,LF,'$'
-
- public copyright_msg
- copyright_msg db "Packet driver for 3-Com 3C503, version "
- db '0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,".",'0'+dp8390_version,CR,LF
- db "Portions Copyright 1989, Robert C. Clements, K1BC",CR,LF,'$'
-
- cfg_err_msg db "3C503 Configuration failed. Check parameters.",CR,LF,'$'
- mem_busted_msg db "Shared RAM on 3C503 card is defective or there is an address conflict.",CR,LF,'$'
-
- int_no_name db "Interrupt number ",'$'
- io_addr_name db "I/O port ",'$'
- mem_base_name db "Memory address ",'$'
-
- thin_msg db "Using the built-in transceiver (thinwire)",CR,LF,'$'
- thick_msg db "Using the external transceiver (thickwire)",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 ; May override interrupt channel
- call get_number
- mov di,offset io_addr ; May override I/O address
- call get_number
- mov di,offset thin_not_thick ; May override thick/thin cable flag
- call get_number
- mov ax,thin_not_thick ; Now make the right bit
- cmp ax,0
- je parse_thin1 ; If zero, leave bit off
- mov al,ECNTRL_THIN ; Else the bit for the card
- parse_thin1:
- mov thin_bit,al ; Save for setting up the card
-
- clc
- ret
-
- do_reset:
- assume ds:code
- loadport
- cli ; Protect the E33G_CNTRL contents
- setport E33G_CNTRL ; Switch control bits to enable SA PROM
- mov al, thin_bit
- or al, ECNTRL_SAPROM
- out dx, al ; ..
- setport E33_SAPROM ; Where the address prom is
-
- cld ; Make sure string mode is right
- push cs ; Point es:di at local copy space
- pop es
- mov di, offset curr_hw_addr
- mov cx, EADDR_LEN ; Set count for loop
- do_reset_1:
- in al, dx ; Get a byte of address
- stosb ; Feed it to caller
- inc dx ; Next byte at next I/O port
- loop do_reset_1 ; Loop over six bytes
-
- loadport ; Re-establish I/O base after dx mods
- setport E33G_CNTRL ; Switch control bits to turn off SA PROM
- mov al, thin_bit
- out dx, al ; Turn off SA PROM windowing
- sti ; Ok for E33G_CNTRL to change now
-
- call set_8390_eaddr
-
- ret
-
- init_card:
- ; Now get the board's physical address from on-board PROM into card_hw_addr
- assume ds:code
- loadport
- cli ; Protect the E33G_CNTRL contents
- setport E33G_CNTRL ; Switch control bits to enable SA PROM
- mov al, thin_bit
- or al, ECNTRL_SAPROM
- out dx, al ; ..
- setport E33_SAPROM ; Where the address prom is
-
- cld ; Make sure string mode is right
- push cs ; Point es:di at local copy space
- pop es
- mov di, offset curr_hw_addr
- mov cx, EADDR_LEN ; Set count for loop
- ini_addr_loop:
- in al, dx ; Get a byte of address
- stosb ; Feed it to caller
- inc dx ; Next byte at next I/O port
- loop ini_addr_loop ; Loop over six bytes
-
- loadport ; Re-establish I/O base after dx mods
- setport E33G_CNTRL ; Switch control bits to turn off SA PROM
- mov al, thin_bit
- out dx, al ; Turn off SA PROM windowing
- sti ; Ok for E33G_CNTRL to change now
- ; Point the "Vector Pointer" registers off into the boonies so we
- ; don't get the shared RAM disabled on us while we're using it.
- ; Ideally a warm boot should reset this too, to get to ROM on this card,
- ; but I don't know a guaranteed way to determine that value.
- setport E33G_VP2
- mov al, 0ffh ; Point this at the ROM restart location
- out dx, al ; of ffff0h.
- setport E33G_VP1
- out dx, al
- xor al, al
- setport E33G_VP0
- out dx, al
- ;Make sure shared memory is jumpered on. Find its address.
- setport E33G_ROMBASE ; Point at rom/ram cfg reg
- xor bx,bx
- in al, dx ; Read it
- test al,0f0h ; Any bits on?
- je memcfg_3 ; no - using I/O.
- memcfg_1:
- mov bx, 0c600h ; Build mem segment here
- test al,0c0h ; DC00 or D800?
- je memcfg_2 ; No
- add bx, 01000h ; Yes, make Dx00
- memcfg_2:
- test al,0a0h ; DC00 or CC00?
- je memcfg_3
- add bx, 00400h ; Yes, make xC00
- memcfg_3:
- mov mem_base,bx ; Remember segment addr of memory
- or bx,bx
- je mem_works ; don't test the memory if we use I/O.
- ; Set up Gate Array's Config Reg to enable and size the RAM.
- setport E33G_GACFR ; Make sure gate array is set up and
- mov al, EGACFR_IRQOFF ; the RAM is enabled (not EPROM)
- out dx, al ; ..
- ; Check the card's memory
- mov ax, mem_base ; Set segment of the shared memory
- add ax, 16*SM_TSTART_PG ; which starts 2000h up from "base"
- mov cx, 2000h ; Length of RAM to test
- call memory_test ; Check it out
- jz mem_works ; Go if it's OK
- jmp mem_busted ; Go report failure if it's bad
- mem_works:
- ; Set up control of shared memory, buffer ring, etc.
- loadport
- setport E33G_STARTPG ; Set ASIC copy of rx's first buffer page
- mov al, SM_RSTART_PG
- out dx, al
- setport E33G_STOPPG ; and ASIC copy of rx's last buffer page + 1
- mov al,SM_RSTOP_PG
- ; mov al, byte ptr sm_rstop_ptr
- out dx, al
- ; Set up interrupt/DMA control register in ASIC.
- ; For now, we won't use the DMA, so B0-B3 are zero.
- xor ah, ah ; Get the interrupt level from arg line
- mov al, int_no ; ..
- cmp al, 9 ; If converted to 9, make back into 2
- jne get_irq1 ; Not 9
- mov al, 2 ; Card thinks it's IRQ2
- get_irq1: ; Now should have level in range 2-5
- sub ax, 2 ; Make 0-3 for tables
- cmp ax, 5-2 ; In range?
- jna get_irq2
- mov dx,offset cfg_err_msg
- jmp error ; If not, can't configure.
- get_irq2:
- xor cx, cx ; Make the bit for the ASIC
- mov cl, al ; Shift count
- mov al, 10h ; Bit for irq2
- shl al, cl ; Shift over as needed.
- setport E33G_IDCFR ; Point at ASIC reg for IRQ level
- out dx, al ; Set the bit
- setport E33G_NBURST ; Set burst size to 8
- mov al, 8
- out dx, al ; ..
- setport E33G_DMAAH ; Set up transmit bfr in DMA addr
- mov al, SM_TSTART_PG
- out dx, al
- xor ax, ax
- setport E33G_DMAAL
- out dx, al
- ret
-
-
- mem_busted:
- mov dx, offset mem_busted_msg
- error:
- mov ah,9 ; Type the msg
- int 21h
- stc ; Indicate error
- ret ; Return to common code
-
-
- public print_parameters
- print_parameters:
- mov di, offset int_no ; May override interrupt channel
- mov dx, offset int_no_name ; Message for it
- call print_number
- mov di, offset io_addr ; May override I/O address
- mov dx, offset io_addr_name ; Message for it
- call print_number
- mov dx,offset thin_msg
- cmp thin_not_thick,0 ; May override thick/thin cable flag
- jne print_parameters_1
- mov dx,offset thick_msg
- print_parameters_1:
- mov ah,9
- int 21h
- ret
-
- include memtest.asm
-
- code ends
-
- end
-