#!/bin/sh

# Created by jiaqiang.ye@lnxall.com
# Lnxall initialization for System
# 2023/06/27

# IMPORTANT: DO NOT CREATE RUNNING PROCESSES WHICH
# CONTINUES TO RUN AFTER THE SCRIPT'S TERMINATION.
# PLEASE DO EXIT SCRIPT WITH ZERO STATUS

# System initialization script for RK3568 aarch64 board

create_sysinfo() {
	local retv=0
	local sysdir='/tmp/sysinfo'

	# create /tmp/sysinfo directory
	mkdir -p -m 0755 ${sysdir} ; retv=$?
	[ $retv -ne 0 ] && return 1

	# write board_name file
	if [ ! -f "${sysdir}/board_name" ] ; then
		echo 'WLOSANY_BAU-B30-003' > "${sysdir}/board_name"
		retv=$?
		chmod 644 "${sysdir}/board_name"
		[ $retv -ne 0 ] && return 2
	fi

	# write model file
	if [ ! -f "${sysdir}/model" ] ; then
		echo 'WLOSANY_RK3568' > "${sysdir}/model"
		retv=$?
		chmod 644 "${sysdir}/model"
	fi
	return $retv
}

create_dir() {
	local dirp="$1"
	if [ -d "${dirp}" ] ; then
		# already created, just return
		return 0
	fi

	[ -e "${dirp}" ] && rm -rf "${dirp}"
	mkdir -p "${dirp}"
	return $?
}

wait_file() {
	local file="$1"
	local maxcnt="$2"
	local count=0
	while [ ${count} -le ${maxcnt} ] ; do
		if [ -e "${file}" ] ; then
			break
		fi
		echo "Waiting for '${file}': ${count}..."
		sleep 1 ; count=$((count + 1))
	done
	return 0
}

symlink_file() {
	local source="$1"
	local target="$2"

	wait_file "${source}" 3 # wait until file show-up

	local dolink=1
	if [ -e "${target}" ] ; then
		local real="$(readlink -f ${target})"
		[ "${real}" = "${source}" ] && dolink=0
	fi

	if [ ${dolink} -ne 0 ] ; then
		rm -v -rf "${target}"
		ln -s -v -f "${source}" "${target}"
		return $?
	fi
	return 0
}

# setup tty serial device for RK3568 arm64 device
setup_ttyserial() {
	symlink_file '/dev/ttyS4'    '/dev/ttylnx6' || return 6
	symlink_file '/dev/ttyS3'    '/dev/ttylnx7' || return 7
	symlink_file '/dev/ttyS7'    '/dev/ttylnx8' || return 8
	symlink_file '/dev/ttyS8'    '/dev/ttylnx9' || return 9
	return 0
}

setup_can() {
	map="
can0:lnxcan1;
can1:lnxcan2;
can2:lnxcan3;
"
	echo "$map" | while IFS= read -r line; do
		[ -z "$line" ] && continue
		#
		old_name=$(echo "$line" | cut -d':' -f1)
		new_name=$(echo "$line" | cut -d':' -f2 | cut -d';' -f1)
		#
		if ip -br link show "$old_name" > /dev/null 2>&1; then
			ip link set $old_name down && ip link set $old_name name $new_name
			if [ $? -ne 0 ]; then
				echo "Failed to rename $old_name to $new_name"
			else
				echo "Successfully renamed $old_name to $new_name"
			fi
		else
			echo "$old_name does not exist"
		fi
	done

	return 0
}


# in order for br-lan to work on RK3568:
# 1, /proc/sys/net/ipv4/ip_forward should be 1;
# 2, NAT should be enabled with iptables.
brlan_setup() {
	if [ "$(cat /proc/sys/net/ipv4/ip_forward)" != "1" ] ; then
		echo 1 > /proc/sys/net/ipv4/ip_forward
	fi

	local masq="$(iptables-legacy -t nat -L POSTROUTING | grep -e MASQUERADE | wc -l)"
	[ -z "${masq}" ] && masq=0
	if [ ${masq} -le 2 ] ; then
		# does this have any other side effects?
		iptables-legacy -t nat -A POSTROUTING -o eth0     -j MASQUERADE
		iptables-legacy -t nat -A POSTROUTING -o usb0     -j MASQUERADE
		iptables-legacy -t nat -A POSTROUTING -o modem0   -j MASQUERADE
	fi
	return 0
}

# power on 4G modem for RK3568
power_on_4g() {
	local gpath=/sys/class/gpio/gpio74
	if [ ! -e "${gpath}" ] ; then
		echo "74" > /sys/class/gpio/export
	fi

	echo "out" > "${gpath}/direction"
	echo 1 > "${gpath}/value"
	return 0
}

power_on_eth2() {
	local gpath=/sys/class/gpio/gpio101
	if [ ! -e "${gpath}" ] ; then
		echo "101" > /sys/class/gpio/export
	fi

	echo "out" > "${gpath}/direction"
	echo 1 > "${gpath}/value"
	#
	#gpath=/sys/class/gpio/gpio100
	#if [ ! -e "${gpath}" ] ; then
	#	echo "100" > /sys/class/gpio/export
	#fi
	#
	#echo "out" > "${gpath}/direction"
	#echo 1 > "${gpath}/value"
	return 0
}

mount_ssd() {
	local MNTDIR='/mnt/ssd'
	if [ ! -d "${MNTDIR}" ] ; then
		rm -rf "${MNTDIR}" # in case it is a file
		mkdir -p "${MNTDIR}"
	fi

	# check again for mount directory
	if [ ! -d "${MNTDIR}" ] ; then
		echo "Error, ssd mount directory not found: '${MNTDIR}'" 1>&2
		return 1
	fi

	# check if already mounted
	if mountpoint -q "${MNTDIR}" ; then
		echo "INFO: SSD already mounted to '${MNTDIR}'."
		return 0
	fi

	local BDEV=/dev/nvme0n1
	if [ ! -b "${BDEV}" ] ; then
		echo "INFO: No SSD character device found, skip mount."
		return 0
	fi

	# to prevent any suspicious, umount it first:
	umount "${MNTDIR}" >/dev/null 2>/dev/null

	mount -orw -t ext4 ${BDEV} "${MNTDIR}"
	if [ $? -ne 0 ] ; then
		e2fsck -p -f ${BDEV}
		mount -orw -t ext4 ${BDEV} "${MNTDIR}"
		if [ $? -ne 0 ] ; then
			echo "Error, failed to mount SSD. you might need to format it first." 1>&2
			return 2
		fi
	fi
	return 0
}

update_wan1_mac() {
	local wanmac="$(uci get network.wan.macaddr)"
	[ -z "${wanmac}" ] && wanmac="$(factory get | awk -F= '/MAC=/{print $2}')"
	if [ ${#wanmac} -eq 17 ] ; then
		uci_set_mac wan1 "${wanmac}" 1 && \
			nothup /bin/sh -c 'sleep 6 ; netuci'
	fi
	return 0
}

# for RK3568/XIENENG
charge_capacitor() {
	local pfx='/sys/class/gpio/gpio30'
	if [ ! -e "${pfx}" ] ; then
		echo 30 > /sys/class/gpio/export
		sleep 1
	fi

	if [ "$(cat ${pfx}/direction)" != "out" ] ; then
		echo out > ${pfx}/direction
	fi

	echo 1 > ${pfx}/value
	return 0
}

mainfunc() {
	local rval=0

	power_on_eth2
	brlan_setup
	# power_on_4g # power on 4G module
	charge_capacitor

	mkdir -p /var/crash/coredumps
	# update linux kernel coredump pattern
	echo '/var/crash/coredumps/%E-%t-%p-%s.core' > /proc/sys/kernel/core_pattern

	create_dir '/var/run/lnxall' ; rval=$?
	if [ ${rval} -ne 0 ] ; then
		echo "Error, failed to create /var/run/lnxall directory!" 1>&2
		return 1
	fi

	create_sysinfo ; rval=$?
	if [ ${rval} -ne 0 ] ; then
		echo "Error, function has failed: create_info: ${rval}" 1>&2
		return 2
	fi

	setup_can
	setup_ttyserial ; retv=$?
	[ ${rval} -ne 0 ] && return 3

	# mount Solid State Drive if it exists
	mount_ssd
	update_wan1_mac # error should be ignored
	return 0
}

mainfunc ; exit $?
