#!/bin/sh
# Realtek drivers

# Dev mode local override
dev_mode_enabled=0
read roku_dev_mode rest < /proc/cmdline
if [ "$roku_dev_mode" = 'dev=1' ]
then
    # Dev mode local override
    if [ -f /nvram/S64wifi ]
    then
        echo
        echo "=== WIFI INIT from /nvram/S64wifi"
        source /nvram/S64wifi
        exit
    fi
    dev_mode_enabled=1
fi

[ -f /tmp/wlan-driver ] && DRIVER=`cat /tmp/wlan-driver`
[ -f /tmp/wlan-module ] && MODULE=`cat /tmp/wlan-module`

PLATFORM="${ROKU_PLATFORM-`roku_platform`}"

. /lib/wlan/wlan-functions

HAS_DUAL_WIFI=$(has_dual_wifi)

STAINTF=wlan0

# All P2P functions are collected in p2p-functions script below, which is
# controlled by three variables:
#
# ENABLE_P2P - starts P2P instance of wpa_supplicant on the specified interface
# STAINTF   - the interface to configure in STA mode
# P2PINTF    - the interface to configure in P2P mode
#
# For platforms that have a single wifi chip, we use wlan0 as STA and wlan1 as
# P2P.  For platforms such as Fruitland we want to take advantage of the
# second chip and start P2P on the second chip rather than the first.  Note
# that these variables only control initialization for THIS script.  Actual
# chip initialization and starting of P2P will be done in the chip specific
# initialization file (e.g. S63wifi for Fruitland)
#
# On dual wifi platforms this script (S64wifi) only handles the STA interface, not P2P.
# P2P is handled separately in S63wifi (and may happen in parallel for faster init.)
#
# On a dual wifi platform that will have its secondary radio disabled, we still need to
# enable the secondary radio during manufacturing to be able to test the hardware.
#
# P2P needs to be disabled when in the rescue image to ensure remotes do not enter
# pairing mode and pair to another nearby Roku device (e.g. Fruitland/Chico's TV).
# We need to ensure the remote keeps using IR fallback (see CHICO-654 for details)

if [ "$HAS_DUAL_WIFI" != "true" ] && [ "$(is_manu_image)" != "1" ] && [ "$(is_rescue_image)" != "1" ]; then
    P2PINTF=wlan1
    P2P_CAPABLE=true
else
    P2P_CAPABLE=false
fi

. /lib/wlan/p2p-functions
. /lib/wlan/networking-functions

unset DBG
[ -f /nvram/wlan-debug ] && DBG="-dbg"

init_driver() {
    # Initialze the driver and entourage

    # If Broadcom chip detected, exit now
    [ ! $MODULE ] && return 1

    #Wait till finalized that this is a realtek chip
    echo $STAINTF > /tmp/sta-interface-name

    # TV platform specific config has to be set for some Mstar SoC based platforms
    set_platform_config $PLATFORM $MODULE

    if lsmod | grep -q $MODULE ; then
        echo "=== Wifi: already running $DRIVER $MODULE"
        return 0
    fi

    echo "=== Wifi: installing $DRIVER $MODULE$DBG"

    get_wlan_region_info COUNTRY_CODE FILE_COUNTRY CHAN_PLAN
  
    echo "Configuring driver with country $FILE_COUNTRY ($COUNTRY_CODE) and channel plan $CHAN_PLAN"

    cp -f /lib/wlan/realtek/TXPWR_LMT_${FILE_COUNTRY}.txt  /tmp/TXPWR_LMT.txt
    cp -f /lib/wlan/realtek/PHY_REG_PG_${FILE_COUNTRY}.txt /tmp/PHY_REG_PG.txt

    DOPTS=$(get_realtek_wlan_module_params)

    DPATH=/lib/wlan/realtek
    if [ $dev_mode_enabled = 1 ]
    then
        [ -f /nvram/$MODULE$DBG.ko ] && DPATH=/nvram
    fi

    # Set interfaces for dual-radio platforms here
    [ "$HAS_DUAL_WIFI" == "true" ] && DOPTS="$DOPTS ifname=wlan0 if2name=wlan1"

    KMOD=$MODULE

    # Look in the custom package for wifi args (e.g., 8812au_WIFI_ARGS=)
    # The following logic could eventually be expanded beyond TV platforms
    if [ $PLATFORM == "liberty" ]; then
        TV_MODEL=`pcedit odmmodel | cut -d"=" -f2 | sed 's/\"//g' | tr -d ' '`
        KEY=$MODULE"_WIFI_ARGS"
        CFGFILE="/custom/mappings/models/$TV_MODEL"
        RFE_ARGS=`grep $KEY $CFGFILE | cut -d"=" -f2- | sed 's/\"//g'`
        if [ ! -z $RFE_ARGS ]; then
            DOPTS="$DOPTS $RFE_ARGS"
            RFE_TYPE_CP=`echo $RFE_ARGS | cut -d"=" -f2`
        fi
    fi

    [ -f /lib/modules/compat.ko ] && insmod /lib/modules/compat.ko
    [ -f /lib/modules/cfg80211.ko ] && insmod /lib/modules/cfg80211.ko

    echo "Wifi: Installing $DPATH/$KMOD$DBG.ko $DOPTS"
    insmod $DPATH/$KMOD$DBG.ko $DOPTS

    TIMEOUT=20
    while ! check_wlan_interface $STAINTF; do
        usleep 100000
        let TIMEOUT=TIMEOUT-1
        [ $TIMEOUT -le 0 ] && break
    done

    set_wifi_mac

    ifconfig $STAINTF up

    # check efuse and reload driver if needed; only if custom package had no setting
    if [ ! $RFE_TYPE_CP ]; then
        RFE_TYPE=$(check_efuse $STAINTF $MODULE)
        if [ $RFE_TYPE = "fail" ]; then
            echo "=== Wifi ERROR === "
            echo "=== Wifi ERROR === "
            echo "WiFi driver failed to load due to efuse being unprogrammed!"
            return 1
        elif [ $RFE_TYPE != "valid" ]; then
            # reload driver with the new RFE_TYPE value
            ifconfig $STAINTF down
            rmmod $MODULE

            sleep 1

            echo "Setting rtw_RFE_type to ${RFE_TYPE}"
            insmod $DPATH/$MODULE$DBG.ko $DOPTS rtw_RFE_type=$RFE_TYPE

            TIMEOUT=20
            while ! check_wlan_interface $STAINTF; do
                usleep 100000
                let TIMEOUT=TIMEOUT-1
                [ $TIMEOUT -le 0 ] && break
            done

            set_wifi_mac
            ifconfig $STAINTF up
        fi
    fi

    [ $TIMEOUT -le 0 ] && return 1

    set_realtek_wlan_proc_parameters $MODULE $STAINTF

    set_wifi_remote_wowl_address $STAINTF

    return 0
}

wait_driver_up_fallback() {
    # On resume, wait until wlan driver is up
    case $MODULE in
        8188fu )          STATUS="read:0x0C" ;;
        8811cu )          STATUS="read:0x09" ;;
        8812bu | 8822bu ) STATUS="read:0x0A" ;;
        8812cu | 8822cu ) STATUS="read:0x0A" ;; #FAKE! TODO: Get a uniform API from Realtek
        *) echo "MODULE undefined" ;;
    esac
    if [ ! $STATUS ]; then
        echo "WiFi MODULE name not set. Status test will not be useful."
        return 0
    fi

    TIMEOUT=80
    while ! iwpriv $STAINTF read 1,0xFC | grep "$STATUS" >/dev/null; do
        echo "P2P: waiting for wlan (iwpriv)"
        [ $TIMEOUT -le 0 ] && return 1
        let TIMEOUT=$TIMEOUT-1
        usleep 100000
    done
    return 0
}

wait_driver_up() {

    # fall back for drivers that do not support this (V4)
    if [ -d /proc/net/rtl$MODULE/$STAINTF ] &&
       [ ! -f /proc/net/rtl$MODULE/$STAINTF/wow_wake_indication ]; then
        wait_driver_up_fallback
        return $?
    fi

    TIMEOUT=80
    while [ $TIMEOUT -gt 0 ]
    do
        DRIVERUP=$(cut -d" " -f3 /proc/net/rtl$MODULE/$STAINTF/wow_wake_indication)
        DRIVERUP=${DRIVERUP#"0x"}
        echo "P2P: waiting for wlan. wait_driver_up: $DRIVERUP"
        [ $DRIVERUP -eq 1 ] && return 0 # proc file read 1, driver ready
        let TIMEOUT=$TIMEOUT-1
        usleep 100000
    done
    echo "P2P: waiting for wlan timed out (proc file)"
    return 1 # timed out
}

init() {
    init_driver && init_wlan_supplicant $STAINTF && init_wlan_test_shell && init_p2p && init_ozmo
}

quit() {
    kill_async_start
    kill_ozmo
    kill_p2p 2
    kill_wlan_supplicant $STAINTF
    if [ ! $HAS_DUAL_WIFI ]; then
        # Make sure no supplicants are running:
        killall wpa_supplicant
    fi
    rm -rf /tmp/wpa_ctrl/
    ifconfig $STAINTF down
    sleep 1
    rmmod $MODULE
    sleep 1
    rmmod cfg80222 2> /dev/null
    rmmod compat 2> /dev/null
}

COMMAND="$1"
echo "=== Wifi: $1 (Realtek)"
case $COMMAND in
start)
    DRIVER="realtek"
    echo $DRIVER > /tmp/wlan-driver

    wlan_reset
    wlan_wait_for_hardware || exit 0
    (
    init_fifos
    # Called on cold power-on to identify the chip/driver in advance:
    # Longview requires reset on cold boot
    init
    wowl_log
    ) < /dev/null &
    ;;
init)
    init
    ;;
quit)
    quit
    ;;
stop)
    touch /tmp/system_in_suspend.$STAINTF
    rm -f  /tmp/reset_wifi.$STAINTF
    kill_async_start
    cat /proc/net/rtl$MODULE/ver_info
    iw $STAINTF link
    ifconfig $STAINTF | grep HWaddr
    # Re-enable WOWL mode (can be removed if driver fixes it)
    PHY=$(iw dev | grep phy | tail -1 | sed s/#//)
    iw $PHY wowlan enable any
    kill_ozmo
    kill_p2p 10
    # Leave driver running
    ;;
restart)
    quit
    wlan_reset
    wlan_wait_for_hardware || exit 0
    init
    ;;
reset)
    # Used by the secret screen for testing purposes:
    wlan_reset
    ;;
resume)
    # Not used, but handy for developers:
    init_fifos
    wlan_reset
    init
    ;;
resume_nonblock)
    # Avoid racing against main app
    wowl_reason $MODULE $STAINTF
    wowl_log
    (
    if ! wait_driver_up; then
        # WSM will reset wifi hardware
        touch /tmp/reset_wifi.$STAINTF
        rm -f /tmp/system_in_suspend.$STAINTF
    else
        init_p2p && init_ozmo
        rm -f /tmp/system_in_suspend.$STAINTF
    fi
    ) < /dev/null &
    ;;
init_p2p)
    if ! wait_driver_up; then
        quit
        wlan_reset
        init
    else
        init_p2p && init_ozmo
    fi
    ;;
quit_p2p)
    kill_ozmo
    kill_p2p 2
    ;;
init_wfd)
    init_wfd 1
    ;;
quit_wfd)
    kill_wfd 1
    ;;
updatename)
    update_dev_name
    ;;
wowl_test)
    wowl_test $STAINTF
    ;;
*)
    echo "Wifi: unknown command, see $0 source"
    ;;
esac
