;History:512,1 version equ 4 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_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: setport E33G_CNTRL mov al,thin_bit or al,0c0h ;start dma, write to board. out dx,al ;;; we should really have another copy of this loop for 186 I/O instructions. setport E33G_STATUS block_o_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_0 setport E33G_FIFOH ;now get ready to read data. cmp cx,8 ;do we have eight more to do? jb block_o_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_0 block_o_1: lodsb out dx,ax loop block_o_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: 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,".",'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