1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
3 
4 #include "vchiq_connected.h"
5 #include "vchiq_core.h"
6 #include <linux/module.h>
7 #include <linux/mutex.h>
8 
9 #define  MAX_CALLBACKS  10
10 
11 static   int                        g_connected;
12 static   int                        g_num_deferred_callbacks;
13 static   void (*g_deferred_callback[MAX_CALLBACKS])(void);
14 static   int                        g_once_init;
15 static   DEFINE_MUTEX(g_connected_mutex);
16 
17 /* Function to initialize our lock */
connected_init(void)18 static void connected_init(void)
19 {
20 	if (!g_once_init)
21 		g_once_init = 1;
22 }
23 
24 /*
25  * This function is used to defer initialization until the vchiq stack is
26  * initialized. If the stack is already initialized, then the callback will
27  * be made immediately, otherwise it will be deferred until
28  * vchiq_call_connected_callbacks is called.
29  */
vchiq_add_connected_callback(void (* callback)(void))30 void vchiq_add_connected_callback(void (*callback)(void))
31 {
32 	connected_init();
33 
34 	if (mutex_lock_killable(&g_connected_mutex))
35 		return;
36 
37 	if (g_connected) {
38 		/* We're already connected. Call the callback immediately. */
39 		callback();
40 	} else {
41 		if (g_num_deferred_callbacks >= MAX_CALLBACKS) {
42 			vchiq_log_error(vchiq_core_log_level,
43 					"There already %d callback registered - please increase MAX_CALLBACKS",
44 					g_num_deferred_callbacks);
45 		} else {
46 			g_deferred_callback[g_num_deferred_callbacks] =
47 				callback;
48 			g_num_deferred_callbacks++;
49 		}
50 	}
51 	mutex_unlock(&g_connected_mutex);
52 }
53 EXPORT_SYMBOL(vchiq_add_connected_callback);
54 
55 /*
56  * This function is called by the vchiq stack once it has been connected to
57  * the videocore and clients can start to use the stack.
58  */
vchiq_call_connected_callbacks(void)59 void vchiq_call_connected_callbacks(void)
60 {
61 	int i;
62 
63 	connected_init();
64 
65 	if (mutex_lock_killable(&g_connected_mutex))
66 		return;
67 
68 	for (i = 0; i <  g_num_deferred_callbacks; i++)
69 		g_deferred_callback[i]();
70 
71 	g_num_deferred_callbacks = 0;
72 	g_connected = 1;
73 	mutex_unlock(&g_connected_mutex);
74 }
75