#!/bin/bash

set -e

. /usr/lib/x86_64-linux-gnu/enyx-hfp/shhelpers

vendor=1d8f

printversion() {
    printf '*** HFP Version ***\n'
    enyx-hfp-version
}

listpids() {
    local path=$1; shift

    for info in $(lsof -F -- "$path")
    do
        case $info in
            p*)
                printf "%s\n" "${info#p}"
            ;;
        esac
    done
}

printpids() {
    local depth=$1; shift
    local path=$1; shift
    local pids;
    pids=$(listpids "$path")

    if [ -n "${pids}" ]; then
        printnode "$depth" "pids(s):"
        for pid in $pids
        do
            printnode $((depth+1)) "$pid ($(ps -p "$pid" -o comm=))"
        done
    fi
}

printmm() {
    local bus=$1; shift
    local show_pid=$1; shift

    for mm in $(listdev "$bus/mm")
    do
        printnode 3 "#$(basename "$mm")"
        if [ "$show_pid" -eq 1 ]; then
            printpids 4 "$mm"
        fi
    done
}

printdma() {
    local bus=$1; shift
    local kind=$1; shift
    local show_pid=$1; shift

    for dma in $(listdev "$bus/${kind}_buffer/by-id")
    do
        printnode 3 "#$(basename "$dma")"
        printnode 4 "$(printattr "$dma" channel_usage)"
        printnode 4 "$(printattr "$dma" mtu)"
        printnode 4 "$(printattr "$dma" buffer_size)"
        if [ "$show_pid" -eq 1 ]; then
            printpids 4 "$dma"
        fi
    done
}

print_product_version() {
    local bus_id=$1; shift
    local version
    version=$(find "/sys/class/enyx_hfp_bus/enyx_hfp_bus${bus_id}/" \
        -mindepth 2 \
        -maxdepth 2 \
        -name product_version \
        -exec cat {} \;)
    if [ -n "${version}" ]; then
        printf "%s" "${version}"
    else
        printf "<unavailable>"
    fi
}

printbusesinfo() {
    local show_pid=$1; shift

    printf '*** HFP Topology ***\n'
    printf 'bus:\n'

    for bus in $(listdev /dev/enyx/hfp/bus)
    do
        bus_id="$(basename "$bus")"
        printnode 1 "#${bus_id}"
        printnode 2 "bus alias: $(print_bus_alias "${bus_id}")"
        printnode 2 "product version: $(print_product_version "${bus_id}")"

        printnode 2 'mm:'
        printmm "$bus" "$show_pid"

        printnode 2 'rx:'
        printdma "$bus" 'rx' "$show_pid"

        printnode 2 'tx:'
        printdma "$bus" 'tx' "$show_pid"
    done
}

printkernelinfo() {
    printf '\n*** Kernel ***\n'
    uname -r
}

printdkmsinfo() {
    printf '\n*** DKMS ***\n'
    dkms status enyx-hfp
}

printdistroinfo() {
    if command -v lsb_release >/dev/null; then
        printf '\n*** Distro ***\n'
        lsb_release -a
    fi
}

printdevicesinfo() {
    if command -v lspci >/dev/null; then
        printf '\n*** Devices ***\n'
        lspci -vvd "$vendor:*"
    fi
}

printcpuinfo() {
    if command -v lscpu >/dev/null; then
        printf '\n*** CPU ***\n'
        lscpu
    fi
}

printfrequencyinfo() {
    if command -v cpupower >/dev/null; then
        printf '\n*** Frequencies ***\n'
        cpupower frequency-info
    fi
}

printdmesg() {
    printf '\n*** Dmesg ***\n'
    dmesg | grep enyx_hfp
}

printcmdline() {
    printf '\n*** Kernel options ***\n'
    cat /proc/cmdline
}

show_pid=0
show_all=0

while getopts "hpva" opt; do
    case "$opt" in
        h)
            printf "%s: [-hpva]\n" "$0"
            printf "See man page\n"
            exit 0
            ;;
        p)
            show_pid=1
            ;;
        a)
            show_all=1
            ;;
        v)
            printf '2.12.0\n'
            exit 0
            ;;
    esac
done

if [ $show_all -eq 1 ]; then
    printversion
    printdistroinfo
    printkernelinfo
    printdkmsinfo
    printdevicesinfo
    printcpuinfo
    printfrequencyinfo
    printdmesg
    printcmdline
fi

if [ -z "$(lspci -d $vendor:*)" ]; then
    printf 'enyx_hfp device(s) is missing !\n' >&2
    exit 1
fi

if [ -z "$(dkms status enyx-hfp)" ]; then
    printf 'enyx_hfp DKMS module is not added !\n' >&2
    exit 1
fi

if ! (dkms status enyx-hfp | grep -q installed); then
    printf 'enyx_hfp DKMS module is not installed on current kernel !\n' >&2
    dkms status enyx_hfp >&2
    exit 1
fi

if ! modinfo enyx_hfp >/dev/null 2>&1; then
    printf 'enyx_hfp modules is not installed on current kernel !\n' >&2
    exit 1
fi

if ! (lsmod | grep -q enyx_hfp); then
    printf 'enyx_hfp modules is not loaded !\n' >&2
    exit 1
fi

printbusesinfo $show_pid

exit 0
