#!/bin/sh
# tlp - handle added usb devices
#
# Copyright (c) 2014 Thomas Koch <linrunner at gmx.net>
# This software is licensed under the GPL v2 or later.

# --- Constants
readonly LOGGER=logger

readonly USBD=/sys/bus/usb/devices
readonly USB_TIMEOUT=2
readonly USB_TIMEOUT_MS=2000
readonly USB_WWAN_VENDORS="0bdb 05c6 1199"

readonly RUNDIR=/var/run/tlp
readonly USB_DONE=usb_done

readonly CONFFILE=/etc/default/tlp

# --- Subroutines
wordinlist () { # test if word in list
                # $1: word, $2: whitespace-separated list of words
    local word

    if [ -n "${1-}" ]; then
        for word in ${2-}; do
            [ "${word}" != "${1}" ] || return 0 # exact match
        done
    fi

    return 1 # no match
}

echo_debug () { # $1: tag; $2: msg; echo debug msg if tag matches
    if wordinlist "$1" "$TLP_DEBUG"; then
        $LOGGER -p debug -t "tlp[$$,$PPID]" "$2"
    fi
}

# --- MAIN

# Read config
[ -f $CONFFILE ] || exit 0
. $CONFFILE

# Exit if TLP or autosuspend disabled
[ "$TLP_ENABLE" = "1" ] && [ "$USB_AUTOSUSPEND" = "1" ] || exit 0

# USB autosuspend has two principal operation modes:
#
# Mode 1 (optional):
# - System startup is handled by tlp-functions:set_usb_suspend()
# - Startup completion is signaled by "flag file" $USB_DONE
# - Newly added devices are handled by this udev script
# - Mode 1 is enabled by the private config variable X_TLP_USB_MODE=1
#
# Mode 2 (default):
# - Everything - including system startup, but not shutdown - is handled by this udev script

# Do exit if mode 1 and no startup completion flag
[ "$X_TLP_USB_MODE" = "1" ] && [ ! -f $RUNDIR/$USB_DONE ] && exit 0

# Get args
usbdev=/sys$1
exc=""

# Handle device
if [ -f $usbdev/power/autosuspend ] || [ -f $usbdev/power/autosuspend_delay_ms ]; then
    # device is autosuspendable

    # wait for sysfs to settle
    sleep 0.5

    # Check for hid subdevices and exclude them
    for subdev in $usbdev/*:*; do
        if [ -d $subdev ] && [ "$(cat $subdev/bInterfaceClass)" = "03" ]; then
            exc="_hid"
            break
        fi
    done

    # Check for wwan vendor ids
    USB_BLACKLIST_WWAN=${USB_BLACKLIST_WWAN:-1} # default is exclude

    if [ $USB_BLACKLIST_WWAN = "1" ] && [ -z "$exc" ]; then
        vendor="$(cat $usbdev/idVendor)"
        if wordinlist "$vendor" "$USB_WWAN_VENDORS"; then
            exc="_wwan"
        fi
    fi

    # Apply autosuspend
    ctrlf="control"
    autof="autosuspend_delay_ms"
    usbid="$(cat $usbdev/idVendor):$(cat $usbdev/idProduct)"
    busdev="Bus $(cat $usbdev/busnum) Dev $(cat $usbdev/devnum)"

    control="auto"
    if [ -n "$exc" ]; then
        # hid or wwan device
        control="on"
    elif wordinlist "$usbid" "$USB_BLACKLIST"; then
        # blacklisted device
        control="on"
        exc="_bl"
    fi

    if [ -f $usbdev/power/control ]; then
        echo "$control" > $usbdev/power/control
    else
        # level is deprecated
        echo "$control" > $usbdev/power/level
        ctrlf="level"
    fi

    if [ -f $usbdev/power/autosuspend_delay_ms ]; then
        echo $USB_TIMEOUT_MS > $usbdev/power/autosuspend_delay_ms 2> /dev/null
        if [ $? != 0 ]; then
            # openSUSE 11.4/2.6.37: writing to autosuspend_delay_ms fails -> fallback to autosuspend
            echo_debug "usb" "udev_usb.autosuspend_delay_ms_not_writable: $busdev ID $usbid $usbdev"
            echo $USB_TIMEOUT > $usbdev/power/autosuspend
            autof="autosuspend"
        fi
    else
        # autosuspend is deprecated
        echo $USB_TIMEOUT > $usbdev/power/autosuspend
        autof="autosuspend"
    fi

    echo_debug "usb" "udev_usb.$control$exc: $busdev ID $usbid $usbdev [$ctrlf $autof]"
fi

exit 0


