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

#ifndef MTK_DEMUX_DEV_H
#define MTK_DEMUX_DEV_H

#include <media/dvbdev.h>
#include <media/dmx2dev.h>
#include <media/dvb_ctrls.h>

#include "mtk_dmx_drv.h"
#include "mtk_dmx_dvrdrv.h"

#define dmx2dev_to_path(dev)	\
	container_of(dev, struct mtk_dmx_path, dmx2dev)

#define dumex2_to_path(demux)	\
	container_of(demux, struct mtk_dmx_path, demux2)

#define dvr2_to_path(dvr)	\
	dvr->path

#define fh_to_path(fh) \
	({ \
		struct dmx2dev *dmx2dev = fh_to_dmx2dev(fh);	\
		dmx2dev_to_path(dmx2dev);	\
	})

enum dmx_path_state {
	DMX_PATH_STATE_IDLE,
	DMX_PATH_STATE_BUSY,
	DMX_PATH_STATE_PAUSE,
	DMX_PATH_STATE_MAX,
};

enum path_id_range {
	PATH_ID_RANGE_MIN = 0,

	PATH_ID_RANGE_START = PATH_ID_RANGE_MIN,
	PATH_ID_RANGE_END,

	PATH_ID_RANGE_MAX,
};

enum path_id_type {
	PATH_ID_TYPE_MIN = 0,

	PATH_ID_TYPE_M2TS = PATH_ID_TYPE_MIN,
	PATH_ID_TYPE_ISDB3,
	PATH_ID_TYPE_ATSC3,

	PATH_ID_TYPE_MAX,
};

static u8 * pad_list [] = {
	"ext_ts_demod_pad_mux",
	"ext_ts_para_demod_pad_mux",
	"ext1_ts_demod_pad_mux",
	"ext1_ts_para_demod_pad_mux",
	"ext2_ts_demod_pad_mux",
	"ext2_ts_para_demod_pad_mux",
	"ext3_ts_demod_pad_mux",
	"ext3_ts_para_demod_pad_mux",
};

static inline u8 *mtk_pad_hacking(u32 pad, bool parallel) {
	u8 *p = NULL;

	if (pad < 4)
		p = (pad_list[(pad * 2) + ((parallel) ? 1 : 0)]);
	return p;
}

struct mtk_hacking {
	// media controller
	bool on_streaming;
	u32 bits;
	u32 port_num;
	u8 *pad;
};

struct mtk_dmx_path {
	int path_id;
	enum dmx_path_state state;

	struct dmx2dev dmx2dev;
	struct mtk_demux2 demux2;
	struct mtk_dvr2 dvr_record;
	struct mtk_dvr2 dvr_playback;

	// media controller
	bool cicam;
	bool cifpga;
	struct dvb_frontend *fe_prev;
	struct task_struct *input_monitor_task;
};

struct mtk_dmx2dev {
	struct device *dev;
	struct dvb_adapter *adapter;
	struct mtk_dmx_rm rm;
	struct mtk_dmx_tm tm;
	struct mtk_dmx_pm pm;

	struct mtk_dmx_path *paths;

	// debug
	struct mtk_hacking hacking;
};

int mtk_dmx2dev_init(struct mtk_dmx2dev *dmxdev);
int mtk_dmx2dev_exit(struct mtk_dmx2dev *dmxdev);
int mtk_dmx2dev_suspend(bool suspend, struct mtk_dmx2dev *dmxdev);
int mtk_dmx2dev_notify(void);

// TODO: Refactor it to another module
int mtk_dvr2_fh_ctx_init(
		struct mtk_dvr2_fh_ctx *ctx,
		struct mtk_dvr2 *dvr,
		enum dvr_data_direction dir,
		u32 size);
// TODO: Refactor it to another module
int mtk_dvr2_fh_ctx_exit(struct mtk_dvr2_fh_ctx *ctx);

bool mtk_dmx_dev_path_id_in_range(
	enum path_id_type path_id_type,
	u16 path_id);
int mtk_dmx_dev_set_path_id_range(
	enum path_id_type path_id_type,
	u16 start, u16 end);
u16 mtk_dmx_dev_get_path_id_range(
	enum path_id_type path_id_type,
	enum path_id_range path_id_range);
u16 mtk_dmx_dev_get_predefined_path_id(u16 path_id);
u16 mtk_dmx_dev_get_path_id(u16 predefined_path_id);

struct mtk_dmx2dev *get_mtk_dmx2dev(void);

#endif /* MTK_DEMUX_DEV_H */
