#!/bin/sh
#
# Copyright (c) 2003 Linuxant inc.
#
# NOTE: The use and distribution of this software is governed by the terms in
# the file LICENSE, which is included in the package. You must read this and
# agree to these terms before using or distributing this software.
#
# This script handles all aspects of installing and configuring the
# @CNXTDRVDSC@ driver under Linux.
#
# It tries to be as distribution-neutral as possible.

ask_yesno()
{
	$automode && return $2

	while true; do
		echo -n "$1"
		read answer
		case "${answer}" in
		[yY] | [yY][eE][sS])
			return 0
			;;
		[nN] | [nN][oO])
			return 1
			;;
		"")
			return $2
			;;
		*)
			echo "Enter 'yes' or 'no'"
			;;
		esac
	done
}

get_region_list()
{
	(cd ${cnxtnvmdir}/${parm_hwprofile[${unit}]}/Region/ && grep '^' ????_NAME) | \
		sed -e 's/ /_/g' -e 's/^\(....\)_NAME:"\(.*\)"/\2 \1/' | sort
}

T35c_to_name()
{
	sed -e 's/"//g' -e 's/ /_/g' \
		< ${cnxtnvmdir}/${parm_hwprofile[${unit}]}/Region/${1}_NAME
}

join_comma_wrap_lines()
{
	${AWK} '{
			if (NR != 1) printf ", "
			printf "%s",$1
		}
		END { print ""}' | fold -s -w78
}

ask_region()
{
	get_region_list > /tmp/cnxtconf.sup.$$

	while true; do
		if [ -n "${setregion}" ]; then
			answer="${setregion}"
		elif ${automode}; then
			answer="${region}"
		else
			echo ""
			echo -n "Please enter region name for modem unit ${unit} [$region]: "
			read answer
			case "${answer}" in
			"" | *"[ 	]"*)
				answer="${region}"
				;;
			*)
				answer="`echo \"${answer}\" | tr '[a-z ]' '[A-Z_]'`"
				;;
			esac
		fi

		if grep -i "^${answer}\** " /tmp/cnxtconf.sup.$$ > /tmp/cnxtconf.ncty.$$
		then
			read region regioncode < /tmp/cnxtconf.ncty.$$
			rm -f /tmp/cnxtconf.sup.$$ /tmp/cnxtconf.ncty.$$
			return 0
		else
			echo ""
			echo "ERROR: Region \"${answer}\" is not supported."

			if ${automode}; then
				rm -f /tmp/cnxtconf.sup.$$ /tmp/cnxtconf.ncty.$$
				return 1
			fi
			setregion=""
			echo ""
			echo "Available countries: "
			echo ""

			grep -v '\*' /tmp/cnxtconf.sup.$$ | join_comma_wrap_lines
			echo ""
			grep '\*' /tmp/cnxtconf.sup.$$ | tr -d '\*' | join_comma_wrap_lines

		fi
	done
}

autodetect_region()
{
	# Try to guess what region we're in, using the timezone settings

	localtime_size="`/bin/ls -lL /etc/localtime 2>/dev/null | ${AWK} '{print $5}'`"

	if ! [ ${localtime_size} -gt 0 ]; then
		return 1
	fi

	zoneinfo_dir=/usr/share/zoneinfo

	if [ ! -d ${zoneinfo_dir} -o ! -f ${zoneinfo_dir}/zone.tab ]; then
		return 1
	fi

	# The following maps ISO-3166 country codes to T.35 codes
	iso_AR=0007 # ARGENTINA
	iso_AU=0009 # AUSTRALIA
	iso_AT=000A # AUSTRIA
	iso_BH=000C # BAHRAIN
	iso_BD=000D # BANGLADESH
	iso_BE=000F # BELGIUM
	iso_BO=0014 # BOLIVIA
	iso_BR=0016 # BRAZIL
	iso_BN=001A # BRUNEI
	iso_BG=001B # BULGARIA
	iso_CA=0020 # CANADA
	iso_CL=0025 # CHILE
	iso_CN=0026 # CHINA
	iso_CO=0027 # COLOMBIA
	iso_CR=002B # COSTA_RICA
	iso_HR=00FA # CROATIA
	iso_CY=002D # CYPRUS
	iso_CZ=002E # CZECH
	iso_DK=0031 # DENMARK
	iso_DO=0033 # DOMINICAN_REPUBLIC
	iso_EC=0035 # ECUADOR
	iso_EG=0036 # EGYPT
	iso_SV=0037 # EL_SALVADOR
	iso_FI=003C # FINLAND
	iso_FR=003D # FRANCE
	iso_DE=0004 # GERMANY
	iso_GR=0046 # GREECE
	iso_GT=0049 # GUATEMALA
	iso_HT=004E # HAITI
	iso_HN=004F # HONDURAS
	iso_HK=0050 # HONG_KONG
	iso_HU=0051 # HUNGARY
	iso_IS=0052 # ICELAND
	iso_IN=0053 # INDIA
	iso_ID=0054 # INDONESIA
	iso_IE=0057 # IRELAND
	iso_IL=0058 # ISRAEL
	iso_IT=0059 # ITALY
	iso_JP=0000 # JAPAN
	iso_KR=0061 # KOREA
	iso_KW=0062 # KUWAIT
	iso_LA=0063 # LAOS
	iso_LV=00F8 # LATVIA
	iso_LI=0068 # LIECHTENSTEIN
	iso_LU=0069 # LUXEMBOURG
	iso_MO=006A # MACAO
	iso_MY=006C # MALAYSIA
	iso_MT=0070 # MALTA
	iso_MX=0073 # MEXICO
	iso_MN=001C # MYANMAR
	iso_NL=007B # NETHERLANDS
	iso_NZ=007E # NEW_ZEALAND
	iso_NO=0082 # NORWAY
	iso_PK=0084 # PAKISTAN
	iso_PA=0085 # PANAMA
	iso_PY=0087 # PARAGUAY
	iso_PE=0088 # PERU
	iso_PH=0089 # PHILIPPINES
	iso_PL=008A # POLAND
	iso_PT=008B # PORTUGAL
	iso_PR=008C # PUERTO_RICO
	iso_RO=008E # ROMANIA
	iso_RU=00B8 # RUSSIA
	iso_SA=0098 # SAUDI_ARABIA
	iso_SG=009C # SINGAPORE
	iso_SK=00FB # SLOVAKIA
	iso_SI=00FC # SLOVENIA
	iso_ZA=009F # SOUTH_AFRICA
	iso_ES=00A0 # SPAIN
	iso_LK=00A1 # SRI_LANKA
	iso_SE=00A5 # SWEDEN
	iso_CH=00A6 # SWITZERLAND
	iso_TW=00FE # TAIWAN
	iso_TH=00A9 # THAILAND
	iso_TR=00AE # TURKEY
	iso_GB=00B4 # UK
	iso_UA=00B2 # UKRAINE
	iso_AE=00B3 # UNITED_ARAB_EMIRATES
	iso_UY=00B7 # URUGUAY
	iso_US=00B5 # USA
	iso_VE=00BB # VENEZUELA
	iso_VN=00BC # VIETNAM

	(
		cd ${zoneinfo_dir} 2>/dev/null || return 1
		find . -type f -size "${localtime_size}"c -print | sed 's@^\./@@' | \
			while read file; do
				cmp -s /etc/localtime $file || continue
# in the egrep and sed regular expressions below, it is very important to
# have tabs, not spaces
				egrep "	$file(	.*|\$)" ${zoneinfo_dir}/zone.tab
			done | sed -n '/^[^#]/s/	.*//p' | sort | uniq | \
				while read code; do
					eval "echo \${iso_${code}}"
				done | sort | uniq
		return 0
	)
}

configure_region()
{
	region="${setregion}"
	if [ -z "${region}" -a -n "${parm_regionName[${unit}]}" ]; then
		region="${parm_regionName[${unit}]}"
	fi

	if [ -z "${region}" -o "${region}" = "AUTO" ]; then
		if [ -z "${autoregion}" ]; then
			regiont35="`autodetect_region | head -1`"
			echo ""
			if [ -z "${regiont35}" ]; then
				echo "Unable to determine region, defaulting to \"USA\""
				autoregion=USA
			else
				autoregion="`T35c_to_name \"${regiont35}\"`"
				echo "Automatically guessed region (using timezone): \"${autoregion}\""
			fi
		fi
		region="${autoregion}"
		if [ "${setregion}" = "AUTO" ]; then
			setregion="${autoregion}"
		fi
	fi

	ask_region || return 1

	parm_regionName[${unit}]="${region}"
	parm_regionT35c[${unit}]="${regioncode}"

	if ! @CNXTTARGET@stop >/dev/null 2>&1; then
		echo ""
		echo "Unable to unload driver to configure region; modem in use?"
		echo "try configuring it manually with \"AT+GCI=${parm_regionT35c[${unit}]}\""
	fi
	sleep 1

	echo ""
	echo "Setting region for modem unit ${unit}: \"${parm_regionName[${unit}]}\""
	touch ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/.region_set
	echo "${parm_regionT35c[${unit}]}" > ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/COUNTRY_CODE
	res=$?

	return ${res}
}

# Convert a key from display to internal format
# The md5sum is used for input verification.
disptokey()
{
	k="`echo \"$1\" | tr '[a-z]' '[A-Z]' | sed 's/FREE/00000000/' | tr -d -c '[0-9A-F\012]'`"
	case $k in
	00000000)
		echo "$k"
		;;
	????????????)
		key="`echo \"$k\" | cut -c1-8`"
		if [ "`echo \"${key}\" | md5sum | cut -c1-4 | tr '[a-f]' '[A-F]'`" = "`echo \"$k\" | cut -c9-12`" ]; then
			echo "${key}"
		else
			echo "checksum error"
		fi
		;;
	*)
		echo "format error"
		;;
	esac
}

# Convert a key from internal to display format
# The md5sum is generated for input verification.
keytodisp()
{
	key="$1"

	if [ "${key}" = "00000000" ]; then
		echo FREE
		return 0
	fi

	sum="`echo \"${key}\" | md5sum | cut -c1-4 | tr '[a-f]' '[A-F]'`"

	echo "${key}${sum}" | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)$/\1-\2-\3-\4-\5-\6/'
}

ask_license()
{
	while true; do
		if [ -n "${setlicense}" ]; then
			answer="`disptokey \"${setlicense}\"`"
		elif ${automode}; then
			answer="${license}"
		else
			echo ""

			echo "License keys can be obtained from http://www.linuxant.com/"
			echo "Without one, the modem operates in FREE mode (max 14.4Kbps data only, no fax)"
			echo ""
			echo "The registration ID for modem unit ${unit} is: ${parm_hwid[${unit}]}"
			echo ""
			echo -n "Please enter license key [`keytodisp \"$license\"`]: "
			read answer
			case "${answer}" in
			"" | *"[ 	]"*)
				answer="${license}"
				;;
			*)
				answer="`disptokey \"${answer}\"`"
				;;
			esac
		fi

		case "${answer}" in
		[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F])
			license="${answer}"
			return 0
			;;
		*)
			echo ""
			echo "ERROR: Invalid license key: \"${answer}\"."
			if ${automode}; then
				return 1
			fi
			setlicense=""
			;;
		esac
	done
}

ask_licowner()
{
	while true; do
		if [ -n "${setlicowner}" ]; then
			answer="${setlicowner}"
		elif ${automode}; then
			if [ -z "${licowner}" ]; then
				return 1
			fi
			answer="${licowner}"
		else
			echo ""
			echo "Note: we respect user privacy. Email addresses are not communicated"
			echo "nor used for any purpose other than to manage licenses!"
			echo ""

			echo -n "Please enter your email address [$licowner]: "
			read answer
			case "${answer}" in
			"" | *"[ 	]"*)
				answer="${licowner}"
				;;
			*)
				answer="`echo \"${answer}\" | tr '[A-Z]' '[a-z]' | tr -d '[ 	<>\012]'`"
				;;
			esac
		fi

		case "${answer}" in
		?*@?*.?*)
			licowner="${answer}"
			return 0
			;;
		*)
			if ! ${automode} || [ "${answer}" != "unknown" ]; then
				echo ""
				echo "ERROR: Invalid email address format: \"${answer}\"."
			fi
			if ${automode}; then
				return 1
			fi
			setlicowner=""
			;;
		esac
	done
}

needfullversion() {
	echo ""
	echo "This is the free version of the driver, limited to 14.4Kbps data only."
	echo "For 56K modem and FAX functionality, please upgrade to the full version"
	echo "available from http://www.linuxant.com/"
}

configure_license()
{
	if ${isfreeversion}; then
		needfullversion
		return 1
	fi

	licowner="${setlicowner}"
	if [ -z "${licowner}" -a -n "${parm_licowner[${unit}]}" ]; then
		licowner="${parm_licowner[${unit}]}"
		if [ "${licowner}" = "unknown" ]; then
			licowner="${lastowner}"
		fi
	fi

	case "${setlicense}" in
	?*/?*)
		setlicowner="`echo \"${setlicense}\" | ${AWK} -F/ '{print $1}'`"
		setlicense="`echo \"${setlicense}\" | ${AWK} -F/ '{print $2}'`"
		;;
	*)
		;;
	esac

	if [ -z "${setlicense}" ]; then
		if [ -n "${parm_lickey[${unit}]}" ]; then
			license="${parm_lickey[${unit}]}"
		else
			license=""
		fi
	else
		license="`disptokey \"${setlicense}\"`"
	fi

	ask_licowner || return 1
	parm_licowner[${unit}]="${licowner}"

	ask_license || return 1
	parm_lickey[${unit}]="${license}"

	if ! @CNXTTARGET@stop >/dev/null 2>&1; then
		echo ""
		echo "Unable to unload driver to configure license; modem in use?"
		echo "\"License status\" information might not be up to date."
	fi
	sleep 1

	echo ""
	echo "Setting license for modem unit ${unit}: \"${parm_licowner[${unit}]}/`keytodisp \"${parm_lickey[${unit}]}\"`\""
	echo "\"${parm_licowner[${unit}]}\"" > ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_OWNER
	[ -n "${parm_licowner[${unit}]}" -a "${parm_licowner[${unit}]}" != "unknown" ] && lastowner="${parm_licowner[${unit}]}"
	echo "${parm_lickey[${unit}]}" > ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_KEY
	rereadparms=true
	res=$?

	return ${res}
}

get_hwprofile_list()
{
	echo "auto"
	(cd ${cnxtnvmdir} && find . -follow -type d -maxdepth 1 -print) | \
		egrep -v '^\.(\/dynamic)?$' | sed 's@^\./@@' | sort
}

ask_hwprofile()
{
	get_hwprofile_list > /tmp/cnxtconf.sup.$$

	while true; do
		if [ -n "${sethwprofile}" ]; then
			answer="${sethwprofile}"
		elif ${automode}; then
			answer="${hwprofile}"
		else
			echo ""
			echo "Available hardware profiles: "
			echo ""

			${AWK} '{
					if (NR != 1) printf ", "
					if (NR % 5 == 0) print ""
					printf "%s",$1
				}
				END { print ""}' </tmp/cnxtconf.sup.$$

			echo ""
			echo "WARNING: choosing an incorrect profile may make the modem unusable"
			echo "or cause system crashes. Use with extreme care!"
			echo ""
			echo -n "Please enter hardware profile name for modem unit ${unit} [$hwprofile]: "
			read answer
			case "${answer}" in
			"" | *"[ 	]"*)
				answer="${hwprofile}"
				;;
			*)
				;;
			esac
		fi

		if grep -q -i "^${answer}$" /tmp/cnxtconf.sup.$$
		then
			hwprofile="${answer}"
			rm -f /tmp/cnxtconf.sup.$$
			return 0
		else
			echo ""
			echo "ERROR: \"${answer}\" is not available."

			if ${automode}; then
				rm -f /tmp/cnxtconf.sup.$$
				return 1
			fi
			sethwprofile=""
		fi
	done
}

configure_hwprofile()
{
	hwprofile="${sethwprofile}"
	if [ -z "${hwprofile}" -a -n "${parm_hwprofile[${unit}]}" ]; then
		if [ -s ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/HARDWARE_PROFILE ]; then
			hwprofile="${parm_hwprofile[${unit}]}"
		else
			hwprofile="auto"
		fi
	fi

	ask_hwprofile || return 1
	parm_hwprofile[${unit}]="${hwprofile}"

	if ! @CNXTTARGET@stop >/dev/null 2>&1; then
		echo ""
		echo "Unable to unload driver to configure hwprofile; modem in use?"
	fi
	sleep 1

	echo ""
	echo "Setting hwprofile for modem unit ${unit}: \"${hwprofile}\""
	if [ "${parm_hwprofile[${unit}]}" = "auto" ]; then
	    rm -f ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/HARDWARE_PROFILE
	    parm_hwprofile[${unit}]="unknown"
	    rereadparms=true
	else
	    echo "\"${parm_hwprofile[${unit}]}\"" > ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/HARDWARE_PROFILE
	fi
	res=$?

	return ${res}
}

use_prebuilt_modules()
{
	rm -f "/lib/modules/${OSKERNVERS}/misc/@CNXTTARGET@"*.${KO}
	if [ ! -d "/lib/modules/${OSKERNVERS}/misc" ]; then
		mkdir -p "/lib/modules/${OSKERNVERS}/misc"
	fi
	ln -s "${cnxtlibdir}/modules/binaries/$1/@CNXTTARGET@"*.${KO} "/lib/modules/${OSKERNVERS}/misc/"
}

files_present()
{
	for f; do
		if [ ! -f "${f}" ]; then
			missing_file="${f}"
			return 1
		fi
	done
}

remove_temp_kernel_tree()
{
	if [ -n "${KERNELORG}" ]; then
		rm -rf "${KERNELSRC}"
		KERNELSRC="${KERNELORG}"
		KERNELORG=""
		return 0
	fi

	return 1
}

create_temp_kernel_tree()
{
	KERNELORG="${KERNELSRC}"
	# get absolute pathname with cd/pwd to ensure that our temp dir
	# is on same filesystem due to use of hardlinks by cp -al
	KERNELSRC="`(cd \"${KERNELORG}\" && /bin/pwd)`-cnxttmp$$"
	rm -rf "${KERNELSRC}"
	if ! cp -al "${KERNELORG}/." "${KERNELSRC}"; then
		remove_temp_kernel_tree
		return 1
	fi

	return 0
}

kernelrebuild_instructions()
{
		echo ""
		echo "First, ensure that the proper kernel source and compiler packages"
		echo "from your distribution vendor and/or the community are installed."
		echo ""
		echo "The Linux kernel can then be reconfigured by running \"make menuconfig\""
		echo "under the kernel source directory (usually /usr/src/linux)."
		echo ""
		echo "Verify that the proper options for your system are selected."
		echo ""
		echo "Then compile and install your new kernel (for more information about"
		echo "this procedure, see the README file under the kernel source directory),"
		echo "reboot the system using the new kernel, and re-run \"@CNXTTARGET@config\"."
}

check_kernel()
{
#	if [ -n "$OSKERNSMP" ]; then
#		echo 1>&2 ""
#		echo 1>&2 "This driver has not been fully tested on SMP kernels."
#		echo 1>&2 "Please report results to <modem.support@linuxant.com>"
#	fi

	case "${OSKERNVERS}" in
	2.2*)
		echo ""
		echo 1>&2 "ERROR: 2.2 kernels are no longer supported by this driver!"
		echo 1>&2 "Please upgrade your Linux distribution or kernel to version 2.4 or 2.6"
		return 1
		;;
	*)
		;;
	esac

	return 0
}

right_version_file()
{
	_versionf="$1"

	FILEKERNELVER="`echo UTS_RELEASE | gcc -E -I"${KERNELSRC}/include" -include "${_versionf}" - | grep '^"' | tr -d '"	 '`"

	[ "${OSKERNVERS}" = "${FILEKERNELVER}" ]
}

update_module_dependencies()
{
	depmod -A -e -u >/tmp/cnxtconf.depmod.$$ 2>&1
	res=$?

	cat 1>&2 /tmp/cnxtconf.depmod.$$

	if [ ${res} -ne 0 ]; then
		# only return error if one of our modules is at cause
		grep -q "@CNXTTARGET@" /tmp/cnxtconf.depmod.$$ || res=0
	fi

	rm -f /tmp/cnxtconf.depmod.$$

	return ${res}
}

recompile_modules()
{
	KERNELSRC=/usr/src/linux
	KERNELORG=""

	if [ -h /lib/modules/${OSKERNVERS}/build -a ! -d /lib/modules/${OSKERNVERS}/build/. ]; then
		echo ""
		echo "ERROR: /lib/modules/${OSKERNVERS}/build points to a missing directory"
		echo ""
		ls -l /lib/modules/${OSKERNVERS}/build
		echo ""
		if rpm -qf /lib/modules/${OSKERNVERS} >/dev/null 2>&1; then
			echo "Please ensure that the kernel-source RPM package is properly installed."
		else
			echo "Please ensure that the kernel-source is properly installed."
		fi
		return 1
	fi

	if [ -d /lib/modules/${OSKERNVERS}/build/include ]; then
		KERNELSRC=/lib/modules/${OSKERNVERS}/build
	elif [ ! -d "${KERNELSRC}" -a -d "/usr/src/kernel-headers-${OSKERNVERS}" ]; then
		# Debian
		KERNELSRC=/usr/src/kernel-headers-${OSKERNVERS}
	elif [ ! -d "${KERNELSRC}" -a -d "/usr/local/src/linux" ]; then
		KERNELSRC=/usr/local/src/linux
	elif [ ! -d "${KERNELSRC}" ]; then
		echo "Please ensure that the kernel-source is properly installed."
		if [ "${OSDISTNAME}" = Debian ]; then
			echo "On Debian, try \"apt-get install kernel-headers-${OSKERNVERS}\""
		fi
	fi
	if ! $automode; then
		echo ""
		echo "Where is the linux source build directory that matches your running kernel?"
		echo -n "[${KERNELSRC}] "
		read answer
		case "${answer}" in
		"")
			;;
		*)
			KERNELSRC="${answer}"
			;;
		esac
	fi

	if [ -e "${KERNELSRC}/scripts/Makefile.build" ]; then
		use_kbuild=true
	else
		use_kbuild=false
	fi

	if ! files_present \
		"${KERNELSRC}/include/linux/autoconf.h" \
		"${KERNELSRC}/include/linux/version.h" ||
		(! ${use_kbuild} && ! files_present "${KERNELSRC}/include/linux/modversions.h"); then
		echo ""
		echo "WARNING: missing file ${missing_file}"
		suspect_tree=true
	elif ! right_version_file "${KERNELSRC}/include/linux/version.h"; then
		echo ""
		echo "WARNING: the kernel version (${FILEKERNELVER}) defined in"
		echo "${KERNELSRC}/include/linux/version.h"
		echo "does not match the currently running kernel (${OSKERNVERS})"
		echo "The cause of this problem is an incorrect kernel source path."
		echo "Please check that ${KERNELSRC} points to the right tree."
		suspect_tree=true
	else
		suspect_tree=false
	fi

	if ${suspect_tree}; then
		echo "The cause of this problem is usually a missing or misconfigured"
		echo "kernel source tree (and sometimes an incorrect directory or symbolic link)."
		# SuSE has copies of autoconf.h and version.h available under /boot
		if [ -d "${KERNELSRC}/include/linux" -a -f /boot/vmlinuz.autoconf.h -a -f /boot/vmlinuz.version.h ] && right_version_file /boot/vmlinuz.version.h && [ -f "${KERNELSRC}/include/linux/modversions.h" ]; then
			echo ""
			echo "However, proper /boot/vmlinuz.{autoconf.h,version.h} were found."
			if ask_yesno "Would you like to try using them (in a temporary kernel tree)? [yes] " 0; then
				if ! create_temp_kernel_tree; then
					echo ""
					echo "Unable to create temporary kernel tree"
					kernelrebuild_instructions
					return 1
				fi
				rm -f "${KERNELSRC}/include/linux/.config" \
						"${KERNELSRC}/include/linux/autoconf.h" \
						"${KERNELSRC}/include/linux/version.h"
				if ! cp -p /boot/vmlinuz.autoconf.h "${KERNELSRC}/include/linux/autoconf.h" || \
					! cp -p /boot/vmlinuz.version.h "${KERNELSRC}/include/linux/version.h"; then
					echo ""
					echo "Unable to copy files to temporary kernel tree"
					remove_temp_kernel_tree
					kernelrebuild_instructions
					return 1
				fi

				# we don't really need .config but it can't hurt if available
				if [ -f /boot/vmlinuz.config ]; then
					cp -p /boot/vmlinuz.config "${KERNELSRC}/include/linux/.config"
				fi
			fi
		fi
	fi

	# are we ok now?
	if [ ! -f "${KERNELSRC}/include/linux/version.h" \
			-o ! -f "${KERNELSRC}/include/linux/autoconf.h" ] || \
			[ ! -f "${KERNELSRC}/include/linux/modversions.h" ] && ! ${use_kbuild}; then
		remove_temp_kernel_tree
		kernelrebuild_instructions
		return 1
	fi

	buildlogf=/tmp/@CNXTTARGET@config-buildlog.txt

	# set FILEKERNELVER if it isn't already
	[ -n "${FILEKERNELVER}" ] || right_version_file "${KERNELSRC}/include/linux/version.h"

	echo ""
	echo "Building modules for kernel ${FILEKERNELVER}, using source directory"
	echo "${KERNELSRC}. Please wait.."

	(cd ${cnxtlibdir}/modules && make "KERNELSRC=${KERNELSRC}" clean minstall) > ${buildlogf} 2>&1
	res=$?

	(cd ${cnxtlibdir}/modules && make "KERNELSRC=${KERNELSRC}" clean) >/dev/null 2>&1

	remove_temp_kernel_tree

	if [ $res -eq 0 ]; then
		rm -f ${buildlogf}
		return 0
	else
		echo ""
		echo "ERROR: Module build failed!"
		echo "Please examine the log file \"${buildlogf}\" to determine why."
		return 1
	fi
}

dcp_supported()
{
	[ "@CNXTDRIVER@" = "hsf" ]
}

diag_supported()
{
	true
}

old_scr_supported()
{
	modinfo -p hsfosspec 2>/dev/null | grep -q scrmajor
}

modules_exist()
{
	files_present "/lib/modules/${OSKERNVERS}/misc/@CNXTTARGET@"*.${KO}
}

remove_kernel_modules()
{
	if modules_exist; then
		echo ""
		echo "Removing @CNXTTARGET@ driver from /lib/modules/${OSKERNVERS}/misc/"
		rm -f "/lib/modules/${OSKERNVERS}/misc/@CNXTTARGET@"*.${KO}
	fi
	return 0
}

binary_modules_avail()
{
	[ -d "${cnxtlibdir}/modules/binaries/$1" ]
}

configure_kernel()
{
	check_kernel || return $?

	if modules_exist; then
		echo ""
		echo "Warning: existing driver modules found under:"
		echo "	/lib/modules/${OSKERNVERS}/misc/"
		if ask_yesno "Would you like to keep using them? [no] " 1; then
			return 0
		fi
	fi

	chosen_binary_modules=""
	if binary_modules_avail "${OSKERNTYPE}/${OSDISTIDNT}/${OSKERNNAME}-${OSKERNVERS}${OSKERNSMP}"; then
		chosen_binary_modules="${OSKERNTYPE}/${OSDISTIDNT}/${OSKERNNAME}-${OSKERNVERS}${OSKERNSMP}"
	fi

	if [ -n "${chosen_binary_modules}" ]; then
		echo ""
		echo "Pre-built driver modules that seem compatible with your system were found under"
		echo "${cnxtlibdir}/modules/binaries/${chosen_binary_modules}."

		if ask_yesno "Would you like to use them? [yes] " 0; then
			if use_prebuilt_modules "${chosen_binary_modules}"; then
				@CNXTTARGET@stop # unload any old modules loaded
				update_module_dependencies || return $?
				return 0
			fi
		fi
	else
		echo ""
		echo "No pre-built modules for: ${OSDISTNAME}-${OSDISTVERS} ${OSKERNNAME}-${OSKERNVERS} ${OSKERNTYPE}${OSKERNSMP}"
	fi

	if [ -f ${cnxtlibdir}/modules/Makefile ]; then
		echo ""
		echo "Trying to automatically build the driver modules.."
		echo "(this requires a C compiler and proper kernel sources to be installed)"

		if recompile_modules; then
				@CNXTTARGET@stop # unload any old modules loaded
				update_module_dependencies || return $?
				echo "done."
				return 0
		fi
	else
		echo ""
		echo "Please obtain the appropriate variant of this package for your system"
		echo "or try the generic RPM or tar version."
	fi

	return 1
}

choose_major()
{
	device=$1
	shift

	first=240
	max=250

	major=${first}

	while [ ${major} -ne ${max} ]; do
		excluded=false
		for exclude in $*; do
			if [ ${major} -eq ${exclude} ]; then
				excluded=true
				break
			fi
		done

		if ! ${excluded} && \
			! grep -q "^ *${major} " /proc/devices && \
			! sed -e 's/#.*//g' \
				-e '/@CNXTTARGET@serial/d' \
				-e '/ttyS@CNXTSERDEV@$/d' \
				-e '/@CNXTTARGET@osspec/d' \
				-e '/@CNXTTARGET@diag/d' \
				-e '/@CNXTTARGET@scr/d' \
				${modulesconf} | grep -q "^alias[ 	][ 	]*char-major-${major}"
			then
				break
		fi

		major="`expr ${major} + 1`"
	done

	if [ ${major} -ne ${max} ]; then
		echo ${major}
		return 0
	else
		echo 1>&2 "$0: Cannot find major device number for ${device} in range ${first}-${max}"
		return 1
	fi
}

devfsd_running()
{
	ps -e | grep -q 'devfsd$'
}

modulesconf_filter_mine()
{
    sed \
	-e '/^alias.*@CNXTTARGET@serial/d' \
	-e '/^alias.*ttyS@CNXTSERDEV@$/d' \
	-e '/^options.*@CNXTTARGET@serial/d' \
	-e '/^probeall.*ttyS@CNXTSERDEV@[ 	]/d' \
	-e '/^probeall.*@CNXTTARGET@serial/d' \
	-e '/^below[ 	]*@CNXTTARGET@hw/d' \
	-e '/^alias.*@CNXTTARGET@osspec/d' \
	-e '/^options.*@CNXTTARGET@osspec/d' \
	-e '/^alias.*@CNXTTARGET@diag/d' \
	-e '/^alias.*@CNXTTARGET@scr/d' \
	-e '/^options.*@CNXTTARGET@scr/d'
}

modprobeconf_filter_mine()
{
    sed \
	-e '/^alias.*@CNXTTARGET@serial/d' \
	-e '/^alias.*ttyS@CNXTSERDEV@$/d' \
	-e '/^options.*@CNXTTARGET@serial/d' \
	-e '/^install.*ttyS@CNXTSERDEV@[ 	]/d' \
	-e '/^install[ 	]*@CNXTTARGET@serial/d' \
	-e '/^remove[ 	]*@CNXTTARGET@serial/d' \
	-e '/^install[ 	]*@CNXTTARGET@osspec/d' \
	-e '/^remove[ 	]*@CNXTTARGET@osspec/d' \
	-e '/^install[ 	]*@CNXTTARGET@hw/d' \
	-e '/^remove[ 	]*@CNXTTARGET@hw/d' \
	-e '/^alias.*@CNXTTARGET@osspec/d' \
	-e '/^options.*@CNXTTARGET@osspec/d' \
	-e '/^alias.*@CNXTTARGET@diag/d' \
	-e '/^alias.*@CNXTTARGET@scr/d' \
	-e '/^options.*@CNXTTARGET@scr/d'
}

unconfigure_serial()
{
	if [ -f /etc/modutils/@CNXTTARGET@ ]; then
		rm -f /etc/modutils/@CNXTTARGET@
		update-modules
	elif [ -f /etc/modules.d/@CNXTTARGET@ ]; then
		rm -f /etc/modules.d/@CNXTTARGET@
		update-modules
	else
		if modulesconf_filter_mine < ${modulesconf} > ${modulesconf}.$$; then
			cp ${modulesconf}.$$ ${modulesconf}
		fi

		rm -f ${modulesconf}.$$
	fi

	if [ -n "${modprobeconf}" -a -f "${modprobeconf}" ]; then
		if modprobeconf_filter_mine < ${modprobeconf} > ${modprobeconf}.$$; then
			cp ${modprobeconf}.$$ ${modprobeconf}
		fi

		rm -f ${modprobeconf}.$$
	fi

	if [ -f /etc/devfs/conf.d/@CNXTTARGET@.conf ]; then
		rm -f /etc/devfs/conf.d/@CNXTTARGET@.conf
		[ -x /usr/sbin/update-devfsd ] && update-devfsd
		killall -HUP devfsd 2>/dev/null
	else
		if [ -f /etc/devfsd.conf ]; then
			if sed -e '/^REGISTER.*ttyS*@CNXTSERDEV@[0-9]/d' -e '/^LOOKUP.*ttyS@CNXTSERDEV@[0-9]/d' \
					< /etc/devfsd.conf > /etc/devfsd.conf.$$; then
				cp /etc/devfsd.conf.$$ /etc/devfsd.conf
			fi
			rm -f /etc/devfsd.conf.$$
			killall -HUP devfsd 2>/dev/null
		fi
	fi

	if ! devfsd_running; then
		rm -f /dev/@CNXTTARGET@dcp[0-9]*
		rm -f /dev/@CNXTTARGET@diag[0-9]* /dev/@CNXTTARGET@diagdmp
		rm -f /dev/ttyS@CNXTSERDEV@[0-9]*
		rm -f /dev/cua@CNXTSERDEV@[0-9]*
	fi

	if [ -h /dev/modem ] && /bin/ls -l /dev/modem 2>/dev/null | ${AWK} '{print $11}' | egrep -q '(ttyS|cua)@CNXTSERDEV@[0-9][0-9]*'; then
		rm -f /dev/modem
	fi
}

mod_aliases_and_options()
{
	echo "alias /dev/ttyS@CNXTSERDEV@[0-9]* /dev/ttyS@CNXTSERDEV@"
	echo "alias char-major-${cnxttty_major} /dev/ttyS@CNXTSERDEV@"
	echo "alias /dev/modem /dev/ttyS@CNXTSERDEV@"
	if [ "$1" = modulesconf ]; then
		echo "alias /dev/cua@CNXTSERDEV@[0-9]* /dev/ttyS@CNXTSERDEV@"
		echo "alias char-major-${cnxtcua_major} /dev/ttyS@CNXTSERDEV@"
		echo "options @CNXTTARGET@serial serialmajor=${cnxttty_major} calloutmajor=${cnxtcua_major}"
	else
		echo "options @CNXTTARGET@serial serialmajor=${cnxttty_major}"
	fi
	osspecargs=""
	if [ -n "${cnxtdcp_major}" ]; then
		osspecargs="${osspecargs} dcpmajor=${cnxtdcp_major}"
	fi
	if [ -n "${cnxtdiag_major}" ]; then
		echo "alias /dev/@CNXTTARGET@diag @CNXTTARGET@osspec"
		echo "alias /dev/@CNXTTARGET@diag* /dev/@CNXTTARGET@diag"
		echo "alias char-major-${cnxtdiag_major} /dev/@CNXTTARGET@diag"
		osspecargs="${osspecargs} diagmajor=${cnxtdiag_major}"
	fi
	if [ -n "${cnxtscr_major}" ]; then
		echo "alias ${scrdevicename} @CNXTTARGET@osspec"
		echo "alias char-major-${cnxtscr_major} @CNXTTARGET@osspec"
		osspecargs="${osspecargs} scrmajor=${cnxtscr_major}"
	fi
	if [ -n "${osspecargs}" ]; then
		echo "options @CNXTTARGET@osspec${osspecargs}"
	fi
}

configure_serial()
{
	cnxttty_major="`choose_major @CNXTTARGET@serial`"

	if [ -z ${cnxttty_major} ]; then
		exit 1
	fi

	cnxtcua_major="`choose_major @CNXTTARGET@serial_callout ${cnxttty_major}`"
	if [ -z ${cnxtcua_major} ]; then
		exit 1
	fi

	if dcp_supported; then
		cnxtdcp_major="`choose_major @CNXTTARGET@dcp ${cnxttty_major} ${cnxtcua_major}`"
		if [ -z ${cnxtdcp_major} ]; then
			exit 1
		fi
	else
		cnxtdcp_major=""
	fi

	if diag_supported; then
		cnxtdiag_major="`choose_major @CNXTTARGET@diag ${cnxttty_major} ${cnxtcua_major} ${cnxtdcp_major}`"
		if [ -z ${cnxtdiag_major} ]; then
			exit 1
		fi
	else
		cnxtdiag_major=""
	fi

	if old_scr_supported; then
		scrdevicename=/dev/@CNXTTARGET@scr

		cnxtscr_major="`choose_major @CNXTTARGET@scr ${cnxttty_major} ${cnxtcua_major} ${cnxtdcp_major} ${cnxtdiag_major}`"
		if [ -z ${cnxtscr_major} ]; then
			exit 1
		fi
	fi

	if [ -d /etc/modutils -a -x /sbin/update-modules ]; then
		# Debian
		runupdatemodules=true
		outmodulesconf=/etc/modutils/@CNXTTARGET@
	elif [ -d /etc/modules.d -a -x /usr/sbin/update-modules ]; then
		# Gentoo
		runupdatemodules=true
		outmodulesconf=/etc/modules.d/@CNXTTARGET@
	else
		runupdatemodules=false
		outmodulesconf=/tmp/cnxtmodconf.$$
	fi

	(
		mod_aliases_and_options modulesconf
		if [ "@CNXTDRIVER@" = "hsf" ]; then
			echo "probeall /dev/ttyS@CNXTSERDEV@ @CNXTTARGET@pcibasic2 @CNXTTARGET@mc97ich @CNXTTARGET@mc97via @CNXTTARGET@mc97ali"
			echo "probeall @CNXTTARGET@serial @CNXTTARGET@pcibasic2 @CNXTTARGET@mc97ich @CNXTTARGET@mc97via @CNXTTARGET@mc97ali"
		fi
		if [ "@CNXTDRIVER@" = "hcf" ]; then
			echo "probeall /dev/ttyS@CNXTSERDEV@ @CNXTTARGET@hw"
			echo "probeall @CNXTTARGET@serial @CNXTTARGET@hw"
		fi

		case "${parm_hwinst[${unit}]}" in
		PCI-4321:*)
			# RipTide HCF
			echo "below @CNXTTARGET@hw riptidelow"
			;;
		*)
			;;
		esac
	) > ${outmodulesconf}

	if ${runupdatemodules}; then
		update-modules
	else
		if (
			modulesconf_filter_mine
			cat ${outmodulesconf}
		)  < ${modulesconf} > ${modulesconf}.$$; then
			if ! cp ${modulesconf}.$$ ${modulesconf}; then
				rm -f ${modulesconf}.$$ ${outmodulesconf}
				exit 1
			fi
		fi

		rm -f ${modulesconf}.$$ ${outmodulesconf}
	fi

	if [ -n "${modprobeconf}" ]; then
		outmodprobeconf=/tmp/cnxtmodconf.$$
		(
			mod_aliases_and_options
			if [ "@CNXTDRIVER@" = "hsf" ]; then
				echo "install /dev/ttyS@CNXTSERDEV@ /sbin/modprobe @CNXTTARGET@pcibasic2; /sbin/modprobe @CNXTTARGET@mc97ich; /sbin/modprobe @CNXTTARGET@mc97via; /sbin/modprobe @CNXTTARGET@mc97ali; /bin/true"
			fi
			if [ "@CNXTDRIVER@" = "hcf" ]; then
				echo "install /dev/ttyS@CNXTSERDEV@ /sbin/modprobe @CNXTTARGET@hw"
			fi

			case "${parm_hwinst[${unit}]}" in
			PCI-4321:*)
				# RipTide HCF
				echo "install @CNXTTARGET@hw /sbin/modprobe riptidelow; /sbin/modprobe --ignore-install @CNXTTARGET@hw"
				echo "remove @CNXTTARGET@hw /sbin/modprobe -r --ignore-remove @CNXTTARGET@hw && /sbin/modprobe -r riptidelow; /bin/true"
				;;
			*)
				;;
			esac

		) > ${outmodprobeconf}

		if (
			modprobeconf_filter_mine
			cat ${outmodprobeconf}
		) < ${modprobeconf} > ${modprobeconf}.$$; then
			if ! cp ${modprobeconf}.$$ ${modprobeconf}; then
				rm -f ${modprobeconf}.$$ ${outmodprobeconf}
				exit 1
			fi
		fi

		rm -f ${modprobeconf}.$$ ${outmodprobeconf}
	fi

	if [ -d /etc/devfs/conf.d ]; then
		# we use nice to bypass the stupid check in devfsd (Hi Richard!)
		# that prevents direct execution of modprobe (in favor of MODLOAD,
		# which unfortunately doesn't provide a way to specify a module
		# name other than the device itself and under Mandrake at least,
		# the ttyS* alias in /etc/modules.devfs overrides our own alias
		# in modules.conf)
		echo 'LOOKUP	^(ttyS@CNXTSERDEV@[0-9]|modem$) EXECUTE nice /sbin/modprobe /dev/ttyS@CNXTSERDEV@
REGISTER	^ttyS@CNXTSERDEV@0$ CFUNCTION GLOBAL symlink $devname modem
UNREGISTER	^ttyS@CNXTSERDEV@0$ CFUNCTION GLOBAL unlink modem' \
			> /etc/devfs/conf.d/@CNXTTARGET@.conf
		rm -f /dev/modem
		[ -x /usr/sbin/update-devfsd ] && update-devfsd
		killall -HUP devfsd 2>/dev/null
	else
		if [ -f /etc/devfsd.conf ]; then
			if (
				sed -e '/REGISTER.*ttyS*@CNXTSERDEV@[0-9]/d' -e '/^LOOKUP.*ttyS@CNXTSERDEV@[0-9]/d'
				echo 'LOOKUP	^(ttyS@CNXTSERDEV@[0-9]|modem$) EXECUTE nice /sbin/modprobe /dev/ttyS@CNXTSERDEV@
REGISTER	^ttyS@CNXTSERDEV@0$ CFUNCTION GLOBAL symlink $devname modem
UNREGISTER	^ttyS@CNXTSERDEV@0$ CFUNCTION GLOBAL unlink modem'
			) < /etc/devfsd.conf > /etc/devfsd.conf.$$; then
				cp /etc/devfsd.conf.$$ /etc/devfsd.conf
			fi
			rm -f /etc/devfsd.conf.$$
			rm -f /dev/modem
			killall -HUP devfsd 2>/dev/null
		fi
	fi

	ttydevicename=/dev/ttyS@CNXTSERDEV@0
	cuadevicename=/dev/cua@CNXTSERDEV@0

	if [ -n "${scrdevicename}" ]; then
		rm -f ${scrdevicename}
		mknod -m 600 ${scrdevicename} c ${cnxtscr_major} 0 || exit 1
	fi

	if ! devfsd_running; then

		rm -f /dev/@CNXTTARGET@dcp[0-9]*
		rm -f /dev/@CNXTTARGET@diag[0-9]* /dev/@CNXTTARGET@diagdmp
		rm -f /dev/ttyS@CNXTSERDEV@[0-9]*
		rm -f /dev/cua@CNXTSERDEV@[0-9]*

		if [ -n "${cnxtdcp_major}" ]; then
			u=0
			while [ $u -lt @CNXTMAXMDM@ ]; do
		    		mknod -m 666 /dev/@CNXTTARGET@dcp${u} c ${cnxtdcp_major} ${u} || exit 1
				u=`expr $u + 1`
			done
		fi

		if [ -n "${cnxtdiag_major}" ]; then
			u=0
			while [ $u -lt @CNXTMAXMDM@ ]; do
		    		mknod -m 666 /dev/@CNXTTARGET@diag${u} c ${cnxtdiag_major} ${u} || exit 1
				u=`expr $u + 1`
			done
			mknod -m 666 /dev/@CNXTTARGET@diagdmp c ${cnxtdiag_major} @CNXTDIAGDMPMINOR@ || exit 1
		fi

		cnxt_minor=@CNXTSERIALMINOR@

		u=0
		while [ $u -lt @CNXTMAXMDM@ ]; do
		    	mknod -m 666 /dev/ttyS@CNXTSERDEV@${u} c ${cnxttty_major} ${cnxt_minor} || exit 1
			mknod -m 666 /dev/cua@CNXTSERDEV@${u} c ${cnxtcua_major} ${cnxt_minor} || exit 1
			cnxt_minor=`expr $cnxt_minor + 1`
			u=`expr $u + 1`
		done

		if [ -h /dev/modem ] && /bin/ls -l /dev/modem 2>/dev/null | ${AWK} '{print $11}' | egrep -q '(ttyS|cua)@CNXTSERDEV@[0-9][0-9]*'; then
			rm -f /dev/modem
		fi

		if [ -e /dev/modem ]; then
			if ! fuser /dev/modem >/dev/null 2>&1; then
				rm -f /dev/modem.old
				mv /dev/modem /dev/modem.old

				echo "WARNING: renamed existing /dev/modem to /dev/modem.old:"
				echo ""
				/bin/ls -l /dev/modem.old
			fi
		fi

		if [ ! -e /dev/modem ]; then
			ln -s /dev/ttyS@CNXTSERDEV@0 /dev/modem
		fi
	fi
}

identify_system()
{
	OSDISTNAME=unknown
	OSDISTIDNT=unknown
	OSDISTVERS=unknown

	if [ -f /etc/debian_version ]; then
		OSDISTNAME=Debian
		OSDISTIDNT=deb
		read OSDISTVERS < /etc/debian_version
	elif [ -f /etc/slackware-version ]; then
		OSDISTNAME=Slackware
		OSDISTIDNT=slack
		OSDISTVERS="`${AWK} '{print $1; exit}' /etc/slackware-version`"
	elif [ -f /etc/conectiva-release ]; then
		OSDISTNAME=Conectiva
		OSDISTIDNT=conectiva
	elif [ -f /etc/SuSE-release ]; then
		OSDISTNAME=SuSE
		OSDISTIDNT=suse
		OSDISTVERS="`sed -n '/^VERSION/s/^.*=[ 	]*//p' < /etc/SuSE-release`"
	elif [ -f /etc/mandrake-release ]; then
		OSDISTNAME=Mandrake
		OSDISTIDNT=mdk
	#it would be better to use rpm instead of sed but it doesn't work
	#recursively (due to database locking) when this script is called during
	#the package's installation
	#	OSDISTVERS="`rpm -q --queryformat '%{VERSION}\n' mandrake-release | sort -r | head -1`"
		OSDISTVERS="`sed -n '/release /{s/^.*release  *\([^ ]*\)/\1/;s/ .*//;p;q;}' < /etc/mandrake-release`"
	#elif [ -f /etc/yellowdog-release ]; then
	#	OSDISTNAME=YellowDog
	elif [ -f /etc/redhat-release ]; then
		OSDISTNAME=RedHat
		OSDISTIDNT=rh
		OSDISTVERS="`sed -n '/release /{s/^.*release  *\([^ ]*\)/\1/;s/ .*//;p;q;}' < /etc/redhat-release`"
	elif [ -d /var/lib/LST ]; then
		OSDISTNAME=Caldera
		OSDISTIDNT=caldera
	fi

	OSKERNNAME="`uname -s | tr '[A-Z]' '[a-z]'`"
	OSKERNARCH="`uname -m`"
	if [ -r /boot/kernel.h ]; then
		OSKERNTYPE="`sed -n '/^#define[ 	]__MODULE_KERNEL_/s/^#define[ 	]__MODULE_KERNEL_\([^ 	]*\)[ 	]*.*/\1/p' </boot/kernel.h`"
	fi
	if [ -z "${OSKERNTYPE}" ]; then
		OSKERNTYPE="${OSKERNARCH}"
	fi
	OSKERNVERS="`uname -r`"

	case "${OSKERNVERS}" in
	2.[234]*)
		KO=o
		ksyms=ksyms
		;;
	*)
		KO=ko
		ksyms=kallsyms
		;;
	esac

	if uname -v | grep -q SMP; then
		OSKERNSMP="-SMP"
	else
		OSKERNSMP=""
	fi

	if [ -r /proc/ksyms ] && [ `egrep -c '_[0-9a-f]{8}$' /proc/ksyms` -gt 100 ]; then
		OSKERNMODV="-MODVERS"
	else
		OSKERNMODV=""
	fi

	echo "$OSKERNNAME-$OSKERNARCH($OSKERNTYPE)-$OSKERNVERS$OSKERNSMP$OSKERNMODV $OSDISTNAME-$OSDISTVERS"
}

dump_cmd()
{
	echo ""
	echo "${dumpprefix} $*"
	eval $@
}

dump_file()
{
	dump_cmd cat -v $@
}

dump_diagnostics()
{
	dumpprefix="+"

	> "${cnxtdiagfile}" || return $?

	if ! ${noprobe}; then
		echo ""
		echo "Probing \"/dev/ttyS@CNXTSERDEV@\"..."
		(
			dump_cmd modprobe -v /dev/ttyS@CNXTSERDEV@
			dump_cmd lsmod
		) >> "${cnxtdiagfile}" 2>&1
	fi

	echo ""
	echo "Dumping system diagnostic information..."

	case "${cnxtdiagfile}" in
	*longdiag*)
		longdiag=true
		;;
	*)
		longdiag=false
		;;
	esac

	(
		dump_cmd date
		dump_cmd $0 --info
		dump_cmd identify_system
		dump_cmd uname -a

		dump_cmd gcc -v

		dump_file /proc/version
		dump_file /proc/cpuinfo

		for f in /etc/*_version /etc/*-version /etc/*-release; do
			if [ -r "${f}" ]; then
				dump_file "${f}"
			fi
		done

		for f in /var/run/@CNXTTARGET@dcpd*; do
			if [ -r "${f}" ]; then
				dump_file "${f}"
			fi
		done

		dump_cmd lspci -n
		dump_cmd lspci -v
		dump_cmd lspci -n -vvv

		for p in pci cmdline uptime \
			devices misc filesystems interrupts \
			iomem ioports dma mtrr \
			partitions mounts swaps meminfo \
			stat apm modules ldiscs
		do
			dump_file /proc/${p}
		done

		dump_cmd modprobe -V
		dump_cmd modprobe -l "*hsf*"
		dump_cmd modprobe -l "*hcf*"
		dump_cmd modprobe -l "*rip*"
		dump_file "${modulesconf}"
		if [ -n "${modprobeconf}" ]; then
			dump_file "${modprobeconf}"
		fi
		dump_cmd depmod -e -a

		dump_file /proc/tty/drivers
		for f in /proc/tty/driver/*; do
			if [ -r "${f}" ]; then
				dump_file "${f}"
			fi
		done

		dump_cmd ls -l '/dev/modem*'
		dump_cmd ls -l '/dev/*@CNXTSERDEV@[0-9]*'
		dump_cmd ls -l '/dev/ttyS*'
		dump_cmd ls -l '/dev/tts*'

		dump_cmd "cd ${cnxtnvmdir} && find . -maxdepth 2 -ls"
		dump_cmd "cd ${cnxtnvmdir} && find dynamic -follow -print -type f -exec cat {} \;"

		dump_cmd ls -lR "${cnxtlibdir}/."

		if ${longdiag}; then
			for p in slabinfo ${ksyms}
			do
				dump_file /proc/${p}
			done

			dump_file /lib/modules/${OSKERNVERS}/build/.config
			dump_file /lib/modules/${OSKERNVERS}/build/include/linux/version.h
			dump_file /lib/modules/${OSKERNVERS}/build/include/linux/autoconf.h
			dump_file /lib/modules/${OSKERNVERS}/build/include/linux/autoconf-up.h
			dump_file /lib/modules/${OSKERNVERS}/build/include/linux/rhconfig.h
			dump_file /lib/modules/${OSKERNVERS}/build/include/linux/modules/ksyms.ver

			dump_file /boot/vmlinuz.version.h
			dump_file /boot/vmlinuz.autoconf.h
			dump_file /boot/vmlinuz.config

			dump_file /boot/kernel.h

			dump_cmd ls -lR /etc/.
			dump_cmd ls -lR /lib/modules/.
			dump_cmd ls -lR /boot/.

			dump_cmd ls -l /usr/src/linux/include/.
			dump_cmd ls -l /usr/src/linux/include/linux/.
			dump_cmd ls -l /usr/src/linux/include/asm-i386/.
			dump_cmd ls -l /usr/include/. /usr/src/.

			dump_cmd env

			dump_cmd ps -efw

			dump_cmd sh --version
			dump_cmd sed --version
			dump_cmd ${AWK} --version
			dump_cmd printf --version

			dump_cmd tar --version

			dump_cmd rpm --version
			dump_cmd rpm --showrc
			dump_cmd rpm --query --all
		fi

		dump_cmd dmesg
		if dmesg | grep -qi 'panic'; then
			dump_cmd dmesg | ksymoops
		fi

	) >> "${cnxtdiagfile}" 2>&1

	if [ -f "${cnxtdiagfile}" ]; then
		echo ""
		echo "System diagnostic information has been saved to the file:"
		echo ""
		ls -l ${cnxtdiagfile}
		echo ""
		echo "As it could contain private information about this system, we recommend that"
		echo "you verify its contents before sending it to third parties."
	fi
}

read_unit_parms()
{
	parm_regionName[${unit}]="AUTO"
	parm_regionT35c[${unit}]=""
	parm_hwprofile[${unit}]="unknown"
	parm_hwrevision[${unit}]=""
	parm_hwinst[${unit}]="none"
	parm_hwid[${unit}]="unknown"
	parm_licowner[${unit}]="${lastowner}"
	parm_lickey[${unit}]="00000000"
	parm_licstatus[${unit}]="unknown"

	if [ ! -d "${procdrvdir}/${unit}" ]; then
		echo ""
		echo 1>&2 "ERROR: no modem found (unit ${unit})"
		return 1
	fi

	read parm_hwprofile[${unit}] < ${procdrvdir}/${unit}/hwprofile
	read parm_hwrevision[${unit}] < ${procdrvdir}/${unit}/hwrevision
	read parm_hwinst[${unit}] < ${procdrvdir}/${unit}/hwinst

	if [ ! -d "${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}" ]; then
		echo ""
		echo 1>&2 "ERROR: hwinst dir not present: ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}"
		return 2
	fi


	if [ -f ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/.region_set ]; then
		read parm_regionT35c[${unit}] < ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/COUNTRY_CODE
		parm_regionName[${unit}]="`T35c_to_name \"${parm_regionT35c[${unit}]}\"`"
	fi

	if ${isfreeversion}; then
		sawfreelicenses=true
	else
		read hwid < ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/HARDWARE_ID
		sum="`echo \"${hwid}\" | md5sum | cut -c1-4 | tr '[a-f]' '[A-F]'`"
		parm_hwid[${unit}]="${sum}-`echo \"${hwid}\" | sed 's/^\(....\)\(....\)$/\1-\2/'`"

		[ -s ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_OWNER ] &&
			parm_licowner[${unit}]="`sed 's/"//g' < ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_OWNER`"
		[ -n "${parm_licowner[${unit}]}" -a "${parm_licowner[${unit}]}" != "unknown" ] && lastowner="${parm_licowner[${unit}]}"

		[ -s ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_KEY ] &&
			read parm_lickey[${unit}] < ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_KEY

		[ -s ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_STATUS ] &&
			parm_licstatus[${unit}]="`sed 's/"//g' < ${cnxtnvmdir}/dynamic/${parm_hwinst[${unit}]}/LICENSE_STATUS`"
		case "${parm_licstatus[${unit}]}" in
		FREE*)
			sawfreelicenses=true
			;;
		*)
			;;
		esac
	fi

	return 0
}

ensure_driver_present()
{
	if [ ! -d ${procdrvdir} ]; then
		modprobe /dev/ttyS@CNXTSERDEV@ >/dev/null 2>&1 # ensure drv loaded
		if [ ! -d ${procdrvdir} ]; then
			echo ""
			echo 1>&2 "ERROR: @CNXTTARGET@ driver not active"
			return 1
		fi
	fi
	return 0
}

read_parms()
{
	sawfreelicenses=false
	
	ensure_driver_present || return $?
	units="${specificunit}"
	if [ -z "${units}" ]; then
		units=`ls ${procdrvdir}`

		if [ -z "${units}" ]; then
			echo ""
			echo 1>&2 "ERROR: no device detected by @CNXTTARGET@ driver"
			return 1
		fi
	fi

	for unit in ${units}; do
		read_unit_parms || return $?
	done
	rereadparms=false
}

show_unit_parms()
{
	echo ""
	echo "Config for modem unit ${unit}: /dev/ttyS@CNXTSERDEV@${unit}"
	echo "	Device instance: ${parm_hwinst[${unit}]}"
	if [ -n "${parm_hwrevision[${unit}]}" ]; then
		echo "	HW revision    : ${parm_hwrevision[${unit}]}"
	fi
	echo "	HW profile name: ${parm_hwprofile[${unit}]}"
	if ! ${isfreeversion}; then
		echo "	Registration ID: ${parm_hwid[${unit}]}"
		echo "	License owner  : ${parm_licowner[${unit}]}"
		echo "	License key    : `keytodisp \"${parm_lickey[${unit}]}\"`"
		echo "	License status : ${parm_licstatus[${unit}]}"
	fi
	if [ -n "${parm_regionT35c[${unit}]}" ]; then
		echo "	Current region : ${parm_regionName[${unit}]} (T.35 code: ${parm_regionT35c[${unit}]})"
	else
		echo "	Current region : ${parm_regionName[${unit}]}"
	fi
}

show_intro()
{
	echo "@CNXTDRVDSC@ driver, version ${cnxtversion}"

	case "${cnxtversion}" in
	*beta*)
		(
		echo ""
		echo "WARNING: this is an EXPERIMENTAL BETA VERSION"
		echo "USE AT YOUR OWN RISK! See the file ${cnxtlibdir}/LICENSE for details."
		) 1>&2
		;;
	esac

#	case "${cnxtversion}" in
#	*lnxt*)
		(
		echo ""
		echo "If you need license keys, assistance or more information, please go to:"
		echo "	http://www.linuxant.com/"
		echo ""
		echo "When reporting a problem for the first time, please send"
		echo "us the file generated by \"@CNXTTARGET@config --dumpdiag\"."
		) 1>&2
#		;;
#	esac
}


show_usage_and_exit()
{
	show_intro

	cat 1>&2 << EOT

Usage: `basename $0` [options]

  -u, --unit=<number>          Select modem unit (default 0)
  -c, --region[=<name>]        Set region, to <name> if specified
                               (Use name "AUTO" to infer from timezone)
  -k, --kernel                 Build and install kernel modules
  -s, --serial                 Install serial port devices

  -i, --info                   Show current configuration information

  -l, --license[=<owner/key>]  Set license key

  -P, --hwprofile[=<name>]     Set HW profile name, to <name> if specified

  -d, --dumpdiag[=<file>]      Probe driver modules and dump system diagnostic
                               information to <file>
                               (default: ${cnxtdiagfile})

  -N, --noprobe                Do dumpdiag without probing modules (safer)

  -a, --auto                   Run in automatic mode, without prompting user
  -r, --remove                 Remove serial devices and kernel modules

  -h, --help                   This small usage guide
  -V, --version                Show version

Default options if none selected: --kernel --serial --region --license --info
EOT
	exit 1
}

# end of functions; execution starts here

PATH=/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/sbin:/usr/local/bin
export PATH

umask 022

cnxtlibdir="@CNXTLIBDIR@"
cnxtetcdir="@CNXTETCDIR@"
cnxtnvmdir="@CNXTNVMDIR@"
cnxtinfdir="/tmp/no/longer/used"
cnxtinffil="/tmp/no/longer/used"
cnxtversion="@CNXTLINUXVERSION@"

case "${cnxtversion}" in
*free*)
	isfreeversion=true
	;;
*)
	isfreeversion=false
	;;
esac

cnxtdiagfile="/tmp/@CNXTDRIVER@diag.txt"

if [ -f /etc/modules.conf ]; then
	modulesconf=/etc/modules.conf
elif [ -f /etc/conf.modules ]; then
	modulesconf=/etc/conf.modules
else
	# create /etc/modules.conf if it doesn't exist
	modulesconf=/etc/modules.conf
	touch ${modulesconf}
fi

if [ -f /etc/modprobe.conf ]; then
	modprobeconf=/etc/modprobe.conf
elif which generate-modprobe.conf >/dev/null 2>&1; then
	modprobeconf=/etc/modprobe.conf
	# create /etc/modprobe.conf if it doesn't exist
	touch ${modprobeconf}
fi

TEMP=`getopt -a -o u::c::C::ksil::P::d::NarhV --long unit::,region::,country::,kernel,serial,info,license::,hwprofile::,dumpdiag::,noprobe,auto,remove,help,version -n "\`basename $0\`" -- "$@"`
if [ $? != 0 ]; then
	show_usage_and_exit
fi

eval set -- "$TEMP"

automode=false
noprobe=false
do_cfgkernel=false
do_cfgserial=false
do_cfglicense=false
do_cfghwprofile=false
do_infocfg=false
do_dumpdiag=false
do_cfgremove=false
do_cfgregion=false
setregion=""
setlicense=""
setlicowner=""
sethwprofile=""
setdiagfile=""
specificunit=""
lastowner="unknown"

if which gawk >/dev/null 2>&1; then
	AWK=gawk
else
	AWK=awk
fi

explicitopt=false

while true ; do
	case "$1" in
		-a|--auto) automode=true; shift ;;
		-c|--region|-C|--country)
			explicitopt=true
			do_cfgregion=true
			if [ -n "$2" ]; then
				setregion="`echo \"$2\" | tr '[a-z ]' '[A-Z_]'`"
			fi
			shift 2
			;;
		-u|--unit)
			explicitopt=true
			specificunit="$2"
			shift 2
			;;
		-k|--kernel) explicitopt=true; do_cfgkernel=true; shift ;;
		-s|--serial) explicitopt=true; do_cfgserial=true; shift ;;
		-l|--license)
			explicitopt=true
			do_cfglicense=true
			if [ -n "$2" ]; then
				setlicense="$2"
			fi
			shift 2
			;;
		-P|--hwprofile)
			explicitopt=true
			do_cfghwprofile=true
			if [ -n "$2" ]; then
				sethwprofile="$2"
			fi
			shift 2
			;;
		-i|--info)   explicitopt=true; do_infocfg=true; shift ;;
		-d|--dumpdiag)
			explicitopt=true
			do_dumpdiag=true
			setdiagfile="$2"
			shift 2
			;;
		-N|--noprobe)
			explicitopt=true
			do_dumpdiag=true
			noprobe=true
			shift
			;;
		-r|--remove) explicitopt=true; do_cfgremove=true; shift ;;
		-h|--help) show_usage_and_exit; shift ;;
		-V|--version) echo "${cnxtversion}"; exit 0;;
		--) shift ; break ;;
		*) echo "Internal error!" ; exit 1 ;;
	esac
done

# Accept --region <name> as equivalent to --region=<name>
if ${do_cfgregion} && [ $# -ge 1 -a -z "${setregion}" ]; then
	setregion="`echo \"$1\" | tr '[a-z ]' '[A-Z_]'`"
	shift
fi

# Accept --license <name> as equivalent to --license=<name>
if ${do_cfglicense} && [ $# -ge 1 -a -z "${setlicense}" ]; then
	setlicense="$1"
	shift
fi

# Accept --hwprofile <name> as equivalent to --hwprofile=<name>
if ${do_cfghwprofile} && [ $# -ge 1 -a -z "${sethwprofile}" ]; then
	sethwprofile="$1"
	shift
fi

# Accept --dumpdiag <file> as equivalent to --dumpdiag=<file>
if ${do_dumpdiag} && [ $# -ge 1 -a -z "${setdiagfile}" ]; then
	setdiagfile="$1"
	shift
fi

procdrvdir="/proc/driver/@CNXTTARGET@"

if [ $# -ne 0 ]; then
	echo 1>&2 "$0: extraneous arguments: $*"
	show_usage_and_exit
fi

# If nothing explicitely specified, configure everything
if ! ${explicitopt}; then
	do_cfgkernel=true
	do_cfgserial=true
	do_cfgregion=true
	if ! ${isfreeversion}; then
		do_cfglicense=true
	fi
	do_infocfg=true
fi

if ! ${do_cfgremove}; then
	show_intro
fi

identify_system >/dev/null

if ${do_cfgremove}; then
	remove_kernel_modules || exit $?
	@CNXTTARGET@stop
	unconfigure_serial || exit $?
	rm -rf "${cnxtnvmdir}/dynamic"
fi

if ${do_cfgkernel}; then
	configure_kernel || exit $?
fi

if ${do_cfgserial}; then
	configure_serial || exit $?
fi

rereadparms=true
if ${do_cfgregion} || ${do_cfglicense} || ${do_cfghwprofile}; then
	read_parms || exit $?
fi

if ${do_cfgregion}; then
	for unit in ${units}; do
		configure_region || exit $?
	done
	echo ""
	echo "To change, use \"@CNXTTARGET@config --region\" or \"AT+GCI=<T35code>\""
	echo "The current region can be displayed by entering \"ATI9\" in a terminal program."
fi

if ${do_cfglicense}; then
	for unit in ${units}; do
		configure_license
		res=$?
		if [ ${res} -ne 0 ] && ${explicitopt}; then
			exit ${res}
		fi
	done
	do_infocfg=true
fi

if ${do_cfghwprofile}; then
	for unit in ${units}; do
		configure_hwprofile || exit $?
	done
	do_infocfg=true
fi

if ${do_infocfg}; then
	if ${rereadparms}; then
		read_parms || exit $?
	fi
	echo ""
	echo "Current parameters: (\"@CNXTTARGET@config --info\")"
	for unit in ${units}; do
		show_unit_parms
	done
	if [ -h /dev/modem ]; then
		echo ""
		echo "The /dev/modem alias (symlink) points to `/bin/ls -l /dev/modem 2>/dev/null | ${AWK} '{print $11}'`"
	fi
	if ${sawfreelicenses}; then
		if ${isfreeversion}; then
			needfullversion
		else
			echo ""
			echo "To enable full 56K modem and FAX functionality, enter your license information"
			echo "with \"@CNXTTARGET@config --license\"."
			echo ""
			echo "License owner and key data must EXACTLY match the information respectively"
			echo "provided to and by Linuxant. Otherwise, license status will remain \"FREE\"!"
		fi
	fi
fi

if ${do_dumpdiag}; then
	if [ -n "${setdiagfile}" ]; then
		cnxtdiagfile="${setdiagfile}"
	fi
	dump_diagnostics || exit $?
fi

