#!/bin/sh
# ============================================================================
# WANPIPE Configuration Script.
# ----------------------------------------------------------------------------
# Copyright (c) 1995-1996, Sangoma Technologies Inc.  All rights reserved.
# ============================================================================
# Rev.#	Date		Who	Details
# -----	---------------	-------	----------------------------------------------
#  2.30	Oct.16,1996	GK	Uses meta-configuration file wanpipe.rc.
#  2.21	Oct.10,1996	GK	
#  2.10	Jun.19,1996	GK	o Added support for S503 adapter
#				o Added bind/unbind functions
#  2.00	May 01,1996	GK	
#  1.00	Apr.19,1996	GK	Initial version.
# ============================================================================

PATH=/bin:/sbin:/usr/bin:/usr/sbin
WANPIPE_RC=/etc/wanpipe.rc
DEVNAME=sdla
SDLACONF="/etc/sdla.conf"
OLDCONF="/etc/wanpipe.conf"
TMPFILE1="/tmp/T$$.001"
APPLY=0
CMD=
SEL=

# Hardware configuration options
# ------------------------------
SDLA_TYPE_OPT="S502E S502A S503 S508"
S502_CLK_OPT="3600 4000 7200 8000 10000"
S502_PORT_OPT="250 300 350 360"
S503_PORT_OPT="250 254 300 304 350 354 360 364"
S508_PORT_OPT="250 270 280 300 350 360 380 390"
S502_IRQ_OPT="2 3 5 7"
S503_IRQ_OPT="2 3 4 5 7"
S508_IRQ_OPT="3 4 5 7 10 11 12"
S502A_MEM_OPT=\
"A0000 A2000 A4000 A6000 A8000 AA000 AC000\
 C0000 C2000 C4000 C6000 C8000 CA000 CC000\
 D0000 D2000 D4000 D6000 D8000 DA000 DC000\
 E0000 E2000 E4000 E6000 E8000 EA000 EC000"
S502E_MEM_OPT=\
"A0000 A2000 A4000 A6000 A8000 AA000 AC000 AE000\
 C0000 C2000 C4000 C6000 C8000 CA000 CC000 CE000\
 D0000 D2000 D4000 D6000 D8000 DA000 DC000 DE000\
 E0000 E2000 E4000 E6000 E8000 EA000 EC000 EE000"

####### FUNCTION DEFINITIONS #################################################

# ----------------------------------------------------------------------------
# Clear the screen if it is supported.
# ----------------------------------------------------------------------------
clearscr() {
	# check if the terminal environment is set up
	[ "$TERM" ] && clear 2> /dev/null
}

# ----------------------------------------------------------------------------
# Prompt user for input.
# ----------------------------------------------------------------------------
prompt() {
	echo -e "\n$*\c"
	read CMD rest
	return 0
}

# ----------------------------------------------------------------------------
# Pause.
# ----------------------------------------------------------------------------
pause() {
	[ $# -ne 0 ] && echo -e $*
	echo -e "Press [Enter] to continue...\c"
	read tmp
	return 0
}

# ----------------------------------------------------------------------------
# Get Yes/No
# ----------------------------------------------------------------------------
getyn() {
	while	echo -e "$* (y/n) \c" >&2
	do	read yn rest
		case $yn in
			[yY])	return 0
 				;;
			[nN])	return 1
				;;
			*)	echo -e "\nPlease answer y or n" >&2
				;;
		esac
	done
}

# ----------------------------------------------------------------------------
# Select an item from the list.
# Return:	0 - selection is in $SEL
#		1 - quit or empty list
# ----------------------------------------------------------------------------
select_list() {
  cnt=0
  SEL=

  [ $# -eq 0 ] && return 1
  for option in $*
  do
    cnt=`expr $cnt + 1`
    echo -e "\t$cnt) $option\c"
    [ $# -lt 16 -o `expr $cnt % 2` -eq 0 ] && echo ""
  done
  echo -e "\tq) quit\n"

  while echo -e "Please enter your selection (1 .. $cnt or q) ->\c"
  do
    read tmp rest
    case ${tmp:="0"} in
      q|Q)	return 1
		;;
      [0-9]|[0-9][0-9])
		[ "$tmp" -ge 1 -a "$tmp" -le "$cnt" ] 2>/dev/null && {
		  until [ "$tmp" = 1 ]
		  do
		    shift
		    tmp=`expr $tmp - 1 2>/dev/null`
		  done
		  SEL=$1
		  return 0
		}
		;;
    esac
  done
}

# ----------------------------------------------------------------------------
# Check to see if a value belongs to the list.
# Return:	0 - yes
#		1 - no
# ----------------------------------------------------------------------------
check_list() {
	val=$1
	shift
	for i in $*
	do [ "$val" = "$i" ] && return 1
	done
	return 0
}

# ----------------------------------------------------------------------------
# Display error message.
# ----------------------------------------------------------------------------
error() {
	echo -e "\nError: $*!"
	return 0
}

# ----------------------------------------------------------------------------
# Display banner.
# ----------------------------------------------------------------------------
banner() {
	clearscr
	cat << BANNER
	----------------------------------------------------------
	    Sangoma WANPIPE v$WANPIPE_VERSION (tm) Configuration Script.
	    Copyright (c) 1995-1996, Sangoma Technologies Inc.
	----------------------------------------------------------

BANNER
	return 0
}

# ----------------------------------------------------------------------------
# Select adapter I/O port address.
# ----------------------------------------------------------------------------
sel_ioport() {
  until
    banner
    cat << ENDOFTEXT
	Each SDLA card needs 3 to 4 consecutive I/O port addresses for
	its operation.  These ports are used by the adapter exclusively
	and can not be shared with any other hardware installed in your
	system.  Make sure the jumpers on the board are set properly!

	Please select base I/O port address for this adapter:

ENDOFTEXT

    case ${WRK_TYPE} in
      S502A | S502E)
		select_list ${S502_PORT_OPT} || return 1
		;;
      S503)
		select_list ${S503_PORT_OPT} || return 1
		;;
      S508)
		select_list ${S508_PORT_OPT} || return 1
		;;
      *)
		error "Adapter type ${WRK_TYPE} not suppored"
		pause ""
		return 1
		;; 
    esac
    check_list ${SEL} ${CONF_PORTS}
  do
    error "I/O port conflict"
    pause ""
  done
}

# ----------------------------------------------------------------------------
# Select adapter shared memory window base address.
# ----------------------------------------------------------------------------
sel_memaddr() {
  banner
  cat << ENDOFTEXT
	Each SDLA card uses 8 kilobytes memory window to exchange data
	with PC.  This memory region is used only when adapter is
	initialized and can not be shared with other hardware.  When
	adapter is shut down the memory region is released and can be
	used by other hardware.

	You can select memory region base address from an options list
	or you can have the driver select one for you automatically
	at initialization time (recommended).

ENDOFTEXT

  if getyn "Woud you like to use autimatic memory address selection"
  then
    SEL="auto"
    return 0
  fi

  until
    banner
    echo -e "\tPlease select memory base address:"
    case ${WRK_TYPE} in
      S502A)	select_list ${S502A_MEM_OPT} || return 1
		;;
      S502E | S503 | S508)
		select_list ${S502E_MEM_OPT} || return 1
		;;
      *)	error "Adapter type ${WRK_TYPE} not suppored"
		pause ""
		return 1
		;; 
    esac
    check_list ${SEL} ${CONF_MEMS}
  do
    error "Memory address conflict"
    pause ""
  done
}

# ----------------------------------------------------------------------------
# Select adapter IRQ level.
# ----------------------------------------------------------------------------
sel_irq() {
  if [ "${WRK_TYPE}" = "S502A" ]
  then
    SEL="polled"
    return 0
  fi

  until
    banner
    cat << ENDOFTEXT
	Each SDLA card should be assigned unique interrupt request
	level (IRQ).  This resource is allocated only when adapter
	is initialized.  When it is shut down the same IRQ line can
	be used by other hardware.

	Please select IRQ level for this adapter:

ENDOFTEXT

    case ${WRK_TYPE} in
      S502E)	select_list ${S502_IRQ_OPT} || return 1
		;;
      S503)	select_list ${S503_IRQ_OPT} || return 1
		;;
      S508)	select_list ${S508_IRQ_OPT} || return 1
		;;
      *)	error "Adapter type ${WRK_TYPE} not suppored"
		pause ""
		return 1
		;; 
    esac
    check_list ${SEL} ${CONF_IRQS}
  do
    error "IRQ conflict"
    pause ""
  done
}

# ----------------------------------------------------------------------------
# Select adapter CPU clock rate.
# ----------------------------------------------------------------------------
sel_cpuclock() {
  if [ "${WRK_TYPE}" = "S508" ]
  then
    SEL="default"
    return 0
  fi

  banner 
  cat << ENDOFTEXT
	SDLA cards can be shipped with different chip sets running
	at different clock rates.  This option is not configurable
	by user, however you should select actual adapter's CPU
	clock rate for the SDLA driver to operate properly.

	Please select adapter's CPU clock speed (in kHz):

ENDOFTEXT
  case ${WRK_TYPE} in
    S502A | S502E | S503)
		select_list ${S502_CLK_OPT} || return 0
		;;
    *)		error "Adapter type ${WRK_TYPE} not suppored"
		pause ""
		return 0
		;; 
  esac
}

# ----------------------------------------------------------------------------
# Add Adapter.
# ----------------------------------------------------------------------------
add_adapter() {

  banner
  if [ "${CONF_UNITS}" -ge 8 ]
  then
    error "Maximum number of cards exceeded"
    pause ""
    return 0
  fi

  until

    # Select device node.
    echo -e "\tSelect device node:\n"
    select_list ${SDLA_NODES} || return 0
    WRK_NODE=${SEL}

    # Select adapter type.
    banner
    echo -e "\tSelect adapter type:\n"
    select_list ${SDLA_TYPE_OPT} || return 0
    WRK_TYPE=${SEL}

    # Select I/O port.
    sel_ioport ${WRK_TYPE} || return 0
    WRK_PORT=${SEL}

    # Select memory base address.
    sel_memaddr ${WRK_TYPE} || return 0
    WRK_MEM=${SEL}

    # Select IRQ level.
    sel_irq ${WRK_TYPE} || return 0
    WRK_IRQ=${SEL}

    # Select CPU clock rate.
    sel_cpuclock ${WRK_TYPE} || return 0
    WRK_CLK=${SEL}

    # Confirm selection.
    banner
    echo -e "\tYou have selected the following options:\n"
    echo -e "\tNode name:      /dev/${WRK_NODE}"
    echo -e "\tAdapter type:   ${WRK_TYPE}"
    echo -e "\tI/O port base:  ${WRK_PORT}"
    echo -e "\tMemory base:    ${WRK_MEM}"
    echo -e "\tIRQ level:      ${WRK_IRQ}"
    echo -e "\tCPU clock, kHz: ${WRK_CLK}"
    getyn "\nIs this correct?"
  do
    banner
  done

  # Modify configuration file
  [ "$WRK_MEM" = "auto" ] && WRK_MEM="-"
  [ "$WRK_IRQ" = "polled" ] && WRK_IRQ="-"
  [ "$WRK_CLK" = "default" ] && WRK_CLK="-"
  echo -e "${WRK_NODE}\
	${WRK_TYPE}\
	${WRK_PORT}\
	${WRK_MEM}\
	${WRK_IRQ}\
	${WRK_CLK}\
	-		-" >> $SDLACONF

  # Update current configuration data.
  get_config $SDLACONF
  APPLY=1
  return 0
}

# ----------------------------------------------------------------------------
# Delete Adapter.
# ----------------------------------------------------------------------------
del_adapter() {

  banner
  if [ "$CONF_UNITS" -eq 0 ]
  then
    echo -e "\tNo cards configured!"
    pause ""
    return 0
  fi

  until
    echo -e "\tSelect adapter node to remove:"
    select_list $CONF_NODES || return 0
    WRK_NODE=$SEL

    # Get configuration for selected adapter.
    while read NODE TYPE PORT MEM IRQ CLK SFM BIND rest
    do [ "$NODE" = "$WRK_NODE" ] && break
    done < $SDLACONF

    [ "$NODE" = "$WRK_NODE" ] || {
      error "Configuration for node $WRK_NODE not found"
      pause ""
      return 0
    }

    # Confirm selection.
    banner
    echo -e "\tYou are about to remove adapter:\n"
    echo -e "\tdevice node:   /dev/$NODE"
    echo -e "\tadapter type:  $TYPE"
    echo -e "\tI/O port:      $PORT"
    echo -e "\tIRQ level:     $IRQ"
    echo -e "\tBound to:      $BIND"
    getyn "\nIs this correct?"
  do
    banner
  done

  # Edit configuration file.
  cp $SDLACONF $TMPFILE1
  sed -e '/'${WRK_NODE}'/d' ${TMPFILE1} > ${SDLACONF}

  # Update current configuration data.
  get_config $SDLACONF
  APPLY=1
  return 0
}

# ----------------------------------------------------------------------------
# Bind Adapter To Protocol-Specific Module.
# ----------------------------------------------------------------------------
bind_adapter() {

  banner
  if [ -z "$SDLA_AVAIL" ]
  then
    echo -e "\tNo configured SDLA cards available!"
    pause ""
    return 0
  fi

  # Select adapter to bind.
  echo -e "\tSelect SDLA card to bind:\n"
  select_list $SDLA_AVAIL || return 0
  WRK_NODE=$SEL

  # Get configuration for selected adapter.
  while read NODE TYPE PORT MEM IRQ CLK SFM BIND rest
  do [ "$NODE" = "$WRK_NODE" ] && break
  done < $SDLACONF

  [ "$NODE" = "$WRK_NODE" ] || {
    error "Configuration for node $WRK_NODE not found"
    pause ""
    return 0
  }

  # Select protocol to bind.
  while
    banner
    echo -e "\tSelect WANPIPE protocol:\n"
    echo -e "\t1) Frame Relay (FLIP)"
    echo -e "\t2) Synchronous PPP (SPPP)"
    echo -e "\tq) Quit"
    prompt "Please enter your selection (1 .. 3 or q) ->"
    case $CMD in
      1)	BIND="flip"
		case $TYPE in
		  S502E | S503)
			SFM=fr502.sfm
			;;
		  S508)
			SFM=fr508.sfm
			;;
		  *)	error "Adapter type $TYPE not supported"
			pause ""
			return 0
			;;
		esac
		break
		;;
      2)	BIND="sppp"
		case $TYPE in
		  S502E | S503)
			SFM=ppp502.sfm
			;;
		  S508) SFM=ppp508.sfm
			;;
		  *)	error "Adapter type $TYPE not supported"
			pause ""
			return 0
			;;
		esac
		break
		;;
      q|Q)	return 0
		;;
    esac
  do echo ""; done

  # Edit configuration file.
  cp $SDLACONF $TMPFILE1
  sed '/^'$WRK_NODE'/c\
'$NODE\	$TYPE\	$PORT\	$MEM\	$IRQ\	$CLK\	$SFM\	$BIND'
' $TMPFILE1 > $SDLACONF

  # Run protocol-specific configuration script.
  [ -f "${CONFSCRDIR}/${BIND}" ] && {
    banner
    cat << ENDOFTEXT
	You have bound adapter /dev/$NODE to the protocol module
	$BIND.  This protocol module provides a script for
	configuring WAN links.  You can configure links now or do
	it later by selecting 'configure link' option from the
	main menu.

	For additional information on configuring links for the
	protocol module $BIND please refer to the appropriate
	section of WANPIPE User's Manual.

ENDOFTEXT
    getyn "\nWould you like to configure link now" && ${CONFSCRDIR}/${BIND}
  }

  # Remind user to create a link-level configuration file.
  [ -f "${CONFSCRDIR}/${BIND}" ] && {
    banner
    cat << ENDOFTEXT
	To complete configuration you have to create or edit link-level
	configuration file $WANPIPE_HOME/cfg/$BIND.N, where N is a minor
	device number of the device $NODE.

	Sample configuration files can be found in $WANPIPE_HOME/sample
	directory.  Please refer to WANPIPE User's Manual for more
	information.

ENDOFTEXT
    pause ""
  }

  # Update current configuration data.
  get_config $SDLACONF
  APPLY=1
  return 0
}

# ----------------------------------------------------------------------------
# Unbind Adapter From Protocol-Specific Module.
# ----------------------------------------------------------------------------
unbind_adapter() {

  banner
  if [ -z "$SDLA_BOUND" ]
  then
    echo -e "\tThere is no SDLA cards bound to protocol-specific modules!"
    pause ""
    return 0
  fi

  until
    echo -e "\tSelect SDLA card to unbind:\n"
    select_list $SDLA_BOUND || return 0
    WRK_NODE=$SEL

    # Get configuration for selected adapter.
    while read NODE TYPE PORT MEM IRQ CLK SFM BIND rest
    do [ "$NODE" = "$WRK_NODE" ] && break
    done < $SDLACONF

    [ "$NODE" = "$WRK_NODE" ] || {
      error "Configuration record for node $WRK_NODE not found"
      pause ""
      return 0
    }

    # Confirm selection.
    banner
    echo -e "\tYou are about to unbind adapter:\n"
    echo -e "\tdevice node:         /dev/$NODE"
    echo -e "\tadapter type:        $TYPE"
    echo -e "\tI/O port:            $PORT"
    echo -e "\tIRQ level:           $IRQ"
    echo -e "\tCurrently bound to:  $BIND"
    getyn "\nIs this correct?"
  do
    banner
  done

  # Edit configuration file.
  cp $SDLACONF $TMPFILE1
  sed '/^'$WRK_NODE'/c\
'$NODE\	$TYPE\	$PORT\	$MEM\	$IRQ\	$CLK\	\-\	\	\-' 
' $TMPFILE1 > $SDLACONF

  # Update current configuration data.
  get_config $SDLACONF
  APPLY=1
  return 0
}

# ----------------------------------------------------------------------------
# Configure Link.
# ----------------------------------------------------------------------------
configure_link() {

  banner
  if [ -z "$SDLA_BOUND" ]
  then
    echo -e "\tThere is no SDLA cards bound to protocol-specific modules!"
    pause ""
    return 0
  fi

  echo -e "\tSelect SDLA card:\n"
  select_list $SDLA_BOUND || return 0
  WRK_NODE=$SEL

  # Get configuration for selected adapter.
  while read NODE TYPE PORT MEM IRQ CLK SFM BIND rest
  do [ "$NODE" = "$WRK_NODE" ] && break
  done < $SDLACONF

  [ "$NODE" = "$WRK_NODE" ] || {
    error "Configuration record for node $WRK_NODE not found"
    pause ""
    return 0
  }

  # Run protocol-specific configuration script.
  if [ -f "${CONFSCRDIR}/${BIND}" ]
  then ${CONFSCRDIR}/${BIND}
  else
    banner
    cat << ENDOFTEXT
	You have selected to configure link for adapter /dev/$NODE
	currently bound to the protocol module $BIND.

	There is no configuration script found for this protocol
	module.  Please refer to appropriate section of WANPIPE
	User's Manual for information on how to configure links
	for the protocol module $BIND.
ENDOFTEXT
    pause ""
  fi

  return 0
}

# ----------------------------------------------------------------------------
# Show Adapter Configuration.
# ----------------------------------------------------------------------------
show_adapter() {

  banner
  if [ "$CONF_UNITS" -eq 0 ]
  then echo -e "\tNo cards configured!"
  else
    echo -e "Currently configured $CONF_UNITS SDLA card(s):\n"
    echo -e "device\ttype\tport\tmemory\tirq\tspeed\tfirmware\tbind" 
    echo -e "------\t----\t----\t------\t---\t-----\t--------\t----"
    grep -v "^#" $SDLACONF
  fi
  pause ""
  return 0
}

# ----------------------------------------------------------------------------
# Apply Changes.
# ----------------------------------------------------------------------------
apply_changes() {

  banner
  cat << ENDOFTEXT
	WANPIPE configuration file has been successfully updated.  For
	the configuration changes to take an effect you have to restart
	WANPIPE now.  If WANPIPE initialization scripts have been
	installed on your system you may simply reboot it.  Otherwise
	restart WANPIPE by executing the following commands:

		${WANPIPE_HOME}/wanpipe stop
		${WANPIPE_HOME}/wanpipe start

ENDOFTEXT
  return 0
}

# ----------------------------------------------------------------------------
# Main Menu.
# ----------------------------------------------------------------------------
main_menu() {
  while
    banner
    echo -e "\t1) configure adapter"
    echo -e "\t2) remove adapter"
    echo -e "\t3) bind adapter"
    echo -e "\t4) unbind adapter"
    echo -e "\t5) show configuration"
    echo -e "\t6) configure link"
    echo -e "\tq) quit"
    prompt "Please enter your selection (1 .. 6 or q) ->"
    case $CMD in
      1)	add_adapter 	;;
      2)	del_adapter	;;
      3)	bind_adapter 	;;
      4)	unbind_adapter	;;
      5)	show_adapter	;;
      6)	configure_link	;;
      q|Q)	if [ "${APPLY}" -eq 0 ]
		then clearscr
		else apply_changes
		fi
		break
		;;
    esac
  do echo ""; done
  return 0
}

# ----------------------------------------------------------------------------
# Get current SDLA configuration.
# Args:	$1	- configuration file name
# ----------------------------------------------------------------------------
get_config() {

  CONF_UNITS=0
  CONF_NODES=
  CONF_TYPES=
  CONF_PORTS=
  CONF_MEMS=
  CONF_IRQS=
  CONF_CLKS=
  CONF_SFMS=
  CONF_BINDS=
  SDLA_NODES=
  SDLA_AVAIL=
  SDLA_BOUND=

  while read NODE TYPE PORT MEM IRQ CLK SFM BIND rest
  do
    if [ -c "/dev/$NODE" ]
    then
      CONF_UNITS=`expr $CONF_UNITS + 1`
      CONF_NODES="$CONF_NODES $NODE"
      CONF_TYPES="$CONF_TYPES $TYPE"
      CONF_PORTS="$CONF_PORTS $PORT"
      CONF_MEMS="$CONF_MEMS $MEM"
      CONF_IRQS="$CONF_IRQS $IRQ"
      CONF_CLKS="$CONF_CLKS $CLK"
      CONF_SFMS="$CONF_SFMS $SFM"
      CONF_BINDS="$CONF_BIND $BIND"
      if [ "$BIND" = "-" ]
        then SDLA_AVAIL="$SDLA_AVAIL $NODE"
        else SDLA_BOUND="$SDLA_BOUND $NODE"
      fi
    fi
  done < $1

  # Build a list of available nodes.
  tmp=`pwd`
  cd /dev
  for j in ${DEVNAME}*
  do
    [ -c "$j" ] && check_list $j ${CONF_NODES} && SDLA_NODES="${SDLA_NODES} $j"
  done
  cd $tmp

  return 0
}

# ----------------------------------------------------------------------------
# Prepare configuration file.
# ----------------------------------------------------------------------------
prepare() {

	# If old configuration file exist, convert it to the new format.
	[ -f "$OLDCONF" ] && {
		mv $OLDCONF $SDLACONF
		return 0
	}

	[ -f "$SDLACONF" ] || cat > $SDLACONF <<-ENDOFTEXT
	# Sangoma Synchronous Data Link Adapter (SDLA) configuration file
	# --------------------------------------------------------------------
	# dev	type	port	memory	irq	speed	firmware	bind
	# ---	----	----	------	---	-----	--------	----
	# sdla0	S502E	360	C8000	7	7200	fr502.sfm	flip
ENDOFTEXT

	return 0
}

# ----------------------------------------------------------------------------
# Remove temporary files, etc.
# ----------------------------------------------------------------------------
cleanup() {
	# remove all temporary files.
	rm -f /tmp/T$$.* 2> /dev/null
	return 0
}

###### MAIN ##################################################################
# set -x

# Check user permissions.
[ "${LOGNAME}" = root ] || {
	error "You should be logged in as a superuser to run this script"
	exit 1
}

# Read meta-configuration file.
[ -f $WANPIPE_RC ] || {
	error "Configuration file $WANPIPE_RC not found"
	exit 1
}
. $WANPIPE_RC

# Set default configuration.
WANPIPE_VERSION=${WANPIPE_VERSION:=0.0.0}
WANPIPE_HOME=${WANPIPE_HOME:=/usr/lib/wanpipe}
WANPIPE_LOG=${WANPIPE_LOG:=/var/log/wanpipe}
WANPIPE_LOCK=${WANPIPE_LOCK:=/var/lock/wanpipe}

CONFSCRDIR="${WANPIPE_HOME}/conf"
MODDIR="${WANPIPE_HOME}/mod"
SFMDIR="${WANPIPE_HOME}/sfm"

trap '' 2
prepare
get_config ${SDLACONF}
main_menu
cleanup
exit 0
