1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | #include "interface/mmal/mmal_logging.h" |
28 | #include "interface/mmal/mmal.h" |
29 | #include "interface/vcos/vcos.h" |
30 | |
31 | #include "interface/mmal/vc/mmal_vc_shm.h" |
32 | |
33 | #ifdef ENABLE_MMAL_VCSM |
34 | # include "user-vcsm.h" |
35 | #endif /* ENABLE_MMAL_VCSM */ |
36 | |
37 | #define MMAL_VC_PAYLOAD_ELEM_MAX 512 |
38 | |
39 | typedef struct MMAL_VC_PAYLOAD_ELEM_T |
40 | { |
41 | struct MMAL_VC_PAYLOAD_ELEM_T *next; |
42 | void *handle; |
43 | void *vc_handle; |
44 | uint8_t *mem; |
45 | MMAL_BOOL_T in_use; |
46 | } MMAL_VC_PAYLOAD_ELEM_T; |
47 | |
48 | typedef struct MMAL_VC_PAYLOAD_LIST_T |
49 | { |
50 | MMAL_VC_PAYLOAD_ELEM_T list[MMAL_VC_PAYLOAD_ELEM_MAX]; |
51 | VCOS_MUTEX_T lock; |
52 | } MMAL_VC_PAYLOAD_LIST_T; |
53 | |
54 | static int mmal_vc_shm_initialised; |
55 | static MMAL_VC_PAYLOAD_LIST_T mmal_vc_payload_list; |
56 | static VCOS_ONCE_T once = VCOS_ONCE_INIT; |
57 | static VCOS_MUTEX_T refcount_lock; |
58 | |
59 | static void mmal_vc_shm_init_once(void) |
60 | { |
61 | vcos_mutex_create(&refcount_lock, VCOS_FUNCTION); |
62 | } |
63 | |
64 | static void mmal_vc_payload_list_init() |
65 | { |
66 | vcos_mutex_create(&mmal_vc_payload_list.lock, "mmal_vc_payload_list" ); |
67 | } |
68 | |
69 | static void mmal_vc_payload_list_exit() |
70 | { |
71 | vcos_mutex_delete(&mmal_vc_payload_list.lock); |
72 | } |
73 | |
74 | static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_get() |
75 | { |
76 | MMAL_VC_PAYLOAD_ELEM_T *elem = 0; |
77 | unsigned int i; |
78 | |
79 | vcos_mutex_lock(&mmal_vc_payload_list.lock); |
80 | for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++) |
81 | { |
82 | if (mmal_vc_payload_list.list[i].in_use) |
83 | continue; |
84 | elem = &mmal_vc_payload_list.list[i]; |
85 | elem->in_use = 1; |
86 | break; |
87 | } |
88 | vcos_mutex_unlock(&mmal_vc_payload_list.lock); |
89 | |
90 | return elem; |
91 | } |
92 | |
93 | static void mmal_vc_payload_list_release(MMAL_VC_PAYLOAD_ELEM_T *elem) |
94 | { |
95 | vcos_mutex_lock(&mmal_vc_payload_list.lock); |
96 | elem->handle = elem->vc_handle = 0; |
97 | elem->mem = 0; |
98 | elem->in_use = 0; |
99 | vcos_mutex_unlock(&mmal_vc_payload_list.lock); |
100 | } |
101 | |
102 | static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_find_mem(uint8_t *mem) |
103 | { |
104 | MMAL_VC_PAYLOAD_ELEM_T *elem = 0; |
105 | unsigned int i; |
106 | |
107 | vcos_mutex_lock(&mmal_vc_payload_list.lock); |
108 | for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++) |
109 | { |
110 | if (!mmal_vc_payload_list.list[i].in_use) |
111 | continue; |
112 | if (mmal_vc_payload_list.list[i].mem != mem) |
113 | continue; |
114 | elem = &mmal_vc_payload_list.list[i]; |
115 | break; |
116 | } |
117 | vcos_mutex_unlock(&mmal_vc_payload_list.lock); |
118 | |
119 | return elem; |
120 | } |
121 | |
122 | static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_find_handle(uint8_t *mem) |
123 | { |
124 | MMAL_VC_PAYLOAD_ELEM_T *elem = 0; |
125 | unsigned int i; |
126 | |
127 | vcos_mutex_lock(&mmal_vc_payload_list.lock); |
128 | for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++) |
129 | { |
130 | if (!mmal_vc_payload_list.list[i].in_use) |
131 | continue; |
132 | if (mmal_vc_payload_list.list[i].vc_handle != (void *)mem) |
133 | continue; |
134 | elem = &mmal_vc_payload_list.list[i]; |
135 | break; |
136 | } |
137 | vcos_mutex_unlock(&mmal_vc_payload_list.lock); |
138 | |
139 | return elem; |
140 | } |
141 | |
142 | /** Initialise the shared memory system */ |
143 | MMAL_STATUS_T mmal_vc_shm_init(void) |
144 | { |
145 | MMAL_STATUS_T ret = MMAL_SUCCESS; |
146 | vcos_once(&once, mmal_vc_shm_init_once); |
147 | |
148 | vcos_mutex_lock(&refcount_lock); |
149 | mmal_vc_shm_initialised++; |
150 | if (mmal_vc_shm_initialised > 1) |
151 | goto unlock; |
152 | |
153 | #ifdef ENABLE_MMAL_VCSM |
154 | if (vcsm_init() != 0) |
155 | { |
156 | LOG_ERROR("could not initialize vc shared memory service" ); |
157 | ret = MMAL_EIO; |
158 | goto unlock; |
159 | } |
160 | #endif /* ENABLE_MMAL_VCSM */ |
161 | |
162 | mmal_vc_payload_list_init(); |
163 | unlock: |
164 | vcos_mutex_unlock(&refcount_lock); |
165 | return ret; |
166 | } |
167 | |
168 | void mmal_vc_shm_exit(void) |
169 | { |
170 | if (mmal_vc_shm_initialised <= 0) |
171 | goto unlock; |
172 | |
173 | mmal_vc_shm_initialised--; |
174 | if (mmal_vc_shm_initialised != 0) |
175 | goto unlock; |
176 | |
177 | #ifdef ENABLE_MMAL_VCSM |
178 | vcsm_exit(); |
179 | #endif |
180 | |
181 | mmal_vc_payload_list_exit(); |
182 | unlock: |
183 | vcos_mutex_unlock(&refcount_lock); |
184 | } |
185 | |
186 | /** Allocate a shared memory buffer */ |
187 | uint8_t *mmal_vc_shm_alloc(uint32_t size) |
188 | { |
189 | uint8_t *mem = NULL; |
190 | |
191 | MMAL_VC_PAYLOAD_ELEM_T *payload_elem = mmal_vc_payload_list_get(); |
192 | if (!payload_elem) |
193 | { |
194 | LOG_ERROR("could not get a free slot in the payload list" ); |
195 | return NULL; |
196 | } |
197 | |
198 | #ifdef ENABLE_MMAL_VCSM |
199 | unsigned int vcsm_handle = vcsm_malloc_cache(size, VCSM_CACHE_TYPE_HOST, "mmal_vc_port buffer" ); |
200 | unsigned int vc_handle = vcsm_vc_hdl_from_hdl(vcsm_handle); |
201 | mem = (uint8_t *)vcsm_lock( vcsm_handle ); |
202 | if (!mem || !vc_handle) |
203 | { |
204 | LOG_ERROR("could not allocate %i bytes of shared memory (handle %x) - mem %p, vc_hdl %08X" , |
205 | (int)size, vcsm_handle, mem, vc_handle); |
206 | if (mem) |
207 | vcsm_unlock_hdl(vcsm_handle); |
208 | if (vcsm_handle) |
209 | vcsm_free(vcsm_handle); |
210 | mmal_vc_payload_list_release(payload_elem); |
211 | return NULL; |
212 | } |
213 | |
214 | /* The memory area is automatically mem-locked by vcsm's fault |
215 | * handler when it is next used. So leave it unlocked until it |
216 | * is needed. |
217 | */ |
218 | vcsm_unlock_hdl(vcsm_handle); |
219 | |
220 | payload_elem->mem = mem; |
221 | payload_elem->handle = (void *)(intptr_t)vcsm_handle; |
222 | payload_elem->vc_handle = (void *)(intptr_t)vc_handle; |
223 | #else /* ENABLE_MMAL_VCSM */ |
224 | MMAL_PARAM_UNUSED(size); |
225 | mmal_vc_payload_list_release(payload_elem); |
226 | #endif /* ENABLE_MMAL_VCSM */ |
227 | |
228 | return mem; |
229 | } |
230 | |
231 | /** Free a shared memory buffer */ |
232 | MMAL_STATUS_T mmal_vc_shm_free(uint8_t *mem) |
233 | { |
234 | MMAL_VC_PAYLOAD_ELEM_T *payload_elem = mmal_vc_payload_list_find_mem(mem); |
235 | if (payload_elem) |
236 | { |
237 | #ifdef ENABLE_MMAL_VCSM |
238 | vcsm_free((uintptr_t)payload_elem->handle); |
239 | #endif /* ENABLE_MMAL_VCSM */ |
240 | mmal_vc_payload_list_release(payload_elem); |
241 | return MMAL_SUCCESS; |
242 | } |
243 | |
244 | return MMAL_EINVAL; |
245 | } |
246 | |
247 | /** Lock a shared memory buffer */ |
248 | uint8_t *mmal_vc_shm_lock(uint8_t *mem, uint32_t workaround) |
249 | { |
250 | /* Zero copy stuff */ |
251 | MMAL_VC_PAYLOAD_ELEM_T *elem = mmal_vc_payload_list_find_handle(mem); |
252 | MMAL_PARAM_UNUSED(workaround); |
253 | |
254 | if (elem) { |
255 | mem = elem->mem; |
256 | #ifdef ENABLE_MMAL_VCSM |
257 | void *p = vcsm_lock((uintptr_t)elem->handle); |
258 | if (!p) |
259 | assert(0); |
260 | #endif /* ENABLE_MMAL_VCSM */ |
261 | } |
262 | |
263 | return mem; |
264 | } |
265 | |
266 | /** Unlock a shared memory buffer */ |
267 | uint8_t *mmal_vc_shm_unlock(uint8_t *mem, uint32_t *length, uint32_t workaround) |
268 | { |
269 | /* Zero copy stuff */ |
270 | MMAL_VC_PAYLOAD_ELEM_T *elem = mmal_vc_payload_list_find_mem(mem); |
271 | MMAL_PARAM_UNUSED(workaround); |
272 | |
273 | if (elem) |
274 | { |
275 | *length = 0; |
276 | mem = (uint8_t *)elem->vc_handle; |
277 | #ifdef ENABLE_MMAL_VCSM |
278 | vcsm_unlock_ptr(elem->mem); |
279 | #endif /* ENABLE_MMAL_VCSM */ |
280 | } |
281 | |
282 | return mem; |
283 | } |
284 | |