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 */ |
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 | */ |
30 | void vchiq_add_connected_callback(struct vchiq_device *device, 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 | dev_err(&device->dev, |
43 | "core: There already %d callback registered - please increase MAX_CALLBACKS\n", |
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(lock: &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 | */ |
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(lock: &g_connected_mutex); |
74 | } |
75 |