#!/bin/sh
# tlp - display power save and usb autosuspend status
#
# Copyright (c) 2011 Thomas Koch <linrunner@gmx.net>
# This software is licensed under the GPL v2.

# --- Definitions
LIB=/usr/lib/tlp-pm/tlp-functions
RFLIB=/usr/lib/tlp-pm/tlp-rf-func
TLPCFG=/etc/default/tlp

HDPARM=hdparm
SMARTCTL=$(which smartctl 2> /dev/null)
LSB=$(which lsb_release 2> /dev/null)

ASPM=/sys/module/pcie_aspm/parameters/policy
USBD=/sys/bus/usb/devices

# --- Functions
echoparm () { # $1: file, $2: n/a message, $3: unit, $4: cutoff
    local val
    
    if [ -f $1 ]; then
        val=`cat $1`
        if [ -n "$4" ]; then
            val=${val%$4}
        fi
        if [ -n "$3" ]; then    
            echo "$1 = $val [$3]"
        else
            echo "$1 = $val"
        fi
    else
        if [ -n "$2" ]; then
            echo "$1 = ($2)"
        else
            echo "$1 = (not available)"
        fi
    fi
}

# --- Read libraries
if [ -f $LIB ]; then
    . $LIB
else
    echo "Fatal error: library $LIB not installed."
    exit 1
fi

if [ -f $RFLIB ]; then
    . $RFLIB
else
    echo "Fatal error: library $RFLIB not installed."
    exit 1
fi

# --- MAIN
check_root

nodebug=1
load_tp_modules

echo "--- tlp $TLPVER --------------------------------------------"

if [ -f $TLPCFG ]; then
    . $TLPCFG
else
    echo "Warning: config file $TLPCFG not present."
    echo
fi

echo "System = $($DMI -s system-manufacturer)" \
       "$($DMI -s system-version)" \
       "$($DMI -s system-product-name)"
echo "BIOS = $($DMI -s bios-version)"

[ -x "$LSB" ] && echo "Release = $(lsb_release -d -s)"
echo "Kernel = $(uname -r -m)"
echo

if check_laptop_mode_tools; then
    if [ "$TLP_ENABLE" = "1" ]; then
        echo "tlp power save = enabled"
    else
        echo "tlp power save = not enabled"
    fi
fi

if get_power_state; then
    echo "power source = ac"
else
    echo "power source = battery"
fi
echo

# cpu
for cpup in /sys/devices/system/cpu/cpu?/cpufreq/scaling_governor; do
    echoparm $cpup
done
echo

for pool in mc smp smt; do
    sdev="/sys/devices/system/cpu/sched_${pool}_power_savings"
    [ -w "$sdev" ] || continue
    echoparm $sdev
    echo
done

for cpup in /sys/devices/system/cpu/cpu?/cpufreq/phc_controls; do
    echoparm $cpup "phc kernel not available"
done
echo 

# temperatures
echoparm /proc/acpi/ibm/thermal "thinkpad_acpi not available"
echo

# laptop-mode, dirty buffers params
echoparm /proc/sys/vm/laptop_mode
echoparm /proc/sys/vm/dirty_writeback_centisecs
echoparm /proc/sys/vm/dirty_expire_centisecs
echoparm /proc/sys/vm/dirty_ratio
echoparm /proc/sys/vm/dirty_background_ratio
echoparm /proc/sys/fs/xfs/age_buffer_centisecs
echoparm /proc/sys/fs/xfs/xfssyncd_centisecs   
echoparm /proc/sys/fs/xfs/xfsbufd_centisecs
echo 

# disk apm level
DISK_DEVICES=${DISK_DEVICES:=sda}
for dev in $DISK_DEVICES; do
    get_disk_dev $dev

    if [ -b /dev/$disk_dev ]; then
        check_disk_hdparm_cap $disk_dev
        if [ $? = 0 ]; then
            echo "/dev/$disk_dev:"
                
            if [ -n "$disk_id" ]; then
                echo "          Disk ID   = $disk_id"
            fi
            
            echo -n "          Model     = "
            echo_disk_model $disk_dev
            
            echo -n "          Firmware  = "
            echo_disk_firmware $disk_dev
            
            get_disk_apm_level $disk_dev
            apm=$?
            echo -n "          APM Level = "
            case $apm in
                0|255) echo "none/disabled" ;;
                *)     echo $apm ;;
            esac
            
            echo "          scheduler = $(cat /sys/block/$disk_dev/queue/scheduler | sed -r 's/.*\[(.*)\].*/\1/')"
        
            if [ -x "$SMARTCTL" ]; then
                echo 
                echo "        SMART info:"
                $SMARTCTL -A /dev/$disk_dev | \
                  awk -F ' ' '$2 ~ /Start_Stop_Count|Reallocated_Sector_Ct|Load_Cycle_Count/ \
                                    { printf "          %3d %-25s = %8d \n", $1, $2, $10 } ; \
                              $2 ~ /Power_On_Hours/ \
                                    { printf "          %3d %-25s = %8d %s\n", $1, $2, $10, "[h]" } ; \
                              $2 ~ /Host_Writes/ \
                                    { printf "          %3d %-25s = %8.3f %s\n", $1, $2, $10 / 32768.0, "[TB]" } ; \
                              $2 ~ /Available_Reservd_Space|Media_Wearout_Indicator/ \
                                    { printf "          %3d %-25s = %8d %s\n", $1, $2, $4, "[%]" }'
            fi
        fi
    fi
done
echo

# sata alpm
cnt=0
for i in /sys/class/scsi_host/host* ; do
    if [ -f $i/link_power_management_policy ]; then
        echoparm $i/link_power_management_policy
        cnt=$((cnt+1))
    fi
done
if [ $cnt = 0 ]; then
    echo "sata link power management: no ahci-enabled host controller detected"
fi  
echo 

# pcie aspm
if [ -f $ASPM ]; then
    pol=$(cat $ASPM | sed -r 's/.*\[(.*)\].*/\1/')
    echo "$pol" > $ASPM 2> /dev/null
    if [ $? = 0 ]; then
        echo "$ASPM = $pol"
    else
        echo "$ASPM = $pol (disabled by kernel)"
    fi 
else
    echo "$ASPM = (not available)"
fi
echo

# radeon power profile
for card in /sys/class/drm/card[0-9]/device ; do
   if [ -f $card/power_method -a -f $card/power_profile ]; then
       echoparm $card/power_method
       echoparm $card/power_profile
       echo
       break
   fi
done

# rfkill state
for i in bluetooth wifi wwan; do
    get_devc $i
    get_devs $i
    echo_device_state $i $devs
done
echo

# wifi power mode
get_wifi_ifaces
for iface in $WIFACES; do
    if [ -n "$iface" ]; then
        wifipm=$($IWC $iface 2> /dev/null | grep "Power Management" | \
          sed -r 's/.*Power Management:(on|off).*/\1/')
        get_wifi_driver $iface
        echo -n "$iface($WIFIDRV): power management = "
        case $wifipm in
            on)
                echo "on"
                ;;
                
            off)
                if [ -z "$($IWC $iface power off 2>&1)" ]; then
                    echo "off"
                else
                    echo "off (disabled by kernel)"
                fi
                ;;
                
            *) 
                echo "unknown"
                ;;
        esac
    fi
done
echo
    
# sound power mode
if [ -d /sys/module/snd_hda_intel ]; then
    echoparm /sys/module/snd_hda_intel/parameters/power_save
    echoparm /sys/module/snd_hda_intel/parameters/power_save_controller
fi
if [ -d /sys/module/snd_ac97_codec ]; then
    echoparm /sys/module/snd_ac97_codec/parameters/power_save
fi
echo 

# battery info & charge thresholds 
if [ -d /sys/devices/platform/smapi ]; then
    # ThinkPad via tp_smapi
    for bat in /sys/devices/platform/smapi/BAT[01]; do
        if [ -d $bat ] && [ "$(cat $bat/installed)" = "1" ]; then
            echoparm $bat/manufacturer
            echoparm $bat/manufacture_date
            echoparm $bat/first_use_date
            echoparm $bat/cycle_count
            echoparm $bat/design_capacity - mWh
            echoparm $bat/last_full_capacity - mWh
            echoparm $bat/remaining_capacity - mWh
            echoparm $bat/remaining_percent - "%"
            echoparm $bat/remaining_running_time_now - min
            echoparm $bat/remaining_charging_time - min
            echo
            echoparm $bat/start_charge_thresh - "%"
            echoparm $bat/stop_charge_thresh - "%"
            echo
        fi
    done
elif [ -d /sys/class/power_supply ]; then
    if [ -d /sys/devices/platform/thinkpad_acpi ]; then
        echo "ThinkPad extended battery info not available (missing tp_smapi kernel module)."
    fi
    # generic
    for bat in /sys/class/power_supply/BAT?; do
        if [ -d $bat ] && [ "$(cat $bat/present)" = "1" ]; then
            echoparm $bat/manufacturer
            if [ -f $bat/energy_full ]; then 
                echoparm $bat/energy_full_design - mWh 000
                echoparm $bat/energy_full - mWh 000
                echoparm $bat/energy_now - mWh 000
            elif [ -f $bat/charge_full ]; then
                echoparm $bat/charge_full_design - mAh 000
                echoparm $bat/charge_full - mAh 000
                echoparm $bat/charge_now - mAh 000
                echoparm $bat/cycle_count - 
            fi
            echo
        fi
    done
fi

# usb autosuspend
if [ "$USB_AUTOSUSPEND" = "1" ]; then
    echo "tlp usb autosuspend = enabled"
else
    echo "tlp usb autosuspend = not enabled"
fi
echo "tlp usb blacklist = ${USB_BLACKLIST:=(not configured)}"
echo

devices=$(ls $USBD | grep -v ':')
for usbdev in $devices; do
    if [ -f $USBD/$usbdev/power/autosuspend_delay_ms ]; then
        asp="$USBD/$usbdev/power/autosuspend_delay_ms"
    elif [ -f $USBD/$usbdev/power/autosuspend ]; then
        asp="$USBD/$usbdev/power/autosuspend"
    else
        asp=""
    fi
    
    if [ -n "$asp" ]; then
        if [ -f $USBD/$usbdev/power/control ]; then
            control="control = $(cat $USBD/$usbdev/power/control)" 
        else
            # level is deprecated
            control="level = $(cat $USBD/$usbdev/power/level)" 
        fi
        
        # show dev path, state, usb id
        echo -n "$asp = $(cat $asp)," \
             "$control --" \
             "$(cat $USBD/$usbdev/idVendor):$(cat $USBD/$usbdev/idProduct) "
        
        # show product string     
        product="$([ -f $USBD/$usbdev/product ] && cat $USBD/$usbdev/product)"
        product="${product%% }"
        echo -n "${product:-unknown device} "
        
        # show drivers
        driverlist=""
        for subdev in $USBD/$usbdev/*:*; do
            if [ -L $subdev/driver ]; then
                driver=$(readlink $subdev/driver)
                driver=${driver##*/}
                if ! patinstr "$driver" "$driverlist"; then
                    if [ -n "$driverlist" ]; then
                        driverlist="$driverlist, $driver"
                    else
                        driverlist="$driver"
                    fi
                fi
            fi
        done 
        echo "(${driverlist:-no driver})"
    fi
done
echo

exit 0
