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