#!/bin/dash
#
# Background settle helper: driver unbind/bind for input stacks that appeared
# late or missed the synchronous libinput settle. Closer to a synthetic hotplug
# than a plain "add" retrigger on event* (see rebind-missed-input.sh).
#
# Environment:
#   VDEV_STATE_DIR          /run/vdev (default)
#   VDEV_SETTLE_REBOUND     rebound log (default: $VDEV_STATE_DIR/vdev-settle.rebound)
#   VDEV_SETTLE_RETRIGGERED  skip events already retriggered with add (optional)
#   VDEV_SETTLE_REBIND_MAX  max devices touched per run (default: 8)
#   VDEV_SETTLE_REBIND_USB_HID_ONLY  1 = HID 0003:* only (default: 0, allow I2C)
#

set -u

STATE_DIR="${VDEV_STATE_DIR:-/run/vdev}"
REBOUND="${VDEV_SETTLE_REBOUND:-${STATE_DIR}/vdev-settle.rebound}"
RETRIGGERED="${VDEV_SETTLE_RETRIGGERED:-${STATE_DIR}/vdev-settle.retriggered}"
MAX="${VDEV_SETTLE_REBIND_MAX:-8}"
USB_HID_ONLY="${VDEV_SETTLE_REBIND_USB_HID_ONLY:-0}"

_hid_parent_of_event() {
	_ev="$1"
	_real=""
	_real=$(readlink -f "$_ev" 2>/dev/null) || return 1
	_inp=$(dirname "$_real") || return 1
	_par=$(dirname "$_inp") || return 1
	printf '%s\n' "$_par"
}

_already_rebound() {
	_id="$1"
	[ -f "$REBOUND" ] || return 1
	grep -Fx "$_id" "$REBOUND" >/dev/null 2>&1
}

_mark_rebound() {
	_id="$1"
	mkdir -p "$(dirname "$REBOUND")"
	grep -Fx "$_id" "$REBOUND" >/dev/null 2>&1 && return 0
	printf '%s\n' "$_id" >>"$REBOUND"
}

_rebind_hid_driver() {
	_base="$1"
	_drv="$2"

	if [ ! -w "/sys/bus/hid/drivers/${_drv}/unbind" ] 2>/dev/null; then
		return 1
	fi
	printf '%s\n' "$_base" >"/sys/bus/hid/drivers/${_drv}/unbind" 2>/dev/null || return 1
	sleep 0.2
	printf '%s\n' "$_base" >"/sys/bus/hid/drivers/${_drv}/bind" 2>/dev/null || return 1
	return 0
}

_trigger_bind_uevent() {
	_syspath="$1"
	vdevadm trigger --action=bind "$_syspath" >/dev/null 2>&1 && return 0
	_uevent="${_syspath}/uevent"
	[ -e "$_uevent" ] || return 1
	printf 'bind\n' >"$_uevent" 2>/dev/null
}

_done=0

mkdir -p "$STATE_DIR" 2>/dev/null || true
touch "$REBOUND" 2>/dev/null || true

for _ev in /sys/class/input/event*; do
	[ -e "$_ev" ] || continue
	_evname=$(basename "$_ev")
	_hid=$(_hid_parent_of_event "$_ev") || continue
	_base=$(basename "$_hid")

	case "$_base" in
	0003:*|0011:*|0018:*|0019:*|i2c-*|serio*) ;;
	*) continue ;;
	esac

	if [ "$USB_HID_ONLY" = "1" ]; then
		case "$_base" in
		0003:*) ;;
		*) continue ;;
		esac
	fi

	if _already_rebound "$_base"; then
		continue
	fi

	if [ -f "$RETRIGGERED" ] && grep -Fx "$_evname" "$RETRIGGERED" >/dev/null 2>&1; then
		:
	fi

	if [ -L "$_hid/driver" ]; then
		_drv=$(basename "$(readlink "$_hid/driver")")
		if [ -n "$_drv" ] && _rebind_hid_driver "$_base" "$_drv"; then
			_mark_rebound "$_base"
			_done=$((_done + 1))
			[ "$_done" -ge "$MAX" ] && break
			continue
		fi
	fi

	if _trigger_bind_uevent "$_hid"; then
		_mark_rebound "$_base"
		_done=$((_done + 1))
	fi

	[ "$_done" -ge "$MAX" ] && break
done

exit 0
