1371ebdbeSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
23baad68aSGreg Kroah-Hartman /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
371bad7f0Spopcornmix 
471bad7f0Spopcornmix #include "vchiq_connected.h"
571bad7f0Spopcornmix #include "vchiq_core.h"
671bad7f0Spopcornmix #include <linux/module.h>
771bad7f0Spopcornmix #include <linux/mutex.h>
871bad7f0Spopcornmix 
971bad7f0Spopcornmix #define  MAX_CALLBACKS  10
1071bad7f0Spopcornmix 
1171bad7f0Spopcornmix static   int                        g_connected;
1271bad7f0Spopcornmix static   int                        g_num_deferred_callbacks;
1371bad7f0Spopcornmix static   VCHIQ_CONNECTED_CALLBACK_T g_deferred_callback[MAX_CALLBACKS];
1471bad7f0Spopcornmix static   int                        g_once_init;
1571bad7f0Spopcornmix static   struct mutex               g_connected_mutex;
1671bad7f0Spopcornmix 
17619f70f0SJohn Oldman /* Function to initialize our lock */
1871bad7f0Spopcornmix static void connected_init(void)
1971bad7f0Spopcornmix {
2071bad7f0Spopcornmix 	if (!g_once_init) {
2171bad7f0Spopcornmix 		mutex_init(&g_connected_mutex);
2271bad7f0Spopcornmix 		g_once_init = 1;
2371bad7f0Spopcornmix 	}
2471bad7f0Spopcornmix }
2571bad7f0Spopcornmix 
26619f70f0SJohn Oldman /*
2771bad7f0Spopcornmix  * This function is used to defer initialization until the vchiq stack is
2871bad7f0Spopcornmix  * initialized. If the stack is already initialized, then the callback will
2971bad7f0Spopcornmix  * be made immediately, otherwise it will be deferred until
3071bad7f0Spopcornmix  * vchiq_call_connected_callbacks is called.
31619f70f0SJohn Oldman  */
3271bad7f0Spopcornmix void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
3371bad7f0Spopcornmix {
3471bad7f0Spopcornmix 	connected_init();
3571bad7f0Spopcornmix 
36023dbe17SNicolas Saenz Julienne 	if (mutex_lock_killable(&g_connected_mutex))
3771bad7f0Spopcornmix 		return;
3871bad7f0Spopcornmix 
3971bad7f0Spopcornmix 	if (g_connected)
4071bad7f0Spopcornmix 		/* We're already connected. Call the callback immediately. */
4171bad7f0Spopcornmix 
4271bad7f0Spopcornmix 		callback();
4371bad7f0Spopcornmix 	else {
4471bad7f0Spopcornmix 		if (g_num_deferred_callbacks >= MAX_CALLBACKS)
4571bad7f0Spopcornmix 			vchiq_log_error(vchiq_core_log_level,
4671bad7f0Spopcornmix 				"There already %d callback registered - "
4771bad7f0Spopcornmix 				"please increase MAX_CALLBACKS",
4871bad7f0Spopcornmix 				g_num_deferred_callbacks);
4971bad7f0Spopcornmix 		else {
5071bad7f0Spopcornmix 			g_deferred_callback[g_num_deferred_callbacks] =
5171bad7f0Spopcornmix 				callback;
5271bad7f0Spopcornmix 			g_num_deferred_callbacks++;
5371bad7f0Spopcornmix 		}
5471bad7f0Spopcornmix 	}
5571bad7f0Spopcornmix 	mutex_unlock(&g_connected_mutex);
5671bad7f0Spopcornmix }
5771bad7f0Spopcornmix 
58619f70f0SJohn Oldman /*
5971bad7f0Spopcornmix  * This function is called by the vchiq stack once it has been connected to
6071bad7f0Spopcornmix  * the videocore and clients can start to use the stack.
61619f70f0SJohn Oldman  */
6271bad7f0Spopcornmix void vchiq_call_connected_callbacks(void)
6371bad7f0Spopcornmix {
6471bad7f0Spopcornmix 	int i;
6571bad7f0Spopcornmix 
6671bad7f0Spopcornmix 	connected_init();
6771bad7f0Spopcornmix 
68023dbe17SNicolas Saenz Julienne 	if (mutex_lock_killable(&g_connected_mutex))
6971bad7f0Spopcornmix 		return;
7071bad7f0Spopcornmix 
7171bad7f0Spopcornmix 	for (i = 0; i <  g_num_deferred_callbacks; i++)
7271bad7f0Spopcornmix 		g_deferred_callback[i]();
7371bad7f0Spopcornmix 
7471bad7f0Spopcornmix 	g_num_deferred_callbacks = 0;
7571bad7f0Spopcornmix 	g_connected = 1;
7671bad7f0Spopcornmix 	mutex_unlock(&g_connected_mutex);
7771bad7f0Spopcornmix }
7871bad7f0Spopcornmix EXPORT_SYMBOL(vchiq_add_connected_callback);
79