#!/usr/bin/env bash set -euo pipefail # Physical USB ports on the RDKx5 carrier. RADAR_PORT="1-1.4" IMU_PORT="1-1.1" # RADAR -> usb_ch343, IMU -> cdc_acm. RADAR_DRIVER="usb_ch343" IMU_DRIVER="cdc_acm" DRIVER_ROOT="/sys/bus/usb/drivers" MAX_WAIT_SECONDS="${MAX_WAIT_SECONDS:-30}" WAIT_INTERVAL_SECONDS="${WAIT_INTERVAL_SECONDS:-1}" INTERFACES=() log() { local message="[radar-driver-switch] $*" if [ -w /dev/kmsg ]; then printf '%s\n' "$message" > /dev/kmsg else printf '%s\n' "$message" fi } load_driver() { local driver="$1" case "$driver" in cdc_acm) modprobe cdc_acm 2>/dev/null || true ;; usb_ch343) modprobe ch343 2>/dev/null || true ;; esac } driver_path() { printf '%s/%s\n' "$DRIVER_ROOT" "$1" } require_driver() { local driver="$1" local path path="$(driver_path "$driver")" if [ ! -d "$path" ]; then log "error: driver path missing: $path" exit 2 fi } collect_interfaces() { local port="$1" shopt -s nullglob INTERFACES=(/sys/bus/usb/devices/"${port}":*) shopt -u nullglob [ "${#INTERFACES[@]}" -gt 0 ] } wait_for_interfaces() { local label="$1" local port="$2" local attempt=0 while [ "$attempt" -le "$MAX_WAIT_SECONDS" ]; do if collect_interfaces "$port"; then return 0 fi log "waiting for $label port $port interfaces (${attempt}s)" sleep "$WAIT_INTERVAL_SECONDS" attempt=$((attempt + WAIT_INTERVAL_SECONDS)) done log "error: timed out waiting for $label port $port interfaces" exit 1 } current_driver() { local iface="$1" local target target="$(readlink -f "$iface/driver" 2>/dev/null || true)" if [ -n "$target" ]; then basename "$target" fi } unbind_from_current_driver() { local iface="$1" local iface_name local driver iface_name="$(basename "$iface")" driver="$(current_driver "$iface")" if [ -z "$driver" ]; then return 0 fi if [ ! -w "$(driver_path "$driver")/unbind" ]; then log "error: cannot unbind $iface_name from $driver" exit 5 fi printf '%s\n' "$iface_name" > "$(driver_path "$driver")/unbind" log "unbound $iface_name from $driver" } bind_to_driver() { local iface="$1" local driver="$2" local iface_name local bind_path iface_name="$(basename "$iface")" bind_path="$(driver_path "$driver")/bind" if [ ! -w "$bind_path" ]; then log "error: cannot bind $iface_name to $driver" exit 6 fi if printf '%s\n' "$iface_name" > "$bind_path" 2>/dev/null; then log "bound $iface_name to $driver" else log "warning: $iface_name did not bind to $driver" fi } ensure_port_bound() { local label="$1" local port="$2" local desired_driver="$3" local iface local iface_name local driver local bound_count=0 wait_for_interfaces "$label" "$port" for iface in "${INTERFACES[@]}"; do iface_name="$(basename "$iface")" driver="$(current_driver "$iface")" if [ "$driver" = "$desired_driver" ]; then log "$label $iface_name already uses $desired_driver" bound_count=$((bound_count + 1)) continue fi if [ -n "$driver" ]; then unbind_from_current_driver "$iface" sleep 0.2 fi bind_to_driver "$iface" "$desired_driver" sleep 0.2 driver="$(current_driver "$iface")" if [ "$driver" = "$desired_driver" ]; then bound_count=$((bound_count + 1)) fi done if [ "$bound_count" -eq 0 ]; then log "error: no $label interface on $port is bound to $desired_driver" exit 7 fi } main() { load_driver "$RADAR_DRIVER" load_driver "$IMU_DRIVER" require_driver "$RADAR_DRIVER" require_driver "$IMU_DRIVER" ensure_port_bound "RADAR" "$RADAR_PORT" "$RADAR_DRIVER" ensure_port_bound "IMU" "$IMU_PORT" "$IMU_DRIVER" udevadm settle --timeout=5 2>/dev/null || true log "done; serial devices: $(ls /dev/ttyACM* /dev/ttyCH343USB* 2>/dev/null | tr '\n' ' ')" } main "$@"