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