version	equ	0
;History:349,1

;  Russell Nelson, Clarkson University.
;  Copyright, 1988-1991, Russell Nelson
;  The following people have contributed to this code: David Horne, Eric
;  Henderson, and Bob Clements.

;   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

code	segment	word public
	assume	cs:code, ds:code

;*****************************************************************************
;
;	hppclan controller board offsets
;	IO port definition (BASE in io_addr)
;*****************************************************************************
NE_DATAPORT	EQU	0ch		; hppclan Port Window.
HP_PROM		equ	00h
HP_OPTION	equ	08h
EN_OFF		equ	10h

ENDCFG_BM8	equ	48h

OPTION_RUN	equ	01h
OPTION_DATA	equ	10h

	include	8390.inc

; Shared memory management parameters

SM_TSTART_PG	EQU	0h		; First page of TX buffer
SM_RSTART_PG	EQU	6h		; start at page 6
SM_RSTOP_PG	EQU	80h		; end at page 80

pause_	macro
;	jmp	$+2
endm

longpause macro
	push	cx
	mov	cx,0
	loop	$
	pop	cx
endm

ram_enable	macro
	endm

mc_chan_on	macro
	mov	al,chan_sel
	mov	dx,96h
	out	dx,al			; select channel

	mov	dx,94h
	mov	al,0a0h			
	out	dx,al			; protect system board

	mov	dx,102h			; point dx at option reg
endm

mc_chan_off	macro
	mov	dx,96h
	xor	al,al
	out	dx,al
endm

reset_8390	macro
	local   reset_8390_1
	local   is_mc_b
	local	not_mc_c
	local	not_mc_d

	test	sys_features,MICROCHANNEL
	jne	is_mc_b
	jmp	not_mc_c
is_mc_b:
	mc_chan_on
	in	al,dx			;capture and save option register
	and	al, not OPTION_RUN	;reset the 8390
	out	dx,al
	longpause
	or	al, OPTION_RUN		;turn it back on
	out	dx,al		
	mc_chan_off
	loadport			;Set DX the way we expect it
	setport	HP_OPTION		
	jmp	not_mc_d

not_mc_c:
	loadport
	setport	HP_OPTION		;hard reset 8390.
	xor	al,al			;reset the 8390
	out	dx,al
	longpause
	mov	al,int_no		;get our interrupt number, and
	cmp	al,9			;is it really interrupt 2?
	jne	reset_8390_1
	mov	al,2
reset_8390_1:
	shl	al,1			;put it where we need it
	or	al, OPTION_RUN		;turn it back on
	out	dx,al		

not_mc_d:
	endm

terminate_board	macro
	local is_mc_a
	local not_mc_a
	local not_mc_b
	test	sys_features,MICROCHANNEL
	jne	is_mc_a
	jmp	not_mc_a

is_mc_a:
	in	al,dx			;capture and save option register
	and	al, not OPTION_RUN	;reset the 8390
	out	dx,al
	mc_chan_off
	loadport			;Set DX the way we expect it
	setport	HP_OPTION		
	jmp	not_mc_b

not_mc_a:
	loadport
	setport	HP_OPTION		;hard reset 8390.
	xor	al,al
	out	dx,al
not_mc_b:
	endm

	extrn	sys_features: byte

	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

;enter with al = single character
	extrn	chrout: near

	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)

	public	driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class	db	BLUEBOOK, IEEE8023, 0		;from the packet spec
driver_type	db	?		;Wild card matches any type
driver_name	db	"HP ",20 dup(?)	;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

chan_sel	db	0	;Channel select for MICROCHANNEL machines
;
;	Special case Block input routine. Used on extra memory
;	space for board ID etc. DMA count is set X2,
;	CX = byte count, es:si = buffer location, ax = buffer address
;
sp_block_input:
;	Nothing special needed for hppclan
;
;	Block input routine
;	CX = byte count, es:si = buffer location, ax = buffer address

	public	block_input
block_input:
	push	ax			; save buffer address

	loadport
	setport	HP_OPTION		
	test	sys_features,MICROCHANNEL
	je	not_mc_1
	jmp	is_mc_1
not_mc_1:
	in	al,dx
	or	al,OPTION_DATA		;Enable the data port except on MCA
	out	dx,al

is_mc_1:
	setport EN_CCMD
	pause_
	mov	al,ENC_NODMA+ENC_PAGE0+ENC_START
	out	dx,al
	setport	EN0_RCNTLO	; remote byte count 0
	pause_
	mov	al,cl
	out	dx,al
	setport	EN0_RCNTHI
	pause_
	mov	al,ch
	out	dx,al
	pop	ax		; get our page back
	setport	EN0_RSARLO
	pause_
	out	dx,al		; set as hi address
	setport	EN0_RSARHI
	pause_
	mov	al,ah
	out	dx,al
	setport EN_CCMD
	pause_
	mov	al,ENC_RREAD+ENC_START	; read and start
	out	dx,al
	setport	NE_DATAPORT
	pause_
	cmp	is_186,0
	jnz	read_186
	shr	cx,1
read_loop:
	in	ax,dx		; get a word
	stosw			; save it
	loop	read_loop
	jnc	read_done
	in	al,dx
	stosb
	jmp	short read_done
read_186:
	shr	cx,1
	db	0f3h, 06dh	;masm 4.0 doesn't grok "rep insw"
	jnc	read_done
	db	06ch		;masm 4.0 doesn't grok "insb"
read_done:
	setport	HP_OPTION
	test	sys_features,MICROCHANNEL
	je	not_mc_2
	ret
not_mc_2:
	in	al,dx
	and	al,not OPTION_DATA
	out	dx,al
	ret
;
;	Block output routine
;	CX = byte count, ds:si = buffer location, ax = buffer address


block_output:
	assume	ds:nothing
	push	ax		; save buffer address

	loadport
	setport	HP_OPTION
	test	sys_features,MICROCHANNEL
	je	not_mc_3
	jmp	is_mc_3
not_mc_3:
	in	al,dx
	or	al,OPTION_DATA	; enable the data port except on MCA
	out	dx,al

is_mc_3:
	inc	cx		; make even
	and	cx,0fffeh
	setport EN_CCMD
	pause_
	mov	al,ENC_NODMA+ENC_START
	out	dx,al		; stop & clear the chip
	setport	EN0_RCNTLO	; remote byte count 0
	pause_
	mov	al,cl
	out	dx,al
	setport	EN0_RCNTHI
	pause_
	mov	al,ch
	out	dx,al
	pop	ax		; get our page back
	setport	EN0_RSARLO
	pause_
	out	dx,al		; set as lo address
	setport	EN0_RSARHI
	pause_
	mov	al,ah
	out	dx,al
	setport EN_CCMD
	pause_
	mov	al,ENC_RWRITE+ENC_START	; write and start
	out	dx,al
	setport	NE_DATAPORT
	pause_
	shr	cx,1
	cmp	is_186,0
	jnz	write_186
write_loop:
	lodsw			; get a word
	out	dx,ax		; save it
	loop	write_loop
	jmp	short write_done
write_186:
	db	0f3h, 06fh		;masm 4.0 doesn't grok "rep outsw"
write_done:
	mov	cx,0
	setport	EN0_ISR
tx_check_rdc:
	in	al,dx
	test	al,ENISR_RDC	; dma done ???
	clc
	jnz	tx_start
	loop	tx_check_rdc
	stc
tx_start:
	setport	HP_OPTION
	test	sys_features,MICROCHANNEL
	je	not_mc_4
	ret
not_mc_4:
	lahf				;save cy.
	in	al,dx
	and	al,not OPTION_DATA
	out	dx,al
	sahf				;restore cy.
	ret

	include	8390.asm

	public	usage_msg
usage_msg	db	"usage: hppclan [-n] [-d] [-w] <packet_int_no> [<int_no> [<io_addr>]]",CR,LF

	public	copyright_msg
copyright_msg	db	"Packet driver for HP PC LAN cards, version "
		db	'0'+majver,".",'0'+version,".",'0'+dp8390_version,CR,LF,'$'

no_hp_msg	db	"No HP PC LAN card found (matching io_addr or int_no if spedified).",CR,LF,'$'
cfg_err_msg	db	"Configuration failed. Check parameters.",CR,LF,'$'
int_no_name	db	"Interrupt number ",'$'
io_addr_name	db	"I/O port ",'$'

comment \

Here are the ID byte values for all released cards.  Bit 7 of the ID byte
for AT cards indicates bus width (as well as RAM buffer size).

The ID byte was added to give a unique number to every revision of every card
produced.  However, it is a little more than just a flat assignment; there is
some fields.  For driver software it is assumed the driver knows what bus it
is on (eg. AT verses MC):

The format of the ID byte (offset 0x07 from I/O base) is:

        7  6  5  4  3  2  1  0
        a  b  b  b  c  c  c  c
where,
        "a"   is the AT bus width bit
         0 =  8 bit AT cards (32K bytes of buffer RAM)
         1 = 16 bit AT cards (64K bytes of buffer RAM)

        "bbb" is for board revisions

        "ccc" is the LAN Media type
         000 = HP StarLAN-10
         001 = 10-Base-T (Ethertwist)
         002 = 10-Base-2 (ThinLAN)
         ??? = reserved for future

The current ID bytes assigned are:
        0x00 = (obsolete) HP27240 AT8  StarLAN
        0x10 = (obsolete) HP24240 AT8  StarLAN rev B
        0x00 = (obsolete) HP27241 MC16 StarLAN
        0x01 = HP27245 AT8  10-Base-T
        0x01 = HP27246 MC16 10-Base-T
        0x02 = HP27250 AT8  ThinLAN
        0x81 = HP27247 AT16 10-Base-T

NOTE:   All Microchannel cards are 16 bits wide.
        All 8 bit cards have 32K bytes of buffer RAM.
        All 16 bit cards (AT & MC) have 64K bytes of buffer RAM.
\

this_board_msg	db	"This board is an HP",'$'

ISA_name_list	dw	board_00ISA, board_10, board_01ISA, board_02, board_81
		dw	board_unk
MCA_name_list	dw	board_00MCA, board_01MCA
		dw	board_unk

board_00ISA	db	00h, "27240",0,60	;AT8  StarLAN
board_10	db	10h, "24240",0,60	;AT8  StarLAN rev B
board_00MCA	db	00h, "27241",0,60	;MC16 StarLAN
board_01ISA	db	01h, "27245",0,60	;AT8  10-Base-T
board_01MCA	db	01h, "27246",0,60	;MC16 10-Base-T
board_02	db	02h, "27250",0,60	;AT8  ThinLAN
board_81	db	81h, "27247",0,60	;AT16 10-Base-T
board_unk	db	-1h, "Unknown HP272xx",0,60	;just a guess.

; ISA DEFAULTS for io_addr and int_no,
; MCA DEFAULTS to first found.

DEF_IO_ADDR	equ	0300h	
DEF_INT_NO	equ	3

MC_DEF_IO	equ	1
MC_DEF_INT	equ	2
MC_DEF_BOTH	equ	MC_DEF_IO+MC_DEF_INT

mc_def_req	db	0

int_no_table	db	3, 4, 5, 7, 9, 10, 11, 12

; First 3 bytes of the LAN Addres will identify the board as HP

hp_vendor_id	db	08h,00h,09h

	public	parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
	test	sys_features,MICROCHANNEL
	jne	parse_args_mc
	jmp	parse_args_1

parse_args_mc:

; first determine if non-default values have been requested
; get_number will return requested value, -1, or carry flag set

	mov	di,offset int_no
	call	get_number
	mov	BYTE PTR [di+1], 0
	mov	WORD PTR [di+2], 0
	jnc	parse_args_mc2
	mov	BYTE PTR [di], 0ffh	; error return, use -1 value

parse_args_mc2:
	mov	di,offset io_addr
	call	get_number
	mov	WORD PTR [di+2], 0
	jnc	parse_args_mc3
	mov	WORD PTR [di], 0ffffh	; error return, use -1 value

parse_args_mc3:
	
	xor	al,al
	cmp	io_addr,0ffffh
	jne	parse_args_mc4
	mov	al,MC_DEF_IO

parse_args_mc4:
	cmp	int_no,0ffh
	jne	parse_args_mc5
	or	al,MC_DEF_INT

parse_args_mc5:
	mov	mc_def_req,al

;The following code to read the POS registers is courtesy of Racal-Interlan.

; channel selector resides at io 96h
; POS register base is at io 100h

; search thro' the slots for a 9210 card
	mov	cx, 8			; for all channels(slots)

; channel select value for slots 0,1,2.. is 8,9,A etc
; start with slot 0, and then 7,6,5,4,3,2,1

get_01:
	mov	ax, cx			; channel number
	or	ax, 08h			; reg. select value
	mov	chan_sel,al		; save each one, the LAST will right
	mov	dx, 96h			; channel select register
	out	dx, al			; select channel

	mov	dx, 94h			; protect system board
	mov	al, 0a0h
	out	dx, al			

; read adapter id
	mov	dx, 100h
	in	al, dx			; adapter id - ms byte
	mov	ah, al
	inc	dx
	in	al, dx			; adapter id - ls byte

; Check if HP
	cmp	ax, 0ca63h
	je	get_03
	
get_02:
	; come back to here if card found does not match user 
	; requirements below

	loop	get_01

	mc_chan_off
	mov	dx,offset no_hp_msg
	jmp	error

get_03:		; found an HP adapter, is it the right one?

comment \

The only POS registers defined for the Microchannel card (HP27246) are:

        0x100 = Adapter Identification LSB (0xCA) Read only
        0x101 = Adapter Identification MSB (0x63) Read only
        0x102 = Option Register Read/Write

The Option register bits are defined as:

        7 6 5 4 3 2 1 0
        a a a - b b b c

where,
        "aaa" is the I/O Base Address Relocation bits
         000 = 0x0400 to 0x041f
         001 = 0x1400 to 0x141f
         010 = 0x2400 to 0x241f
         011 = 0x3400 to 0x341f
         100 = 0x4400 to 0x441f
         101 = 0x5400 to 0x541f
         110 = 0x6400 to 0x641f
         111 = 0x7400 to 0x741f


        "bbb" is the Interrupt Level bits
         000 = INT 3
         001 = INT 4
         010 = INT 5
         011 = INT 7
         100 = INT 9
         101 = INT 10
         110 = INT 11
         111 = INT 12

        "c" is the Card Enable / NIC Reset bit
         0 = NIC held in reset (eg. cannot access its registers)
         1 = NIC not reset (eg. regster can be accessed)
         NOTE: Access to the PROM should only occur while NIC is held in reset.

\

	mov	dx,102h
	in	al,dx
	and	ax,00e0h		;leave only the base address bits
	push	cx
	mov	cl,12-5			;now ends at bit 5, should end at bit 12
	shl	ax,cl
	pop	cx
	or	ax,400h
	mov	di,ax		; temporary save

	in	al,dx
	shr	al,1
	and	al,7
	mov	bl,al
	xor	bh,bh
	mov	al,int_no_table[bx]

	; check for matches with user selects

	mov	ah,mc_def_req
	test	ah,MC_DEF_IO
	jz	get_04
	mov	io_addr,di	; user wants default, copy temp address

get_04:
	test	ah,MC_DEF_INT
	jz	get_05
	mov	int_no,al	; user wants default, copy temp int number

get_05:	
	cmp	di,io_addr
	je 	get_06
	jmp	get_02		; correct io_addr not found, keep looking

get_06:	
	cmp	al,int_no
	je 	get_07
	jmp	get_02		; correct io_addr not found, keep looking

get_07:		; if we get here we now have the io_addr and int_no
		; that the user wanted
	mc_chan_off
	jmp parse_args_5

;
; Much simpler code for ISA machine parse_args
;
parse_args_1:
	mov	di,offset int_no
	call	get_number
	jc	parse_args_2
	cmp	WORD PTR [di],0
	jl	parse_args_2
	jmp	parse_args_3

parse_args_2:
	mov	WORD PTR [di],DEF_INT_NO
	mov	WORD PTR [di+2],0

parse_args_3:
	mov	di,offset io_addr
	call	get_number
	jc	parse_args_4
	cmp	WORD PTR [di],0
	jl	parse_args_4
	jmp	parse_args_5

parse_args_4:
	mov	WORD PTR [di],DEF_IO_ADDR
	mov	WORD PTR [di+2],0

parse_args_5:	;Finally verify HP Vendor ID in 1st 3 bytes of station addr
	loadport
	setport	HP_PROM
	mov	di,offset hp_vendor_id
	mov	cx,3
id_card_loop:
	in	al,dx
	cmp	al, BYTE PTR [di]
	je	id_card_loop1
	mov	dx,offset no_hp_msg
	jmp	error

id_card_loop1:
	inc	di
	inc	dx
	loop	id_card_loop
	clc
	ret


	extrn	etopen_diagn: byte

init_card:
;Read PROM contents
	loadport
	setport	HP_PROM
	mov	di,offset curr_hw_addr
	mov	ax,cs
	mov	es,ax
	mov	cx,EADDR_LEN
	xor	ah,ah
init_card_1:
	in	al,dx
	add	ah,al
	inc	dx
	stosb
	loop	init_card_1
	in	al,dx			;now get the checksum.
	xor	ah,al			;add it in.
	cmp	ah,-1			;now it should have all ones set.
;ugh.  The checksum was botched on some boards, so we can't use it.
;	jne	init_card_2		;did it match?  Nope, return error.
	inc	dx
	in	al,dx			;get the hardware revision number.

	test	sys_features,MICROCHANNEL	;ISA or MCA?
	jne	is_16bit		;MCA - all MCA cards are 16-bit cards.
	test	al,80h			;16-bit system?
	je	check_16bit
is_16bit:
	or	endcfg,ENDCFG_WTS	;yes, use word transfer mode.

check_16bit:

	mov	bx,offset MCA_name_list		;assume MCA
	test	sys_features,MICROCHANNEL	;ISA or MCA?
	jne	check_board_name		;MCA.
	mov	bx,offset ISA_name_list		;otherwise ISA.
check_board_name:
	mov	si,[bx]			;get a pointer to a string.
	add	bx,2
	cmp	byte ptr [si],-1	;is this the end?
	je	check_board_found
	cmp	al,[si]			;is this the right one?
	jne	check_board_name
check_board_found:
	inc	si			;skip the board revision number.

	mov	dx,offset this_board_msg
	mov	ah,9
	int	21h

	mov	ax,ds			;copy the driver name to where
	mov	es,ax			;  we need it.
	mov	di,offset driver_name+3
check_board_copy:
	lodsb
	stosb
	or	al,al
	je	check_board_done_print
	call	chrout			;print the character.
	jmp	check_board_copy
check_board_done_print:
	lodsb				;copy the driver type number over
	mov	driver_type,al
	mov	al,CR
	call	chrout
	mov	al,LF
	call	chrout

	clc
	ret
init_card_2:
	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 io_addr
	mov	dx,offset io_addr_name
	call	print_number
	ret

code	ends

	end
