1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "mmal.h"
29#include "core/mmal_component_private.h"
30#include "core/mmal_port_private.h"
31#include "core/mmal_core_private.h"
32#include "mmal_logging.h"
33
34/* Minimum number of buffers that will be available on the control port */
35#define MMAL_CONTROL_PORT_BUFFERS_MIN 4
36
37/** Definition of the core private context. */
38typedef struct
39{
40 MMAL_COMPONENT_PRIVATE_T private;
41
42 /** Action registered by component and run when buffers are received by any of the ports */
43 void (*pf_action)(MMAL_COMPONENT_T *component);
44
45 /** Action thread */
46 VCOS_THREAD_T action_thread;
47 VCOS_EVENT_T action_event;
48 VCOS_MUTEX_T action_mutex;
49 MMAL_BOOL_T action_quit;
50
51 VCOS_MUTEX_T lock; /**< Used to lock access to the component */
52 MMAL_BOOL_T destruction_pending;
53
54} MMAL_COMPONENT_CORE_PRIVATE_T;
55
56/*****************************************************************************/
57static void mmal_core_init(void);
58static void mmal_core_deinit(void);
59
60static MMAL_STATUS_T mmal_component_supplier_create(const char *name, MMAL_COMPONENT_T *component);
61static void mmal_component_init_control_port(MMAL_PORT_T *port);
62
63static MMAL_STATUS_T mmal_component_destroy_internal(MMAL_COMPONENT_T *component);
64static MMAL_STATUS_T mmal_component_release_internal(MMAL_COMPONENT_T *component);
65
66/*****************************************************************************/
67static VCOS_MUTEX_T mmal_core_lock;
68/** Used to generate a unique id for each MMAL component in this context. */
69static unsigned int mmal_core_instance_count;
70static unsigned int mmal_core_refcount;
71/*****************************************************************************/
72
73/** Create an instance of a component */
74static MMAL_STATUS_T mmal_component_create_core(const char *name,
75 MMAL_STATUS_T (*constructor)(const char *name, MMAL_COMPONENT_T *),
76 struct MMAL_COMPONENT_MODULE_T *constructor_private,
77 MMAL_COMPONENT_T **component)
78{
79 MMAL_COMPONENT_CORE_PRIVATE_T *private;
80 MMAL_STATUS_T status = MMAL_ENOMEM;
81 unsigned int size = sizeof(MMAL_COMPONENT_T) + sizeof(MMAL_COMPONENT_CORE_PRIVATE_T);
82 unsigned int i, name_length = strlen(name) + 1;
83 unsigned int port_index;
84 char *component_name;
85
86 if(!component)
87 return MMAL_EINVAL;
88
89 mmal_core_init();
90
91 *component = vcos_calloc(1, size + name_length, "mmal component");
92 if(!*component)
93 return MMAL_ENOMEM;
94
95 private = (MMAL_COMPONENT_CORE_PRIVATE_T *)&(*component)[1];
96 (*component)->priv = (MMAL_COMPONENT_PRIVATE_T *)private;
97 (*component)->name = component_name= (char *)&((MMAL_COMPONENT_CORE_PRIVATE_T *)(*component)->priv)[1];
98 memcpy(component_name, name, name_length);
99 /* coverity[missing_lock] Component and mutex have just been created. No need to lock yet */
100 (*component)->priv->refcount = 1;
101 (*component)->priv->priority = VCOS_THREAD_PRI_NORMAL;
102
103 if(vcos_mutex_create(&private->lock, "mmal component lock") != VCOS_SUCCESS)
104 {
105 vcos_free(*component);
106 return MMAL_ENOMEM;
107 }
108
109 vcos_mutex_lock(&mmal_core_lock);
110 (*component)->id=mmal_core_instance_count++;
111 vcos_mutex_unlock(&mmal_core_lock);
112
113 /* Create the control port */
114 (*component)->control = mmal_port_alloc(*component, MMAL_PORT_TYPE_CONTROL, 0);
115 if(!(*component)->control)
116 goto error;
117 mmal_component_init_control_port((*component)->control);
118
119 /* Create the actual component */
120 (*component)->priv->module = constructor_private;
121 if (!constructor)
122 constructor = mmal_component_supplier_create;
123 status = constructor(name, *component);
124 if (status != MMAL_SUCCESS)
125 {
126 if (status == MMAL_ENOSYS)
127 LOG_ERROR("could not find component '%s'", name);
128 else
129 LOG_ERROR("could not create component '%s' (%i)", name, status);
130 goto error;
131 }
132
133 /* Make sure we have enough space for at least a MMAL_EVENT_FORMAT_CHANGED */
134 if ((*component)->control->buffer_size_min <
135 sizeof(MMAL_ES_FORMAT_T) + sizeof(MMAL_ES_SPECIFIC_FORMAT_T) + sizeof(MMAL_EVENT_FORMAT_CHANGED_T))
136 (*component)->control->buffer_size_min = sizeof(MMAL_ES_FORMAT_T) +
137 sizeof(MMAL_ES_SPECIFIC_FORMAT_T) + sizeof(MMAL_EVENT_FORMAT_CHANGED_T);
138 /* Make sure we have enough events */
139 if ((*component)->control->buffer_num_min < MMAL_CONTROL_PORT_BUFFERS_MIN)
140 (*component)->control->buffer_num_min = MMAL_CONTROL_PORT_BUFFERS_MIN;
141
142 /* Create the event pool */
143 (*component)->priv->event_pool = mmal_pool_create((*component)->control->buffer_num_min,
144 (*component)->control->buffer_size_min);
145 if (!(*component)->priv->event_pool)
146 {
147 status = MMAL_ENOMEM;
148 LOG_ERROR("could not create event pool (%d, %d)", (*component)->control->buffer_num_min,
149 (*component)->control->buffer_size_min);
150 goto error;
151 }
152
153 /* Build the list of all the ports */
154 (*component)->port_num = (*component)->input_num + (*component)->output_num + (*component)->clock_num + 1;
155 (*component)->port = vcos_malloc((*component)->port_num * sizeof(MMAL_PORT_T *), "mmal ports");
156 if (!(*component)->port)
157 {
158 status = MMAL_ENOMEM;
159 LOG_ERROR("could not create list of ports");
160 goto error;
161 }
162 port_index = 0;
163 (*component)->port[port_index++] = (*component)->control;
164 for (i = 0; i < (*component)->input_num; i++)
165 (*component)->port[port_index++] = (*component)->input[i];
166 for (i = 0; i < (*component)->output_num; i++)
167 (*component)->port[port_index++] = (*component)->output[i];
168 for (i = 0; i < (*component)->clock_num; i++)
169 (*component)->port[port_index++] = (*component)->clock[i];
170 for (i = 0; i < (*component)->port_num; i++)
171 (*component)->port[i]->index_all = i;
172
173 LOG_INFO("created '%s' %d %p", name, (*component)->id, *component);
174
175 /* Make sure the port types, indexes and buffer sizes are set correctly */
176 (*component)->control->type = MMAL_PORT_TYPE_CONTROL;
177 (*component)->control->index = 0;
178 for (i = 0; i < (*component)->input_num; i++)
179 {
180 MMAL_PORT_T *port = (*component)->input[i];
181 port->type = MMAL_PORT_TYPE_INPUT;
182 port->index = i;
183 }
184 for (i = 0; i < (*component)->output_num; i++)
185 {
186 MMAL_PORT_T *port = (*component)->output[i];
187 port->type = MMAL_PORT_TYPE_OUTPUT;
188 port->index = i;
189 }
190 for (i = 0; i < (*component)->clock_num; i++)
191 {
192 MMAL_PORT_T *port = (*component)->clock[i];
193 port->type = MMAL_PORT_TYPE_CLOCK;
194 port->index = i;
195 }
196 for (i = 0; i < (*component)->port_num; i++)
197 {
198 MMAL_PORT_T *port = (*component)->port[i];
199 if (port->buffer_size < port->buffer_size_min)
200 port->buffer_size = port->buffer_size_min;
201 if (port->buffer_num < port->buffer_num_min)
202 port->buffer_num = port->buffer_num_min;
203 }
204
205 return MMAL_SUCCESS;
206
207 error:
208 mmal_component_destroy_internal(*component);
209 *component = 0;
210 return status;
211}
212
213/** Create an instance of a component */
214MMAL_STATUS_T mmal_component_create(const char *name,
215 MMAL_COMPONENT_T **component)
216{
217 LOG_TRACE("%s", name);
218 return mmal_component_create_core(name, 0, 0, component);
219}
220
221/** Create an instance of a component */
222MMAL_STATUS_T mmal_component_create_with_constructor(const char *name,
223 MMAL_STATUS_T (*constructor)(const char *name, MMAL_COMPONENT_T *),
224 struct MMAL_COMPONENT_MODULE_T *constructor_private,
225 MMAL_COMPONENT_T **component)
226{
227 LOG_TRACE("%s", name);
228 return mmal_component_create_core(name, constructor, constructor_private, component);
229}
230
231/** Destroy a previously created component */
232static MMAL_STATUS_T mmal_component_destroy_internal(MMAL_COMPONENT_T *component)
233{
234 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
235 MMAL_STATUS_T status;
236
237 LOG_TRACE("%s %d", component->name, component->id);
238
239 mmal_component_action_deregister(component);
240
241 /* Should pf_destroy be allowed to fail ?
242 * If so, what do we do if it fails ?
243 */
244 if (component->priv->pf_destroy)
245 {
246 status = component->priv->pf_destroy(component);
247 if(!vcos_verify(status == MMAL_SUCCESS))
248 return status;
249 }
250
251 if (component->priv->event_pool)
252 mmal_pool_destroy(component->priv->event_pool);
253
254 if (component->control)
255 mmal_port_free(component->control);
256
257 if (component->port)
258 vcos_free(component->port);
259
260 vcos_mutex_delete(&private->lock);
261 vcos_free(component);
262 mmal_core_deinit();
263 return MMAL_SUCCESS;
264}
265
266/** Release a reference to a component */
267static MMAL_STATUS_T mmal_component_release_internal(MMAL_COMPONENT_T *component)
268{
269 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
270 unsigned int i;
271
272 if (!vcos_verify(component->priv->refcount > 0))
273 return MMAL_EINVAL;
274
275 vcos_mutex_lock(&private->lock);
276 if (--component->priv->refcount)
277 {
278 vcos_mutex_unlock(&private->lock);
279 return MMAL_SUCCESS;
280 }
281 private->destruction_pending = 1;
282 vcos_mutex_unlock(&private->lock);
283
284 LOG_TRACE("%s %d preparing for destruction", component->name, component->id);
285
286 /* Make sure the ports are all disabled */
287 for(i = 0; i < component->input_num; i++)
288 if(component->input[i]->is_enabled)
289 mmal_port_disable(component->input[i]);
290 for(i = 0; i < component->output_num; i++)
291 if(component->output[i]->is_enabled)
292 mmal_port_disable(component->output[i]);
293 for(i = 0; i < component->clock_num; i++)
294 if(component->clock[i]->is_enabled)
295 mmal_port_disable(component->clock[i]);
296 if(component->control->is_enabled)
297 mmal_port_disable(component->control);
298
299 /* Make sure all the ports are disconnected. This is necessary to prevent
300 * connected ports from referencing destroyed components */
301 for(i = 0; i < component->input_num; i++)
302 mmal_port_disconnect(component->input[i]);
303 for(i = 0; i < component->output_num; i++)
304 mmal_port_disconnect(component->output[i]);
305 for(i = 0; i < component->clock_num; i++)
306 mmal_port_disconnect(component->clock[i]);
307
308 /* If there is any reference pending on the ports we will delay the actual destruction */
309 vcos_mutex_lock(&private->lock);
310 if (component->priv->refcount_ports)
311 {
312 private->destruction_pending = 0;
313 vcos_mutex_unlock(&private->lock);
314 LOG_TRACE("%s %d delaying destruction", component->name, component->id);
315 return MMAL_SUCCESS;
316 }
317 vcos_mutex_unlock(&private->lock);
318
319 return mmal_component_destroy_internal(component);
320}
321
322/** Destroy a component */
323MMAL_STATUS_T mmal_component_destroy(MMAL_COMPONENT_T *component)
324{
325 if(!component)
326 return MMAL_EINVAL;
327
328 LOG_TRACE("%s %d", component->name, component->id);
329
330 return mmal_component_release_internal(component);
331}
332
333/** Acquire a reference to a component */
334void mmal_component_acquire(MMAL_COMPONENT_T *component)
335{
336 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
337
338 LOG_TRACE("component %s(%d), refcount %i", component->name, component->id,
339 component->priv->refcount);
340
341 vcos_mutex_lock(&private->lock);
342 component->priv->refcount++;
343 vcos_mutex_unlock(&private->lock);
344}
345
346/** Release a reference to a component */
347MMAL_STATUS_T mmal_component_release(MMAL_COMPONENT_T *component)
348{
349 if(!component)
350 return MMAL_EINVAL;
351
352 LOG_TRACE("component %s(%d), refcount %i", component->name, component->id,
353 component->priv->refcount);
354
355 return mmal_component_release_internal(component);
356}
357
358/** Enable processing on a component */
359MMAL_STATUS_T mmal_component_enable(MMAL_COMPONENT_T *component)
360{
361 MMAL_COMPONENT_CORE_PRIVATE_T *private;
362 MMAL_STATUS_T status = MMAL_ENOSYS;
363 unsigned int i;
364
365 if(!component)
366 return MMAL_EINVAL;
367
368 private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
369
370 LOG_TRACE("%s %d", component->name, component->id);
371
372 vcos_mutex_lock(&private->lock);
373
374 /* Check we have anything to do */
375 if (component->is_enabled)
376 {
377 vcos_mutex_unlock(&private->lock);
378 return MMAL_SUCCESS;
379 }
380
381 if (component->priv->pf_enable)
382 status = component->priv->pf_enable(component);
383
384 /* If the component does not support enable/disable, we handle that
385 * in the core itself */
386 if (status == MMAL_ENOSYS)
387 {
388 status = MMAL_SUCCESS;
389
390 /* Resume all input / output ports */
391 for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
392 status = mmal_port_pause(component->input[i], MMAL_FALSE);
393 for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
394 status = mmal_port_pause(component->output[i], MMAL_FALSE);
395 }
396
397 if (status == MMAL_SUCCESS)
398 component->is_enabled = 1;
399
400 vcos_mutex_unlock(&private->lock);
401
402 return status;
403}
404
405/** Disable processing on a component */
406MMAL_STATUS_T mmal_component_disable(MMAL_COMPONENT_T *component)
407{
408 MMAL_COMPONENT_CORE_PRIVATE_T *private;
409 MMAL_STATUS_T status = MMAL_ENOSYS;
410 unsigned int i;
411
412 if (!component)
413 return MMAL_EINVAL;
414
415 private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
416
417 LOG_TRACE("%s %d", component->name, component->id);
418
419 vcos_mutex_lock(&private->lock);
420
421 /* Check we have anything to do */
422 if (!component->is_enabled)
423 {
424 vcos_mutex_unlock(&private->lock);
425 return MMAL_SUCCESS;
426 }
427
428 if (component->priv->pf_disable)
429 status = component->priv->pf_disable(component);
430
431 /* If the component does not support enable/disable, we handle that
432 * in the core itself */
433 if (status == MMAL_ENOSYS)
434 {
435 status = MMAL_SUCCESS;
436
437 /* Pause all input / output ports */
438 for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
439 status = mmal_port_pause(component->input[i], MMAL_TRUE);
440 for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
441 status = mmal_port_pause(component->output[i], MMAL_TRUE);
442 }
443
444 if (status == MMAL_SUCCESS)
445 component->is_enabled = 0;
446
447 vcos_mutex_unlock(&private->lock);
448
449 return status;
450}
451
452static MMAL_STATUS_T mmal_component_enable_control_port(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
453{
454 (void)port;
455 (void)cb;
456 return MMAL_SUCCESS;
457}
458
459static MMAL_STATUS_T mmal_component_disable_control_port(MMAL_PORT_T *port)
460{
461 (void)port;
462 return MMAL_SUCCESS;
463}
464
465MMAL_STATUS_T mmal_component_parameter_set(MMAL_PORT_T *control_port,
466 const MMAL_PARAMETER_HEADER_T *param)
467{
468 (void)control_port;
469 (void)param;
470 /* No generic component control parameters */
471 LOG_ERROR("parameter id 0x%08x not supported", param->id);
472 return MMAL_ENOSYS;
473}
474
475MMAL_STATUS_T mmal_component_parameter_get(MMAL_PORT_T *control_port,
476 MMAL_PARAMETER_HEADER_T *param)
477{
478 (void)control_port;
479 (void)param;
480 /* No generic component control parameters */
481 LOG_ERROR("parameter id 0x%08x not supported", param->id);
482 return MMAL_ENOSYS;
483}
484
485static void mmal_component_init_control_port(MMAL_PORT_T *port)
486{
487 port->format->type = MMAL_ES_TYPE_CONTROL;
488 port->buffer_num_min = MMAL_CONTROL_PORT_BUFFERS_MIN;
489 port->buffer_num = port->buffer_num_min;
490 port->buffer_size_min = sizeof(MMAL_ES_FORMAT_T) + sizeof(MMAL_ES_SPECIFIC_FORMAT_T);
491 port->buffer_size = port->buffer_size_min;
492
493 /* Default to generic handling */
494 port->priv->pf_enable = mmal_component_enable_control_port;
495 port->priv->pf_disable = mmal_component_disable_control_port;
496 port->priv->pf_parameter_set = mmal_component_parameter_set;
497 port->priv->pf_parameter_get = mmal_component_parameter_get;
498 /* No pf_set_format - format of control port cannot be changed */
499 /* No pf_send - buffers cannot be sent to control port */
500}
501
502/** Acquire a reference on a port */
503void mmal_port_acquire(MMAL_PORT_T *port)
504{
505 MMAL_COMPONENT_T *component = port->component;
506 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
507
508 LOG_TRACE("port %s(%p), refcount %i", port->name, port,
509 component->priv->refcount_ports);
510
511 vcos_mutex_lock(&private->lock);
512 component->priv->refcount_ports++;
513 vcos_mutex_unlock(&private->lock);
514}
515
516/** Release a reference on a port */
517MMAL_STATUS_T mmal_port_release(MMAL_PORT_T *port)
518{
519 MMAL_COMPONENT_T *component = port->component;
520 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
521
522 LOG_TRACE("port %s(%p), refcount %i", port->name, port,
523 component->priv->refcount_ports);
524
525 /* Sanity check the refcount */
526 if (!vcos_verify(component->priv->refcount_ports > 0))
527 return MMAL_EINVAL;
528
529 vcos_mutex_lock(&private->lock);
530 if (--component->priv->refcount_ports ||
531 component->priv->refcount || private->destruction_pending)
532 {
533 vcos_mutex_unlock(&private->lock);
534 return MMAL_SUCCESS;
535 }
536 vcos_mutex_unlock(&private->lock);
537
538 return mmal_component_destroy_internal(component);
539}
540
541/*****************************************************************************
542 * Actions support
543 *****************************************************************************/
544
545/** Registers an action with the core */
546static void *mmal_component_action_thread_func(void *arg)
547{
548 MMAL_COMPONENT_T *component = (MMAL_COMPONENT_T *)arg;
549 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
550 VCOS_STATUS_T status;
551
552 while (1)
553 {
554 status = vcos_event_wait(&private->action_event);
555
556 if (status == VCOS_EAGAIN)
557 continue;
558 if (private->action_quit)
559 break;
560 if (!vcos_verify(status == VCOS_SUCCESS))
561 break;
562
563 vcos_mutex_lock(&private->action_mutex);
564 private->pf_action(component);
565 vcos_mutex_unlock(&private->action_mutex);
566 }
567 return 0;
568}
569
570/** Registers an action with the core */
571MMAL_STATUS_T mmal_component_action_register(MMAL_COMPONENT_T *component,
572 void (*pf_action)(MMAL_COMPONENT_T *) )
573{
574 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
575 VCOS_THREAD_ATTR_T attrs;
576 VCOS_STATUS_T status;
577
578 if (private->pf_action)
579 return MMAL_EINVAL;
580
581 status = vcos_event_create(&private->action_event, component->name);
582 if (status != VCOS_SUCCESS)
583 return MMAL_ENOMEM;
584
585 status = vcos_mutex_create(&private->action_mutex, component->name);
586 if (status != VCOS_SUCCESS)
587 {
588 vcos_event_delete(&private->action_event);
589 return MMAL_ENOMEM;
590 }
591
592 vcos_thread_attr_init(&attrs);
593 vcos_thread_attr_setpriority(&attrs,
594 private->private.priority);
595 status = vcos_thread_create(&private->action_thread, component->name, &attrs,
596 mmal_component_action_thread_func, component);
597 if (status != VCOS_SUCCESS)
598 {
599 vcos_mutex_delete(&private->action_mutex);
600 vcos_event_delete(&private->action_event);
601 return MMAL_ENOMEM;
602 }
603
604 private->pf_action = pf_action;
605 return MMAL_SUCCESS;
606}
607
608/** De-registers the current action with the core */
609MMAL_STATUS_T mmal_component_action_deregister(MMAL_COMPONENT_T *component)
610{
611 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
612
613 if (!private->pf_action)
614 return MMAL_EINVAL;
615
616 private->action_quit = 1;
617 vcos_event_signal(&private->action_event);
618 vcos_thread_join(&private->action_thread, NULL);
619 vcos_event_delete(&private->action_event);
620 vcos_mutex_delete(&private->action_mutex);
621 private->pf_action = NULL;
622 private->action_quit = 0;
623 return MMAL_SUCCESS;
624}
625
626/** Triggers a registered action */
627MMAL_STATUS_T mmal_component_action_trigger(MMAL_COMPONENT_T *component)
628{
629 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
630
631 if (!private->pf_action)
632 return MMAL_EINVAL;
633
634 vcos_event_signal(&private->action_event);
635 return MMAL_SUCCESS;
636}
637
638/** Lock an action to prevent it from running */
639MMAL_STATUS_T mmal_component_action_lock(MMAL_COMPONENT_T *component)
640{
641 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
642
643 if (!private->pf_action)
644 return MMAL_EINVAL;
645
646 vcos_mutex_lock(&private->action_mutex);
647 return MMAL_SUCCESS;
648}
649
650/** Unlock an action to allow it to run again */
651MMAL_STATUS_T mmal_component_action_unlock(MMAL_COMPONENT_T *component)
652{
653 MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
654
655 if (!private->pf_action)
656 return MMAL_EINVAL;
657
658 vcos_mutex_unlock(&private->action_mutex);
659 return MMAL_SUCCESS;
660}
661
662/*****************************************************************************
663 * Initialisation / Deinitialisation of the MMAL core
664 *****************************************************************************/
665static void mmal_core_init_once(void)
666{
667 vcos_mutex_create(&mmal_core_lock, VCOS_FUNCTION);
668}
669
670static void mmal_core_init(void)
671{
672 static VCOS_ONCE_T once = VCOS_ONCE_INIT;
673 vcos_init();
674 vcos_once(&once, mmal_core_init_once);
675
676 vcos_mutex_lock(&mmal_core_lock);
677 if (mmal_core_refcount++)
678 {
679 vcos_mutex_unlock(&mmal_core_lock);
680 return;
681 }
682
683 mmal_logging_init();
684 vcos_mutex_unlock(&mmal_core_lock);
685}
686
687static void mmal_core_deinit(void)
688{
689 vcos_mutex_lock(&mmal_core_lock);
690 if (!mmal_core_refcount || --mmal_core_refcount)
691 {
692 vcos_mutex_unlock(&mmal_core_lock);
693 return;
694 }
695
696 mmal_logging_deinit();
697 vcos_mutex_unlock(&mmal_core_lock);
698 vcos_deinit();
699}
700
701/*****************************************************************************
702 * Supplier support
703 *****************************************************************************/
704
705/** a component supplier gets passed a string and returns a
706 * component (if it can) based on that string.
707 */
708
709#define SUPPLIER_PREFIX_LEN 32
710typedef struct MMAL_COMPONENT_SUPPLIER_T
711{
712 struct MMAL_COMPONENT_SUPPLIER_T *next;
713 MMAL_COMPONENT_SUPPLIER_FUNCTION_T create;
714 char prefix[SUPPLIER_PREFIX_LEN];
715} MMAL_COMPONENT_SUPPLIER_T;
716
717/** List of component suppliers.
718 *
719 * Does not need to be thread-safe if we assume that suppliers
720 * can never be removed.
721 */
722static MMAL_COMPONENT_SUPPLIER_T *suppliers;
723
724/** Create an instance of a component */
725static MMAL_STATUS_T mmal_component_supplier_create(const char *name, MMAL_COMPONENT_T *component)
726{
727 MMAL_COMPONENT_SUPPLIER_T *supplier = suppliers;
728 MMAL_STATUS_T status = MMAL_ENOSYS;
729 const char *dot = strchr(name, '.');
730 size_t dot_size = dot ? dot - name : (int)strlen(name);
731
732 /* walk list of suppliers to see if any can create this component */
733 while (supplier)
734 {
735 if (strlen(supplier->prefix) == dot_size && !memcmp(supplier->prefix, name, dot_size))
736 {
737 status = supplier->create(name, component);
738 if (status == MMAL_SUCCESS)
739 break;
740 }
741 supplier = supplier->next;
742 }
743 return status;
744}
745
746void mmal_component_supplier_register(const char *prefix,
747 MMAL_COMPONENT_SUPPLIER_FUNCTION_T create_fn)
748{
749 MMAL_COMPONENT_SUPPLIER_T *supplier = vcos_calloc(1,sizeof(*supplier),NULL);
750
751 LOG_TRACE("prefix %s fn %p", (prefix ? prefix : "NULL"), create_fn);
752
753 if (vcos_verify(supplier))
754 {
755 supplier->create = create_fn;
756 strncpy(supplier->prefix, prefix, SUPPLIER_PREFIX_LEN);
757 supplier->prefix[SUPPLIER_PREFIX_LEN-1] = '\0';
758
759 supplier->next = suppliers;
760 suppliers = supplier;
761 }
762 else
763 {
764 LOG_ERROR("no memory for supplier registry entry");
765 }
766}
767
768MMAL_DESTRUCTOR(mmal_component_supplier_destructor);
769void mmal_component_supplier_destructor(void)
770{
771 MMAL_COMPONENT_SUPPLIER_T *supplier = suppliers;
772
773 /* walk list of suppliers and free associated memory */
774 while (supplier)
775 {
776 MMAL_COMPONENT_SUPPLIER_T *current = supplier;
777 supplier = supplier->next;
778 vcos_free(current);
779 }
780}
781