| // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ |
| |
| #include "vchiq_connected.h" |
| #include "vchiq_core.h" |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| |
| #define MAX_CALLBACKS 10 |
| |
| static int g_connected; |
| static int g_num_deferred_callbacks; |
| static void (*g_deferred_callback[MAX_CALLBACKS])(void); |
| static int g_once_init; |
| static DEFINE_MUTEX(g_connected_mutex); |
| |
| /* Function to initialize our lock */ |
| static void connected_init(void) |
| { |
| if (!g_once_init) |
| g_once_init = 1; |
| } |
| |
| /* |
| * This function is used to defer initialization until the vchiq stack is |
| * initialized. If the stack is already initialized, then the callback will |
| * be made immediately, otherwise it will be deferred until |
| * vchiq_call_connected_callbacks is called. |
| */ |
| void vchiq_add_connected_callback(void (*callback)(void)) |
| { |
| connected_init(); |
| |
| if (mutex_lock_killable(&g_connected_mutex)) |
| return; |
| |
| if (g_connected) { |
| /* We're already connected. Call the callback immediately. */ |
| callback(); |
| } else { |
| if (g_num_deferred_callbacks >= MAX_CALLBACKS) { |
| vchiq_log_error(vchiq_core_log_level, |
| "There already %d callback registered - please increase MAX_CALLBACKS", |
| g_num_deferred_callbacks); |
| } else { |
| g_deferred_callback[g_num_deferred_callbacks] = |
| callback; |
| g_num_deferred_callbacks++; |
| } |
| } |
| mutex_unlock(&g_connected_mutex); |
| } |
| EXPORT_SYMBOL(vchiq_add_connected_callback); |
| |
| /* |
| * This function is called by the vchiq stack once it has been connected to |
| * the videocore and clients can start to use the stack. |
| */ |
| void vchiq_call_connected_callbacks(void) |
| { |
| int i; |
| |
| connected_init(); |
| |
| if (mutex_lock_killable(&g_connected_mutex)) |
| return; |
| |
| for (i = 0; i < g_num_deferred_callbacks; i++) |
| g_deferred_callback[i](); |
| |
| g_num_deferred_callbacks = 0; |
| g_connected = 1; |
| mutex_unlock(&g_connected_mutex); |
| } |