#!/bin/sh
#
# chkconfig:	12345 02 98
# description:	Forcedeth-wol is used to work-around nVidia \
#		ethernet drivers and enable Wake-On-Lan for it.
#

# Set the path.
PATH=/sbin:/bin:/usr/sbin:/usr/bin

# NLS
NLS_DOMAIN="forcedeth-wol"

# Source function library
. /etc/rc.d/init.d/functions

# Workaround for Wake-On-Lan for nForce ethernet drivers.
# To realy help it also requires patched kernel module.
# Written by Pawel Wilk using idea from Arjen Verweij,
# see: http://atlas.et.tudelft.nl/verwei90/nforce2/
#
# Call it only when system halts, there is no real
# return to the D0 power state after execution!
#
forcedeth_workaround() {
    RESULT=0
    LC_ALL=C modinfo -F description forcedeth 2>&1 | grep -qi 'timerirq disabled' || return 0

    typeset iface bus_dev_fn bus lookfor dev_index cur_state
    
    RESULT=0
    for iface in $(ip link show | awk -F'[ :]+' '/eth[0-9]+/ {print $2}')
    do
	if LC_ALL=C ethtool -i "${iface}" 2>&1 | egrep -qi 'driver:[[:blank:]]forcedeth'; then
	    case $(LC_ALL=C ethtool "${iface}" 2>&1 | awk 'tolower($1) ~ "wake-on:" {print $2}') in
		*d*) continue ;; # 'd' letter means that the WON is DISABLED for this interface
		"") continue ;;  # nothing means that the WON is not supported here
	    esac
	    set $(LC_ALL=C ethtool -i ${iface} 2>&1 | awk -F'[ :.]+' '/^bus-info:/ {printf ("%d %d %d",$3,$4,$5) }')
	    bus="$1"
	    dev="$2"
	    fn="$3"
	    if [ -n "${bus} ${dev} ${fn}" -a "${bus} ${dev} ${fn}" != "0 0 0" ]; then
		lookfor="at bus ${bus} device/function ${dev}/${fn}"
		dev_index=$(LC_ALL=C pci-config -B${bus} 2>&1 | grep -i "${lookfor}" | awk '/Device \#[0-9]+/ {print $2}')
		if [ -n "${dev_index}" ]; then
		    show "Forcing sleep state for the nForce interface (%s)" ${iface} ; busy
		    ip link set ${iface} up >/dev/null 2>&1 # need it to be up
		    sleep 1
		    pci-config -S -$dev_index >/dev/null 2>&1
		    RESULT=$?
		    cur_state=$(LC_ALL=C pci-config -a -$dev_index 2>&1 | awk -F'[ \t:.]+' ' tolower($2$3) ~ "powerstate" {print tolower($4)}')
		    if [ "${cur_state}" != "d3" ]; then
			RESULT=1
		    fi
		    if [ $RESULT -gt 0 ]; then
                	fail
            	    else
                        ok
                    fi
		fi
	    fi
	fi
    done
    return $RESULT
}

# See how we were called.
case "$1" in
  start)
  	[ ! -f /var/lock/subsys/forcedeth-wol ] && touch /var/lock/subsys/forcedeth-wol
	exit 0
	;;
  stop)
	[ -x /sbin/runlevel -o -x /usr/sbin/runlevel ] || exit 2
	[ -x /sbin/ethtool -o -x /usr/sbin/ethtool ] || exit 2
	[ -x /sbin/pci-config -o -x /usr/sbin/pci-config ] || exit 2
	rlevel=$(/sbin/runlevel | awk '{print $2}')
	if [ "${rlevel}" = "0" ]; then
	    forcedeth_workaround
	else
	    show "Delaying work-around for nForce interfaces" ; busy
	    RESULT=0
	    ok
	fi
	rm -f /var/lock/subsys/forcedeth-wol >/dev/null 2>&1
	exit $RESULT
	;;
  status)
	if LC_ALL=C modinfo -F description forcedeth | grep -qi 'timerirq disabled'; then
	    if [ -f /var/lock/subsys/forcedeth-wol ]; then
		nls "Work-around is ready to launch on system shutdown."
	    else
		nls "Work-around is manually disabled from launching on system shutdown."
	    fi
	    exit 0
	else
	    nls "Work-around is not ready - kernel module is NOT patched."
	    exit 1
	fi
	;;
  *)
	msg_usage "$0 {start|stop|status}"
	exit 1
	;;
esac

exit 0
