#
#		(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
#
# This script was modifyed to be used for the dce driver on JAN - 93
# by DC-ISV drivers group.
# The name it is called with will cause different operation.
# dce0 dce1 dce2 dce3		== DC21x4 PCI boards 0 - 3
#
#
# ISV modification history
# ========================
#
# Jan-19-93  General cleanup and transfer for 21040 .   
#                                                      Ilan Hindy.
#
# Jan-30-93  Add /usr/lib/lli to the path so that ha and hc can 
#           be used
#                                                      Ilan Hindy.
# Jan-30-93 Fix a bug in writing system
#
# May-10-94 Add dupport to PCI boards (must be slot number 0 and IRQ 
#           is selected by the PCI BIOS)
#                                                      Rivki Vizen. 
# May-19-94 Fix bug - in error cases (in the init scripts) the remove script 
#           (that was called after the error was detected), decrease the number
#           of buffers in /etc/conf/cf.d/stune even those numbers wasn't
#           increase (because an error was detected). To fix this bug a new 
#           parameter was added to cleanup routine - this parameter indicate 
#           if we should add buffers in /etc/conf/cf.d/stune. 
#                                                      Rivki Vizen. 
# May-31-94 Add support to interrupt sharing.
#                                                      Rivki Vizen. 
# May-31-94 Dynamically add interrupt handler in PCI cards.
#                                                      Rivki Vizen. 
# Jun-01-94 Dynamically add interrupt handler in EISA cards.
#                                                      Rivki Vizen. 
# May-03-95 Add support to Everest (not full support yet): Add another
#           path that the driver can be found : /usr/lib/lli#.
#                                                      Rivki Vizen. 
# Sep-10-95 Add support to incremental interface in netconfig 
#                                                      Rivki Vizen. 
# Nov-05-95 Remove EISA support 
#                                                      Rivki Vizen. 
# Jan-11-96 Add bug in driver's name
#                                                      Rivki Vizen. 
#
LIB=/usr/lib/lli
CONF=/etc/conf
PATH=/bin:/usr/bin:/etc/:$CONF/bin:$LIB:/usr/lib/lli#
#
# Set possible return codes for this script
#
OK=0;	FAIL=1;	RELINK=2;

#
# 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 1;;
		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
		echo "${mesg} (${values}) [${default}] or 'q' to quit: \c"
		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
#
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
	cd $dir
}


#  This function creates string of numbers that contains the numbers between 
# $1 and $2, and echo it to the standart output.
get_range() {
i=$1
max_range=$2
range=""
while [ $i -le $max_range ]   
do
   range="$range $i"
   i=`expr $i + 1`
done
echo $range
}


#  This function checks if the $1 board is allready inatalled.
ins_bd() {
if /bin/grep ${drv}$1 $chains > /dev/null 2>&1
then return $OK
else return $FAIL
fi
}

#  This function removes the files (if they exsist) of board $1 in the
# netconfig directories,if they exist.

rmv_bd_files () {
  [ -f $netconfigdir/info/${drv}$1 ] && {
    rm $netconfigdir/info/${drv}$1
    rm $netconfigdir/init/${drv}$1
    rm $netconfigdir/remove/${drv}$1
    rm $netconfigdir/reconf/${drv}$1
  }
}

#  This function adds board $1's files (if they not exsist), to the netconfig 
# dircetories  
add_bd_files () {

   newboard=$1
   currdir1=`pwd`
   [ -f $netconfigdir/info/${drv}${newboard} ] && return

   cd $netconfigdir/info
   newfile=${drv}${newboard}
   cp ${drv}0 $newfile
   sed -e '/^NAME=.*'"[^0]"'/s/0\"/'$newboard'\"/p' $newfile > /tmp/bog$$
   sed -e '/^DESCRIPTION=.*'"[^0]"'/s/0\"/'$newboard'\"/p' /tmp/bog$$ > $newfile
   rm -r /tmp/bog$$
   chown bin $newfile
   chgrp bin $newfile
   chmod 750 $newfile

   cd $netconfigdir/init
   ln ${drv}0 ${drv}${newboard} > /dev/null 2>&1

   cd $netconfigdir/remove
   ln ${drv}0 ${drv}${newboard} > /dev/null 2>&1

   cd $netconfigdir/reconf
   ln ${drv}0 ${drv}${newboard} > /dev/null 2>&1

   cd $currdir1
}

#  This function checks the consistantion of the netconfig directories, 
# compareable to the chains file in lli directory. The function checks that
# the upper installed board nunber and all the lower boards have there files,
# and if all the lower boards are installed, its add new board files for the 
# customer use.
                 
check_bds() {

bds=`get_range 0 $MAX_BD`   
not_ins_bds=""              #contains a list of not installed boards.
max_ins_bd=""               #contains the number of the biggest installed board.


for i in $bds 
do
  if ins_bd $i
  then
    max_ins_bd=$i
  else 
    not_ins_bds="$not_ins_bds $i"
  fi
done

if [ -z "$max_ins_bd" ]
then
  # ( this should never be true because we in init script )
  # If there is no board installed we remove all the 
  #  upper boards from netconfig directories.
  upper_bds=`get_range 1 $MAX_BD `
  for j in $upper_bds
  do
    rmv_bd_files $j
  done
  return
else
 #adds the biggest installed board to netconfig directories.
 add_bd_files $max_ins_bd
fi

if [ $max_ins_bd -eq $MAX_BD ]
then
   return
else
   lower_bd=`expr $max_ins_bd - 1`
   upper_bd=`expr $max_ins_bd + 1`
   lower_bds=`get_range 0 $lower_bd`
   upper_bds=`get_range $upper_bd $MAX_BD `
   for i in $lower_bds
   do
     if echo $not_ins_bds | grep $i >/dev/null 2>&1
     then
     #  If there is a board lower then the max board installed that is not
     # installed yet, then no bigger board should be apper in netconfig dirs.
       for j in $upper_bds
       do
         rmv_bd_files $j
       done
       return
     fi
   done

   #  If all the boards until 'max board installed' are installed, we shoul add
   # the next board files to netconfig dir and delete the upper.
   add_bd_files $upper_bd
   upper_bd=`expr $upper_bd + 1`
   upper_bds=`get_range $upper_bd $MAX_BD`
   for j in $upper_bds
   do
      rmv_bd_files $j
   done
fi
}

cleanup() {
   cd /
   rm -fr /tmp/dev$$
   rm -fr /tmp/$base
   if [ $2 -eq 1 ]
      then
	  currdir=`pwd`
	  cd /etc/conf/cf.d
	  echo "Modifying Streams Data Configuration Parameters"

	  sparam=0
	  sparam=`./configure -y NBLK2048`
           echo -n Value of NBLK2048 changed from $sparam t
	  sparam=`expr $sparam + 10`
           echo o $sparam 
	  idtune -f NBLK2048 $sparam
	    
      sparam=0
	  sparam=`./configure -y NBLK64`
           echo -n Value of NBLK64 changed from $sparam t
	  sparam=`expr $sparam + 10`
           echo o $sparam
      idtune -f NBLK64 $sparam

      cd $currdir
   fi
   if [ $1 -eq $RELINK ]
      then
	  check_bds
   fi

   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 1
		}
		# 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 1
			}
		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 1
		}
		case $result in
		1)	rmvector $clash $vector || { 
				echo "Failed to remove vector $vector"
				cleanup $FAIL 1
			}
			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
}

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

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

	while doaddrclash $driver $addr1 $addr2
	do
		prompt_yn "
Addresses $addr1-$addr2 are already in use by 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 1
		if [ "$result" = "Y" ]
		then
			return $FAIL
		else	
			cleanup $FAIL 1
		fi
	done
	return $OK
}


#
# check_args ()
# 
# Check the name and board number.
# The name have to be dce and the board number between 0..3
# 
# This function defines the variables :
#  bd
#  name
#  PREFIX
#  MAX_BD
# 
# which are used as global variables in main() 

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

	case $name in
        dlkpci) echo "Configuring D-Link  PCI board $bd";
		PREFIX="dce";
		MAX_BD=3;
		;;
	*) echo "ERROR: Unknown LLI driver being configured ($name$bd)";
		cleanup $FAIL 1;
		;;
	esac

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

#
# select_PCI()
#
# Let user to select PCI type used by driver to figure out PCI configuration
# space.
#
select_PCI() {
	bd=$1

        PCI_type=0;
        
        echo ""
        echo "Note:"
        echo "  The default is to use the PCI BIOS calls (in 32-bit protected"
        echo "  mode). Some systems may not support these calls, in which case"
        echo "  there will be problems at boot time. If using a system that"
        echo "  does not support 32-bit protected mode PCI BIOS calls, direct"
        echo "  hardware accesses must be used."
        echo "  PCI mechanism 1 or PCI mechanism 2 should be selected depending"
        echo "  on your machine support."
        echo ""
        echo ""
        echo "Please specify the way used by PCI to access hardware........."
        echo ""
        echo "  0. Use 32-bit protected mode PCI BIOS calls."
        echo "  1. Direct access to the HW, using PCI mechanism 1."
        echo "  2. Direct access to the HW, using PCI mechanism 2."
        echo ""
        prompt_select " Enter number of PCI access type selection" $PCI_type "0 1 2" || cleanup $FAIL 1
                PCI_type=$result
        echo ""
        case $PCI_type in
          0) echo "PCI access type : Use 32-bit protected mode PCI BIOS calls";
             PCIaccess="XXX_USE_PCI_BIOS";
             ;;
          1) echo "PCI access type : Direct access to the HW, using PCI mechanism 1.";
             PCIaccess="XXX_USE_PCI_MECHANISM1";
             ;;
          2) echo "PCI access type : Direct access to the HW, using PCI mechanism 2.";
             PCIaccess="XXX_USE_PCI_MECHANISM2";
             ;;
        esac
        echo ""
        ed -s /etc/conf/pack.d/dlkpci0/space.c << TOAST > /dev/null
/#define XXX_HW_ACCESSES/
d
i
#define XXX_HW_ACCESSES           $PCIaccess
.
w
q
TOAST

}

#
# system_dce()
#
# function to produce the info for the System file for the DC21x4
# boards
#
# The info produced :
# 
# The interrupt level - from the user
# The slot number (and IO space used by the board ) - from the user
# The buffers consumed by the driver.
# 
system_dce() {
	bd=$1

#
# Added by Aaron on 11/24/95
#
        if [ $bd -eq 0 ]
        then    
                select_PCI  $bd
        fi
        
        MediaType=0;
        LineSpeed=0;

        echo "Please choose the line speed that you want............"
        echo ""
        echo "  0. Use default value."
        echo "  1. 10 MB/sec mode."
        echo "  2. 100 MB/sec mode."
        echo "  3. Automatic detection between 10 MB/sec and 100 MB/sec mode."
        echo ""
        prompt_select " Enter number of line speed selection" $LineSpeed "0 1 2 3" || cleanup $FAIL 1
                LineSpeed=$result
        echo ""
        case $LineSpeed in
          0) echo "Line Speed : Use default value.";
             SerialTXT="XXX_DC21140_DEF_SERIAL_MODE";
             ;;
          1) echo "Line Speed : 10 MB/sec mode.";
             SerialTXT="XXX_TP";
             ;;
          2) echo "Line Speed : 100 MB/sec mode.";
             SerialTXT="XXX_100TX";
             SIAModeTXT="XXX_DC2104X_DEF_SERIAL_MODE";
             ;;
          3) echo "Line Speed : AUTOSENSE_MODE";
             SerialTXT="XXX_AUTOSENSE";
             ;;
        esac
        echo ""
##        if [ $LineSpeed -eq 2 ]
##        then
##          prompt_yn "Do you want to use point to point full duplex mode?" "n" || cleanup $FAIL 1
##          [ $result = "Y" ] && SerialTXT="XXX_SYM_SCR_FULL_DUPLEX"
##        else
          echo "Please choose the media mode that you want............"
          echo ""
	  echo "  0. Use default value."
          echo "  1. Point to point full duplex twisted pair connection."
#
# Masked by Aaron on 03/14/96
#
##          echo "  2. AUI connection."
          echo "  2. BNC connection."
          echo "  3. Twisted pair connection."
          echo "  4. Automatic detection between TP and BNC."
          echo "  5. Twisted pair connection with linkfail test ignore & set polarity plus."
          echo ""
          prompt_select " Enter number of media mode selection" $MediaType "0 1 2 3 4 5" || cleanup $FAIL 1
               MediaType=$result
          echo ""
          case $MediaType in
	     0) SIAModeTXT="XXX_DC2104X_DEF_SERIAL_MODE";
        	echo "Media Mode : Use default value.";
		;;
             1) SIAModeTXT="XXX_TP_FULL_DUPLEX";
                SerialTXT="XXX_TP_FULL_DUPLEX";
                [ $LineSpeed -eq 2 ] && SerialTXT="XXX_100TX_FULL_DUPLEX";
                echo "Media Mode : TP_FULL_DUPLEX_MODE";
                ;;
#
# Masked by Aaron on 03/14/96
#
##             2) SIAModeTXT="XXX_AUI";
##                echo "Media Mode : AUI_MODE";
##                ;;
             2) SIAModeTXT="XXX_BNC";
                echo "Media Mode : BNC_MODE";
                ;;
             3) SIAModeTXT="XXX_TP";
                echo "Media Mode : TP_MODE";
                ;;
             4) SIAModeTXT="XXX_AUTOSENSE";
                echo "Media Mode : AUTOSENSE_MODE";
                ;;
             5) SIAModeTXT="XXX_TP_LINK_DISABLE";
                echo "Media Mode : TP_LINK_DISABLE_MODE";
                ;;
          esac
##        fi

        ed -s /etc/conf/pack.d/dlkpci$bd/space.c << TOAST > /dev/null
/#define XXX_DC2104X_SIA_MODE_$bd/
d
i
#define XXX_DC2104X_SIA_MODE_$bd        $SIAModeTXT
.
/#define XXX_DC21140_SERIAL_MODE_$bd
d
i
#define XXX_DC21140_SERIAL_MODE_$bd        $SerialTXT
.
w
q
TOAST

##
## Added by Aaron on 04/02/96 
## to solve the problem of add/remove driver on SCO OpenServer
## if "dlkpci0" line still in sdevice and is 'N' then add driver and
## re-build will cause 
## kslgen: "cannot determine major/minor numbers for node /dev/dlkpci0
##
        ed -s /etc/conf/cf.d/sdevice << TOAST > /dev/null
/dlkpci$bd
d
.
w
q
TOAST

    BIO=0
    EIO=0
    IRQ=0

	currdir=`pwd`

	cd /etc/conf/cf.d
	
	echo "Modifying Streams Data Configuration Parameters"

	sparam=0
	sparam=`./configure -y NBLK2048`
        echo -n Value of NBLK2048 changed from $sparam t
	sparam=`expr $sparam + 10`
        echo o $sparam 
	idtune -f NBLK2048 $sparam
	
	sparam=0
	sparam=`./configure -y NBLK64`
        echo -n Value of NBLK64 changed from $sparam t
	sparam=`expr $sparam + 10`
        echo o $sparam
	idtune -f NBLK64 $sparam

        cd $currdir
 
	NMINORS="1"
}


# 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 : '.*\(.\)'`
chains=/usr/lib/lli/chains
chain=$base:$name_above
netconfigdir=/usr/lib/netconfig

makedevs
check_args $drv $bd

#
# Check and manage our internal chains file.
# This file allows coexistent mkdev and netconfig calls.
#
# chain already installed
grep $chain $chains > /dev/null 2>& 1 && {
	cleanup $OK 0
}
# this board already installed
grep $base: $chains > /dev/null 2>& 1 && {
	echo $base already configured.
	echo $chain >> $chains
	cleanup $OK 0
}
#
# Now check that if we are not board zero that board zero is installed
#
[ "$bd" -ne "0" ] && {
	grep ${drv}0 $chains > /dev/null 2>& 1 || {
		echo "${drv}0 not configured, you must configure it first"
		cleanup $FAIL 1
	}
}

#
# check to see if the driver is already in the kernel link-kit so we can
# either add it or update it later on
#
idcheck -p $base -i /tmp/dev$$
if [ $? -gt 16 ]
then
	installed="TRUE"
else
	installed="FALSE"
fi

if [ "$bd" = "0" ]
then
	echo "Installing the $drv driver into the link kit"
	cd /usr/lib/lli/$drv
	if [ "$installed" = "TRUE" ]
	then
		idinstall -u -e -k $base
	else
		idinstall -a -e -k $base
	fi
	makedevs
else
	idcheck -p ${drv}0 -i /tmp/dev$$
	if [ $? -le 16 ]
	then
		echo "${drv}0 must be configured before attempting to configure $drv"
		cleanup 1 1
	fi
fi

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

#
# Do special board dependent processing
#
case $drv in
	dlkpci)	system_dce $bd;;
esac
echo
if [ "$IRQ" = "2" ]
then
	IRQ=9
fi

echo "$base\tY\t$NMINORS\t0\t0\t$IRQ\t$BIO\t$EIO\t0\t0" >./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    p      iScH    $PREFIX$bd       0       0       1           256	-1" >./Master
	echo "clone	$base	c	$base" >./Node

	if [ "$installed" = "TRUE" ]
	then
		idinstall -u -m -s -n -e -k $base
	else
        if [ -f $LIB/Driver.o ] 
        then
    		cp $LIB/Driver.o .
        else
    		cp /usr/lib/lli#/Driver.o .
	    fi
	    idinstall -a -e -k $base
	fi
else
	idinstall -u -s -e -k $base
fi
# we successfully installed this driver, add it to the chains file
echo $chain >> $chains

echo "NODE=/etc/conf/node.d/$base" >/tmp/$base.src
chmod 777 /tmp/$base.src

cleanup $RELINK 0
