:
# Mkdev script for BocaBoard Serial driver.
# Copyright (c) 1992, Boca Research, Inc.
#
# 	Ver: 1.4
#
#		Ars-1  	Comment out the CNTYPE which not needed in this case
#			The correct value of CNTYPE is zero (0).	
#

PATH=/etc:/bin:/usr/bin
LANG=english_us.ascii
export PATH LANG

IODIR=/usr/sys/io
STOREL="/usr/lib/storel -DM_I386 -Mx -r -octmp.o"
BBFILE=bbconf.asm
BBOFILE=bbconf.o
TMPFILE=/tmp/bbconfig$$

: ${OK=0} ${FAIL=1} ${TRUE=0} ${FALSE=1}

NAME=bb
FUNCS="bbinit bbopen bbclose bbread bbwrite bbioctl bbintr bb_tty"
IPL=5

# Function Definitions
#########################

# ---------- STANDARD ROUTINES -------- These routines are commen to scripts
#					requiring kernel relinking.
# Define traps for critical and non critical code.
set_trap ()  {	
	trap 'echo "\nInterrupted! Exiting ..."; cleanup 1' 1 2 3 15
}

unset_trap ()  {
	trap '' 1 2 3 15
}
 
# Remove temp files and exit with the status passed as argument
cleanup () {
	trap '' 1 2 3 15
	[ "$tmp" ] && rm -f $tmp*
	exit $1
}

# Prompt for yes or no answer - returns non-zero for no
getyn () {
	while	echo "$* (y/n) \c">&2
	do	read yn rest
		case $yn in
		[yY])	return $OK 			;;
		[nN])	return $FAIL			;;
		*)	echo "Please answer y or n" >&2	;;
		esac
	done
}

# Prompt with mesg, return non-zero on q
prompt () {
	while	echo "\n${mesg}or enter q to quit: \c" >&2
	do	read cmd
		case $cmd in
		+x|-x)	set $cmd					;;
		Q|q)	return $FAIL					;;
		!*)	eval `expr "$cmd" : "!\(.*\)"`			;;
		"")	# If there is an argument use it as the default
			# else loop until 'cmd' is set
			[ "$1" ] && { 
				cmd=$1
				return $OK
			}
			: continue
			;;
		*)	return $OK					;;
		esac
	done
}

# Print an error message
error () {
	echo "\nError: $*" >&2
	return $FAIL
}

# Configure error message
conferr ()  {
	error "configure failed to update system configuration.
Check ${CONFDIR}/conflog for details."
}

# Determine operating system
get_os () {
	OSVER=`uname -r`
	case "$OSVER" in
		3.2* ) OS=unix; CONFDIR=/etc/conf/cf.d ;;
		2.[23]* ) OS=xenix; CONFDIR=/usr/sys/conf ;;
		*)  error "cannot determine operating system release"
			return $FAIL ;;
	esac
	return $OK
}

# perms list needed if link kit must be installed
permschk () {
	if [ -f /etc/perms/inst ]; then
		PERM=/etc/perms/inst
	else
		error "Cannot locate /etc/perms/inst. Needed to verify
linkkit installation"
		cleanup $FAIL
	fi
}

# test to see if link kit is installed
linkchk ()  {
	cd /
	until	fixperm -i -d LINK $PERM
	do	case $? in
		4)  echo "\nThe Link Kit is not installed." >&2	;;
		5)  echo "\nThe Link Kit is only partially installed." >&2  ;;
		*)  echo "\nError testing for Link Kit.  Exiting." >&2
			cleanup $FAIL ;;
		esac

		# Not fully installed. Do so here
		getyn "\nDo you wish to install it now?" || {
			# answered no
			echo "
The link kit must be installed to run this program.  Exiting ..."
			cleanup $OK
		}

		# answered yes, so install link kit
		echo "\nInvoking /etc/custom\n"
		/etc/custom -o -i LINK || {
			# custom exited unsuccessfully
			error "custom failed to install Link Kit successfully.  Please try again."
			cleanup $FAIL
		}
	done
}

# See if driver already configured
prodchk () {
	confchk

	echo "\n\n\tBocaBoard (TM) SCO UNIX/XENIX driver installation."
	echo "\tCopyright (c) 1992, Boca Research, Inc."
	echo "\n\n\tThe Boca Research BocaBoard driver supports up to 4"
	echo "\tBocaBoards.  These can be any combination of 4, 8, or 16"
	echo "\tport boards.  This script configures the BocaBoard driver"
	echo "\tinto the system and allows you to rebuild the kernel."
	echo "\n\n"

	case $cf_state in
	YES|PART) echo "
The BocaBoard driver is already installed.  If you continue
you may overwrite the existing system configuration."
		getyn "Do you wish to continue?" || return $FAIL
		;;
	NO) echo "Configuring BocaBoard driver."
		;;
	esac

	return $OK
}

asklink ()  {
	getyn "
You must create a new kernel to effect the driver change you specified.
Do you wish to create a new kernel now?"  ||  {
		echo "
To create a new kernel execute ${CONFDIR}/link_${OS}. Then you
must reboot your system by executing  /etc/shutdown  before the 
changes you have specified will be implemented.\n"
			return $FAIL 
		}
	return $OK
}

#Link the kernel
klink () {
	[ "$_RELINK" ] && return	

	cd $CONFDIR

	if [ "$OS" = "unix" ]
	then
		../bin/idbuild || return $FAIL
		return $OK
	else
		./link_xenix || {
			echo "
The xenix kernel has failed to link.  Recheck the configuration of your
system and try again by changing to the $CONFDIR directory and 
running ./link_xenix\n" 
			return $FAIL
		}
		getyn "
The xenix kernel has been successfully relinked.  Do you want this 
kernel to boot by default?" || {
			echo "The new kernel is in ${CONFDIR}/xenix."
			return $OK
		}
		./hdinstall
		return $OK
	fi
}

# CONFIGURE routines

confchk () {
	cd $CONFDIR

	MAJOR=`./configure -j ${NAME}` || {
		cf_state=NO
		return $TRUE
	}
	cf_state=YES
	return $TRUE
}

confadd () {
	echo "\nAdding device to system configuration files ..."
	cd $CONFDIR
	[ $cf_state = YES ] && {
		echo "Deleting previous driver"
		./configure -d -c -m $MAJOR
		killnodes || return $FAIL
	}
	MAJOR=`./configure -j NEXTMAJOR`
	echo "\n\nConfiguring driver with major number ${MAJOR}."

	if [ "$OS" = "unix" ]
	then 
		confuadd || return $FAIL
	else
		confxadd || return $FAIL
	fi

	echo "\n\nSystem configuration successfully modified."
	return $OK
}

# Unix. Configure a non-required driver. Make an sdevice file for it.
confuadd () {
	./configure -c -a $FUNCS -m $MAJOR -h $NAME -M 1 4 > conflog || {
		conferr
		return $FAIL
	}
	./configure -c -m $MAJOR -d -R > conflog || {
		conferr
		return $FAIL
	}

	rm -f conflog

	[ "$IO1" ] || return $OK
	echo "$NAME	Y	1	$IPL	1	$V1	$IO1	$IO1END	0	0" > ../sdevice.d/$NAME

	[ "$IO2" ] || return $OK
	echo "$NAME	Y	1	$IPL	1	$V2	$IO2	$IO2END	0	0" >> ../sdevice.d/$NAME

	[ "$IO3" ] || return $OK
	echo "$NAME	Y	1	$IPL	1	$V3	$IO3	$IO3END	0	0" >> ../sdevice.d/$NAME

	[ "$IO4" ] || return $OK
	echo "$NAME	Y	1	$IPL	1	$V4	$IO4	$IO4END	0	0" >> ../sdevice.d/$NAME

	return $OK
}

# Xenix. Calculate the vectors and configure the driver.
confxadd () {
	[ "$V1" -gt 8 ] && V1=`expr $V1 + 16`
	[ "$V2" -gt 8 ] && V2=`expr $V2 + 16`
	[ "$V3" -gt 8 ] && V3=`expr $V3 + 16`
	[ "$V4" -gt 8 ] && V4=`expr $V4 + 16`
	./configure -c -a $FUNCS -m $MAJOR -l $IPL -v $V1 $V2 $V3 $V4 -r\
	  > conflog || {
		conferr
		return $FAIL
	}

	return $OK
}

# Get the params for each board. This sets 'IO#', 'v#', and 'PT#' 
# variables.

getbrds () {
	while echo "Enter the number of boards to configure (1 - 4) or 'q' to quit "
	read x
	do
		case $x in 
			1|2|3|4)	BOARDS=$x; break	;;
			q|Q)		echo "\nInstallation aborted" >&2
					cleanup $FAIL	;;
			*)		echo "
You cannot configure more than 4 boards."
					continue	;;
		esac
	done

# For each board, get the IRQ, the IO base and the number of ports

	BRD=0
	PORTSUM=0

	getbrd || return $FAIL
	V1=$VEC
	IO1=$IOBASE
	IO1END=$IOEND
	PTCNT1=$PORTS
	PT1=`expr $PORTS + ${CNTYPE}`
	BRD=`expr $BRD + 1`
	PORTSUM=`expr $PORTSUM + ${PORTS}`
	[ "$BRD" != "$BOARDS" ] || return $OK

	getbrd || return $FAIL
	V2=$VEC
	IO2=$IOBASE
	IO2END=$IOEND
	PTCNT2=$PORTS
	PT2=`expr $PORTS + ${CNTYPE}`
	BRD=`expr $BRD + 1`
	PORTSUM=`expr $PORTSUM + ${PORTS}`
	[ "$BRD" != "$BOARDS" ] || return $OK

	getbrd || return $FAIL
	V3=$VEC
	IO3=$IOBASE
	IO3END=$IOEND
	PTCNT3=$PORTS
	PT3=`expr $PORTS + ${CNTYPE}`
	BRD=`expr $BRD + 1`
	PORTSUM=`expr $PORTSUM + ${PORTS}`
	[ "$BRD" != "$BOARDS" ] || return $OK

	getbrd || return $FAIL
	V4=$VEC
	IO4=$IOBASE
	IO4END=$IOEND
	PTCNT4=$PORTS
	PT4=`expr $PORTS + ${CNTYPE}`
	BRD=`expr $BRD + 1`
	PORTSUM=`expr $PORTSUM + ${PORTS}`
	[ "$BRD" != "$BOARDS" ] || return $OK

	return $FAIL
}

# Get info for a single board. Sets the 'PORTS', 'IOBASE', and 'VEC' vars

getbrd () {
	while true
	do
		while echo "\n\nEnter the IRQ for board $BRD or 'q' to quit"
		read x
		do
			case $x in 
				3|4|5|7|10|11|12|15)	VEC=$x; break	;;
				Q|q)			echo "
Installation aborted" >&2; cleanup $FAIL				;;
				*)			echo "
The IRQ must be one of the following: 3, 4, 5, 7, 10, 11, 12, 15
Please try again"
							continue	;;
			esac
		done
		
		while echo "
Enter the base I/O address, in hex, for board $BRD, or 'q' to quit." 
		read x
		do
			IOBASE=`echo $x | tr "[a-f]" "[A-F]"`
			case $IOBASE in
				[0-9A-F][0-9A-F][0-9A-F]*)
						break		;;
				Q|q)		echo "
Installation aborted" >&2; cleanup $FAIL			;;
				*)		echo "
The base I/O address you entered does not seem to be a valid hexidecimal
address.  Please enter the number as a string of hex digits [0-9A-F]."
						continue	;;
			esac
		done
		
		while	echo "
Select the number of ports on this board

	1.	4 ports
	2.	8 ports
	3. 	16 ports
	4. 	4 ports (Microchannel)
	5. 	16 ports (Microchannel)

Select an option or enter 'q' to quit: \c"

# Products which use an RJ11 connector need to have the high bit of CNTYPE set

		read x
		do	case $x in

# Ars-1			1)	PORTS=4; prtend=31; CNTYPE=32768; break	;;
# Ars-1 		2)	PORTS=8; prtend=63; CNTYPE=32768; break	;;

			1)	PORTS=4; prtend=31; CNTYPE=0; break	;;
			2)	PORTS=8; prtend=63; CNTYPE=0; break	;;
			3)	PORTS=16;prtend=127;CNTYPE=0;  break	;;
			4)	PORTS=4; prtend=31; CNTYPE=0; break;;
			5)	PORTS=16;prtend=127;CNTYPE=0;  break	;;
			Q|q)	echo "\nInstallation aborted" >&2
				cleanup $FAIL	;;
			*)	echo "\nEnter 1, 2, 3, 4 or 5 q\n" >&2 ;;
			esac
		done

		htod $IOBASE
		iodec=`expr $decval + $prtend`
		IOEND=`echo $iodec | awk '{ printf("%x", $1) }'`

		getyn "
You wish to configure board $BRD as:

	$PORTS port board, using IRQ $VEC and I/O addresses $IOBASE - $IOEND

Is this correct? " || {
			echo "Reenter configuration information"
			continue
		}

		return $OK
	done
}

# Get decimal value from hex number
htod() {
	decval=`echo $1 | awk '
		{ len = length($1); dec = 0; mult = 1; }
		{ for (x = len; x > 0; x--) {
			c = substr($1, x, 1);
			if (c >= "0" && c <= "9") val = c;
			if (c == "A") val = 10;
			if (c == "B") val = 11;
			if (c == "C") val = 12;
			if (c == "D") val = 13;
			if (c == "E") val = 14;
			if (c == "F") val = 15;
			dec += val * mult;
			mult *= 16;
			}
		}
		{ printf("%d", dec); }
	'`
}

# Unix. Create the new space.c file.
updspace () {
	echo "Updating driver configuration ..."
	cd /etc/conf/pack.d
	[ -d ./bb ] || { echo "
The directory /etc/conf/pack.d/bb does not exist.  Please be sure to
install the product according to the installation instructions."
		return $FAIL
	}
	cd bb
	echo "
#include <sys/types.h>
#include <sys/tty.h>
#include \"bb.h\"

#define BB_BOARDS $BOARDS

int Bb_numbrds = BB_BOARDS;
struct tty bb_tty[${PORTSUM}];
BB_BOARD Bb_brds[BB_BOARDS] = {
\c" > ./space.c

	[ "$IO1" ] || {
		echo "};" >> ./space.c
		return $OK
	}
	echo "\t0x$IO1, $V1, $PT1," >> ./space.c

	[ "$IO2" ] || {
		echo "};" >> ./space.c
		return $OK
	}
	echo "\t0x$IO2, $V2, $PT2," >> ./space.c

	[ "$IO3" ] || {
		echo "};" >> ./space.c
		return $OK
	}
	echo "\t0x$IO3, $V3, $PT3," >> ./space.c

	[ "$IO4" ] || {
		echo "};" >> ./space.c
		return $OK
	}
	echo "\t0x$IO4, $V4, $PT4," >> ./space.c

echo "};" >> ./space.c
	return $OK
}

# Xenix. Create the new bbconf.asm file. Note that this makes a hard
# assumption about the byte size of the tty structure (96 bytes).

updxconf () {
	echo "Updating driver configuration ..."
	cd $IODIR
	echo "
	TITLE	\$bbconf

	.386
DGROUP	GROUP	CONST, _BSS, _DATA
PUBLIC  _Bb_numbrds
PUBLIC  _Bb_brds
_DATA	SEGMENT  DWORD USE32 PUBLIC 'DATA'
_Bb_numbrds	DD	$BOARDS
COMM	_bb_tty:BYTE:96*${PORTSUM}" >  ${IODIR}/$BBFILE

echo "_Bb_brds\t\c" >> ${IODIR}/$BBFILE

	case $BOARDS in
	1) echo "\tDD\t${IO1}H\n\tDD\t${V1}\n\tDD\t${PT1}" >>  ${IODIR}/$BBFILE
	   ;;
	2) echo "\tDD\t${IO1}H\n\tDD\t${V1}\n\tDD\t${PT1}" >>  ${IODIR}/$BBFILE 
	   echo "\tDD\t${IO2}H\n\tDD\t${V2}\n\tDD\t${PT2}" >>  ${IODIR}/$BBFILE
	   ;;
	3) echo "\tDD\t${IO1}H\n\tDD\t${V1}\n\tDD\t${PT1}" >>  ${IODIR}/$BBFILE 
	   echo "\tDD\t${IO2}H\n\tDD\t${V2}\n\tDD\t${PT2}" >>  ${IODIR}/$BBFILE
	   echo "\tDD\t${IO3}H\n\tDD\t${V3}\n\tDD\t${PT3}" >>  ${IODIR}/$BBFILE
	   ;;
	4) echo "\tDD\t${IO1}H\n\tDD\t${V1}\n\tDD\t${PT1}" >>  ${IODIR}/$BBFILE 
	   echo "\tDD\t${IO2}H\n\tDD\t${V2}\n\tDD\t${PT2}" >>  ${IODIR}/$BBFILE
	   echo "\tDD\t${IO3}H\n\tDD\t${V3}\n\tDD\t${PT3}" >>  ${IODIR}/$BBFILE
	   echo "\tDD\t${IO4}H\n\tDD\t${V4}\n\tDD\t${PT4}" >>  ${IODIR}/$BBFILE
	   ;;
	esac

	echo "\n
_DATA      ENDS
_BSS	SEGMENT  DWORD USE32 PUBLIC 'BSS'
_BSS      ENDS
CONST	SEGMENT  DWORD USE32 PUBLIC 'CONST'
CONST      ENDS
_TEXT	SEGMENT  DWORD USE32 PUBLIC 'CODE'
	ASSUME   CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
_TEXT	ENDS
END\n" >>  ${IODIR}/$BBFILE
	return $OK
}

# Xenix. Assemble the new bbconf.asm
asmxconf () {
	cd $IODIR

	$STOREL $BBFILE > /dev/null 2>&1 || {
			echo "
The configuration file ${IODIR}/$BBFILE could not be assembled."
			return $FAIL
	}
	mv ctmp.o $BBOFILE
	return $OK
}

# Xenix. Patch the link script with the new object names
updxlink () {
	cd /usr/sys/conf

	grep -s bb.o link_xenix > /dev/null || {
		cp link_xenix link_xenix.00 || {
			echo "Cannot copy link_xenix" >&2
			exit $FAIL
		}
		trap "mv link_xenix.00 link_xenix; exit $FAIL" 1 2 3 15
		sed "s!c.o!& ../io/bb.o ../io/bbconf.o!" link_xenix.00 \
		  > link_xenix || {
			echo "Cannot edit link_xenix" >&2
			mv link_xenix.00 link_xenix
			exit $FAIL
		}
		unset_trap
		chmod 700 link_xenix
		return $OK
	}
	return $OK
}

# Update the init and node config files. This expects the 'BOARDS',
# 'PTCNT1-4' variables to be set.

updinit () {
	echo "Updating system node and init files ..."
	[ -d /usr/lib/bb ] || mkdir /usr/lib/bb
	[ -f /usr/lib/bb/bbttys ] && rm -f /usr/lib/bb/bbttys

	[ "$OS" = "unix" ] && {
		rm -f /etc/conf/init.d/$NAME
		rm -f /etc/conf/node.d/$NAME
	}

	prt=0
	b=0
	while [ "$b" != "$BOARDS" ]
	do
		bx=`expr $b + 3`
		case $b in 
			0)	pcnt=$PTCNT1 ;;
			1)	pcnt=$PTCNT2 ;;
			2)	pcnt=$PTCNT3 ;;
			3)	pcnt=$PTCNT4 ;;
			*)	echo "$b is not a support number of boards"
				return $FAIL ;;
		esac

		pidx=0
		c="a"
		while [ "$pidx" != "$pcnt" ]
		do 
			t=$bx$c
			donode $t $prt
			c=`echo $c | tr abcdefghijklmnop bcdefghijklmnopq`
			prt=`expr $prt + 1`
			pidx=`expr $pidx + 1`
		done
		b=`expr $b + 1`
	done
	[ "$OS" = "xenix" ] && chmod 664 /etc/ttys
	return $OK
}

# Given a tty name (1) and a minor device # (2) create the node file
# entry and the init file entry for terminal and modem devices

donode () {
	echo "/dev/tty$1\r\c"
	m=`echo $1 | tr "[a-z]" "[A-Z]"`
	mdm=`expr $2 + 128`

	if [ "$OS" = "unix" ] 
	then
		echo "$1:2:off:/etc/getty tty$1 m" >>/etc/conf/init.d/$NAME
		echo "$m:2:off:/usr/lib/uucp/uugetty -t60 tty$m 3" >> \
		  /etc/conf/init.d/$NAME

		echo "$NAME	tty$1	c	$2" >> /etc/conf/node.d/$NAME	
		echo "$NAME	tty$m	c	$mdm" >> /etc/conf/node.d/$NAME	
	else

		grep -s tty$1 /etc/ttys > /dev/null \
		  || echo "0mtty$1" >> /etc/ttys
		grep -s tty$m /etc/ttys > /dev/null \
		  || echo "03tty$m" >> /etc/ttys
		grep -s tty$1 /etc/ttytype > /dev/null \
		  || echo "unknown\ttty$1" >> /etc/ttytype
		grep -s tty$m /etc/ttytype > /dev/null \
		  || echo "dialup\ttty$m" >> /etc/ttytype

		echo "tty$1" >> /usr/lib/bb/bbttys
		echo "tty$m" >> /usr/lib/bb/bbttys

		[ /dev/tty$1 ] && {
			mknod /dev/tty$1 c $MAJOR $2
			chmod 666 /dev/tty$1
		}
		[ /dev/tty$m ] && {
			mknod /dev/tty$m c $MAJOR $mdm
			chmod 666 /dev/tty$m
		}
	fi
}

# Xenix.  Unix deletes old nodes and inittab entries when the kernel
# environment is rebuilt.  For Xenix we build a configuration file
# so that we know which nodes and tty entries to extirpate.
killnodes() {
	echo "Removing device nodes and /etc/ttys entries"

	if [ "$OS" = "xenix" ]
	then
		cd /etc
		cp ttys ttys.00
		cp ttytype ttytype.00
		trap "mv ttys.00 ttys; mv ttytype.00 ttytype; exit $FAIL" 1 2 3 15
		cat /usr/lib/bb/bbttys | while read x 
		do
			[ -c /dev/$x ] && {
				rm /dev/$x
				grep -v $x ttys > /tmp/ttys
				mv /tmp/ttys ttys
				grep -v $x ttytype > /tmp/ttytype
				mv /tmp/ttytype ttytype
			}
			echo "/dev/$x\r\c"
		done
		rm ttys.00 ttytype.00
		echo "\n"
		cd $CONFDIR
	fi
	return $OK
}

# main

set_trap
permschk
linkchk
get_os || cleanup $FAIL
prodchk || cleanup $FAIL
getbrds || cleanup $FAIL
confadd || cleanup $FAIL
if [ "$OS" = "unix" ]
then
	updspace || cleanup $FAIL
else
	updxconf || cleanup $FAIL
	asmxconf || cleanup $FAIL
	updxlink || cleanup $FAIL
fi
updinit || cleanup $FAIL
asklink || cleanup $OK
klink || cleanup $FAIL
cleanup $OK
