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