#!/bin/sh
#
### BEGIN INIT INFO
# Provides: pcmcia
# Default-Start: 1 2 3 4 5
# Default-Stop: 0 6
# Required-Start:
# Required-Stop:
# Short-Description: PCMCIA support (obsolete implementation)
# Description: This service provides user space management of
#  PCMCIA devices, but using an obsolete kernel interface.
#  Please use pcmciautils and udev instead.
### END INIT INFO

test -x /sbin/cardmgr || exit 5

umask 022

# 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_action_begin_msg ()
    {
	echo "$@..."
    }
    log_success_msg ()
    {
	echo "$@"
    }
    log_failure_msg ()
    {
	echo "$@"
    }
    log_warning_msg ()
    {
	echo "$@"
    }
    log_action_end_msg ()
    {
	if [ "$1" = 0 ]; then
	    echo "done."
	else
	    echo "fail!"
	fi
    }
fi

KERNEL_VERSION="$(uname -r | sed 's/-.*//')"

pcmciautils_supported_kernel()
{
    case $KERNEL_VERSION in
	2.[012345].*|2.6.[0-9]|2.6.[0-9][!0-9]*) return 1 ;;
	2.6.1[012]|2.6.1[012][!0-9]*) return 1 ;;
    esac
    return 0
}

# Are we running from init?
run_by_init()
{
    ([ "$previous" ] && [ "$runlevel" ]) || [ "$runlevel" = S ]
}

if [ -e /dev/.udev ] && pcmciautils_supported_kernel; then
    if ! run_by_init; then
	log_failure_msg "Linux >= 2.6.13-rc1 and udev is enabled; use pcmciautils instead"
    fi
    exit 0
fi

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
}

# returns 0 if module was loaded and is now removed
remove_module()
{
    module_is_loaded "$1" && /sbin/rmmod "$1"
}

# Source PCMCIA configuration, if available
if [ -f /etc/default/pcmcia ]; then
    # 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

    . /etc/default/pcmcia
    
    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
fi

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

case "$1" in
    start)
	if [ "x$PCIC" = x ] && expr $(uname -r) : "2.6.*" >/dev/null 2>&1 \
	    && ! ls /sys/class/pcmcia_socket/* >/dev/null 2>&1; then
	    log_success_msg "PCMCIA not present"
	    exit 1
	fi

	log_action_begin_msg "Starting PCMCIA services"

	# Move scheme file if it's at the old location
	if [ -d /var/lib/pcmcia ]; then
	    mv /var/lib/pcmcia/scheme /var/lib/misc/pcmcia-scheme || true
	    rm -rf /var/lib/pcmcia
	fi

	SC=/var/lib/misc/pcmcia-scheme
	RUN=/var/run

	if [ -L $SC -o ! -O $SC ]; then
	    rm -f $SC
	fi
	if [ ! -f $SC ]; then
	    touch $SC
	fi
	if [ "$SCHEME" ]; then
	    echo $SCHEME > $SC
	fi

	if [ "x$CORE_OPTS" != "x" ]; then
	    modprobe -q pcmcia_core $CORE_OPTS
	fi

	if ! ls /sys/class/pcmcia_socket/* >/dev/null 2>&1 \
	    && [ "x$PCIC" != "x" ]; then
	    # 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"
			modprobe -q yenta_socket
		    else
			modprobe -q $PCIC $PCIC_OPTS >/dev/null 2>&1
			if [ $? -ne 0 ]; then
			    if modprobe -q yenta_socket >/dev/null 2>&1; then
				[ "$VERBOSE" != no ] && log_warning_msg "Using yenta_socket instead of $PCIC"
			    else
				modprobe -q $PCIC $PCIC_OPTS
			    fi
			fi
		    fi
		fi
	    else
		modprobe -q $PCIC $PCIC_OPTS
	    fi
	fi

	if ! grep -q ' pcmcia$' /proc/devices; then
	    if ! modprobe ds; then
		log_failure_msg "No kernel PCMCIA Driver Services available"
		exit 1
	    fi
	fi
	if ! grep -q ' pcmcia$' /proc/devices; then
	    modprobe -q pcmcia || failed_to_load pcmcia
	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_action_end_msg 0
	    exit 0
	else
	    if [ -r $RUN/stab ]; then
		cat $RUN/stab | cleanup
	    fi

	    if /sbin/cardmgr -f $CARDMGR_OPTS; then
		log_action_end_msg 0
		exit 0
	    else
	        log_action_end_msg 1
		exit 1
	    fi
	fi
	;;

    stop)
	log_action_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"
	remove_module ds
	remove_module pcmcia
	if [ "x$PCIC" != "x" ]; then
	    rmmod "$PCIC" 2>/dev/null || rmmod yenta_socket 2>/dev/null
	    rmmod rsrc_nonstatic 2>/dev/null
	    rmmod pcmcia_core 2>/dev/null
	fi

	log_action_end_msg 0
	;;
    
    restart)
	$0 stop
	$0 start
	exit $?
	;;

    try-restart)
	if [ -s /var/run/cardmgr.pid ] \
	    && kill -0 `cat /var/run/cardmgr.pid` 2>/dev/null; then
	    $0 stop
	    $0 start
	    exit $?
	else
	    log_success_msg "cardmgr not running"
	    exit 0
	fi
	;;

    reload|force-reload)
	log_action_begin_msg "Reloading PCMCIA configuration files"
	if [ -s /var/run/cardmgr.pid ] \
	    && kill -0 `cat /var/run/cardmgr.pid` 2>/dev/null; then
	    if kill -1 `cat /var/run/cardmgr.pid` 2>/dev/null; then
		log_action_end_msg 0
		exit 0
	    else
		log_action_end_msg 1
		exit 1
	    fi
	else
	    log_action_end_msg 1
	    exit 7
	fi
	;;

    status)
	if [ -s /var/run/cardmgr.pid ]; then
	    if kill -0 `cat /var/run/cardmgr.pid` 2>/dev/null; then
		log_success_msg "cardmgr is running"
		exit 0
	    else
		log_failure_msg "/var/run/cardmgr.pid exists but cardmgr is not running"
		exit 1
	    fi
	else
	    log_success_msg "cardmgr is not running"
	    exit 3
	fi
	;;

    *)
	log_success_msg "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
	exit 2
	;;
esac
