#! /bin/sh
#
# Laptop mode tools module: usb-autosuspend.
#

# Check whether a USB device is listed by ID
listed_by_id() {
	device=$1
	list=$2
	for usbid in $list; do
		if ! echo $usbid | grep -q ':'; then
			log "MSG" "WARNING: Invalid entry \"$usbid\" in \"$2\"."
		fi
		vendor=$(echo $usbid | cut -d: -f1)
		product=$(echo $usbid | cut -d: -f2)
		grep -qi $vendor $device/idVendor 2>/dev/null\
		 && grep -qi $product $device/idProduct 2>/dev/null\
		 && return 0
	done
	return 1
}

# Check whether the USB driver type is blacklisted
listed_by_type() {
	device=$1
	device_base=`basename $device`
	list=$2
	for driver_type in $list; do
		# The device could have been removed in the meantime
		[ -r $device/uevent ] || continue
		if grep -s -q DRIVER=$driver_type $device/uevent; then
			return 0
		fi
		# Check child devices as well.  The actual driver type is
		# listed in a child device, not the top-level device.
		for subdevice in $device/$device_base*; do
			if [ -f $subdevice/uevent ]; then
				if grep -q DRIVER=$driver_type\
				    $subdevice/uevent; then
					return 0
				fi
			fi
		done
	done
	return 1
}

# Checks whether a device is blacklisted by either ID or driver type
blacklisted() {
	listed_by_id $1 "$AUTOSUSPEND_USBID_BLACKLIST"\
	|| listed_by_type $1 "$AUTOSUSPEND_USBTYPE_BLACKLIST"\
	|| return 1
	return 0
}

# Checks whether a device is whitelisted by either ID or driver type
whitelisted() {
	listed_by_id $1 "$AUTOSUSPEND_USBID_WHITELIST"\
	|| listed_by_type $1 "$AUTOSUSPEND_USBTYPE_WHITELIST"\
	|| return 1
	return 0
}

if [ x$CONTROL_USB_AUTOSUSPEND = x1 ] || [ x$ENABLE_AUTO_MODULES = x1 -a x$CONTROL_USB_AUTOSUSPEND = xauto ]; then
	if [ $ON_AC -eq 1 ]; then
		if [ "$ACTIVATE" -eq 1 ]; then
			SUSPEND_USB_DEVICES="$LM_AC_SUSPEND_USB"
		else
			SUSPEND_USB_DEVICES="$NOLM_AC_SUSPEND_USB"
		fi
	else
		SUSPEND_USB_DEVICES="$BATT_SUSPEND_USB"
	fi

	if [ -d /sys/bus/usb/devices ]; then
		if [ "$DEVICES" != "" ]; then
			# If a list of devices has been provided, operate on only the
			# listed USB devices.
			DEVICE_LIST=""
			for DEVICE in $DEVICES; do
				DEVICE_LIST="$DEVICE_LIST $DEVICE"
			done
		else
			# If no list was provided, operate on all USB devices
			DEVICE_LIST=/sys/bus/usb/devices/*
		fi
	else
		# This will rarely happen.
		log "VERBOSE" "There are no USB devices."
	fi

	if [ x$SUSPEND_USB_DEVICES = x1 ]; then

		if [ "$DEVICE_LIST" != "" ]; then
			for usb_device in $DEVICE_LIST; do
				usb_device=`basename $usb_device`;

				USE_DEVICE=0
				if [ x$AUTOSUSPEND_USE_WHITELIST = x1 ]; then
					if whitelisted /sys/bus/usb/devices/$usb_device; then
						USE_DEVICE=1
					else
						log "VERBOSE" "Device $usb_device not whitelisted, skipping auto suspend."
					fi
				else
					if ! blacklisted /sys/bus/usb/devices/$usb_device; then
						USE_DEVICE=1
					else
						logger "Device $usb_device is blacklisted, skipping auto suspend."
					fi
				fi

				if [ x$USE_DEVICE = x1 ]; then
					if [ -f /sys/bus/usb/devices/$usb_device/power/autosuspend ]; then
						echo $AUTOSUSPEND_TIMEOUT > /sys/bus/usb/devices/$usb_device/power/autosuspend;
						log "VERBOSE" "Enabling auto suspend mode for usb device $usb_device."
					else
						log "VERBOSE" "Not enabling auto suspend mode for usb device $usb_device"
					fi

					if [ -f /sys/bus/usb/devices/$usb_device/power/control ]; then
						echo "auto" > /sys/bus/usb/devices/$usb_device/power/control;
						log "VERBOSE" "Enabling auto power level for usb device $usb_device."
					elif [ -f /sys/bus/usb/devices/$usb_device/power/level ]; then
						echo "auto" > /sys/bus/usb/devices/$usb_device/power/level;
						log "VERBOSE" "Enabling auto power level for usb device $usb_device."
					else
						log "VERBOSE" "Not enabling auto power level for usb device $usb_device"
					fi
				fi
			done
		fi
	else
		AUTOSUSPEND_TIMEOUT=0
		if [ "$DEVICE_LIST" != "" ]; then
			for usb_device in $DEVICE_LIST;
			do
				usb_device=`basename $usb_device`;
				if [ -f /sys/bus/usb/devices/$usb_device/power/autosuspend ]; then
					echo $AUTOSUSPEND_TIMEOUT > /sys/bus/usb/devices/$usb_device/power/autosuspend;
					log "VERBOSE" "Disabling auto suspend mode for usb device $usb_device."
				else
					log "VERBOSE" "Not disabling auto suspend mode for usb device $usb_device"
				fi

				if [ -f /sys/bus/usb/devices/$usb_device/power/control ]; then
					echo "on" > /sys/bus/usb/devices/$usb_device/power/control;
					log "VERBOSE" "Enabling ON power level for usb device $usb_device."
				elif [ -f /sys/bus/usb/devices/$usb_device/power/level ]; then
					echo "on" > /sys/bus/usb/devices/$usb_device/power/level;
					log "VERBOSE" "Enabling ON power level for usb device $usb_device."
				else
					log "VERBOSE" "Not enabling ON power level for usb device $usb_device"
				fi
			done
		fi
	fi
else
	log "VERBOSE" "USB autosuspend is disabled."
fi

