#!/bin/sh
# Attach the ddcci driver to external monitors on their DP AUX bus.
# The connector's `ddc` symlink points at the native I2C bus, which is dead on
# DisplayPort, so the aux adapter is selected by name instead.
#
# Monitors often do not answer DDC/CI for the first several seconds after boot
# or a hotplug, and that probe failure leaves a live i2c client with no backlight
# behind, so binding is retried rather than attempted once.
#
# Retries only ever discard a client whose probe failed. ddcci-dkms 0.4.4 leaks a
# chardev minor whenever a real ddcci device is destroyed, and the orphan blocks
# the next monitor with -EEXIST until a reboot, but a failed probe never created
# one. A client that did produce a ddcci device is left strictly alone.

RETRIES=5
SETTLE=3

exec 9>/run/ddcci-bind.lock
flock -w 120 9 || exit 0

[ -n "$DDCCI_BIND_DELAY" ] && sleep "$DDCCI_BIND_DELAY"

has_backlight() {
    ls "/sys/bus/i2c/devices/$1-0037"/ddcci*/backlight/* >/dev/null 2>&1
}

has_ddcci_device() {
    ls -d "/sys/bus/i2c/devices/$1-0037"/ddcci* >/dev/null 2>&1
}

bind_bus() {
    n=$1
    i=0
    while [ "$i" -lt "$RETRIES" ]; do
        has_backlight "$n" && return 0

        if [ -e "/sys/bus/i2c/devices/$n-0037" ]; then
            has_ddcci_device "$n" && return 1
            echo 0x37 > "/sys/bus/i2c/devices/i2c-$n/delete_device" 2>/dev/null
            sleep 1
        fi

        echo ddcci 0x37 > "/sys/bus/i2c/devices/i2c-$n/new_device" 2>/dev/null
        sleep "$SETTLE"
        i=$((i + 1))
    done

    has_backlight "$n"
}

for conn in /sys/class/drm/card*-DP-* /sys/class/drm/card*-HDMI-*; do
    [ -r "$conn/status" ] || continue
    [ "$(cat "$conn/status")" = connected ] || continue

    for bus in "$conn"/i2c-*; do
        [ -d "$bus" ] || continue
        n=${bus##*/i2c-}

        case "$(cat "/sys/bus/i2c/devices/i2c-$n/name" 2>/dev/null)" in
            *aux*) bind_bus "$n" ;;
        esac
    done
done
