// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * Copyright (c) 2020 MediaTek Inc.
 */

#include <uapi/linux/sched/types.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <media/dvb_demux.h>

#include "atsc30_log.h"
#include "alp_hal_hw.h"

#include "mdrv_atsc30_if.h"
#include "mdrv_atsc30_internal.h"
#include "mdrv_atsc30_msg_q.h"

#include "mtk_dmx_filter.h"
#include "mtk_dmx_dev.h"

//-------------------------------------------------------------------------------------------------
//  Debug Constants and Macros
//-------------------------------------------------------------------------------------------------
//#define MDRV_ATSC30_INTERNAL_MUTEX_DEBUG_ENABLE

#ifdef MDRV_ATSC30_INTERNAL_MUTEX_DEBUG_ENABLE
#define MDRV_ATSC30_INTERNAL_MUTEX_LOG(...) \
	ATSC30_DRVIF_LOG_DEBUG(##__VA_ARGS__)
#else
#define MDRV_ATSC30_INTERNAL_MUTEX_LOG(...)
#endif

//#define MDRV_ATSC30_INTERNAL_MUTEX_ENABLE

//-------------------------------------------------------------------------------------------------
//  Constants
//-------------------------------------------------------------------------------------------------
#define MDRV_ATSC30_INTERNAL_MSG_PROC_PRIORITY (1) // MIN:1 MAX:99
#define MDRV_ATSC30_INTERNAL_BUF_WAIT_TIME (1) //ms

#define MDRV_ATSC30_INTERNAL_PROFILE_LOG_US_MIN (1000)

#define MDRV_ATSC30_INTERNAL_MSG_TIMEOUT (100) //ms

//-------------------------------------------------------------------------------------------------
//  Macros
//-------------------------------------------------------------------------------------------------
#define MDRV_ATSC30_INTERNAL_LOCK(framer_idx) \
	do { \
		MDRV_ATSC30_INTERNAL_MUTEX_LOG( \
			"MDRV_ATSC30_INTERNAL_LOCK %d\n", \
			framer_idx); \
		mutex_lock(&_locks[framer_idx]); \
	} while (0)

#define MDRV_ATSC30_INTERNAL_UNLOCK(framer_idx) \
	do { \
		mutex_unlock(&_locks[framer_idx]); \
		MDRV_ATSC30_INTERNAL_MUTEX_LOG( \
			"MDRV_ATSC30_INTERNAL_UNLOCK %d\n", \
			framer_idx); \
	} while (0)

//-------------------------------------------------------------------------------------------------
//  Structs and Enums
//-------------------------------------------------------------------------------------------------
typedef struct {
	bool working;
	u8 framer_idx;

	struct mdrv_atsc30_msg_q *msg_q;
	struct task_struct *msg_proc_thread;
} alp_hal_packet_msg_handler_t;

//-------------------------------------------------------------------------------------------------
//  Functions Prototype
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Variables
//-------------------------------------------------------------------------------------------------
static mdrv_atsc30_hw_config_t _hw_cfg = {
	.hw_fe_input_pkt_type = FRONTEND_INPUT_PKT_ALP,
	.hw_mode = HW_FRAMER_MODE_NORMAL_BYPASS_DE_ADAPTION,
	.hw_cfg_flags = 0,
};

static alp_hal_packet_msg_handler_t _packet_msg_handlers[eATSC30_SUPPORT_FRAMER_NUM] = {
	{
		.working = false,
		.framer_idx = eATSC30_ALP_FRAMER_0,
		.msg_q = NULL,
		.msg_proc_thread = NULL,
	},
	{
		.working = false,
		.framer_idx = eATSC30_ALP_FRAMER_1,
		.msg_q = NULL,
		.msg_proc_thread = NULL,
	},
};

static struct mutex _locks[eATSC30_SUPPORT_FRAMER_NUM] = {
	__MUTEX_INITIALIZER(_locks[eATSC30_ALP_FRAMER_0]),
	__MUTEX_INITIALIZER(_locks[eATSC30_ALP_FRAMER_1]),
};

//-------------------------------------------------------------------------------------------------
//  Internal Functions
//-------------------------------------------------------------------------------------------------
static int priv_msg_q_wait_recv(
		struct mdrv_atsc30_msg_q *const msg_q,
		alp_packet_msg_t *msg)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	size_t msg_size = sizeof(alp_packet_msg_t);

	if (ATSC30_DRVIF_VERIFY(msg == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (ATSC30_DRVIF_VERIFY(msg_q == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	memset((msg), 0, msg_size);

	ret = mdrv_atsc30_msg_q_get(
			msg_q,
			(u8 *)msg,
			&msg_size,
			MDRV_ATSC30_INTERNAL_MSG_TIMEOUT,
			MDRV_ATSC30_MSG_Q_FLAG_WAIT);
	if ((ret != MDRV_ATSC30_RETURN_CODE_OK)
		|| (msg_size != sizeof(alp_packet_msg_t))) {
		ATSC30_DRVIF_LOG_ENHANCED_VERBOS(
			"mdrv_atsc30_msg_q_get is failed. ret = %d, msg_size = %d\n",
			ret,
			(s32)msg_size);
	} else {
		alp_hal_if_alp_packet_msg_dump(
			A30_DBG_LVL_DEBUG,
			msg);
	}

	return ret;
}

static int priv_packet_msg_proc_thread(void *pvArg)
{
	alp_packet_msg_t msg;
	u8 framer_idx;
	struct sched_param param = {
		.sched_priority = MDRV_ATSC30_INTERNAL_MSG_PROC_PRIORITY,
	};

	framer_idx = (u8)(uintptr_t)pvArg;

	if (!ATSC30_ALP_IS_FRAMER_INDEX_VALID(framer_idx)) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"framer_idx[%d] is invalid.\n",
			framer_idx);

		return -EINVAL;
	}

	if (sched_setscheduler(current, SCHED_RR, &param) != 0) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"sched_setscheduler(..., SCHED_RR, %d) for framer_idx[%d] is failed.\n",
			param.sched_priority,
			framer_idx);

		return -EIO;
	}

	ATSC30_DRVIF_LOG_ENHANCED_INFO(
		"ALP packet msg proc thread: start for framer_idx[%d]\n",
		framer_idx);

	set_freezable();
	while (!kthread_should_stop()) {
		try_to_freeze();
		if (_packet_msg_handlers[framer_idx].working) {
			if (priv_msg_q_wait_recv(_packet_msg_handlers[framer_idx].msg_q, &msg) ==
				MDRV_ATSC30_RETURN_CODE_OK) {
				if (_packet_msg_handlers[framer_idx].working) {
					struct atsc30_profile profile = {
						.log_level = A30_DBG_LVL_INFO,
						.log_module = ATSC30_LOG_MODULE_DRVIF,
						.log_prefix = __func__,
						.log_us = MDRV_ATSC30_INTERNAL_PROFILE_LOG_US_MIN,
					};
					alp_hal_if_alp_packet_msg_dump(
						A30_DBG_LVL_DEBUG,
						&msg);
					atsc30_profile_get_begin_time(&profile);
					alp_hal_if_handle_packet(
						framer_idx,
						msg.addr_1,
						msg.addr_len_1,
						msg.addr_2,
						msg.addr_len_2);
					ATSC30_PROFILE_GET_END_TIME(&profile);
				}
			}
		}
	}

	return 0;
}

//-------------------------------------------------------------------------------------------------
//  Public Functions
//-------------------------------------------------------------------------------------------------
int mdrv_atsc30_priv_get_hw_config(
		mdrv_atsc30_hw_config_t **ppstCfg)
{
	if (ATSC30_DRVIF_VERIFY(ppstCfg == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	*ppstCfg = &_hw_cfg;

	return MDRV_ATSC30_RETURN_CODE_OK;
}

int mdrv_atsc30_priv_decide_alp_parser_config(
		alp_hal_framer_mode_t hw_mode,
		alp_sw_parser_config_t *pstCfg)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;

	if (ATSC30_DRVIF_VERIFY(pstCfg == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	switch (_hw_cfg.hw_fe_input_pkt_type) {
	case FRONTEND_INPUT_PKT_ALP:
		if (hw_mode == HW_FRAMER_MODE_NORMAL_BYPASS_DE_ADAPTION) {
			pstCfg->enable_sw_parse_rdt = false;
			pstCfg->enable_sw_deadaption = true;
			pstCfg->enable_sw_ptp_update = true;
		} else if (hw_mode == HW_FRAMER_MODE_NORMAL) {
			pstCfg->enable_sw_parse_rdt = false;
			pstCfg->enable_sw_deadaption = false;
			pstCfg->enable_sw_ptp_update = true;
		} else if (hw_mode == HW_FRAMER_MODE_BYPASS_ALL) {
			pstCfg->enable_sw_parse_rdt = true;
			pstCfg->enable_sw_deadaption = true;
			pstCfg->enable_sw_ptp_update = true;
		} else {
			ATSC30_DRVIF_LOG_ENHANCED_ERROR(
				"hw_mode %d is not support by atsc3.0\n",
				hw_mode);

			ret = MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
		}
		break;

	case FRONTEND_INPUT_PKT_TS188:
		pstCfg->enable_sw_parse_rdt = true;
		pstCfg->enable_sw_deadaption = true;
		pstCfg->enable_sw_ptp_update = true;
		break;

	default:
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"fe input type(%d) not support by atsc3.0\n",
			_hw_cfg.hw_fe_input_pkt_type);

		ret = MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
		break;
	}

	if (ret == MDRV_ATSC30_RETURN_CODE_OK)
		ATSC30_DRVIF_LOG_ENHANCED_INFO(
			"prs cfg(hw_fe_input_pkt_type(%d), hw_mode(%d), enable_sw_deadaption(%d), enable_sw_parse_rdt(%d), enable_sw_ptp_update(%d))\n",
			_hw_cfg.hw_fe_input_pkt_type,
			hw_mode,
			pstCfg->enable_sw_deadaption,
			pstCfg->enable_sw_parse_rdt,
			pstCfg->enable_sw_ptp_update);

	return ret;
}

int mdrv_atsc30_priv_packet_msg_get_available_size(
		u8 framer_idx,
		size_t *q_available_size)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;

	if (!ATSC30_ALP_IS_FRAMER_INDEX_VALID(framer_idx))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	if (!_packet_msg_handlers[framer_idx].working) {
		ATSC30_DRVIF_LOG_ENHANCED_WARN(
			"g_packet_msg_hdlr[%d] is not in working status\n",
			framer_idx);

		return MDRV_ATSC30_RETURN_CODE_RESOURCE;
	}

	ret = mdrv_atsc30_msg_q_get_available_size(
		_packet_msg_handlers[framer_idx].msg_q,
		q_available_size);
	if (ret != MDRV_ATSC30_RETURN_CODE_OK) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"mdrv_atsc30_msg_q_get_available_size(...) of %d is failed\n",
			framer_idx);

		return MDRV_ATSC30_RETURN_CODE_FAILURE;
	}

	return MDRV_ATSC30_RETURN_CODE_OK;
}

int mdrv_atsc30_priv_packet_msg_handle_new_msg(
		u8 framer_idx,
		alp_packet_msg_t msg)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	size_t q_size = 0;
	size_t msg_size = sizeof(alp_packet_msg_t);

	if (!ATSC30_ALP_IS_FRAMER_INDEX_VALID(framer_idx))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	if (_packet_msg_handlers[framer_idx].working) {
		ret = mdrv_atsc30_msg_q_put(
				_packet_msg_handlers[framer_idx].msg_q,
				(u8 *)(&msg),
				&msg_size,
				MDRV_ATSC30_MSG_Q_TIMEOUT_FOREVER,
				MDRV_ATSC30_MSG_Q_FLAG_WAIT
					| MDRV_ATSC30_MSG_Q_FLAG_PRIORITY_HIGH);
		if (ret != MDRV_ATSC30_RETURN_CODE_OK) {
			ATSC30_DRVIF_VERIFY(
				mdrv_atsc30_msg_q_get_available_size(
					_packet_msg_handlers[framer_idx].msg_q,
					&q_size) != MDRV_ATSC30_RETURN_CODE_OK);
			ATSC30_DRVIF_LOG_ENHANCED_WARN(
				"Add ALP packet msg Fail(%d), MsgQBufCount %zd\n",
				ret,
				q_size);

			ret = MDRV_ATSC30_RETURN_CODE_RESOURCE;
		} else {
			ATSC30_DRVIF_LOG_ENHANCED_DEBUG(
				"framer_idx[%d] ALP packet msg sent:\n",
				framer_idx);
			alp_hal_if_alp_packet_msg_dump(
				A30_DBG_LVL_DEBUG,
				&msg);
		}
	} else {
		ATSC30_DRVIF_LOG_ENHANCED_INFO(
			"framer_idx[%d] Not ready for ALP packet receiver\n",
			framer_idx);

		ret = MDRV_ATSC30_RETURN_CODE_RESOURCE;
	}

	return ret;
}

static int priv_packet_msg_handler_init(u8 framer_idx)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	struct mdrv_atsc30_if_context *atsc30_if_context = NULL;

	ret = mdrv_atsc30_if_get_context(framer_idx, &atsc30_if_context);
	if (ATSC30_DRVIF_VERIFY_AND_PRINT_ERR_MSG(
		ret != MDRV_ATSC30_RETURN_CODE_OK,
		"[%s][%d] mdrv_atsc30_if_get_context(%d) is failed\n",
		__func__,
		__LINE__,
		framer_idx))
		return ret;

	_packet_msg_handlers[framer_idx].msg_q = &atsc30_if_context->packet_msg_q;
	_packet_msg_handlers[framer_idx].msg_proc_thread =
			kthread_run(
				priv_packet_msg_proc_thread,
				(void *)(uintptr_t)framer_idx,
				"ALP_%d_PACKET_MSGQ", framer_idx);
	if (ATSC30_DRVIF_VERIFY_AND_PRINT_ERR_MSG(
		IS_ERR(_packet_msg_handlers[framer_idx].msg_proc_thread),
		"[%s][%d] kthread_create for framer_idx[%d] is failed\n",
		__func__,
		__LINE__,
		framer_idx))
		return MDRV_ATSC30_RETURN_CODE_RESOURCE;

	// TODO: Is another place to start working?
	_packet_msg_handlers[framer_idx].working = true;

	return MDRV_ATSC30_RETURN_CODE_OK;
}

static int priv_packet_msg_handler_exit(u8 framer_idx)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	int ret_tmp = 0;
	struct mdrv_atsc30_if_context *atsc30_if_context = NULL;

	ret = mdrv_atsc30_if_get_context(framer_idx, &atsc30_if_context);
	if (ATSC30_DRVIF_VERIFY_AND_PRINT_ERR_MSG(
		ret != MDRV_ATSC30_RETURN_CODE_OK,
		"[%s][%d] mdrv_atsc30_if_get_context(%d) is failed\n",
		__func__,
		__LINE__,
		framer_idx))
		return ret;

	if (!IS_ERR(_packet_msg_handlers[framer_idx].msg_proc_thread)) {
		// TODO: Is another place to stop working?
		_packet_msg_handlers[framer_idx].working = false;
		wake_up_interruptible(&(_packet_msg_handlers[framer_idx].msg_q->wait_q_head_get));
		ret_tmp = kthread_stop(
				_packet_msg_handlers[framer_idx].msg_proc_thread);
		if (ret_tmp != 0)
			ATSC30_DRVIF_LOG_ENHANCED_INFO(
				"kthread_stop for framer_idx[%d] is failed\n",
				framer_idx);
		_packet_msg_handlers[framer_idx].msg_proc_thread = NULL;
		_packet_msg_handlers[framer_idx].msg_q = NULL;
	}

	return ret;
}

int mdrv_atsc30_priv_packet_msg_handler_init(u8 framer_idx)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	int ret_tmp = MDRV_ATSC30_RETURN_CODE_OK;

	MDRV_ATSC30_INTERNAL_LOCK(framer_idx);

	ret = priv_packet_msg_handler_init(framer_idx);
	if (ret != MDRV_ATSC30_RETURN_CODE_OK) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"priv_packet_msg_handler_init(%d) is failed\n",
			framer_idx);

		ret_tmp = priv_packet_msg_handler_exit(framer_idx);
		if (ret_tmp != MDRV_ATSC30_RETURN_CODE_OK)
			ATSC30_DRVIF_LOG_ENHANCED_INFO(
				"priv_packet_msg_handler_exit(%d) is failed\n",
				framer_idx);
	}

	MDRV_ATSC30_INTERNAL_UNLOCK(framer_idx);

	return ret;
}

int mdrv_atsc30_priv_packet_msg_handler_exit(
		u8 framer_idx)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;

	MDRV_ATSC30_INTERNAL_LOCK(framer_idx);

	ret = priv_packet_msg_handler_exit(framer_idx);
	if (ret != MDRV_ATSC30_RETURN_CODE_OK)
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"priv_packet_msg_handler_exit(%d) is failed\n",
			framer_idx);

	MDRV_ATSC30_INTERNAL_UNLOCK(framer_idx);

	return ret;
}

int mdrv_atsc30_priv_get_fh_ctx(
		struct dmx2_filter *dmx2_filter,
		struct mtk_demux2_fh_ctx **ctx)
{
	struct dvb_fh *fh = NULL;

	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (ATSC30_DRVIF_VERIFY(ctx == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	fh = dmx2_filter->fh;
	if (ATSC30_DRVIF_VERIFY(fh == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	*ctx = fh_to_dmxctx(fh);

	return MDRV_ATSC30_RETURN_CODE_OK;
}

int mdrv_atsc30_priv_get_bc_ctx(
		struct dmx2_filter *dmx2_filter,
		struct mtk_bc_ctx **bc_ctx)
{
	struct mtk_demux2_fh_ctx *ctx = NULL;

	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (ATSC30_DRVIF_VERIFY(bc_ctx == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	if (mdrv_atsc30_priv_get_fh_ctx(
		dmx2_filter,
		&ctx) != MDRV_ATSC30_RETURN_CODE_OK) {

		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	}

	*bc_ctx = fh_dmxctx_get_bc_ctx(ctx);

	return MDRV_ATSC30_RETURN_CODE_OK;
}

int mdrv_atsc30_priv_set_filter_info(
		struct dmx2_filter *dmx2_filter,
		void *data, u32 size)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	struct mtk_demux2_fh_ctx *ctx = NULL;

	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (mdrv_atsc30_priv_get_fh_ctx(
		dmx2_filter,
		&ctx) != MDRV_ATSC30_RETURN_CODE_OK) {

		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	}

	ret = fh_dmxctx_set_filter_info(ctx, data, size);
	if (ret != 0) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"fh_dmxctx_set_filter_info is failed\n");

		return MDRV_ATSC30_RETURN_CODE_FAILURE;
	}

	return ret;
}

int mdrv_atsc30_priv_get_filter_info(
		struct dmx2_filter *dmx2_filter,
		void *data, u32 size)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	struct mtk_demux2_fh_ctx *ctx = NULL;

	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (mdrv_atsc30_priv_get_fh_ctx(
		dmx2_filter,
		&ctx) != MDRV_ATSC30_RETURN_CODE_OK) {

		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	}

	ret = fh_dmxctx_get_filter_info(ctx, data, size);
	if (ret != 0) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"fh_dmxctx_get_filter_info is failed\n");

		return MDRV_ATSC30_RETURN_CODE_FAILURE;
	}

	return ret;
}

int mdrv_atsc30_priv_get_stc_info(
		struct dmx2_filter *dmx2_filter,
		void *data)
{
	int ret = 0;
	struct mtk_demux2_fh_ctx *ctx = NULL;

	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return -EINVAL;
	if (mdrv_atsc30_priv_get_fh_ctx(
		dmx2_filter,
		&ctx) != MDRV_ATSC30_RETURN_CODE_OK) {

		return -EINVAL;
	}

	fh_dmxctx_get_stc_info(ctx, data);

	return ret;
}

bool mdrv_atsc30_priv_is_buffer_enough(
		struct dmx2_filter *dmx2_filter,
		u32 len)
{
	struct mtk_bc_ctx *bc_ctx = NULL;
	struct dvb_ringbuffer *buffer = NULL;

	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return false;

	if (mdrv_atsc30_priv_get_bc_ctx(
		dmx2_filter,
		&bc_ctx) != MDRV_ATSC30_RETURN_CODE_OK)
		return false;

	// TODO: dmx2_output
	// TODO: VB2
	buffer = &bc_ctx->d_ctx.buf.ring;

	if (dvb_ringbuffer_free(buffer) > len)
		return true;

	ATSC30_DRVIF_LOG_ENHANCED_DEBUG(
		"Buffer is not enough\n");

	return false;
}

static bool priv_is_metadata_buffer_enough_no_operation(
		struct dmx2_filter *dmx2_filter)
{
	return true;
}

bool mdrv_atsc30_priv_is_metadata_buffer_enough(
		struct dmx2_filter *dmx2_filter)
{
	struct mtk_bc_ctx *bc_ctx = NULL;

	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return false;

	if (mdrv_atsc30_priv_get_bc_ctx(
		dmx2_filter,
		&bc_ctx) != MDRV_ATSC30_RETURN_CODE_OK)
		return false;

	if (mtk_bc_metabuf_avail(bc_ctx) == 0)
		return true;

	ATSC30_DRVIF_LOG_ENHANCED_DEBUG(
		"Metadata buffer is not enough\n");

	return false;
}

#ifdef MDRV_ATSC30_INTERNAL_MUTEX_ENABLE
bool mdrv_atsc30_priv_wait_for_buffer_enough(
		mdrv_atsc30_cb_is_metadata_buffer_enough
			cb_is_metadata_buffer_enough,
		mdrv_atsc30_cb_is_buffer_enough
			cb_is_buffer_enough,
		struct dmx2_filter *dmx2_filter,
		u32 len)
{
	struct dmx2_feed *dmx2_feed = NULL;
	struct dvb_demux2 *dvb_demux2 = NULL;
	struct mtk_demux2 *mtk_demux2 = NULL;
	struct mtk_dmx_path *path = NULL;
	struct dmx2dev *dmx2dev = NULL;
	bool is_enough = false;

	if (ATSC30_DRVIF_VERIFY(cb_is_buffer_enough == NULL))
		return false;
	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return false;
	dmx2_feed = dmx2_filter->feed;
	if (ATSC30_DRVIF_VERIFY(dmx2_feed == NULL))
		return false;
	dvb_demux2 = dmx2_feed->parent;
	if (ATSC30_DRVIF_VERIFY(dvb_demux2 == NULL))
		return false;
	mtk_demux2 = cast_to_mtk_demux(dvb_demux2);
	path = dumex2_to_path(mtk_demux2);
	dmx2dev = &path->dmx2dev;

	if (cb_is_metadata_buffer_enough == NULL)
		cb_is_metadata_buffer_enough =
			priv_is_metadata_buffer_enough_no_operation;

	if (mutex_lock_interruptible(&dmx2dev->mutex)) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"mutex_lock_interruptible(&path->mutex) return fail\n");

		return false;
	}

	do {
		if (ATSC30_DRVIF_VERIFY(path->state != DMX_PATH_STATE_IDLE))
			break;

		do {
			if (cb_is_metadata_buffer_enough(dmx2_filter) &&
				cb_is_buffer_enough(dmx2_filter, len))
				path->state = DMX_PATH_STATE_IDLE;
			else
				path->state = DMX_PATH_STATE_BUSY;

			if (path->state == DMX_PATH_STATE_BUSY) {
				mutex_unlock(&dmx2dev->mutex);

				msleep_interruptible(
					MDRV_ATSC30_INTERNAL_BUF_WAIT_TIME);

				if (mutex_lock_interruptible(&dmx2dev->mutex)) {
					ATSC30_DRVIF_LOG_ENHANCED_ERROR(
						"mutex_lock_interruptible(&path->mutex) return fail\n");

					// Unlock a not locked mutex is not allowed.
					return false;
				}
			}
		} while (path->state == DMX_PATH_STATE_BUSY);
	} while (0);

	if (path->state == DMX_PATH_STATE_IDLE)
		is_enough = true;
	else
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"path(%d)->state is not idle\n",
			path->path_id);

	mutex_unlock(&dmx2dev->mutex);

	return is_enough;
}
#else
bool mdrv_atsc30_priv_wait_for_buffer_enough(
		mdrv_atsc30_cb_is_metadata_buffer_enough
			cb_is_metadata_buffer_enough,
		mdrv_atsc30_cb_is_buffer_enough
			cb_is_buffer_enough,
		struct dmx2_filter *dmx2_filter,
		u32 len)
{
	if (ATSC30_DRVIF_VERIFY(cb_is_buffer_enough == NULL))
		return false;
	if (ATSC30_DRVIF_VERIFY(dmx2_filter == NULL))
		return false;

	if (cb_is_metadata_buffer_enough == NULL)
		cb_is_metadata_buffer_enough =
			priv_is_metadata_buffer_enough_no_operation;

	if (cb_is_metadata_buffer_enough(dmx2_filter) &&
		cb_is_buffer_enough(dmx2_filter, len))
		return true;

	ATSC30_DRVIF_LOG_ENHANCED_INFO(
		"Packet w/ length 0x%x is dropped\n",
		len);

	return false;
}
#endif //#ifdef MDRV_ATSC30_INTERNAL_MUTEX_ENABLE

int mdrv_atsc30_priv_context_init(
		struct mdrv_atsc30_internal_context *context)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	struct list_head *head = NULL;

	if (ATSC30_DRVIF_VERIFY(context == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (ATSC30_DRVIF_VERIFY(context->framer_idx >= eATSC30_SUPPORT_FRAMER_NUM))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	if (context->inited) {
		ATSC30_DRVIF_LOG_ENHANCED_VERBOS(
			"context of %d is already initialized\n",
			context->framer_idx);
		context->ref_count++;

		return ret;
	}

	head = &context->head;
	INIT_LIST_HEAD(head);

	context->pkt_id_counter = 0;
	context->ref_count++;

	context->inited = true;

	return ret;
}

int mdrv_atsc30_priv_context_exit(
		struct mdrv_atsc30_internal_context *context)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	struct list_head *head = NULL;
	struct mdrv_atsc30_filter *pos = NULL;
	struct mdrv_atsc30_filter *npos = NULL;

	if (ATSC30_DRVIF_VERIFY(context == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (ATSC30_DRVIF_VERIFY(context->framer_idx >= eATSC30_SUPPORT_FRAMER_NUM))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	if (!context->inited) {
		ATSC30_DRVIF_LOG_ENHANCED_VERBOS(
			"context of %d is not initialized\n",
			context->framer_idx);

		return ret;
	}

	if (context->ref_count > 0)
		context->ref_count--;
	if (context->ref_count > 0) {
		ATSC30_DRVIF_LOG_ENHANCED_VERBOS(
			"ref_count of %d > 0\n",
			context->framer_idx);

		return ret;
	}

	head = &context->head;

	list_for_each_entry_safe(pos, npos, head, list) {
		list_del(&pos->list);
		vfree(pos);
	}

	context->inited = false;

	return ret;
}

int mdrv_atsc30_priv_filter_add(
		struct mdrv_atsc30_internal_context *context,
		struct dmx2_filter *demux_filter)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	struct list_head *head = NULL;
	struct mdrv_atsc30_filter *pos = NULL;
	struct mdrv_atsc30_filter *new_item = NULL;

	if (ATSC30_DRVIF_VERIFY(context == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (ATSC30_DRVIF_VERIFY(context->framer_idx >= eATSC30_SUPPORT_FRAMER_NUM))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	if (!context->inited) {
		ATSC30_DRVIF_LOG_ENHANCED_VERBOS(
			"context of %d is not initialized\n",
			context->framer_idx);

		return MDRV_ATSC30_RETURN_CODE_FAILURE;
	}

	head = &context->head;
	list_for_each_entry(pos, head, list)
		if (pos->demux_filter == demux_filter) {
			ATSC30_DRVIF_LOG_ENHANCED_INFO(
				"it is existed\n");

			return ret;
		}

	new_item = vzalloc(sizeof(struct mdrv_atsc30_filter));
	if (new_item == NULL) {
		ATSC30_DRVIF_LOG_ENHANCED_ERROR(
			"vzalloc(0x%zx) is failed\n",
			sizeof(struct mdrv_atsc30_filter));

		ret = MDRV_ATSC30_RETURN_CODE_RESOURCE;
	} else {
		new_item->demux_filter = demux_filter;
		list_add(&new_item->list, head);
	}

	return ret;
}

int mdrv_atsc30_priv_filter_del(
		struct mdrv_atsc30_internal_context *context,
		struct dmx2_filter *demux_filter)
{
	int ret = MDRV_ATSC30_RETURN_CODE_OK;
	struct list_head *head = NULL;
	struct mdrv_atsc30_filter *pos = NULL;
	struct mdrv_atsc30_filter *npos = NULL;

	if (ATSC30_DRVIF_VERIFY(context == NULL))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;
	if (ATSC30_DRVIF_VERIFY(context->framer_idx >= eATSC30_SUPPORT_FRAMER_NUM))
		return MDRV_ATSC30_RETURN_CODE_INVALID_PARAMETER;

	if (!context->inited) {
		ATSC30_DRVIF_LOG_ENHANCED_VERBOS(
			"context of %d is not initialized\n",
			context->framer_idx);

		return MDRV_ATSC30_RETURN_CODE_FAILURE;
	}

	head = &context->head;
	list_for_each_entry_safe(pos, npos, head, list)
		if (pos->demux_filter == demux_filter) {
			list_del(&pos->list);
			vfree(pos);
		}

	return ret;
}
