Files
op-packages/luci-app-modem-manager-next/root/usr/libexec/modem-detect
T

205 lines
4.8 KiB
Bash
Executable File

#!/bin/sh
# Cellular Modem Auto-Detector for OpenWrt
# Outputs discovered modems in JSON format and updates /tmp/run/modem-manager/devices.json
RUN_DIR="/tmp/run/modem-manager"
CACHE_FILE="$RUN_DIR/devices.json"
KNOWN_VENDORS="2c7c 2cb7 1e0e 12d1 19d2 1bbb 05c6 413c 0bdb 1199 2977 1508 1bc7 0e8d 1782 0489 1fac 2dee 33f8 3731 2df3 20a6"
get_sys_attr() {
local path="$1"
if [ -f "$path" ]; then
tr -d '\r\n' < "$path" 2>/dev/null
fi
}
detect_all() {
echo "{"
echo ' "devices": ['
local FIRST=1
for dev in /sys/bus/usb/devices/*; do
[ -d "$dev" ] || continue
[ -f "$dev/idVendor" ] || continue
[ -f "$dev/idProduct" ] || continue
local VID=$(get_sys_attr "$dev/idVendor")
local PID=$(get_sys_attr "$dev/idProduct")
local DEVCLASS=$(get_sys_attr "$dev/bDeviceClass")
case "$VID" in
1d6b|2109|1d50) continue ;;
esac
[ "$DEVCLASS" = "09" ] && continue
local IS_MODEM=0
for kv in $KNOWN_VENDORS; do
if [ "$VID" = "$kv" ]; then
IS_MODEM=1
break
fi
done
local DEVNAME=$(basename "$dev")
# Direct sysfs tree discovery for serial ports under this USB device
local TTYS=""
for t in $(find "$dev" -maxdepth 5 \( -name "ttyUSB*" -o -name "ttyACM*" \) 2>/dev/null); do
local b=$(basename "$t")
case "$b" in
ttyUSB*|ttyACM*)
if [ -e "/dev/$b" ]; then
case " $TTYS " in
*" /dev/$b "*) ;;
*) TTYS="$TTYS /dev/$b" ;;
esac
fi
;;
esac
done
# Fallback tty search via /sys/class/tty
if [ -z "$TTYS" ]; then
for t in /sys/class/tty/ttyUSB* /sys/class/tty/ttyACM*; do
[ -e "$t" ] || continue
local t_target=$(readlink "$t" 2>/dev/null || readlink -f "$t" 2>/dev/null)
case "$t_target" in
*"$DEVNAME"*)
local b=$(basename "$t")
[ -e "/dev/$b" ] && case " $TTYS " in *" /dev/$b "*) ;; *) TTYS="$TTYS /dev/$b" ;; esac
;;
esac
done
fi
TTYS=$(echo "$TTYS" | sed 's/^ *//')
# Network interfaces discovery under this USB device
local NETS=""
for n in $(find "$dev" -maxdepth 5 -name "net" 2>/dev/null); do
[ -d "$n" ] || continue
for iface in "$n"/*; do
[ -d "$iface" ] || continue
local b=$(basename "$iface")
case "$b" in
lo|br-*|eth*|lan*|wan*|sfp*) ;;
*) case " $NETS " in *" $b "*) ;; *) NETS="$NETS $b" ;; esac ;;
esac
done
done
# Fallback net search via /sys/class/net
if [ -z "$NETS" ]; then
for n in /sys/class/net/*; do
[ -d "$n" ] || continue
local n_target=$(readlink "$n" 2>/dev/null || readlink -f "$n" 2>/dev/null)
case "$n_target" in
*"$DEVNAME"*)
local b=$(basename "$n")
case "$b" in
lo|br-*|eth*|lan*|wan*|sfp*) ;;
*) case " $NETS " in *" $b "*) ;; *) NETS="$NETS $b" ;; esac ;;
esac
;;
esac
done
fi
NETS=$(echo "$NETS" | sed 's/^ *//')
if [ -n "$TTYS" ] || [ -n "$NETS" ] || [ $IS_MODEM -eq 1 ]; then
IS_MODEM=1
fi
[ $IS_MODEM -eq 1 ] || continue
local MFG=$(get_sys_attr "$dev/manufacturer")
local PROD=$(get_sys_attr "$dev/product")
local SER=$(get_sys_attr "$dev/serial")
local DRIVER="option"
for net_iface in $NETS; do
if [ -e "/sys/class/net/$net_iface/device/driver" ]; then
local drv_target=$(basename "$(readlink -f "/sys/class/net/$net_iface/device/driver" 2>/dev/null)")
case "$drv_target" in
cdc_ncm|cdc_ether|cdc_mbim|qmi_wwan)
DRIVER="$drv_target"
break
;;
esac
fi
done
local PRIMARY_TTY=""
for t in $TTYS; do
case "$t" in
*ttyUSB2|*ttyACM0)
PRIMARY_TTY="$t"
break
;;
esac
done
if [ -z "$PRIMARY_TTY" ]; then
for t in $TTYS; do
case "$t" in
*ttyUSB3)
PRIMARY_TTY="$t"
break
;;
esac
done
fi
[ -z "$PRIMARY_TTY" ] && PRIMARY_TTY=$(echo "$TTYS" | awk '{print $1}')
local PRIMARY_NET=$(echo "$NETS" | awk '{print $1}')
[ $FIRST -eq 1 ] || echo ","
FIRST=0
local TTY_JSON=""
for t in $TTYS; do
[ -n "$TTY_JSON" ] && TTY_JSON="$TTY_JSON, "
TTY_JSON="$TTY_JSON\"$t\""
done
local NET_JSON=""
for n in $NETS; do
[ -n "$NET_JSON" ] && NET_JSON="$NET_JSON, "
NET_JSON="$NET_JSON\"$n\""
done
local MODES_JSON="\"ncm\", \"ecm\""
cat <<EOF
{
"id": "$DEVNAME",
"vid": "$VID",
"pid": "$PID",
"vendor": "${MFG:-Generic}",
"model": "${PROD:-Modem}",
"serial": "${SER}",
"driver": "$DRIVER",
"primary_port": "$PRIMARY_TTY",
"primary_net": "$PRIMARY_NET",
"supported_modes": [ $MODES_JSON ],
"ports": [ $TTY_JSON ],
"nets": [ $NET_JSON ]
}
EOF
done
echo " ]"
echo "}"
}
mkdir -p "$RUN_DIR"
OUTPUT=$(detect_all)
# Atomic update cache
echo "$OUTPUT" > "${CACHE_FILE}.tmp" && mv -f "${CACHE_FILE}.tmp" "$CACHE_FILE"
# Output to stdout if not purely --cache mode
if [ "$1" != "--cache" ]; then
echo "$OUTPUT"
fi
exit 0