// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
 */

/* Standard Linux headers */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>

/* Amlogic headers */
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>

/* Local headers */
#include "vfm.h"

#define MAX_RECEIVER_NUM    64
struct vframe_receiver_s *receiver_table[MAX_RECEIVER_NUM];
static DEFINE_MUTEX(mutex);

int receiver_list(char *buf)
{
	struct vframe_receiver_s *r = NULL;
	int len = 0;
	int i = 0;

	len += sprintf(buf + len, "\nreceiver list:\n");
	for (i = 0; i < MAX_RECEIVER_NUM; i++) {
		r = receiver_table[i];
		if (r)
			len += sprintf(buf + len, "   %s\n", r->name);
	}

	return len;
}

/*
 * get vframe provider from the provider list by receiver name.
 *
 */
struct vframe_receiver_s *vf_get_receiver(const char *provider_name)
{
	struct vframe_receiver_s *r = NULL;
	char *receiver_name = NULL;
	int i;

	receiver_name = vf_get_receiver_name(provider_name);
	if (vfm_debug_flag & 2)
		pr_info("%s:receiver_name:%s\n", __func__, receiver_name);
	if (receiver_name) {
		for (i = 0; i < MAX_RECEIVER_NUM; i++) {
			r = receiver_table[i];
			if (r) {
				if (vfm_debug_flag & 2) {
					pr_info("%s: r: %s\n", __func__,
						r->name);
				}
				if (!strcmp(r->name, receiver_name))
					break;
			}
		}
		if (i == MAX_RECEIVER_NUM)
			r = NULL;
	}
	return r;
}
EXPORT_SYMBOL(vf_get_receiver);

struct vframe_receiver_s *vf_get_receiver_by_name(const char *receiver_name)
{
	struct vframe_receiver_s *r = NULL;
	int i = 0;

	if (receiver_name) {
		for (i = 0; i < MAX_RECEIVER_NUM; i++) {
			r = receiver_table[i];
			if (r) {
				if (vfm_debug_flag & 2) {
					pr_info("%s: r: %s\n", __func__,
						r->name);
				}
				if (!strcmp(r->name, receiver_name))
					break;
			}
		}
		if (i == MAX_RECEIVER_NUM)
			r = NULL;
	}
	return r;
}

int vf_notify_receiver(const char *provider_name, int event_type, void *data)
{
	int ret = -1;
	struct vframe_receiver_s *receiver = NULL;

	receiver = vf_get_receiver(provider_name);
	if (receiver) {
		if (receiver->ops && receiver->ops->event_cb) {
			ret = receiver->ops->event_cb(event_type, data,
				receiver->op_arg);
		}
	} else {
		pr_err("Error: %s, fail to get receiver of provider %s\n",
		       __func__, provider_name);
	}
	return ret;
}
EXPORT_SYMBOL(vf_notify_receiver);

int vf_notify_receiver_by_name(const char *receiver_name, int event_type,
			       void *data)
{
	int ret = -1;
	struct vframe_receiver_s *receiver = NULL;

	receiver = vf_get_receiver_by_name(receiver_name);
	if (receiver) {
		if (receiver->ops && receiver->ops->event_cb) {
			ret = receiver->ops->event_cb(event_type, data,
				receiver->op_arg);
		}
	}
	return ret;
}
EXPORT_SYMBOL(vf_notify_receiver_by_name);

void vf_receiver_init(struct vframe_receiver_s *recv,
		      const char *name,
		      const struct vframe_receiver_op_s *ops, void *op_arg)
{
	if (!recv)
		return;
	memset(recv, 0, sizeof(struct vframe_receiver_s));
	recv->name = name;
	recv->ops = ops;
	recv->op_arg = op_arg;
	INIT_LIST_HEAD(&recv->list);
}
EXPORT_SYMBOL(vf_receiver_init);

int vf_reg_receiver(struct vframe_receiver_s *recv)
{
	struct vframe_receiver_s *r;
	int i;

	if (!recv)
		return -1;
	mutex_lock(&mutex);
	for (i = 0; i < MAX_RECEIVER_NUM; i++) {
		r = receiver_table[i];
		if (r) {
			if (!strcmp(r->name, recv->name)) {
				mutex_unlock(&mutex);
				return -1;
			}
		}
	}
	for (i = 0; i < MAX_RECEIVER_NUM; i++) {
		if (!receiver_table[i]) {
			receiver_table[i] = recv;
			break;
		}
	}
	mutex_unlock(&mutex);
	return 0;
}
EXPORT_SYMBOL(vf_reg_receiver);

void vf_unreg_receiver(struct vframe_receiver_s *recv)
{
	struct vframe_receiver_s *r;
	int i;

	if (!recv)
		return;
	mutex_lock(&mutex);
	for (i = 0; i < MAX_RECEIVER_NUM; i++) {
		r = receiver_table[i];
		if (r) {
			if (!strcmp(r->name, recv->name)) {
				receiver_table[i] = NULL;
				break;
			}
		}
	}
	mutex_unlock(&mutex);
}
EXPORT_SYMBOL(vf_unreg_receiver);
