1371ebdbeSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
271bad7f0Spopcornmix /**
371bad7f0Spopcornmix  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
471bad7f0Spopcornmix  *
571bad7f0Spopcornmix  * Redistribution and use in source and binary forms, with or without
671bad7f0Spopcornmix  * modification, are permitted provided that the following conditions
771bad7f0Spopcornmix  * are met:
871bad7f0Spopcornmix  * 1. Redistributions of source code must retain the above copyright
971bad7f0Spopcornmix  *    notice, this list of conditions, and the following disclaimer,
1071bad7f0Spopcornmix  *    without modification.
1171bad7f0Spopcornmix  * 2. Redistributions in binary form must reproduce the above copyright
1271bad7f0Spopcornmix  *    notice, this list of conditions and the following disclaimer in the
1371bad7f0Spopcornmix  *    documentation and/or other materials provided with the distribution.
1471bad7f0Spopcornmix  * 3. The names of the above-listed copyright holders may not be used
1571bad7f0Spopcornmix  *    to endorse or promote products derived from this software without
1671bad7f0Spopcornmix  *    specific prior written permission.
1771bad7f0Spopcornmix  *
1871bad7f0Spopcornmix  * ALTERNATIVELY, this software may be distributed under the terms of the
1971bad7f0Spopcornmix  * GNU General Public License ("GPL") version 2, as published by the Free
2071bad7f0Spopcornmix  * Software Foundation.
2171bad7f0Spopcornmix  *
2271bad7f0Spopcornmix  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2371bad7f0Spopcornmix  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2471bad7f0Spopcornmix  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2571bad7f0Spopcornmix  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2671bad7f0Spopcornmix  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2771bad7f0Spopcornmix  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2871bad7f0Spopcornmix  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2971bad7f0Spopcornmix  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3071bad7f0Spopcornmix  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3171bad7f0Spopcornmix  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3271bad7f0Spopcornmix  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3371bad7f0Spopcornmix  */
3471bad7f0Spopcornmix 
3571bad7f0Spopcornmix #include "vchiq_connected.h"
3671bad7f0Spopcornmix #include "vchiq_core.h"
3771bad7f0Spopcornmix #include <linux/module.h>
3871bad7f0Spopcornmix #include <linux/mutex.h>
3971bad7f0Spopcornmix 
4071bad7f0Spopcornmix #define  MAX_CALLBACKS  10
4171bad7f0Spopcornmix 
4271bad7f0Spopcornmix static   int                        g_connected;
4371bad7f0Spopcornmix static   int                        g_num_deferred_callbacks;
4471bad7f0Spopcornmix static   VCHIQ_CONNECTED_CALLBACK_T g_deferred_callback[MAX_CALLBACKS];
4571bad7f0Spopcornmix static   int                        g_once_init;
4671bad7f0Spopcornmix static   struct mutex               g_connected_mutex;
4771bad7f0Spopcornmix 
4871bad7f0Spopcornmix /****************************************************************************
4971bad7f0Spopcornmix *
5071bad7f0Spopcornmix * Function to initialize our lock.
5171bad7f0Spopcornmix *
5271bad7f0Spopcornmix ***************************************************************************/
5371bad7f0Spopcornmix 
5471bad7f0Spopcornmix static void connected_init(void)
5571bad7f0Spopcornmix {
5671bad7f0Spopcornmix 	if (!g_once_init) {
5771bad7f0Spopcornmix 		mutex_init(&g_connected_mutex);
5871bad7f0Spopcornmix 		g_once_init = 1;
5971bad7f0Spopcornmix 	}
6071bad7f0Spopcornmix }
6171bad7f0Spopcornmix 
6271bad7f0Spopcornmix /****************************************************************************
6371bad7f0Spopcornmix *
6471bad7f0Spopcornmix * This function is used to defer initialization until the vchiq stack is
6571bad7f0Spopcornmix * initialized. If the stack is already initialized, then the callback will
6671bad7f0Spopcornmix * be made immediately, otherwise it will be deferred until
6771bad7f0Spopcornmix * vchiq_call_connected_callbacks is called.
6871bad7f0Spopcornmix *
6971bad7f0Spopcornmix ***************************************************************************/
7071bad7f0Spopcornmix 
7171bad7f0Spopcornmix void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
7271bad7f0Spopcornmix {
7371bad7f0Spopcornmix 	connected_init();
7471bad7f0Spopcornmix 
75b826d73bSArnd Bergmann 	if (mutex_lock_killable(&g_connected_mutex) != 0)
7671bad7f0Spopcornmix 		return;
7771bad7f0Spopcornmix 
7871bad7f0Spopcornmix 	if (g_connected)
7971bad7f0Spopcornmix 		/* We're already connected. Call the callback immediately. */
8071bad7f0Spopcornmix 
8171bad7f0Spopcornmix 		callback();
8271bad7f0Spopcornmix 	else {
8371bad7f0Spopcornmix 		if (g_num_deferred_callbacks >= MAX_CALLBACKS)
8471bad7f0Spopcornmix 			vchiq_log_error(vchiq_core_log_level,
8571bad7f0Spopcornmix 				"There already %d callback registered - "
8671bad7f0Spopcornmix 				"please increase MAX_CALLBACKS",
8771bad7f0Spopcornmix 				g_num_deferred_callbacks);
8871bad7f0Spopcornmix 		else {
8971bad7f0Spopcornmix 			g_deferred_callback[g_num_deferred_callbacks] =
9071bad7f0Spopcornmix 				callback;
9171bad7f0Spopcornmix 			g_num_deferred_callbacks++;
9271bad7f0Spopcornmix 		}
9371bad7f0Spopcornmix 	}
9471bad7f0Spopcornmix 	mutex_unlock(&g_connected_mutex);
9571bad7f0Spopcornmix }
9671bad7f0Spopcornmix 
9771bad7f0Spopcornmix /****************************************************************************
9871bad7f0Spopcornmix *
9971bad7f0Spopcornmix * This function is called by the vchiq stack once it has been connected to
10071bad7f0Spopcornmix * the videocore and clients can start to use the stack.
10171bad7f0Spopcornmix *
10271bad7f0Spopcornmix ***************************************************************************/
10371bad7f0Spopcornmix 
10471bad7f0Spopcornmix void vchiq_call_connected_callbacks(void)
10571bad7f0Spopcornmix {
10671bad7f0Spopcornmix 	int i;
10771bad7f0Spopcornmix 
10871bad7f0Spopcornmix 	connected_init();
10971bad7f0Spopcornmix 
110b826d73bSArnd Bergmann 	if (mutex_lock_killable(&g_connected_mutex) != 0)
11171bad7f0Spopcornmix 		return;
11271bad7f0Spopcornmix 
11371bad7f0Spopcornmix 	for (i = 0; i <  g_num_deferred_callbacks; i++)
11471bad7f0Spopcornmix 		g_deferred_callback[i]();
11571bad7f0Spopcornmix 
11671bad7f0Spopcornmix 	g_num_deferred_callbacks = 0;
11771bad7f0Spopcornmix 	g_connected = 1;
11871bad7f0Spopcornmix 	mutex_unlock(&g_connected_mutex);
11971bad7f0Spopcornmix }
12071bad7f0Spopcornmix EXPORT_SYMBOL(vchiq_add_connected_callback);
121