Forked from crossan007/gist:733ff15f60c61d5d4412d08d06f43965
Created
August 20, 2026 14:52
-
-
Save gtxaspec/757db86fe86169a5f006764b500a6182 to your computer and use it in GitHub Desktop.
Thingino 802.11AC USB Adapter Driver Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| LOGTAG="8821_run.sh" | |
| # Global variables | |
| RTL_IFACE="" | |
| WORK_DIR="" | |
| # --------------------------------------------------------------------------- | |
| # Supported USB WiFi adapters | |
| # | |
| # Different Realtek chipsets need different, incompatible kernel modules, so | |
| # each adapter profile carries its own download URL, hash, on-disk filename, | |
| # and lsmod module name. At runtime we look at which VID:PID is actually | |
| # plugged in and load the matching driver. To support another chipset, add | |
| # a new block below and list its profile name in ADAPTER_PROFILES. | |
| # --------------------------------------------------------------------------- | |
| # --- RTL8812A/RTL8821A family (e.g. TP-Link Archer T2U Nano, 2357:011e) --- | |
| # Source: https://github.com/svpcom/rtl8812au @ 47d89ba3d8114e2854112e0a1349e0ef89b43760 | |
| # Patches: thingino-firmware/package/wifi-rtl8812au/0002-ioctl_cfg80211_fix.patch | |
| # thingino-firmware/package/wifi-rtl8812au/0003-wifi_regd_fix.patch | |
| # (both needed to build against this camera's 3.10.14 kernel headers; | |
| # without them the build fails on NL80211_CHAN_WIDTH_5/10 and an | |
| # old-kernel #if/#else bug in wifi_regd.c) | |
| # Build: Makefile defaults already set CONFIG_RTL8812A=y CONFIG_RTL8821A=y - | |
| # leave them as-is, that combo is what produces the "88XXau" naming. | |
| # Cross-compile against the matching camera kernel tree/toolchain | |
| # (e.g. docker-worker/workspace/output-stable/<camera_target>/{host/bin,build/linux-*}): | |
| # make -j$(nproc) CONFIG_PLATFORM_I386_PC=n ARCH=mips \ | |
| # CROSS_COMPILE=<toolchain>/mipsel-linux- KSRC=<kernel_build_dir> \ | |
| # KVER=<uname -r on target, e.g. 3.10.14__isvp_swan_1.0__> \ | |
| # USER_EXTRA_CFLAGS="-DCONFIG_LITTLE_ENDIAN -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT" | |
| # Output is 88XXau_wfb.ko - rename to 88XXau.ko before hashing/uploading. | |
| RTL8812_VID="2357" | |
| RTL8812_PID="011e" | |
| RTL8812_DRIVER_FILE="88XXau.ko" | |
| RTL8812_DRIVER_URL="https://<<URL>>/88XXau.ko" | |
| RTL8812_DRIVER_HASH="c9f8589bb8f6e8239c39d1c85a2b3feef971a720b53aa5164263287ab414ff80" # <-- Update with actual SHA256 hash | |
| RTL8812_MODULE_NAME="88XXau" | |
| # --- RTL8822B family (e.g. TP-Link Archer T3U Nano, 2357:012e) --- | |
| # Source: https://github.com/RinCat/RTL88x2BU-Linux-Driver @ ad889cc324baf2f13724e3d7b6e880804d3adae7 | |
| # Patches: none needed - builds clean against this camera's 3.10.14 kernel as-is. | |
| # Build: Makefile default already sets CONFIG_RTL8822B=y, no override needed. | |
| # Same cross-compile setup as the RTL8812 profile above: | |
| # make -j$(nproc) CONFIG_PLATFORM_I386_PC=n ARCH=mips \ | |
| # CROSS_COMPILE=<toolchain>/mipsel-linux- KSRC=<kernel_build_dir> \ | |
| # KVER=<uname -r on target, e.g. 3.10.14__isvp_swan_1.0__> \ | |
| # USER_EXTRA_CFLAGS="-DCONFIG_LITTLE_ENDIAN -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT" | |
| # Output is already named 88x2bu.ko - no rename needed. | |
| # NOTE: Do NOT use the svpcom/rtl8812au driver for this chip even though its | |
| # USB ID table lists 2357:012e - direct chip-register readout confirms | |
| # this is genuine RTL8822B silicon, and the au driver pushes the wrong | |
| # firmware to it (manifests as USB write timeouts during firmware | |
| # download, easy to mistake for a power/hardware problem). | |
| RTL8822B_VID="2357" | |
| RTL8822B_PID="012e" | |
| RTL8822B_DRIVER_FILE="88x2bu.ko" | |
| RTL8822B_DRIVER_URL="https://<<URL>>/88x2bu.ko" | |
| RTL8822B_DRIVER_HASH="bcc53df7285d1db0e65ce8dbad99f8f162df762929d783f4eefd05991f33f10a" # <-- Update with actual SHA256 hash | |
| RTL8822B_MODULE_NAME="88x2bu" | |
| ADAPTER_PROFILES="RTL8812 RTL8822B" | |
| # Selected at runtime by detect_adapter_profile() | |
| SELECTED_PROFILE="" | |
| SELECTED_VID="" | |
| SELECTED_PID="" | |
| SELECTED_DRIVER_FILE="" | |
| SELECTED_DRIVER_URL="" | |
| SELECTED_DRIVER_HASH="" | |
| SELECTED_MODULE_NAME="" | |
| # --------------------------------------------------------------------------- | |
| # Connection watchdog settings | |
| # | |
| # Once the USB WiFi interface is up, we keep checking that it can actually | |
| # reach its gateway (not just that it's "associated"). If it can't: | |
| # - the first MAX_LIGHT_RECOVERY_ATTEMPTS failures trigger a lightweight | |
| # recovery (restart wpa_supplicant + renew DHCP) | |
| # - if connectivity is still down after REBOOT_AFTER_FAILS consecutive | |
| # checks, we reboot as a last resort. | |
| # | |
| # We deliberately do NOT rmmod/reload the kernel module as a recovery step: | |
| # we've seen that specific operation wedge the USB bus on this hardware | |
| # badly enough to require a physical unplug/replug to recover, which an | |
| # unattended watchdog can't do. A full reboot resets the USB controller far | |
| # more reliably than a software-only unbind/rmmod does. | |
| # --------------------------------------------------------------------------- | |
| CHECK_INTERVAL=60 # seconds between connectivity checks | |
| MAX_LIGHT_RECOVERY_ATTEMPTS=3 # consecutive failures that trigger wpa_supplicant/DHCP restart | |
| REBOOT_AFTER_FAILS=15 # consecutive failed checks (~15 min) before rebooting | |
| log() { | |
| echo "[$LOGTAG] $*" | |
| if [ -n "$WORK_DIR" ]; then | |
| echo "[$LOGTAG] $*" >> "$WORK_DIR/8821_run.log" | |
| fi | |
| } | |
| detect_adapter_profile() { | |
| # Scan attached USB devices for a VID:PID we have a driver profile for. | |
| # Sets SELECTED_* globals and returns 0 on match, 1 if nothing matched. | |
| local vid pid profile devdir profile_vid profile_pid | |
| for devdir in /sys/bus/usb/devices/*/; do | |
| [ -f "${devdir}idVendor" ] && [ -f "${devdir}idProduct" ] || continue | |
| vid=$(cat "${devdir}idVendor" 2>/dev/null) | |
| pid=$(cat "${devdir}idProduct" 2>/dev/null) | |
| [ -z "$vid" ] && continue | |
| for profile in $ADAPTER_PROFILES; do | |
| eval "profile_vid=\$${profile}_VID" | |
| eval "profile_pid=\$${profile}_PID" | |
| if [ "$vid" = "$profile_vid" ] && [ "$pid" = "$profile_pid" ]; then | |
| SELECTED_PROFILE="$profile" | |
| SELECTED_VID="$vid" | |
| SELECTED_PID="$pid" | |
| eval "SELECTED_DRIVER_FILE=\$${profile}_DRIVER_FILE" | |
| eval "SELECTED_DRIVER_URL=\$${profile}_DRIVER_URL" | |
| eval "SELECTED_DRIVER_HASH=\$${profile}_DRIVER_HASH" | |
| eval "SELECTED_MODULE_NAME=\$${profile}_MODULE_NAME" | |
| return 0 | |
| fi | |
| done | |
| done | |
| return 1 | |
| } | |
| wait_for_adapter_profile() { | |
| log "Waiting for a supported USB WiFi adapter..." | |
| for i in $(seq 1 30); do | |
| if detect_adapter_profile; then | |
| log "Detected $SELECTED_PROFILE adapter ($SELECTED_VID:$SELECTED_PID - driver: $SELECTED_DRIVER_FILE)" | |
| return 0 | |
| fi | |
| sleep 1 | |
| done | |
| log "No supported USB WiFi adapter found after 30s" | |
| return 1 | |
| } | |
| load_module() { | |
| if lsmod | grep -q "^$SELECTED_MODULE_NAME"; then | |
| log "$SELECTED_PROFILE module ($SELECTED_MODULE_NAME) already loaded." | |
| else | |
| log "Loading $SELECTED_PROFILE driver ($SELECTED_DRIVER_FILE)..." | |
| insmod "$WORK_DIR/$SELECTED_DRIVER_FILE" || { log "Failed to load $SELECTED_DRIVER_FILE from $WORK_DIR"; exit 1; } | |
| fi | |
| } | |
| # Add a quiet version for use in loops | |
| detect_sdio_wifi_interfaces_quiet() { | |
| # Find wlan interfaces that correspond to SDIO devices (quiet version) | |
| local sdio_interfaces="" | |
| # Get all wlan interfaces | |
| local all_wlan_ifaces=$(ip link | awk '$0 ~ /^[0-9]+:/ && $2 ~ /^wlan/ {gsub(":", "", $2); print $2}') | |
| # Check each wlan interface to see if it's SDIO-based | |
| for iface in $all_wlan_ifaces; do | |
| # Check if interface has a corresponding device | |
| if [ -d "/sys/class/net/$iface/device" ]; then | |
| # Method 1: Check for SDIO device ID (from your lssdio output: Device ID: 0xf179) | |
| if [ -f "/sys/class/net/$iface/device/device" ]; then | |
| local device_id=$(cat "/sys/class/net/$iface/device/device" 2>/dev/null) | |
| if [ "$device_id" = "0xf179" ]; then | |
| sdio_interfaces="$sdio_interfaces $iface" | |
| continue | |
| fi | |
| fi | |
| # Method 2: Check device path for SDIO/MMC indicators | |
| local device_path=$(readlink -f "/sys/class/net/$iface/device" 2>/dev/null) | |
| if [ -n "$device_path" ] && (echo "$device_path" | grep -q "mmc\|sdio"); then | |
| sdio_interfaces="$sdio_interfaces $iface" | |
| continue | |
| fi | |
| # Method 3: Check for wireless subsystem and absence of USB indicators | |
| if [ -d "/sys/class/net/$iface/wireless" ] || [ -d "/sys/class/net/$iface/phy80211" ]; then | |
| # It's a wireless interface, check if it's NOT USB | |
| if ! echo "$device_path" | grep -q "usb"; then | |
| # Check if modalias indicates SDIO | |
| local modalias="" | |
| if [ -f "/sys/class/net/$iface/device/modalias" ]; then | |
| modalias=$(cat "/sys/class/net/$iface/device/modalias" 2>/dev/null) | |
| fi | |
| if echo "$modalias" | grep -q "sdio"; then | |
| sdio_interfaces="$sdio_interfaces $iface" | |
| fi | |
| fi | |
| fi | |
| fi | |
| done | |
| echo "$sdio_interfaces" | xargs | |
| } | |
| wait_for_onboard_wlan() { | |
| log "Waiting for all onboard wlan interfaces to be available..." | |
| for i in $(seq 1 100); do | |
| ONBOARD_IFACES=$(detect_sdio_wifi_interfaces_quiet) | |
| # Debug: log what we found every 10 iterations | |
| if [ $((i % 10)) -eq 1 ]; then | |
| log "Iteration $i: Found onboard interfaces: '$ONBOARD_IFACES'" | |
| fi | |
| if [ -z "$ONBOARD_IFACES" ]; then | |
| sleep 1 | |
| continue | |
| fi | |
| ALL_PRESENT=true | |
| for IFACE in $ONBOARD_IFACES; do | |
| if ! ip link show "$IFACE" > /dev/null 2>&1; then | |
| ALL_PRESENT=false | |
| break | |
| fi | |
| done | |
| if $ALL_PRESENT; then | |
| log "All onboard wlan interfaces are available: $ONBOARD_IFACES" | |
| return 0 | |
| fi | |
| sleep 1 | |
| done | |
| log "Timeout waiting for onboard wlan interfaces." | |
| exit 1 | |
| } | |
| detect_usb_wifi_interfaces() { | |
| # Find wlan interfaces that correspond to USB devices | |
| local usb_interfaces="" | |
| # Get all wlan interfaces | |
| local all_wlan_ifaces=$(ip link | awk '$0 ~ /^[0-9]+:/ && $2 ~ /^wlan/ {gsub(":", "", $2); print $2}') | |
| # Check each wlan interface to see if it's USB-based | |
| for iface in $all_wlan_ifaces; do | |
| # Check if interface has a corresponding USB device path | |
| if [ -d "/sys/class/net/$iface/device" ]; then | |
| # Follow the device symlink to see if it points to a USB device | |
| local device_path=$(readlink -f "/sys/class/net/$iface/device" 2>/dev/null) | |
| if echo "$device_path" | grep -q "usb"; then | |
| usb_interfaces="$usb_interfaces $iface" | |
| log "Detected USB WiFi interface: $iface" >&2 | |
| fi | |
| fi | |
| done | |
| echo "$usb_interfaces" | xargs | |
| } | |
| manage_prudynt_service() { | |
| local action="$1" # "start" or "stop" | |
| if [ "$action" = "start" ]; then | |
| log "Starting prudynt service..." | |
| service start prudynt || log "Warning: Failed to start prudynt service" | |
| elif [ "$action" = "stop" ]; then | |
| log "Stopping prudynt service..." | |
| service stop prudynt || log "Warning: Failed to stop prudynt service" | |
| else | |
| log "Invalid action for prudynt service: $action" | |
| return 1 | |
| fi | |
| } | |
| stop_wlan0() { | |
| log "Bringing down wlan0..." | |
| fw_setenv wlanap_enabled false | |
| # Release DHCP lease before stopping interface | |
| release_dhcp_lease "wlan0" | |
| # kill wpa_supplicant for wlan0 | |
| for PID in $(pgrep -f "wpa_supplicant.*-i.*wlan0"); do | |
| log "Killing wpa_supplicant for wlan0 (PID $PID)..." | |
| kill "$PID" || log "Failed to kill wpa_supplicant for wlan0" | |
| done | |
| # Finally bring down the interface | |
| ip link set wlan0 down || log "Failed to bring down wlan0 (may already be down)" | |
| } | |
| find_rtl_iface() { | |
| # Find USB WiFi interfaces (should be the Realtek adapter) | |
| local usb_ifaces=$(detect_usb_wifi_interfaces) | |
| if [ -n "$usb_ifaces" ]; then | |
| RTL_IFACE=$(echo "$usb_ifaces" | awk '{print $1}') # Take first USB WiFi interface | |
| log "Detected Realtek interface: $RTL_IFACE" | |
| else | |
| log "Could not find USB WiFi interface (Realtek adapter)" | |
| exit 1 | |
| fi | |
| } | |
| cleanup_rtl_services() { | |
| # Release DHCP lease for Realtek interface if active | |
| release_dhcp_lease "$RTL_IFACE" | |
| # Kill any old wpa_supplicant for Realtek interface | |
| for PID in $(pgrep -f "wpa_supplicant.*-i.*$RTL_IFACE"); do | |
| log "Killing old wpa_supplicant (PID $PID) for $RTL_IFACE" | |
| kill $PID | |
| done | |
| # Extra: kill any duplicate udhcpc for $RTL_IFACE not tracked by pidfile | |
| for PID in $(pgrep -f "udhcpc.*-i.*$RTL_IFACE"); do | |
| log "Killing extra udhcpc (PID $PID) for $RTL_IFACE" | |
| kill $PID | |
| done | |
| } | |
| start_rtl_wlan8821() { | |
| log "Waiting for Realtek interface..." | |
| for i in $(seq 1 10); do | |
| find_rtl_iface | |
| if [ -n "$RTL_IFACE" ]; then | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| if [ -z "$RTL_IFACE" ]; then | |
| log "Could not find Realtek USB interface" | |
| exit 1 | |
| fi | |
| cleanup_rtl_services | |
| log "Bringing up $RTL_IFACE..." | |
| ip link set "$RTL_IFACE" up || { log "Failed to bring up $RTL_IFACE"; exit 1; } | |
| log "Starting wpa_supplicant for $RTL_IFACE..." | |
| wpa_supplicant -i "$RTL_IFACE" -c /etc/wpa_supplicant.conf -B || { log "Failed to start wpa_supplicant"; exit 1; } | |
| sleep 5 | |
| BASE_HOSTNAME="$(hostname)" | |
| wlan8821_HOSTNAME="${BASE_HOSTNAME}" | |
| log "Using DHCP hostname: $wlan8821_HOSTNAME" | |
| udhcpc -x hostname:$wlan8821_HOSTNAME -S -T1 -t15 -R -b -O search -O 100 -O 101 -O 160 -p /var/run/udhcpc."$RTL_IFACE".pid -i "$RTL_IFACE" || { log "DHCP failed for $RTL_IFACE"; exit 1; } | |
| # Check if the Realtek interface got an IP address | |
| IP_ADDR=$(ip -4 addr show "$RTL_IFACE" | awk '/inet / {print $2}' | cut -d/ -f1) | |
| if [ -n "$IP_ADDR" ]; then | |
| log "$RTL_IFACE got IP $IP_ADDR, stopping wlan0." | |
| stop_wlan0 | |
| # Start prudynt service when USB WiFi is active and has IP | |
| manage_prudynt_service "start" | |
| log "$RTL_IFACE setup complete." | |
| monitor_connection | |
| else | |
| log "$RTL_IFACE did not get an IP address, keeping wlan0 up." | |
| log "$RTL_IFACE setup complete." | |
| fi | |
| } | |
| release_dhcp_lease() { | |
| local interface="$1" | |
| if [ -z "$interface" ]; then | |
| log "No interface specified for DHCP release" | |
| return 1 | |
| fi | |
| local pidfile="/var/run/udhcpc.$interface.pid" | |
| if [ -f "$pidfile" ]; then | |
| log "Releasing DHCP lease for $interface..." | |
| # Send DHCPRELEASE with timeout to prevent hanging | |
| timeout 5 udhcpc -R -i "$interface" 2>/dev/null || log "DHCP release timed out or failed for $interface" | |
| PID=$(cat "$pidfile") | |
| log "Stopping udhcpc for $interface (PID $PID)..." | |
| kill "$PID" || log "Failed to kill udhcpc for $interface" | |
| rm -f "$pidfile" | |
| # Kill any lingering DHCP release processes for this interface | |
| for release_pid in $(pgrep -f "udhcpc.*-R.*-i.*$interface"); do | |
| log "Killing lingering DHCP release process (PID $release_pid) for $interface" | |
| kill "$release_pid" 2>/dev/null || true | |
| done | |
| else | |
| log "No DHCP client pidfile found for $interface" | |
| fi | |
| } | |
| check_connectivity() { | |
| # Returns 0 if $RTL_IFACE has an IP and can reach its gateway, 1 otherwise | |
| local gw | |
| if ! ip link show "$RTL_IFACE" >/dev/null 2>&1; then | |
| return 1 | |
| fi | |
| if ! ip -4 addr show "$RTL_IFACE" | grep -q "inet "; then | |
| return 1 | |
| fi | |
| gw=$(ip route show dev "$RTL_IFACE" | awk '/^default/ {print $3; exit}') | |
| if [ -z "$gw" ]; then | |
| return 1 | |
| fi | |
| ping -c 2 -W 3 -I "$RTL_IFACE" "$gw" >/dev/null 2>&1 | |
| } | |
| monitor_connection() { | |
| local fail_count=0 | |
| local light_recovery_attempts=0 | |
| log "Starting connection watchdog for $RTL_IFACE (check every ${CHECK_INTERVAL}s)" | |
| while true; do | |
| sleep "$CHECK_INTERVAL" | |
| if check_connectivity; then | |
| if [ "$fail_count" -gt 0 ]; then | |
| log "Connectivity restored for $RTL_IFACE after $fail_count failed check(s)" | |
| fi | |
| fail_count=0 | |
| light_recovery_attempts=0 | |
| continue | |
| fi | |
| fail_count=$((fail_count + 1)) | |
| log "Connectivity check failed for $RTL_IFACE ($fail_count/$REBOOT_AFTER_FAILS)" | |
| if [ "$fail_count" -ge "$REBOOT_AFTER_FAILS" ]; then | |
| log "Connectivity not restored after $fail_count checks (~$((fail_count * CHECK_INTERVAL / 60)) min) - rebooting" | |
| sync | |
| reboot | |
| exit 0 | |
| fi | |
| if [ "$light_recovery_attempts" -lt "$MAX_LIGHT_RECOVERY_ATTEMPTS" ]; then | |
| light_recovery_attempts=$((light_recovery_attempts + 1)) | |
| log "Attempting lightweight recovery for $RTL_IFACE (attempt $light_recovery_attempts)" | |
| for PID in $(pgrep -f "wpa_supplicant.*-i.*$RTL_IFACE"); do | |
| kill "$PID" 2>/dev/null | |
| done | |
| release_dhcp_lease "$RTL_IFACE" | |
| wpa_supplicant -i "$RTL_IFACE" -c /etc/wpa_supplicant.conf -B || log "Failed to restart wpa_supplicant during recovery" | |
| sleep 5 | |
| udhcpc -x hostname:"$(hostname)" -S -T1 -t15 -R -b -O search -O 100 -O 101 -O 160 -p /var/run/udhcpc."$RTL_IFACE".pid -i "$RTL_IFACE" || log "DHCP renewal failed during recovery" | |
| else | |
| log "Lightweight recovery exhausted ($light_recovery_attempts attempts); waiting for reboot threshold" | |
| fi | |
| done | |
| } | |
| determine_working_directory() { | |
| local sd_path="/mnt/mmcblk0p1" | |
| local tmp_path="/tmp/8821_workdir" | |
| # Check if SD card path exists and is mounted | |
| if [ -d "$sd_path" ] && mountpoint -q "$sd_path" 2>/dev/null; then | |
| # Check if it's actually an mmcblk device (SD card) | |
| local device=$(df "$sd_path" | tail -n1 | awk '{print $1}') | |
| if echo "$device" | grep -q "mmcblk"; then | |
| # Check available space (in KB, convert 64MB to KB = 65536) | |
| local available_kb=$(df "$sd_path" | tail -n1 | awk '{print $4}') | |
| if [ "$available_kb" -gt 65536 ]; then | |
| log "Using SD card working directory: $sd_path" >&2 | |
| echo "$sd_path" | |
| return 0 | |
| else | |
| log "SD card has insufficient space ($available_kb KB < 64MB)" >&2 | |
| fi | |
| else | |
| log "Path $sd_path is not an SD card device" >&2 | |
| fi | |
| else | |
| log "SD card path $sd_path not available" >&2 | |
| fi | |
| # Fallback to /tmp directory | |
| if [ ! -d "$tmp_path" ]; then | |
| mkdir -p "$tmp_path" || { log "Failed to create $tmp_path" >&2; echo "/tmp"; return 1; } | |
| log "Created working directory: $tmp_path" >&2 | |
| fi | |
| log "Using temporary working directory: $tmp_path" >&2 | |
| echo "$tmp_path" | |
| return 0 | |
| } | |
| fetch_driver_file() { | |
| local driver_file="$WORK_DIR/$SELECTED_DRIVER_FILE" | |
| local temp_file="$WORK_DIR/$SELECTED_DRIVER_FILE.tmp" | |
| if [ -z "$WORK_DIR" ]; then | |
| log "No working directory set for driver fetch" >&2 | |
| return 1 | |
| fi | |
| if [ -z "$SELECTED_DRIVER_URL" ]; then | |
| log "No driver URL configured for $SELECTED_PROFILE" >&2 | |
| return 1 | |
| fi | |
| log "Downloading $SELECTED_PROFILE driver from $SELECTED_DRIVER_URL..." >&2 | |
| # Try different download tools | |
| if command -v wget >/dev/null 2>&1; then | |
| wget -q -O "$temp_file" "$SELECTED_DRIVER_URL" || { | |
| log "Failed to download driver with wget" >&2 | |
| rm -f "$temp_file" | |
| return 1 | |
| } | |
| elif command -v curl >/dev/null 2>&1; then | |
| curl -s -o "$temp_file" "$SELECTED_DRIVER_URL" || { | |
| log "Failed to download driver with curl" >&2 | |
| rm -f "$temp_file" | |
| return 1 | |
| } | |
| else | |
| log "No download tool available (wget or curl)" >&2 | |
| return 1 | |
| fi | |
| # Move temp file to final location | |
| mv "$temp_file" "$driver_file" || { | |
| log "Failed to move downloaded driver to final location" >&2 | |
| rm -f "$temp_file" | |
| return 1 | |
| } | |
| log "Driver file successfully downloaded: $driver_file" >&2 | |
| return 0 | |
| } | |
| validate_driver_hash() { | |
| local driver_file="$WORK_DIR/$SELECTED_DRIVER_FILE" | |
| if [ -z "$SELECTED_DRIVER_HASH" ]; then | |
| log "Warning: No driver hash configured for $SELECTED_PROFILE, skipping validation" >&2 | |
| return 0 | |
| fi | |
| if ! command -v sha256sum >/dev/null 2>&1; then | |
| log "Warning: sha256sum not available, skipping hash validation" >&2 | |
| return 0 | |
| fi | |
| if [ ! -f "$driver_file" ]; then | |
| log "Driver file does not exist for hash validation" >&2 | |
| return 1 | |
| fi | |
| local file_hash=$(sha256sum "$driver_file" | cut -d' ' -f1) | |
| if [ "$file_hash" != "$SELECTED_DRIVER_HASH" ]; then | |
| log "Driver hash mismatch. Expected: $SELECTED_DRIVER_HASH, Got: $file_hash" >&2 | |
| return 1 | |
| fi | |
| log "Driver hash validated successfully" >&2 | |
| return 0 | |
| } | |
| ensure_driver_file() { | |
| local driver_file="$WORK_DIR/$SELECTED_DRIVER_FILE" | |
| local max_attempts=2 | |
| local attempt=1 | |
| while [ $attempt -le $max_attempts ]; do | |
| # Ensure file exists | |
| if ! check_driver_file; then | |
| log "Driver file missing (attempt $attempt), downloading..." >&2 | |
| fetch_driver_file || { | |
| log "Download failed on attempt $attempt" >&2 | |
| attempt=$((attempt + 1)) | |
| continue | |
| } | |
| else | |
| log "Driver file exists (attempt $attempt)" >&2 | |
| fi | |
| # Validate hash | |
| if validate_driver_hash; then | |
| log "Driver file ready and validated" >&2 | |
| return 0 | |
| else | |
| log "Hash validation failed on attempt $attempt" >&2 | |
| if [ $attempt -lt $max_attempts ]; then | |
| log "Removing invalid file and retrying..." >&2 | |
| rm -f "$driver_file" | |
| fi | |
| fi | |
| attempt=$((attempt + 1)) | |
| done | |
| log "Failed to ensure valid driver file after $max_attempts attempts" >&2 | |
| return 1 | |
| } | |
| check_driver_file() { | |
| local driver_file="$WORK_DIR/$SELECTED_DRIVER_FILE" | |
| if [ -z "$WORK_DIR" ]; then | |
| log "No working directory set for driver check" | |
| return 1 | |
| fi | |
| if [ -f "$driver_file" ]; then | |
| log "Driver file found: $driver_file" | |
| return 0 | |
| else | |
| log "Driver file not found: $driver_file" | |
| return 1 | |
| fi | |
| } | |
| install_to_bin() { | |
| local script_path="$0" | |
| local script_name="8821_run.sh" | |
| local bin_path="/bin/$script_name" | |
| # Check if we're already running from /bin | |
| if [ "$script_path" = "$bin_path" ] || [ "$(readlink -f "$script_path")" = "$bin_path" ]; then | |
| log "Script is already running from /bin, skipping installation" | |
| # Still need to ensure boot entry exists | |
| add_to_boot | |
| return $? | |
| fi | |
| log "Installing script to /bin..." | |
| # Check if script path is valid | |
| if [ ! -f "$script_path" ]; then | |
| log "Error: Cannot find current script at $script_path" | |
| return 1 | |
| fi | |
| # Copy script to /bin | |
| cp "$script_path" "$bin_path" || { | |
| log "Failed to copy script to $bin_path" | |
| return 1 | |
| } | |
| # Make it executable | |
| chmod +x "$bin_path" || { | |
| log "Failed to make $bin_path executable" | |
| return 1 | |
| } | |
| log "Script successfully installed to $bin_path" | |
| # Also create the boot entry | |
| add_to_boot || { | |
| log "Warning: Failed to add script to boot process" | |
| return 1 | |
| } | |
| return 0 | |
| } | |
| remove_old_boot_entries() { | |
| local service_name="S398821wifi" | |
| local service_path="/etc/init.d/$service_name" | |
| if [ -f "$service_path" ]; then | |
| log "Removing old boot entry $service_name..." | |
| rm -f "$service_path" || log "Failed to remove old boot entry $service_name" | |
| else | |
| log "No old boot entry $service_name found, skipping removal" | |
| fi | |
| } | |
| add_to_boot() { | |
| remove_old_boot_entries | |
| local service_name="S998821wifi" | |
| local service_path="/etc/init.d/$service_name" | |
| local script_path="/bin/8821_run.sh" | |
| log "Adding script to boot process..." | |
| # Check if script exists in /bin (should be installed already) | |
| if [ ! -f "$script_path" ]; then | |
| log "Error: Script not found at $script_path - run install_to_bin first" | |
| return 1 | |
| fi | |
| # Check if init script already exists and is up to date | |
| if [ -f "$service_path" ]; then | |
| if grep -q "$script_path" "$service_path" 2>/dev/null; then | |
| log "Boot service already configured" | |
| return 0 | |
| else | |
| log "Updating existing boot service" | |
| fi | |
| else | |
| log "Creating new boot service" | |
| fi | |
| # Create the init script | |
| cat > "$service_path" << 'EOF' | |
| #!/bin/sh | |
| DESC="8821 WiFi USB Adapter Service" | |
| DAEMON="/bin/8821_run.sh" | |
| case "$1" in | |
| start) | |
| echo "Starting $DESC" | |
| if [ -x "$DAEMON" ]; then | |
| $DAEMON --sync | |
| else | |
| echo "Error: $DAEMON not found or not executable" | |
| exit 1 | |
| fi | |
| ;; | |
| stop) | |
| echo "Stopping $DESC" | |
| # Kill any running instances | |
| pkill -f "8821_run.sh" || true | |
| ;; | |
| restart) | |
| $0 stop | |
| sleep 2 | |
| $0 start | |
| ;; | |
| *) | |
| echo "Usage: $0 {start|stop|restart}" | |
| exit 1 | |
| ;; | |
| esac | |
| exit 0 | |
| EOF | |
| # Make it executable | |
| chmod +x "$service_path" || { | |
| log "Failed to make service executable" | |
| return 1 | |
| } | |
| log "Boot service installed as $service_name" | |
| return 0 | |
| } | |
| main() { | |
| install_to_bin | |
| manage_prudynt_service "stop" | |
| WORK_DIR=$(determine_working_directory) | |
| wait_for_adapter_profile || { log "No supported USB WiFi adapter attached, aborting"; exit 1; } | |
| ensure_driver_file || { log "Failed to ensure driver file availability"; exit 1; } | |
| wait_for_onboard_wlan | |
| load_module | |
| start_rtl_wlan8821 | |
| } | |
| if [ "$1" = "--sync" ]; then | |
| main | |
| else | |
| main & | |
| fi | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment