#!/bin/bash

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# (c) 11/2004 by Erik Auerswald <auerswal@unix-ag.uni-kl.de>

# Version 1.1

### variables ###

declare GAMEPORTS		# chosen gameport hardware
declare -i PC_GAMEPORT		# any PC gameport chosen?
declare -i SERIAL		# serial port chosen?
declare JOYSTICKS		# chosen joystick hardware
declare INPUTATTACH		# commandline to attach serial joysticks
declare ANALOG_OPTIONS		# options for module analog
declare MODULES			# modules to be loaded to activate config
declare DEBUG			# control debug output:
				#  0 - no debug output
				#  1 - some debug output
				#  2 - more debug output
				#  (2 means all debug output right now)
declare PATH_TO_LSJOYSTICK	# non standard location on lsjoystick
				# i.e. not in /sbin:/usr/sbin:/bin:/usr/bin
declare SUDO=""			# to use sudo

# initialize DEBUG variable
if [ -z "${DEBUG}" ]
then
  DEBUG=0
fi

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: checking for lsjoystick"
fi
# check for lsjoystick
if [ \( -z "$(which lsjoystick)" \) -a \
     \( ! -x ${PATH_TO_LSJOYSTICK}/lsjoystick \) ]
then
  echo "Error: lsjoystick not found, cannot display joystick list" > /dev/stderr
fi

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: checking for superuser rights"
fi
# checking for superuser rights
if [ ${EUID} -ne 0 ]
then
  if [ ${DEBUG} -ge 1 ]
  then
    echo "DEBUG: EUID=${EUID}, using sudo"
  fi
  SUDO=sudo
fi

### functions ###

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of configure_analog"
fi

# display a radiolist to chose from predefined joysticks
# or chose custom setup and display an checklist of supported features
function configure_analog()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin configure_analog"
  fi
  local new_analog_options
  local sum
  local i
  if [ -z "${1}" ]
  then
    echo "Error: configure_serial() used without parameter" > /dev/stderr
    return
  fi
  new_analog_options=\
$(Xdialog --title "$(basename $0)" --stdout --separate-output --item-help \
 --no-tags --radiolist \
  "What kind of PC style joystick is connected to ${1}?" 0 0 0 \
  "none" "none" "off" "no analog joystick on ${1}" \
  "auto" "autodetect" "on" "autodetect joystick (joysticks with up to 4 buttons and 4 axis or Saitek Cyborg)" \
  "2btn" "joystick with 2 buttons" "off" "joystick with 2 buttons and up to 4 axis" \
  "y-joy" "two joysticks, each w. 2 buttons and 2 axis" "off" "two joysticks, each with 2 buttons and 2 axis, connected via an Y-cable or 2 ports on one gamecard" \
  "y-pad" "two gamepads, each w. 2 buttons and 2 axis" "off" "two gamepads, each with 2 buttons and 2 axis, connected via an Y-cable or 2 ports on one gamecard" \
  "fcs" "Thrustmaster FCS" "off" "Thrustmaster Flight Control System or compatible joystick" \
  "chf" "simple CH Flightstick" "off" "CH Flightstick or compatible joystick (this is a joystick with hat)" \
  "fullchf" "CH Flightstick" "off" "CH Flightstick or compatible joystick with 2 hats and 6 buttons" \
  "gamepad" "4 or 6 button gamepad" "off" "gamepad with 4 or 6 buttons" \
  "gamepad8" "8 button, 2 axis gamepad" "off" "gamepad with 8 buttons and 2 axis" \
  "custom" "custom joystick" "off" "define the features of your joystick" )
  # if custom was chosen, display a checklist with existing features
  if [ "${new_analog_options}a" = "customa" ]
  then
    new_analog_options=$( \
    Xdialog --title "$(basename $0)" --stdout --separate-output --item-help \
    --no-tags --checklist \
    "What features has the joystick on ${1}?" 0 0 0\
    "1" "Axis X1" "off" "Axis X1" \
    "2" "Axis Y1" "off" "Axis Y1" \
    "4" "Axis X2" "off" "Axis X2" \
    "8" "Axis Y2" "off" "Axis Y2" \
    "16" "Button A" "off" "Button A" \
    "32" "Button B" "off" "Button B" \
    "64" "Button C" "off" "Button C" \
    "128" "Button D" "off" "Button D" \
    "256" "CHF Buttons X and Y" "off" "CHF Buttons X and Y" \
    "512" "CHF Hat 1" "off" "CHF Hat 1" \
    "1024" "CHF Hat 2" "off" "CHF Hat 2" \
    "2048" "FCS Hat" "off" "FCS Hat" \
    "4096" "Pad Button X" "off" "Pad Button X" \
    "8192" "Pad Button Y" "off" "Pad Button Y" \
    "16384" "Pad Button U" "off" "Pad Button U" \
    "32768" "Pad Button V" "off" "Pad Button V" \
    "65536" "Saitek F1-F4 Buttons" "off" "Saitek F1-F4 Buttons" \
    "131072" "Saitek Digital Mode" "off" "Saitek Digital Mode" \
    "524288" "GamePad" "off" "GamePad" \
    "1048576" "Joy2 Axis X1" "off" "Joy2 Axis X1" \
    "2097152" "Joy2 Axis Y1" "off" "Joy2 Axis Y1" \
    "4194304" "Joy2 Axis X2" "off" "Joy2 Axis X2" \
    "8388608" "Joy2 Axis Y2" "off" "Joy2 Axis Y2" \
    "16777216" "Joy2 Button A" "off" "Joy2 Button A" \
    "33554432" "Joy2 Button B" "off" "Joy2 Button B" \
    "67108864" "Joy2 Button C" "off" "Joy2 Button C" \
    "134217728" "Joy2 Button D" "off" "Joy2 Button D" \
    "2147483648" "Joy2 GamePad" "off" "Joy2 GamePad" \
    )
    # DEBUG output
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: new_analog_options=${new_analog_options}"
    fi
    # combine numbers in new_analog_options
    sum=0
    for i in ${new_analog_options}
    do
      let sum+=$i
    done
    # DEBUG output
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: sum=${sum}"
    fi
    new_analog_options=${sum}
    # DEBUG output
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: new_analog_options=${new_analog_options}"
    fi
  fi
  # build option string
  if [ -n "${new_analog_options}" ]
  then
    ANALOG_OPTIONS="${ANALOG_OPTIONS},${new_analog_options}"
  fi
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end configure_analog"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of configure_analog"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of configure_serial"
fi

# display a radiolist to chose joystick connected to serial port
# serial port needs to be given as first parameter
function configure_serial()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin configure_serial"
  fi
  local new_inputattach
  if [ -z "${1}" ]
  then
    echo "Error: configure_serial() used without parameter" > /dev/stderr
    return
  fi
  new_inputattach=$(
  Xdialog --title "$(basename $0)" --stdout --separate-output --item-help \
  --no-tags --radiolist \
  "What kind of joystick is connected to serial port ${1#*S} (device ${1})?" 0 0 0 \
  "spaceorb" "SpaceOrb" "off" "SpaceTec SpaceBall Avenger or SpaceOrb 360" \
  "sball4" "SpaceBall" "off" "SpaceTec SpaceBall 4000 FLX" \
  "warrior" "Logitech SWIFT" "off" "Logitech WingMan Warrior" \
  "joy-magellan" "Magellan / Space Mouse" "off" "Magellan 3D or Space Mouse" \
  "iforce" "I-Force" "off" "AVB Mag Turbo Force, Top Shot Pegasus, Logitech WingMan Force, WingMan Force 3D, WingMan Force Wheel, WingMan Strike Force 3D or Guillemot Race Leader Force Feedback" \
  "stinger" "Gravis Stinger" "off" "Gravis Stinger gamepad" \
  "none" "no joystick" "on" "to chose none of the above" )
  case ${new_inputattach} in
    spaceorb)	INPUTATTACH="inputattach --spaceorb ${1} &;${INPUTATTACH}";;
    sball4)	INPUTATTACH="inputattach --sball4 ${1} &;${INPUTATTACH}";;
    warrior)	INPUTATTACH="inputattach --warrior ${1} &;${INPUTATTACH}";;
    joy-magellan) INPUTATTACH="inputattach --magellan ${1} &;${INPUTATTACH}";;
    iforce)	INPUTATTACH="inputattach --iforce ${1} &;${INPUTATTACH}";;
    stinger)	INPUTATTACH="inputattach --stinger ${1} &;${INPUTATTACH}";;
  esac
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end configure_serial"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of configure_serial"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of configure_pc_joystick"
fi

# display a radiolist to chose the connected joystick(s)
# $1 needs to contain the name of the gameport hardware
function chose_pc_joystick()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin chose_pc_joystick"
  fi
  local new_joysticks
  if [ -z "${1}" ]
  then
    echo "Error: chose_pc_joystick() used without parameter" > /dev/stderr
    return
  fi
  # display dialogbox to chose which joysticks are connected to gameport
  new_joysticks=$(
  Xdialog --title "$(basename $0)" --stdout --separate-output --item-help \
  --no-tags --radiolist \
  "What kind of joystick is connected to ${1}?" 0 0 0 \
  "analog" "PC style joystick" "off" "standard 'analog' PC joystick or gamepad or Saitek Cyborg" \
  "sidewinder" "Microsoft Sidewinder" "off" "Microsoft SideWinder 3D Pro, Force Feedback Pro, Force Feedback Wheel, FreeStyle Pro, GamePad, Precision Pro or Precision Pro USB" \
  "adi" "Logitech ADI" "off" "Logitech CyberMan 2, ThunderPad Digital, WingMan Extreme Digital, WingMan Formula, WingMan Interceptor, WingMan GamePad, WingMan GamePad USB, WingMan GamePad Extreme or WingMan Extreme Digital 3D" \
  "grip" "Gravis GrIP" "off" "Gravis GamePad Pro, Gravis BlackHawk Digital, Gravis Xterminator or Gravis Xterminator DualControl" \
  "a3d" "A3D" "off" "FPGaming Assassin 3D, MadCatz Panther or Panther XL" \
  "tmdc" "ThrustMaster DirectConnect" "off" "ThrustMaster Millenium 3D Inceptor, 3D Rage Pad, Fusion Digital Game Pad, FragMaster or Attack Throttle" \
  "cobra" "Creative Labs Blaster" "off" "Creative Blaster GamePad Cobra" \
  "gf2k" "Genius Digital" "off" "Genius Flight2000 F-23 joystick, Flight2000 F-31 joystick or G-09D gamepad" \
  "interact" "InterAct Digital" "off" "InterAct HammerHead/FX or ProPad8" \
  "none" "no joystick" "on" "to chose none of the above" )
  # if analog joystick chosen, configure it
  # otherwise, add option none to ANALOG_OPTIONS
  if [ "${new_joysticks}a" = "analoga" ]
  then
    configure_analog ${1}
  else
    ANALOG_OPTIONS="${ANALOG_OPTIONS},none"
  fi
  if [ -n "${new_joysticks}" ]
  then
    JOYSTICKS="${JOYSTICKS} ${new_joysticks}"
  fi
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end chose_pc_joystick"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of configure_pc_joystick"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of chose_serial"
fi

# display a radiolist to chose the connected joystick(s)
# chose the serial port(s) to which joysticks are connected
function chose_serial()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin chose_serial"
  fi
  local serial_ports_list
  local used_serial_ports
  local port
  # and not well tested
  echo "Warning: serial joystick support ist untested" > /dev/stderr
  # display dialogbox to chose serial devices
  # find serial ports via `ls /dev/ttyS*`, transform this into a parameter list
  # for Xdialog
  serial_ports_list=$(echo /dev/ttyS* | sed 's/\([a-zA-Z/]\+\)\([0-9]\+\) */\1\2\tSerial Port No \2\toff\tdevice \1\2\t/g')
  # display a checklist to chose the serial ports
  # use internal field separator to separate parameters containing spaces
  IFS=$(echo -e "\t\n")
  used_serial_ports=$(
  Xdialog --title "$(basename $0)" --stdout --separate-output --item-help \
  --no-tags --checklist \
  "To which serial ports are joysticks connected?" 0 0 0 \
  $(echo "${serial_ports_list[@]}"))
  unset IFS
  # configure joysticks connected to chosen serial ports
  for port in ${used_serial_ports}
  do
    configure_serial ${port}
  done
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end chose_serial"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of chose_serial"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of chose_gameports"
fi

# display a radiolist to chose the connected joystick(s)
# get a list of gameports
# joysticks connected (via adapters) to the parallel port are not yet supported
# by this config program
function chose_gameports()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin chose_gameports"
  fi
  local new_gameports
  new_gameports=$(
  Xdialog --title "$(basename $0)" --stdout --separate-output --item-help \
  --no-tags --checklist \
  "Connection type(s) of joystick(s)?" 0 0 0 \
  "usb" "USB" "on" "joystick(s) connected via USB" \
  "ns558" "PC gameport" "off" "joystick(s) connected to PC gameport" \
  "lightning" "Ligtning 4" "off" \
    "joystick(s) connected to PDPI Lightning 4 gamecard" \
  "pcigame" "4DWave" "off" \
    "joystick(s) connected to Trident 4DWave / Aureal Vortex" \
  "cs461x" "SoundFusion" "off" "joystick(s) connected to Crystal SoundFusion" \
  "emu10k1-gp" 'Live!' "off" 'joystick(s) connected to SoundBlaster Live!' \
  "soundcard" "SB 64/128, ES1370/ES1371, Solo1, SonicVibes" "off" \
    "SoundBlaster 64 and 128 - ES1370 and ES1371, ESS Solo1 and S3 SonicVibes" \
  "serport" "serial" "off" "joystick(s) connected to serial port(s)")
  # keep old config on cancel button
  if [ $? -eq 0 ]
  then
    GAMEPORTS=${new_gameports}
  fi
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end chose_gameports"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of chose_gameports"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of unload_all_modules"
fi

# display a radiolist to chose the connected joystick(s)
# function to unload gameport and joystick modules
function unload_all_modules()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin unload_all_modules"
  fi
  # all modules to unload
  # order is important as some modules depend on others
  local all_modules="analog sidewinder adi grip a3d tmdc cobra gf2k interact \
                     spaceorb spaceball warrior joy-magellan iforce stinger \
		     ns558 lightning pcigame cs461x emu10k1-gp \
		     gameport joydev serport"
  # kill all inputattach processes
  # DEBUG output
  if [ ${DEBUG} -ge 1 ]
  then
    echo "DEBUG: killing inputattach processes (Warning: this is untestet)"
  fi
  ${SUDO} killall -q inputattach
  # now unload all modules
  # DEBUG output
  if [ ${DEBUG} -ge 1 ]
  then
    echo "DEBUG: unloading all gameport / joystick modules"
  fi
  if [ ${DEBUG} -ge 1 ]
  then
    echo "DEBUG: all_modules=${all_modules}"
  fi
  ${SUDO} modprobe -qr ${all_modules}
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end unload_all_modules"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of unload_all_modules"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of unload_modules"
fi

# display a radiolist to chose the connected joystick(s)
# function to unload modules
function unload_modules
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin unload_modules"
  fi
  local reversed_modules
  local module
  # unload modules to load gameport drivers in correct order later
  # only those modules are unloaded that are configured by this program
  # if there are some gameport/joystick modules loaded by other means or
  # an old run of this program, they stay untouched, so you can configure
  # gameport/joystick hardware independent of this tool
  # modules need to be unloaded in the correct order
  # as gameport is added in front of game port hardware, we can just reverse
  # the order of $MODULES
  for module in ${MODULES}
  do
    reversed_modules="${module} ${reversed_modules}"
  done
  for module in ${reversed_modules}
  do
    # DEBUG output
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: module=${module}"
    fi
    # check, if module already loaded
    if [ -n "$(lsmod | grep ${module})" ]
    then
      # DEBUG output
      if [ ${DEBUG} -ge 1 ]
      then
        echo "DEBUG: module ${module} already loaded"
      fi
      # modules under control of this program should be reloaded
      # exceptions: input hid serial
      case ${module} in
        input | hid | serial)
          # don't touch these modules
          if [ ${DEBUG} -ge 1 ]
          then
            echo "DEBUG: module ${module} will not be unloaded"
          fi;;
        *)
          # DEBUG output
  	if [ ${DEBUG} -ge 1 ]
  	then
  	  echo "DEBUG: unloading module ${module}"
  	fi
  	${SUDO} modprobe -qr ${module}
      esac
    fi
  done
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end unload_modules"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of unload_modules"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of load_modules"
fi

# display a radiolist to chose the connected joystick(s)
# function to load the configured modules
function load_modules()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin load_modules"
  fi
  # now load the modules
  for module in ${MODULES}
  do
    # DEBUG output
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: module=${module}"
    fi
    # check, if module already loaded
    if [ -n "$(lsmod | grep ${module})" ]
    then
      # DEBUG output
      if [ ${DEBUG} -ge 1 ]
      then
        echo "DEBUG: module ${module} already loaded"
      fi
    else
      # load module
      # module analog needs options
      if [ "${module}a" = "analoga" ]
      then
        # DEBUG use echo to show what we want to do
        # DEBUG output
        if [ ${DEBUG} -ge 1 ]
        then
          echo "DEBUG: loading module ${module} js=${ANALOG_OPTIONS}"
        fi
        ${SUDO} modprobe -q ${module} js=${ANALOG_OPTIONS}
      else
        # DEBUG use echo to show what we want to do
        # DEBUG output
        if [ ${DEBUG} -ge 1 ]
        then
          echo "DEBUG: loading module ${module}"
        fi
        ${SUDO} modprobe -q ${module}
      fi
    fi
  done
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end load_modules"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of load_modules"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of create_device_nodes"
fi

# display a radiolist to chose the connected joystick(s)
# function to (re)create joystick devices
# wants number of devices as first parameter, uses 16 as default
function create_device_nodes()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin create_device_nodes"
  fi
  # get number from first parameter or use the default of 16
  local number_of_nodes=${1:-16}
  local node
  if [ -n "$(grep '[[:space:]]devfs[[:space:]]' /etc/mtab)" ]
  then
    echo "Error: devfs creates device nodes" > /dev/stderr
    Xdialog --title "$(basename $0)" --infobox \
    "Error: devfs creates device nodes" 0 0 10000
    return
  fi
  if [ ${number_of_nodes} -lt 4 ]
  then
    echo "Warning: refusing to create less than 4 joystick devices"\
      > /dev/stderr
    echo "Warning: creating 4 device nodes" > /dev/stderr
    number_of_nodes=4
  fi
  # unload joystick modules to be able to remove device nodes
  unload_all_modules
  # remove existing device nodes
  # DEBUG output
  if [ ${DEBUG} -ge 1 ]
  then
    echo "DEBUG: removing /dev/js*, /dev/input/js* and /dev/input/event*"
  fi
  if [ "$(uname -n)a" = "Knoppixa" ]
  then
    ${SUDO} rm -f /dev/js*
  else
    ${SUDO} rm -f /dev/js* /dev/input/js* /dev/input/event*
  fi
  for node in $(seq 0 $((${number_of_nodes}-1)))
  do
    # DEBUG output
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: creating device node ${node}"
    fi
    # cannot create all devices on knoppix
    if [ "$(uname -n)a" = "Knoppixa" ]
    then
      ${SUDO} mknod /dev/js${node} c 13 ${node}
    else
      ${SUDO} mknod /dev/input/js${node} c 13 ${node}
      ${SUDO} ln -s input/js${node} /dev/js${node}
      ${SUDO} mknod /dev/input/event${node} c 13 $((${node}+64))
    fi
  done
  # load configured modules
  load_modules
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end create_device_nodes"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of create_device_nodes"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of add_gameport_modules"
fi

# display a radiolist to chose the connected joystick(s)
# function to add modules for gameport hardware to $MODULES
function add_gameport_modules()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin add_gameport_modules"
  fi
  for gameport in ${GAMEPORTS}
  do
    case ${gameport} in
      # USB might need HID module, further USB configuration is not the purpose
      # of this configuration program
      usb)
        if [ -z "$(echo ${MODULES} | fgrep hid)" ]
	then
          MODULES="${MODULES} hid"
	fi;;
      # use of any gameport compatible hardware needs the gameport module as
      # well as the specific gameport module
      ns558 | lightning | pcigame | cs461x | emu10k1-gp)
        if [ ${PC_GAMEPORT} -eq 0 ]
        then
          MODULES="${MODULES} gameport"
  	PC_GAMEPORT=1
        fi
        if [ -z "$(echo ${MODULES} | fgrep ${gameport})" ]
	then
          MODULES="${MODULES} ${gameport}"
	fi;;
      # this program does not (yet?) configure the sound driver, it assumes a
      # working configuration and configures the joystick(s) connected to the
      # soundcard
      soundcard)
        if [ ${PC_GAMEPORT} -eq 0 ]
        then
          MODULES="${MODULES} gameport"
  	PC_GAMEPORT=1
        fi;;
      # use of the serial port needs the serport module
      serport)
        if [ ${SERIAL} -eq 0 ]
        then
          MODULES="serial serport ${MODULES}"
  	SERIAL=1
        fi;;
    esac
  done
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end add_gameport_modules"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of add_gameport_modules"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of chose_joysticks"
fi

# display a radiolist to chose the connected joystick(s)
# function to chose joystick drivers
function chose_joysticks()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin chose_joysticks"
  fi
  # only pc style gameports and serial port need special drivers
  if [ \( ${PC_GAMEPORT} -eq 1 \) -o \( ${SERIAL} -eq 1 \) ]
  then
    # chose joysticks
    for gameport in ${GAMEPORTS}
    do
      case ${gameport} in
        ns558)		chose_pc_joystick "PC Gameport";;
        lightning)	chose_pc_joystick "Lightning 4 Gamecard";;
        pcigame)	chose_pc_joystick "Trident 4DWave or Aureal Vortex";;
        cs461x)		chose_pc_joystick "Crystal SoundFusion";;
        emu10k1-gp)	chose_pc_joystick 'SoundBlaster Live!';;
        soundcard)	chose_pc_joystick "Soundcard";;
        serport)	chose_serial;;
      esac
    done
    # sanitize $JOYSTICKS
    JOYSTICKS=$(echo "${JOYSTICKS}" | sed 's/ none//g;s/^ \+//;s/ \+/\n/g' | \
                sort -u)
    JOYSTICKS=$(echo ${JOYSTICKS})
    # append joystick modules to $MODULES
    if [ -n "${JOYSTICKS}" ]
    then
      MODULES="${MODULES} ${JOYSTICKS}"
    fi
  fi
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end chose_joysticks"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of chose_joysticks"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of attach_serial"
fi

# display a radiolist to chose the connected joystick(s)
# function to attach serial joysticks
function attach_serial()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin attach_serial"
  fi
  # if serial joystick(s) configured invoke inputattach
  if [ ${SERIAL} -eq 1 ]
  then
    # kill all existing inputattach processes
    echo "Warning: killing all existing inputattach processes (untestet)" \
      > /dev/stderr
    killall -q inputattach
    # start configured inputattach processes
    if [ -n "${INPUTATTACH}" ]
    then
      echo ${INPUTATTACH}
    fi
  fi
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end attach_serial"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of attach_serial"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of show_joystick_list"
fi

# display a radiolist to chose the connected joystick(s)
# function to display list of joysticks known to the system
function show_joystick_list()
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin show_joystick_list"
  fi
  # use lsjoystick to check for joysticks and display the results in a textbox
  lsjoystick -ql | Xdialog --no-cancel --title \
  "$(basename $0): joysticks found" --textbox - 0 0
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end show_joystick_list"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of show_joystick_list"
fi
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: before definition of configure_hardware"
fi

# display a radiolist to chose the connected joystick(s)
# function to configure driver modules
function configure_hardware
{
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: begin configure_hardware"
  fi
  # chose gameports
  chose_gameports
  # if no gameport is chosen, there is no need to configure anything
  # otherwise, the input subsystem and the module joydev are needed at least
  if [ -n "${GAMEPORTS}" ]
  then
    MODULES="input joydev"
    # the different gameports need their driver modules
    add_gameport_modules
    # configuration of the different joystick types
    # (depending on connection hardware)
    chose_joysticks
    # sanitize $ANALOG_OPTIONS
    ANALOG_OPTIONS=$(echo ${ANALOG_OPTIONS} | sed 's/^,//')
    # now a configuration is chosen
    # the needed modules are stored in $MODULES
    # the options for module analog are stored in $ANALOG_OPTIONS
    # the commandline to invoke inputattach ist stored in $INPUTATTACH
    # DEBUG output:
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: MODULES=${MODULES}"
    fi
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: ANALOG_OPTIONS=${ANALOG_OPTIONS}"
    fi
    if [ ${DEBUG} -ge 1 ]
    then
      echo "DEBUG: INPUTATTACH=${INPUTATTACH}"
    fi
    # unload configured modules to get a consistent state
    unload_modules
    # load configured modules
    load_modules
    # use inputattach to attach serial joysticks
    attach_serial
  fi
  # DEBUG output
  if [ ${DEBUG} -ge 2 ]
  then
    echo "DEBUG: end configure_hardware"
  fi
}

# DEBUG output
if [ ${DEBUG} -ge 2 ]
then
  echo "DEBUG: after definition of configure_hardware"
fi

# display a radiolist to chose the connected joystick(s)
### begin of program execution ###

# initialize variables
GAMEPORTS=""
JOYSTICKS=""
INPUTATTACH=""
ANALOG_OPTIONS=""
MODULES=""
PC_GAMEPORT=0		# 0 for no, 1 for yes
SERIAL=0

# set a sensible path
PATH=/sbin:/usr/sbin:/bin:/usr/bin
# make sure that lsjoystick is in the PATH
if [ \( -n "${PATH_TO_LSJOYSTICK}" \) -a \( -z "$(which lsjoystick)" \) -a \
     \( -x "${PATH_TO_LSJOYSTICK}/lsjoystick" \) ]
then
  PATH="${PATH}:${PATH_TO_LSJOYSTICK}"
fi

# basic functionality is provided by those two functions
# chose hardware
#configure_hardware
# show found joysticks
#show_joystick_list

# main loop
while true
do
  # present main menu
  # get function name to execute
  menu_item=$( \
  Xdialog --title "$(basename $0)" --stdout --separate-output --item-help \
  --no-cancel --no-tags --menubox \
  "chose action" 0 0 0 \
  "show_joystick_list" "show detected joysticks" "shows a list of all\
 joysticks already detected by the system" \
  "configure_hardware" "configure joystick hardware" "manually configure what\
 kinds of joysticks are connected" \
  "create_device_nodes" "create joystick devices" "creates 16 joystick devices
 (only needed if you don't have devfs and more joysticks than device nodes)" \
  "unload_all_modules" "unload drivers" "unloads every joystick driver module" \
  "exit 0" "quit" "quits joystick configuration program"
  )
  case ${menu_item} in
    configure_hardware)
      # check for kernel 2.4.x
      if [ $(uname -r|sed 's/^[^.]*\.\([^.]*\)..*$/\1/') -ne 4 ]
      then
        echo "Warning: only configuration of kernel 2.4 is supported" \
	  > /dev/stderr
        Xdialog --title "$(basename $0)" --infobox \
	  "only configuration of kernel 2.4 supported" 0 0 10000
	continue
      fi
      # reset configuration
      GAMEPORTS=""
      PC_GAMEPORT=0
      SERIAL=0
      JOYSTICKS=""
      INPUTATTACH=""
      ANALOG_OPTIONS=""
      MODULES=""
      # execute function
      ${menu_item};;

    unload_all_modules)
      # check for kernel 2.4.x
      if [ $(uname -r|sed 's/^[^.]*\.\([^.]*\)..*$/\1/') -ne 4 ]
      then
        echo "Warning: only configuration of kernel 2.4 is supported" \
	  > /dev/stderr
        Xdialog --title "$(basename $0)" --infobox \
	  "only configuration of kernel 2.4 supported" 0 0 10000
	continue
      fi
      # execute function
      ${menu_item};;

    *)
      # execute function
      ${menu_item};;
  esac
done
