#!/bin/sh
#
# Copyright 2014 Canonical Ltd.
#
# Author: Alberto Milone <alberto.milone@canonical.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

host_arch_main=x86_64-linux-gnu
host_arch_other=i386-linux-gnu
main_arch=""$host_arch_main"_gl_conf"
other_arch=""$host_arch_other"_gl_conf"

last_boot_gfx="/etc/last_boot_gfx"

xorg_conf="/etc/X11/xorg.conf"
amd_vendor_id="1002"
intel_vendor_id="8086"

is_test=false
test_laptop=false
test_no_fglrx=false
log=/var/log/amd-xconfig.log

args="$@"

while test $# -gt 0; do
    case $1 in
        --test)
            fake=$2
            is_test=true
            shift
            ;;
        --laptop)
            test_laptop=true
            #shift
            ;;
        --no-fglrx)
            test_no_fglrx=true
            #shift
            ;;
        --log)
            log=$2
            shift
            ;;
        --last-boot)
            last_boot_gfx=$2
            shift
            ;;
#        *)
#            echo >&2 "Invalid argument: $1"
#            ;;
    esac
    shift
done

# Remove the log
rm -f $log

# Cache the devices
if $is_test; then
    echo "\n=====" >> $log 2>&1
    echo "ARGUMENTS:\n$args" >> $log 2>&1
    echo "\nRESULTS:\n" >> $log 2>&1
    if [ "$fake" = "intel" ]; then
        cards=`cat <<"EOF"
00:01.0 0300: 8086:0150 (rev 09)
00:00.0 0600: 8086:0150 (rev 09)
00:01.0 0604: 8086:0151 (rev 09)
EOF`
    elif [ "$fake" = "intel_amd" ]; then
        cards=`cat <<"EOF"
00:01.0 0300: 8086:0150 (rev 09)
00:00.2 0806: 1022:1423
01:00.0 0300: 1002:130f
EOF`
    elif [ "$fake" = "intel_nvidia" ]; then
        cards=`cat <<"EOF"
00:01.0 0300: 8086:0150 (rev 09)
00:00.2 0806: 1022:1423
01:00.0 0300: 10de:130f
EOF`
    elif [ "$fake" = "amd" ]; then
        cards=`cat <<"EOF"
00:00.0 0600: 1022:1422
00:00.2 0806: 1022:1423
00:01.0 0300: 1002:130f
EOF`
    elif [ "$fake" = "amd_amd" ]; then
        cards=`cat <<"EOF"
00:00.0 0600: 1022:1422
00:00.2 0806: 1022:1423
00:01.0 0300: 1002:130f
01:00.0 0300: 1002:665c
EOF`
    elif [ "$fake" = "multi_amd" ]; then
        cards=`cat <<"EOF"
00:00.0 0600: 1022:1422
00:00.2 0806: 1022:1423
00:01.0 0300: 1002:130f
01:00.0 0300: 1002:665c
02:00.0 0300: 1002:666c
EOF`
    elif [ "$fake" = "amd_nvidia" ]; then
        cards=`cat <<"EOF"
00:00.0 0600: 1022:1422
00:00.2 0806: 1022:1423
00:01.0 0300: 1002:130f
01:00.0 0300: 10de:665c
EOF`
    else
        echo "unknown test"
        exit 0
    fi
else
    cards="$(lspci -n)"
fi

gfx_300="$(echo "$cards" | grep 300)"
gfx_301="$(echo "$cards" | grep 301)"
gfx_302="$(echo "$cards" | grep 302)"
gfx_380="$(echo "$cards" | grep 380)"

gfx_300="${gfx_300:-}"
gfx_301="${gfx_301:-}"
gfx_302="${gfx_302:-}"
gfx_380="${gfx_380:-}"

has_amd=false
has_intel=false
amd_cards_number=0
cards_number=0
has_changed=false
first_time=false

is_laptop () {
    # We only support laptops by default,
    # you can override this check by creating
    # the /etc/force-pxpress file
    if [ -f "$force_pxpress" ]; then
        echo "yes"
    else
        if [ -n "`ls -A /sys/class/power_supply/`" ] && \
           [ -d "/proc/acpi/button/lid" ]; then
            echo "yes"
        else
            echo "no"
        fi
    fi
}

get_current_alternative() {
    master_link="$1"
    value=""
    alternatives="$(/usr/bin/update-alternatives --query "$master_link" 2>/dev/null || true)"
    if [ -n "$alternatives" ]; then
        value="$(echo "$alternatives" | grep "Value:" | sed "s/Value: //g")"
    fi
    echo "$value"
}

set_alternative() {
    master_link="$1"
    path="$2"
    /usr/bin/update-alternatives --set "$master_link" "$path" || true
}

select_mesa() {
    set_alternative "$main_arch" "/usr/lib/$host_arch_main/mesa/ld.so.conf"
    set_alternative "$other_arch" "/usr/lib/$other_arch_main/mesa/ld.so.conf" || true
    /sbin/ldconfig
}

get_cards_data() {
    for gfx_class in "$gfx_300" "$gfx_301" "$gfx_302" "$gfx_380"; do
        if [ -n "$gfx_class" ]; then
            if echo "$gfx_class" | egrep -q "$intel_vendor_id"; then
                # Intel detected
                has_intel=true
            fi
            if echo "$gfx_class" | egrep -q "$amd_vendor_id"; then
                amd_cards_number=$((amd_cards_number + 1))
                # AMD detected
                has_amd=true
            fi
            cards_number=$((cards_number + `echo "$gfx_class" | wc -l`))
        fi
    done
}

enable_all_amds() {
    if [ -f /usr/lib/fglrx/bin/aticonfig ]; then
        /usr/lib/fglrx/bin/aticonfig --adapter=all --initial
    fi
}

config_changed() {
    if [ -s "$last_boot_gfx" ]; then
        last_gfx="`cat $last_boot_gfx`"
        if [ "$last_gfx" != "$cards_number" ]; then
            has_changed=true
        else
            has_changed=false
        fi
    else
        # First time
        has_changed=true
        first_time=true
    fi
}


if $is_test; then
    if $test_no_fglrx; then
        current_alternative="mesa"
    else
        current_alternative="fglrx"
    fi
else
    current_alternative="$(get_current_alternative $main_arch)"
fi

# Check that we're dealing with fglrx
if ! echo "$current_alternative" | egrep -q "fglrx"; then
    echo "Nothing to do. fglrx is not the alternative in use" >> $log 2>&1
    exit 0
fi

# Get the devices
get_cards_data

# See if we're dealing with a laptop
if $is_test; then
    if $test_laptop; then
        laptop=true
    else
        laptop=false
    fi
else
    if [ "`is_laptop`" = "yes" ]; then
        laptop=true
    else
        laptop=false
    fi
fi

# See if the configuration has changed
config_changed

# Write to the file
if $first_time || $has_changed; then
    echo "$cards_number" > $last_boot_gfx
fi

if $has_intel; then
    if $has_amd; then
        if "$laptop"; then
            # Shouldn't the alternative be pxpress instead of fglrx?
            echo "hybrid intel+amd: no need to do anything" >> $log 2>&1
        else
            # Probably dealing with a desktop
            # the Intel GPU is integrated and we'll switch to AMD
            echo "intel+amd desktop detected" >> $log 2>&1
            if $has_changed; then
                # Have the graphics cards changed?
                echo "The devices have changed: reconfiguring X" >> $log 2>&1
                if ! $is_test; then
                    enable_all_amds
                fi
            fi
        fi
    else
        if [ $cards_number -eq 1 ]; then
            # The user unplugged the discrete card and is using intel
            echo "intel only: setting the alternative back to mesa" >> $log 2>&1
            if ! $is_test; then
                select_mesa
            fi
        else
            echo "intel+unsupported brand: doing nothing" >> $log 2>&1
        fi
    fi
else
    if $has_amd; then
        if [ $cards_number -gt 1 ]; then
            echo "multi gpu system with amd(s) detected" >> $log 2>&1
            if $has_changed; then
                echo "The devices have changed: reconfiguring X" >> $log 2>&1
                if ! $is_test; then
                    enable_all_amds
                fi
            fi
        else
            echo "single amd system detected" >> $log 2>&1
            if $has_changed; then
                # Have the graphics cards changed?
                echo "removing xorg.conf" >> $log 2>&1
                if ! $is_test; then
                    rm -f /etc/X11/xorg.conf
                fi
            fi
        fi
    fi
fi

exit 0

