#!/bin/sh

# rc.pcmcia 1.45 2002/08/08 06:43:43 (David Hinds)
#
# This is designed to work in BSD as well as SysV init setups.  See
# the HOWTO for customization instructions.
# Modified to comply with Debian's standards by Brian Mays
# <brian@debian.org>.
# Further Debian-specific modifications by Per Olofsson <pelle@dsv.su.se>.

# Tags for Red Hat init configuration tools
#
# chkconfig: 2345 45 96
# processname: cardmgr
# pidfile: /var/run/cardmgr.pid
# config: /etc/pcmcia/config
# config: /etc/pcmcia/config.opts
# description: PCMCIA support is usually to support things like ethernet \
#              and modems in laptops.  It won't get started unless \
#              configured so it is safe to have it installed on machines \
#              that don't need it.

# Exit if pcmcia-cs is not installed
test -x /sbin/cardmgr || exit 0

# If /lib/lsb/init-functions doesn't exist
# define them here, otherwise installer breaks
if [ -f /lib/lsb/init-functions ]; then
	. /lib/lsb/init-functions
else
	log_begin_msg () {
		echo "$@"
	}
	log_success_msg () {
		echo "$@"
	}
	log_failure_msg () {
		echo "$@"
	}
	log_warning_msg () {
		echo "$@"
	}
	log_end_msg () {
		if [ "$1" == 0 ]; then
			echo "   ...done."
		else
			echo "   ...fail!"
		fi
	}
fi

have_pcmcia=0
case "$(uname -r)" in
  2.4*)
    if [ -e "/proc/bus/pccard/drivers" ]; then
      have_pcmcia=1
    fi
  ;;
  2.6*)
    if ls /sys/class/pcmcia_socket/* >/dev/null 2>&1; then
      have_pcmcia=1
    fi
  ;;
esac

[ -f /etc/default/rcS ] && . /etc/default/rcS

# Save option values passed in through the environment
for N in PCMCIA PCIC PCIC_OPTS CORE_OPTS CARDMGR_OPTS SCHEME ; do
    V=`eval echo '$'$N` ; if [ "$V" ] ; then eval ENV_$N=\"$V\" ; fi
done

# Source PCMCIA configuration, if available
if [ -f /etc/default/pcmcia ] ; then
    # Debian startup option file
    . /etc/default/pcmcia
elif [ -f /etc/sysconfig/pcmcia ] ; then
    # Red Hat startup option file
    . /etc/sysconfig/pcmcia
else
    # Slackware startup options go right here:
    # Should be either i82365 or tcic
    PCIC=i82365
    # Put socket driver timing parameters here
    PCIC_OPTS=
    # Put pcmcia_core options here
    CORE_OPTS=
    # Put cardmgr options here
    CARDMGR_OPTS=
    # To set the PCMCIA scheme at startup...
    SCHEME=
fi
for N in PCMCIA PCIC PCIC_OPTS CORE_OPTS CARDMGR_OPTS SCHEME ; do
    V=`eval echo '$'ENV_$N` ; if [ "$V" ] ; then eval $N=\"$V\" ; fi
done
if [ "$PCMCIA" -a "$PCMCIA" != "yes" ] ; then exit 0 ; fi

usage()
{
    log_success_msg "Usage: $0 {start|stop|status|restart|reload|force-reload}"
}

cleanup()
{
    while read SN CLASS MOD INST DEV EXTRA ; do
	if [ "$SN" != "Socket" ] ; then
	    /etc/pcmcia/$CLASS stop $DEV 2> /dev/null
	fi
    done
}

module_is_loaded()
{
    grep -q "^$1 " /proc/modules
}

bridge_module_loaded()
{
    module_is_loaded yenta_socket || module_is_loaded i82365 \
	|| module_is_loaded tcic || module_is_loaded i82092
}

# Only works on 2.6 kernels
cardbus_bridge_present()
{
    [ -d /sys/bus/pci/devices ] && grep -q 0x060700 \
	/sys/bus/pci/devices/*/class
}

failed_to_load()
{
    log_failure_msg "Failed to load $1" >&2
    exit 1
}

load_module()
{
    module_is_loaded $1 || modprobe $@
}


EXITCODE=1
for x in "1" ; do

    if [ "$PCIC" = "" ] ; then
	log_failure_msg "PCIC module not defined in startup options!"
	break
    fi

    if [ $# -lt 1 ] ; then usage ; break ; fi
    action=$1

    case "$action" in

    start)
	if [ "$have_pcmcia" -eq 1 ]; then
	    log_begin_msg "Starting PCMCIA services..."

	    if [ -d /var/lib/pcmcia ] ; then
		SC=/var/lib/pcmcia/scheme
		RUN=/var/lib/pcmcia
	    else
		SC=/var/lib/misc/pcmcia-scheme
		RUN=/var/run
	    fi
	    if [ -L $SC -o ! -O $SC ] ; then rm -f $SC ; fi
	    if [ ! -f $SC ] ; then umask 022 ; touch $SC ; fi
	    if [ "$SCHEME" ] ; then umask 022 ; echo $SCHEME > $SC ; fi
		
	    if ! grep -q pcmcia /proc/devices ; then
		load_module pcmcia_core $CORE_OPTS || failed_to_load pcmcia_core
		# Treat i82365 specially, as many people with yenta_socket
		# incorrectly has PCIC set to i82365 for historical reasons
		if [ "$PCIC" = i82365 ]; then
		    if ! bridge_module_loaded ; then
			# On 2.6 kernels, we must not load any other bridge
			# modules than the right one
			if cardbus_bridge_present ; then
			    [ "$VERBOSE" != no ] && log_warning_msg "Using yenta_socket instead of $PCIC"
			    load_module yenta_socket || failed_to_load yenta_socket
			else
			    load_module $PCIC $PCIC_OPTS >/dev/null 2>&1
			    if [ $? -ne 0 ]; then
				if load_module yenta_socket >/dev/null 2>&1; then
				    [ "$VERBOSE" != no ] && log_warning_msg "Using yenta_socket instead of $PCIC"
				else
				    load_module $PCIC $PCIC_OPTS || failed_to_load $PCIC
				fi
			    fi
			fi
		    fi
		else
		    load_module $PCIC $PCIC_OPTS || failed_to_load $PCIC
		fi
		load_module ds || failed_to_load ds
	    fi

	    if [ -s /var/run/cardmgr.pid ] && kill -0 `cat /var/run/cardmgr.pid` 2>/dev/null ; then
		[ "$VERBOSE" != no ] && log_warning_msg "Cardmgr is already running"
		log_end_msg 0
	    else
		if [ -r $RUN/stab ] ; then
		    cat $RUN/stab | cleanup
		fi

		# If the cardmgr can't start and this system *does* have pcmcia hardware, show an error
		if ! /sbin/cardmgr $CARDMGR_OPTS 2>/dev/null && [ -d /sys/module/pcmcia_core ]; then
		    log_end_msg 1
		else
		    log_end_msg 0
		fi
	    fi
	    touch /var/lock/subsys/pcmcia 2>/dev/null
	else
	    log_success_msg "PCMCIA not present"
	fi
	EXITCODE=0
	;;

    stop)
	if [ "$have_pcmcia" -eq 1 ]; then
	    log_begin_msg "Shutting down PCMCIA services..."
	    if [ -s /var/run/cardmgr.pid ] ; then
		PID=`cat /var/run/cardmgr.pid`
		kill $PID
		# Give cardmgr a few seconds to handle the signal
		for N in 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 ; do
		    kill -0 $PID 2>/dev/null || break
		    sleep 2
		done
	    fi
	    killall -q "CardBus Watcher"
	    if module_is_loaded ds ; then
		/sbin/rmmod ds
		/sbin/rmmod $PCIC 2>/dev/null || \
		    /sbin/rmmod yenta_socket 2>/dev/null
		/sbin/rmmod pcmcia_core 2>/dev/null
	    fi
	    rm -f /var/lock/subsys/pcmcia
	    log_end_msg $?
	else
	    log_success_msg "PCMCIA not present"
	fi
	EXITCODE=0
	;;

    status)
	pid=`/bin/pidof cardmgr`
	log_begin_msg "Status of PCMCIA service is..."
	if [ "$pid" != "" ] ; then
	    log_end_msg 0
	    EXITCODE=0
	else
	    log_end_msg 1
	    EXITCODE=3
	fi
	;;

    restart)
	$0 stop
	$0 start
	EXITCODE=$?
	;;

    reload|force-reload)
	log_begin_msg "Reloading PCMCIA configuration files..."
	if [ -s /var/run/cardmgr.pid ] ; then # DEB: add check for pid file
	kill -1 `cat /var/run/cardmgr.pid` 2>/dev/null
	fi
	log_end_msg $?
	EXITCODE=0
	;;

    *)
	usage
	;;

    esac

done

# Only exit if we're in our own subshell
case $0 in *pcmcia) exit $EXITCODE ;; esac
