#!/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