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;
13e4c1935eSOjaswin Mujoo static   void (*g_deferred_callback[MAX_CALLBACKS])(void);
1471bad7f0Spopcornmix static   int                        g_once_init;
151790f2beSZheng Yongjun static   DEFINE_MUTEX(g_connected_mutex);
1671bad7f0Spopcornmix 
17619f70f0SJohn Oldman /* Function to initialize our lock */
connected_init(void)1871bad7f0Spopcornmix static void connected_init(void)
1971bad7f0Spopcornmix {
205b3087efSGaston Gonzalez 	if (!g_once_init)
2171bad7f0Spopcornmix 		g_once_init = 1;
2271bad7f0Spopcornmix }
2371bad7f0Spopcornmix 
24619f70f0SJohn Oldman /*
2571bad7f0Spopcornmix  * This function is used to defer initialization until the vchiq stack is
2671bad7f0Spopcornmix  * initialized. If the stack is already initialized, then the callback will
2771bad7f0Spopcornmix  * be made immediately, otherwise it will be deferred until
2871bad7f0Spopcornmix  * vchiq_call_connected_callbacks is called.
29619f70f0SJohn Oldman  */
vchiq_add_connected_callback(void (* callback)(void))30e4c1935eSOjaswin Mujoo void vchiq_add_connected_callback(void (*callback)(void))
3171bad7f0Spopcornmix {
3271bad7f0Spopcornmix 	connected_init();
3371bad7f0Spopcornmix 
34023dbe17SNicolas Saenz Julienne 	if (mutex_lock_killable(&g_connected_mutex))
3571bad7f0Spopcornmix 		return;
3671bad7f0Spopcornmix 
37*34197588SGaston Gonzalez 	if (g_connected) {
3871bad7f0Spopcornmix 		/* We're already connected. Call the callback immediately. */
3971bad7f0Spopcornmix 		callback();
40*34197588SGaston Gonzalez 	} else {
41*34197588SGaston Gonzalez 		if (g_num_deferred_callbacks >= MAX_CALLBACKS) {
4271bad7f0Spopcornmix 			vchiq_log_error(vchiq_core_log_level,
43c2ec4a6eSAmarjargal Gundjalam 					"There already %d callback registered - please increase MAX_CALLBACKS",
4471bad7f0Spopcornmix 					g_num_deferred_callbacks);
45*34197588SGaston Gonzalez 		} else {
4671bad7f0Spopcornmix 			g_deferred_callback[g_num_deferred_callbacks] =
4771bad7f0Spopcornmix 				callback;
4871bad7f0Spopcornmix 			g_num_deferred_callbacks++;
4971bad7f0Spopcornmix 		}
5071bad7f0Spopcornmix 	}
5171bad7f0Spopcornmix 	mutex_unlock(&g_connected_mutex);
5271bad7f0Spopcornmix }
53826818f8SStefan Wahren EXPORT_SYMBOL(vchiq_add_connected_callback);
5471bad7f0Spopcornmix 
55619f70f0SJohn Oldman /*
5671bad7f0Spopcornmix  * This function is called by the vchiq stack once it has been connected to
5771bad7f0Spopcornmix  * the videocore and clients can start to use the stack.
58619f70f0SJohn Oldman  */
vchiq_call_connected_callbacks(void)5971bad7f0Spopcornmix void vchiq_call_connected_callbacks(void)
6071bad7f0Spopcornmix {
6171bad7f0Spopcornmix 	int i;
6271bad7f0Spopcornmix 
6371bad7f0Spopcornmix 	connected_init();
6471bad7f0Spopcornmix 
65023dbe17SNicolas Saenz Julienne 	if (mutex_lock_killable(&g_connected_mutex))
6671bad7f0Spopcornmix 		return;
6771bad7f0Spopcornmix 
6871bad7f0Spopcornmix 	for (i = 0; i <  g_num_deferred_callbacks; i++)
6971bad7f0Spopcornmix 		g_deferred_callback[i]();
7071bad7f0Spopcornmix 
7171bad7f0Spopcornmix 	g_num_deferred_callbacks = 0;
7271bad7f0Spopcornmix 	g_connected = 1;
7371bad7f0Spopcornmix 	mutex_unlock(&g_connected_mutex);
7471bad7f0Spopcornmix }
75