// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */

#include "vchiq_connected.h"
#include "vchiq_core.h"
#include <linux/module.h>
#include <linux/mutex.h>

#define  MAX_CALLBACKS  10

static   int                        g_connected;
static   int                        g_num_deferred_callbacks;
static   void (*g_deferred_callback[MAX_CALLBACKS])(void);
static   int                        g_once_init;
static   DEFINE_MUTEX(g_connected_mutex);

/* Function to initialize our lock */
static void connected_init(void)
{
	if (!g_once_init)
		g_once_init = 1;
}

/*
 * This function is used to defer initialization until the vchiq stack is
 * initialized. If the stack is already initialized, then the callback will
 * be made immediately, otherwise it will be deferred until
 * vchiq_call_connected_callbacks is called.
 */
void vchiq_add_connected_callback(void (*callback)(void))
{
	connected_init();

	if (mutex_lock_killable(&g_connected_mutex))
		return;

	if (g_connected) {
		/* We're already connected. Call the callback immediately. */
		callback();
	} else {
		if (g_num_deferred_callbacks >= MAX_CALLBACKS) {
			vchiq_log_error(vchiq_core_log_level,
					"There already %d callback registered - please increase MAX_CALLBACKS",
					g_num_deferred_callbacks);
		} else {
			g_deferred_callback[g_num_deferred_callbacks] =
				callback;
			g_num_deferred_callbacks++;
		}
	}
	mutex_unlock(&g_connected_mutex);
}
EXPORT_SYMBOL(vchiq_add_connected_callback);

/*
 * This function is called by the vchiq stack once it has been connected to
 * the videocore and clients can start to use the stack.
 */
void vchiq_call_connected_callbacks(void)
{
	int i;

	connected_init();

	if (mutex_lock_killable(&g_connected_mutex))
		return;

	for (i = 0; i <  g_num_deferred_callbacks; i++)
		g_deferred_callback[i]();

	g_num_deferred_callbacks = 0;
	g_connected = 1;
	mutex_unlock(&g_connected_mutex);
}