:
#		(C) 1989-1990 The Santa Cruz Operation, Inc.  All Rights
#		Reserved.  The user has unlimited right to use, modify
#		and incorporate this code into other products provided
#		it is used with SCO products and the user includes
#		this notice and the associated copyright notices with
#		any such application.

# This script is for installing an LLI driver using netconfig
# 
# The name it is called with will cause different operation.
# lmac0				== Digital EtherWORKS board 0
#
LIB=/usr/lib/lli
CONF=/etc/conf
PATH=/bin:/usr/bin:/etc/:$CONF/bin:$LIB
#
# Set possible return codes for this script
#
OK=0;	FAIL=1;	RELINK=2;

BRAM="0"
ERAM="0"

#
# Prompt the user for a hex value, it must be within a given range
# Usage:
# 	prompt_range "Message" default min max [step]
#
prompt_range() {
	mesg=$1
	default=$2
	range_min=$3 range_max=$4
	step="1"
	if [ $# -eq 5 ]
	then
		step=$5
	fi

	while :
	do
		echo "${mesg} (${range_min}..${range_max}) [${default}] or 'q' to quit: \c"
		read result
		case $result in
		Q|q)
			return $FAIL
			;;
		"")
			result=$default
			;;
		esac

		hc $result $range_min $range_max $step
		case $? in
		0) return $OK;;
		1) cleanup $FAIL;;
		2) cleanup $FAIL;;
		esac
	done
}

#
# Prompt the user to make a selection a list of values
# Usage:
#	prompt_select "Message" default "value_list"
prompt_select() {
	mesg=$1
	default=$2
	values=$3

	while :
	do
		if [ "$default" = "" ]
		then
			echo "${mesg} (${values}) or 'q' to quit: \c"
		else
			echo "${mesg} (${values}) [${default}] or 'q' to quit: \c"
		fi
		read result
		case $result in
		Q|q)
			return $FAIL
			;;
		"")
			result=$default
			;;
		esac

		for i in $values
		do
			if [ "$i" = "$result" ]
			then
				return $OK
			fi
		done
		echo "Illegal value, must be one of (${values})"
	done
}

#
# prompt the user to answer a yes no question or 'q' to quit
# Usage:
#	prompt_yn "Message" default
prompt_yn() {
	mesg=$1
	default=$2

	while :
	do
		echo "${mesg} (y/n) [${default}] or 'q' to quit: \c"
		read result

		case $result in
		q|Q) return $FAIL;;
		y|Y) result="Y"; return $OK;;
		n|N) result="N"; return $OK;;
		"") result=`echo $default | tr "yn" "YN"`; return $OK;;
		esac

		echo "Illegal value, please type 'y' 'n' or 'q'"
	done
}

#
# Fake up an mdevice and an sdevice for idcheck
# Do not remove $base if called with an argument...
#
makedevs() {
	dir=`pwd`
	rm -fr /tmp/dev$$
	mkdir /tmp/dev$$
	cd /etc/conf/cf.d
	cp mdevice /tmp/dev$$
	cd ../sdevice.d
	cat * > /tmp/dev$$/sdevice
	[ $1 ] && {
		# remove driver being reconfigured from sdevice & mdevice files.
		sed -e "/^$base/d" < /tmp/dev$$/sdevice > /tmp/bog$$
		mv /tmp/bog$$ /tmp/dev$$/sdevice 
		sed -e "/^$base/d" < /tmp/dev$$/mdevice > /tmp/bog$$
		mv /tmp/bog$$ /tmp/dev$$/mdevice 
	}
	cd $dir
}

cleanup() {
	cd /
	rm -fr /tmp/dev$$
	rm -fr /tmp/$base
	exit $1
}

# Removes the given interrupt vector for the $clash device.
rmvector() {
	clash=$1
	vec=$2

	cd $confdir
	echo "\nRemoving interrupt vector $vec for the $clash device ..."

	[ "$vec" = "2" ] && vec=9
	major=`./configure -j $clash` && { 
		# remove device but leave it required
		./configure -d -c -m $major -v $vec -Y >> conflog 2>&1 || { 
			cd $currdir
			cleanup $FAIL
		}
		# remove required setting if no more left
		if grep "Y" ../sdevice.d/$clash > /dev/null 2>&1
		then
			true
		else
			./configure -d -c -m $major -v $vec -R -Y >> conflog 2>&1 || { 
				cd $currdir
				cleanup $FAIL
			}
		fi
    	}
	cd $currdir
	return $OK
}

# On unix, we must check the files in sdevice.d.
# Sets the variable $clash to the driver code name if there is a driver that
# has already been allocated the given vector. Uses awk.
dointclash() {
	driver=$1
	vec=$2

	[ "$vec" = "2" ] && vec=9
	cd $confdir/../sdevice.d
	clash=`cat * | awk '{ if ( $6 == intr && $2 == "Y" ) exit } \
			END { print $1 }' intr=$vec`

	cd $currdir

	[ "$clash" = "" -o "$clash" = "$driver" ] && return $FAIL
	# found a clash
	return $OK
}

checkvec() {
	driver=$1
	vector=$2
	clash=

	currdir=`pwd`
	confdir=/etc/conf/cf.d

	while dointclash $driver $vector
	do
		prompt_select "Interrupt vector $vector is already in use for the $clash device.\n\n\
The alternatives available to you are:\n\n\
\t1. Continue the installation and remove vector $vector for the $clash device.\n\
\t2. Select a different interrupt vector.\n\n\
Select an option" 1 "1 2" || { 
			cleanup $FAIL
		}
		case $result in
		1)	rmvector $clash $vector || { 
				echo "Failed to remove vector $vector"
				cleanup $FAIL
			}
			makedevs
			return $OK
			;;
		2)	return $FAIL
			;;
		esac
	done
	return $OK
}

doaddrclash() {
	driver=$1
	addr1=$2
	addr2=$3

	cd $confdir
	clash=`../bin/idcheck -ar -l $addr1 -u $addr2 -i /tmp/dev$$`
	cd $currdir

	[ "$clash" = "" -o "$clash" = "$driver" ] && return $FAIL
	# found a clash
	return $OK
}

# Removes the $clash device.
rmaddr() {
	clash=$1

	cd $confdir
	echo "\nRemoving the $clash device ..."

	major=`./configure -j $clash` && { 
		# remove device but leave it required
		./configure -d -c -m $major -Y >> conflog 2>&1 || { 
			cd $currdir
			cleanup $FAIL
		}
		# remove required setting if no more left
		if grep "Y" ../sdevice.d/$clash > /dev/null 2>&1
		then
			true
		else
			./configure -d -c -m $major -R -Y >> conflog 2>&1 || { 
				cd $currdir
				cleanup $FAIL
			}
		fi
    	}
	cd $currdir
	return $OK
}

checkaddr() {
	driver=$1
	addr1=$2
	addr2=$3
	clash=

	currdir=`pwd`
	confdir=/etc/conf/cf.d

	while doaddrclash $driver $addr1 $addr2
	do
		if [ "$clash" = "ad" ]
		then
			echo "\n\nWARNING: Do not remove the $clash device \c"
			echo "if you are using an Adaptec disk controller"
		fi
		prompt_select "Addresses $addr1-$addr2 are already in use by the $clash device.\n\n\
The alternatives available to you are:\n\n\
\t1. Continue the installation and remove the $clash device.\n\
\t2. Select a different address.\n\n\
Select an option" 1 "1 2" || { 
			cleanup $FAIL
		}
		case $result in
		1)	rmaddr $clash || { 
				echo "Failed to remove $clash device"
				cleanup $FAIL
			}
			makedevs
			return $OK
			;;
		2)	return $FAIL
			;;
		esac
	done
	return $OK
}

doramclash() {
	driver=$1
	addr1=$2
	addr2=$3

	cd $confdir
	clash=`../bin/idcheck -cr -l $addr1 -u $addr2 -i /tmp/dev$$`
	cd $currdir

	[ "$clash" = "" -o "$clash" = "$driver" ] && return $FAIL
	# found a clash
	return $OK
}

checkram() {
	driver=$1
	addr1=$2
	addr2=$3
	clash=

	currdir=`pwd`
	confdir=/etc/conf/cf.d

	while doramclash $driver $addr1 $addr2
	do
		prompt_yn "
Ram addresses $addr1-$addr2 is already in use for the $clash device.
You must choose a unique address for this device to work. 
Do you wish to choose another address now?" y || cleanup $FAIL
		if [ "$result" = "Y" ]
		then
			return $FAIL
		else	
			cleanup $FAIL
		fi
	done
	return $OK
}

# On unix, we must check the lines in mdevice file.
# Sets the variable $clash to the driver code name if there is a driver that
# has already been allocated the given channel. Uses awk.
dodmaclash() {
	driver=$1
	chan=$2
 	clash=

	# -1 is never a clash
	[ "$chan" = "-1" ] && return $FAIL

	cd $confdir
	clash=`awk '{ if ( $1 != driver && $9 == dma ) print $1 }' dma=$chan driver=$driver mdevice`

	cd $currdir
	[ "$clash" = "" ] && return $FAIL

	return $OK
}

#
# Check if there is a clash of DMA channels
#
checkdma() {
	driver=$1
	channel=$2
	clash=

	currdir=`pwd`
	confdir=/etc/conf/cf.d

	while dodmaclash $driver $channel
	do
		prompt_yn "
DMA channel ${channel} is already in use by the $clash device.
You must choose a unique channel for this device to work. 
Do you wish to choose another channel now?" y || cleanup $FAIL
		if [ "$result" = "Y" ]
		then
			return $FAIL
		else	
			cleanup $FAIL
		fi
	done
	return $OK
}

check_args() {
	name=$1
	bd=$2

	case $name in
	lmac) echo "" 
		echo "Configuring Digital EtherWORKS board $bd";
		PREFIX="lmac";
		MAX_BD=0;
		;;
	*) echo "ERROR: Unknown LLI driver being configured ($name$bd)";
		cleanup $FAIL;
		;;
	esac

	if [ $bd -gt $MAX_BD ]
	then
		echo "ERROR: Only boards 0..$MAX_BD are supported by this driver";
		cleanup $FAIL
	fi
	echo
}

#
# function to restore and remove address conflicts in the sio driver
#
sio_conflict() {
	if [ "$BIO" = "$OBIO" ]
	then
		return $OK
	fi

	currdir=`pwd`
	cd /etc/conf/pack.d/sio
	grep "/* LLI {" space.c > /dev/null && {
		echo "Restoring serial cards using base address 0x$OBIO into link kit..."
		sed -e /"LLI.*$OBIO,/s/^\/\* LLI //" space.c >/tmp/bog$$
		mv /tmp/bog$$ space.c 
	}
	grep "(sd)0x$BIO" space.c > /dev/null && {
		echo "Removing serial cards using base address 0x$BIO from link kit..."
		[ ! -f space.c.rls ] && cp space.c space.c.rls
		sed -e /"(sd)0x$BIO,/s/^{/\/* LLI {/p" space.c >/tmp/bog$$
		mv /tmp/bog$$ space.c
	}
	cd $currdir
}

# restorevector check for sio (vecs 3-4) and pa drivers (vec 7)
# if these are being released by lli then let us restore them to sio or pa
restorevector() {
	currdir=`pwd`
	cd /etc/conf/cf.d

	intvector=$1
	test="0"
	[ "$intvector" = "3" -o "$intvector" = "4" ] && {
		prompt_yn "Restore vector $intvector to sio driver" y
		[ "$result" = "Y" ] && {
			echo "Restoring vector $intvector to sio driver"
			siomajor=`./configure -j sio`
			./configure -m $siomajor -c -v $intvector -a -Y
			return $OK
		}
	}
	[ "$intvector" = "7" ] && {
		prompt_yn "Restore vector $intvector to pa driver" y
		[ "$result" = "Y" ] && {
			echo "Restoring vector $intvector to pa driver"
			pamajor=`./configure -j pa`
			./configure -m $pamajor -c -v $intvector -a -Y
			return $OK
		}
	}
	return $OK
}

#
# determine release, and AT or MCA bus - set rel and type variables accordingly.
#
os_type() {
	rel=`sed -n 's/^#rel=\(.*\).$/\1/p' /etc/perms/inst`
	if [ "$rel" = "3.2.0" -o "$rel" = "3.2.1" -o "$rel" = "3.2.2" ]
	then
		type=`sed -n 's/^#typ=\(.*\)$/\1/p' /etc/perms/inst`
	else
		# 3.2.4 - one release supports AT, MCA, and EISA.
		uname -X | grep "BusType = MCA" >/dev/null 2>&1
		if [ $? -eq 0 ]
		then
			type=386MC
		else
			type=386GT
		fi
	fi
}

# function to produce the information for the System file for the 
# digital EtherWORKS board
#
system_lmac() {
	bd=$1

	case $bd in
	0) IRQ=5;;
	esac

	while :
	do
		prompt_select "Enter IRQ" $IRQ "5 9 10 11 15" || cleanup $FAIL
		irq=$result
		checkvec $name$bd $irq && break
	done
	IRQ=$irq

	BIO="0"
	EIO="0"
	BRAM="0"
	ERAM="0"
	NMINORS="1"
}

lmac_conf()
{
# print a prompt
#
p() {
	set -f
	/bin/echo $*
	set +f
	return $?
}

# lmac driver banner message
lmacprompt() {
/bin/cat - <<	EOF

			EtherWORKS DRIVER SETUP

For the EtherWORKS3/TURBO (lmac0) driver installation you will need to 
supply the Interrupt Vector Number, the I/O Base Address and the Memory 
Base Address. These parameters must match the hardware configuration on 
the card and must not conflict with other devices in the system. If you 
have not reconfigured your EtherWORKS3/TURBO card since removing it 
from the box, then press return at the prompts to accept the default 
values. If you have changed the default settings on your 
EtherWORKS3/TURBO card, then enter the new values when prompted. If you 
make a mistake and enter a valid, but incorrect value, then run 
netconfig again to reconfigure the lmac0 driver. If you want to make 
changes to the EtherWORKS3/TURBO settings then please refer to the 
NICSETUP utility documentation included with the hardware. 

EOF
}

#
# Deal with the lmac driver
#
lmacprompt

BIO=300
BRAM=d0000 

while :
do
	IRQ=5
	while	p "lmac${bd}: IRQ number [${IRQ}]: \c"
	do	read irq
		case "$irq" in
		"")
			break;
			;;
		2)
			IRQ=9;
			break;
			;;
		[3-9]|1[0-5])
			IRQ=$irq;
			break; 
			;;
		*)
			p "Invalid IRQ number ... "
			;;
		esac
	done

	checkvec $name$bd $IRQ && break
done

	while	p "lmac${bd}: I/O Base Address (in hexadecimal) [${BIO}]: \c"
	do	read bio
		case "$bio" in
		"")
			EIO=`echo $BIO | tr -d 0`0f;
			break;
			;;
		[2-3]00)	
			BIO=$bio;
			EIO=`echo $BIO | tr -d 0`0f;
			break;
			;;
		[1-9]c00|[a-f]c00)
			BIO=$bio;
			EIO=`echo $BIO | tr -d 0`0f;
			break;
			;;
		*) 
			BIO=$bio;
			EIO=`echo $BIO | tr -d 0`1f;
			break;
			;;
		esac
	done

	while	p "lmac${bd}: Memory Base Address (in hexadecimal) [${BRAM}]: \c"
	do	read bram
		case "$bram" in
		"")
			ERAM=dffff;
			break;
			;;
		[Cc]0000)	
			BRAM=$bram;
			ERAM=cffff;
			break;
			;;
		[Dd]0000)	
			BRAM=$bram;
			ERAM=dffff;
			break;
			;;
		[Ee]0000)	
			BRAM=$bram;
			ERAM=effff;
			break;
			;;
		*) 
			BRAM=$bram;
			ERAM=e0800;
			ERAM=`addhex $BRAM 800`
			break;
			;;
		esac
	done
}


# addhex(a,b) : add two hexadecimal numbers using awk.
# a and b are ascii strings of digits and the letters a-f
# no known side-effects, but illegal characters act as 0 place holders.

addhex() {
echo "$1 $2" | nawk ' {   
	printf("%x", atoh($1) + atoh($2));
    }
    function atoh(number) {
	i = 0
	j = length(number)
	result = 0
	while ( i < j ) {
	    result = result + (hexval(substr(number,j - i,1)) * (16 ^ i))
	    i = i + 1
	}
	return result
    }
    function hexval(letter) {
	if (letter == "a" || letter == "A") return 10 + 0
	if (letter == "b" || letter == "B") return 11 + 0
	if (letter == "c" || letter == "C") return 12 + 0
	if (letter == "d" || letter == "D") return 13 + 0
	if (letter == "e" || letter == "E") return 14 + 0
	if (letter == "f" || letter == "F") return 15 + 0
	return (letter + 0)
    }'
}


#
# main()
#

#
# get the name of the init script being run, since one script
# is used for multiple drivers; get the number at the end of the
# script's name
#
if [ $# -gt 1 ]
then
	name_below=$1; if_below=$2
	name_above=$3; if_above=$4
	configure=$5
fi

base=`basename $0`
drv=`echo $base | sed -e 's/[0-9]*$//`
bd=`expr $base : '.*\(.\)'`

makedevs $OK
check_args $drv $bd

#
# verify the driver is in the kernel link-kit
#
idcheck -p $base -i /tmp/dev$$
if [ $? -le 16 ]
then
	echo "Error: $base driver is not installed"
	cleanup $FAIL
fi

echo "Reconfiguring the $drv driver"
cd /usr/lib/lli/$drv
makedevs

#
# create the temporary directory for installing the driver
#
cd /tmp; rm -rf $base
mkdir $base; cd $base

DMACHAN="-1"

#
# set rel, type variables.
#
os_type

# get the interrupt vector & Base I/O address for the board that we are removing
currdir=`pwd`
cd /etc/conf/sdevice.d
ivec=`awk '{ if ( $1 != "*" ) print $6 }' < $base`
OBIO=`awk '{ if ( $1 != "*" ) print $7 }' < $base`
cd $currdir

#
# Do special board dependent processing
#
#system_$drv $bd

lmac_conf

#echo
#if [ "$IRQ" = "2" ]
#then
#	IRQ=9
#fi

NMINORS="1"

echo "$base\tY\t$NMINORS\t5\t1\t$IRQ\t$BIO\t$EIO\t$BRAM\t$ERAM" >./System

#
# All the drivers support more than one board.  In fact all the code to
# support all the boards is in the Driver.o for the board for the 1st board
# (eg the e3A0 driver acually contains enough code for the e3A1, e3A2 & e3A3
# boards).  As we need a Driver.o to be associated with 2nd, 3rd or 4th board
# we install a dummy Driver.o, and a Master and Node which will actually cause
# calls into the base driver.
#
if [ $bd -gt 0 ]
then
	echo "$base	-	iScH	$PREFIX$bd	0	0	1	256	$DMACHAN" >./Master
	echo "clone	$base	c	$base" >./Node

	idinstall -u -m -s -n -e -k $base
else
	echo "$base	Ioch	iScH	$PREFIX	0	0	1	256	$DMACHAN" >./Master
	idinstall -u -m -s -e -k $base
fi

# delete any potential BASE I/O address conflicts with the sio driver
sio_conflict

if [ "$ivec" = "3" -o "$ivec" = "4" -o "$ivec" = "7" ]
then
	[ ${ivec} != ${IRQ} ] && restorevector $ivec
fi

cleanup $RELINK
