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_clock.h"
29#include "mmal_logging.h"
30#include "core/mmal_clock_private.h"
31#include "core/mmal_port_private.h"
32#include "util/mmal_util.h"
33
34#ifdef __VIDEOCORE__
35# include "vcfw/rtos/common/rtos_common_mem.h"
36#endif
37
38/** Minimum number of buffers required on a clock port */
39#define MMAL_PORT_CLOCK_BUFFERS_MIN 16
40
41/** Private clock port context */
42typedef struct MMAL_PORT_CLOCK_T
43{
44 MMAL_PORT_CLOCK_EVENT_CB event_cb; /**< callback for notifying the component of clock events */
45 MMAL_QUEUE_T *queue; /**< queue for empty buffers sent to the port */
46 MMAL_CLOCK_T *clock; /**< clock module for scheduling requests */
47 MMAL_BOOL_T is_reference; /**< TRUE -> clock port is a reference, therefore
48 will forward time updates */
49 MMAL_BOOL_T buffer_info_reporting; /**< controls buffer info reporting */
50} MMAL_PORT_CLOCK_T;
51
52/*****************************************************************************
53 * Private functions
54 *****************************************************************************/
55#ifdef __VIDEOCORE__
56/* FIXME: mmal_buffer_header_mem_lock() assumes that payload memory is on the
57 * relocatable heap when on VC. However that is not always the case. The MMAL
58 * framework will allocate memory from the normal heap when ports are connected.
59 * To work around this, override the default behaviour by providing a payload
60 * allocator for clock ports which always allocates from the relocatable heap. */
61static uint8_t* mmal_port_clock_payload_alloc(MMAL_PORT_T *port, uint32_t payload_size)
62{
63 int alignment = port->buffer_alignment_min;
64 uint8_t *mem;
65
66 if (!alignment)
67 alignment = 32;
68 vcos_assert((alignment & (alignment-1)) == 0);
69
70 mem = (uint8_t*)mem_alloc(payload_size, alignment, MEM_FLAG_DIRECT, port->name);
71 if (!mem)
72 {
73 LOG_ERROR("could not allocate %u bytes", payload_size);
74 return NULL;
75 }
76 return mem;
77}
78
79static void mmal_port_clock_payload_free(MMAL_PORT_T *port, uint8_t *payload)
80{
81 MMAL_PARAM_UNUSED(port);
82 mem_release((MEM_HANDLE_T)payload);
83}
84#endif
85
86
87/* Callback invoked by the clock module in response to a client request */
88static void mmal_port_clock_request_cb(MMAL_CLOCK_T* clock, int64_t media_time, void *cb_data, MMAL_CLOCK_VOID_FP cb)
89{
90 MMAL_PORT_CLOCK_REQUEST_CB cb_client = (MMAL_PORT_CLOCK_REQUEST_CB)cb;
91
92 /* Forward to the client */
93 cb_client((MMAL_PORT_T*)clock->user_data, media_time, cb_data);
94}
95
96/* Process buffers received from other clock ports */
97static MMAL_STATUS_T mmal_port_clock_process_buffer(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
98{
99 MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
100 MMAL_STATUS_T status = MMAL_SUCCESS;
101 MMAL_CLOCK_EVENT_T event = MMAL_CLOCK_EVENT_INIT(MMAL_CLOCK_EVENT_INVALID);
102
103 if (buffer->length != sizeof(MMAL_CLOCK_EVENT_T))
104 {
105 LOG_ERROR("invalid buffer length %d expected %zu",
106 buffer->length, sizeof(MMAL_CLOCK_EVENT_T));
107 return MMAL_EINVAL;
108 }
109
110 mmal_buffer_header_mem_lock(buffer);
111 memcpy(&event, buffer->data, sizeof(MMAL_CLOCK_EVENT_T));
112 mmal_buffer_header_mem_unlock(buffer);
113
114 if (event.magic != MMAL_CLOCK_EVENT_MAGIC)
115 {
116 LOG_ERROR("buffer corrupt (magic %4.4s)", (char*)&event.magic);
117 buffer->length = 0;
118 mmal_port_buffer_header_callback(port, buffer);
119 return MMAL_EINVAL;
120 }
121
122 LOG_TRACE("port %s id %4.4s", port->name, (char*)&event.id);
123
124 switch (event.id)
125 {
126 case MMAL_CLOCK_EVENT_ACTIVE:
127 status = mmal_clock_active_set(priv_clock->clock, event.data.enable);
128 break;
129 case MMAL_CLOCK_EVENT_TIME:
130 status = mmal_clock_media_time_set(priv_clock->clock, event.data.media_time);
131 break;
132 case MMAL_CLOCK_EVENT_SCALE:
133 status = mmal_clock_scale_set(priv_clock->clock, event.data.scale);
134 break;
135 case MMAL_CLOCK_EVENT_UPDATE_THRESHOLD:
136 status = mmal_clock_update_threshold_set(priv_clock->clock, &event.data.update_threshold);
137 break;
138 case MMAL_CLOCK_EVENT_DISCONT_THRESHOLD:
139 status = mmal_clock_discont_threshold_set(priv_clock->clock, &event.data.discont_threshold);
140 break;
141 case MMAL_CLOCK_EVENT_REQUEST_THRESHOLD:
142 status = mmal_clock_request_threshold_set(priv_clock->clock, &event.data.request_threshold);
143 break;
144 case MMAL_CLOCK_EVENT_INPUT_BUFFER_INFO:
145 case MMAL_CLOCK_EVENT_OUTPUT_BUFFER_INFO:
146 /* nothing to do - just forward to the client */
147 break;
148 default:
149 LOG_ERROR("invalid event %4.4s", (char*)&event.id);
150 status = MMAL_EINVAL;
151 break;
152 }
153
154 if (priv_clock->event_cb && status == MMAL_SUCCESS)
155 {
156 /* Notify the component, but don't return the buffer */
157 event.buffer = buffer;
158 priv_clock->event_cb(port, &event);
159 }
160 else
161 {
162 /* Finished with the buffer, so return it */
163 buffer->length = 0;
164 mmal_port_buffer_header_callback(port, buffer);
165 }
166
167 return status;
168}
169
170static MMAL_STATUS_T mmal_port_clock_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
171{
172 MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
173
174 if (buffer->length)
175 return mmal_port_clock_process_buffer(port, buffer);
176
177 /* Queue empty buffers to be used later when forwarding clock updates */
178 mmal_queue_put(priv_clock->queue, buffer);
179
180 return MMAL_SUCCESS;
181}
182
183static MMAL_STATUS_T mmal_port_clock_flush(MMAL_PORT_T *port)
184{
185 MMAL_BUFFER_HEADER_T *buffer;
186
187 /* Flush empty buffers */
188 buffer = mmal_queue_get(port->priv->clock->queue);
189 while (buffer)
190 {
191 mmal_port_buffer_header_callback(port, buffer);
192 buffer = mmal_queue_get(port->priv->clock->queue);
193 }
194
195 return MMAL_SUCCESS;
196}
197
198static MMAL_STATUS_T mmal_port_clock_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
199{
200 MMAL_STATUS_T status = MMAL_SUCCESS;
201 MMAL_CLOCK_EVENT_T event = MMAL_CLOCK_EVENT_INIT(MMAL_CLOCK_EVENT_INVALID);
202
203 switch (param->id)
204 {
205 case MMAL_PARAMETER_CLOCK_REFERENCE:
206 {
207 const MMAL_PARAMETER_BOOLEAN_T *p = (const MMAL_PARAMETER_BOOLEAN_T*)param;
208 status = mmal_port_clock_reference_set(port, p->enable);
209 event.id = MMAL_CLOCK_EVENT_REFERENCE;
210 event.data.enable = p->enable;
211 }
212 break;
213 case MMAL_PARAMETER_CLOCK_ACTIVE:
214 {
215 const MMAL_PARAMETER_BOOLEAN_T *p = (const MMAL_PARAMETER_BOOLEAN_T*)param;
216 status = mmal_port_clock_active_set(port, p->enable);
217 event.id = MMAL_CLOCK_EVENT_ACTIVE;
218 event.data.enable = p->enable;
219 }
220 break;
221 case MMAL_PARAMETER_CLOCK_SCALE:
222 {
223 const MMAL_PARAMETER_RATIONAL_T *p = (const MMAL_PARAMETER_RATIONAL_T*)param;
224 status = mmal_port_clock_scale_set(port, p->value);
225 event.id = MMAL_CLOCK_EVENT_SCALE;
226 event.data.scale = p->value;
227 }
228 break;
229 case MMAL_PARAMETER_CLOCK_TIME:
230 {
231 const MMAL_PARAMETER_INT64_T *p = (const MMAL_PARAMETER_INT64_T*)param;
232 status = mmal_port_clock_media_time_set(port, p->value);
233 event.id = MMAL_CLOCK_EVENT_TIME;
234 event.data.media_time = p->value;
235 }
236 break;
237 case MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD:
238 {
239 const MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *p = (const MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *)param;
240 status = mmal_port_clock_update_threshold_set(port, &p->value);
241 event.id = MMAL_CLOCK_EVENT_UPDATE_THRESHOLD;
242 event.data.update_threshold = p->value;
243 }
244 break;
245 case MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD:
246 {
247 const MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *p = (const MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *)param;
248 status = mmal_port_clock_discont_threshold_set(port, &p->value);
249 event.id = MMAL_CLOCK_EVENT_DISCONT_THRESHOLD;
250 event.data.discont_threshold = p->value;
251 }
252 break;
253 case MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD:
254 {
255 const MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *p = (const MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *)param;
256 status = mmal_port_clock_request_threshold_set(port, &p->value);
257 event.id = MMAL_CLOCK_EVENT_REQUEST_THRESHOLD;
258 event.data.request_threshold = p->value;
259 }
260 break;
261 case MMAL_PARAMETER_CLOCK_ENABLE_BUFFER_INFO:
262 {
263 const MMAL_PARAMETER_BOOLEAN_T *p = (const MMAL_PARAMETER_BOOLEAN_T*)param;
264 port->priv->clock->buffer_info_reporting = p->enable;
265 return MMAL_SUCCESS;
266 }
267 default:
268 LOG_ERROR("unsupported clock parameter 0x%x", param->id);
269 return MMAL_ENOSYS;
270 }
271
272 /* Notify the component */
273 if (port->priv->clock->event_cb && status == MMAL_SUCCESS)
274 port->priv->clock->event_cb(port, &event);
275
276 return status;
277}
278
279static MMAL_STATUS_T mmal_port_clock_parameter_get(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
280{
281 MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
282 MMAL_STATUS_T status = MMAL_SUCCESS;
283
284 switch (param->id)
285 {
286 case MMAL_PARAMETER_CLOCK_REFERENCE:
287 {
288 MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
289 p->enable = priv_clock->is_reference;
290 }
291 break;
292 case MMAL_PARAMETER_CLOCK_ACTIVE:
293 {
294 MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
295 p->enable = mmal_clock_is_active(priv_clock->clock);
296 }
297 break;
298 case MMAL_PARAMETER_CLOCK_SCALE:
299 {
300 MMAL_PARAMETER_RATIONAL_T *p = (MMAL_PARAMETER_RATIONAL_T*)param;
301 p->value = mmal_clock_scale_get(priv_clock->clock);
302 }
303 break;
304 case MMAL_PARAMETER_CLOCK_TIME:
305 {
306 MMAL_PARAMETER_INT64_T *p = (MMAL_PARAMETER_INT64_T*)param;
307 p->value = mmal_clock_media_time_get(priv_clock->clock);
308 }
309 break;
310 case MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD:
311 {
312 MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *)param;
313 status = mmal_clock_update_threshold_get(priv_clock->clock, &p->value);
314 }
315 break;
316 case MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD:
317 {
318 MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *)param;
319 status = mmal_clock_discont_threshold_get(priv_clock->clock, &p->value);
320 }
321 break;
322 case MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD:
323 {
324 MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *)param;
325 status = mmal_clock_request_threshold_get(priv_clock->clock, &p->value);
326 }
327 break;
328 case MMAL_PARAMETER_CLOCK_ENABLE_BUFFER_INFO:
329 {
330 MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
331 p->enable = priv_clock->buffer_info_reporting;
332 }
333 break;
334 default:
335 LOG_ERROR("unsupported clock parameter 0x%x", param->id);
336 return MMAL_ENOSYS;
337 }
338
339 return status;
340}
341
342static MMAL_STATUS_T mmal_port_clock_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
343{
344 MMAL_PARAM_UNUSED(port);
345 MMAL_PARAM_UNUSED(cb);
346 return MMAL_SUCCESS;
347}
348
349static MMAL_STATUS_T mmal_port_clock_disable(MMAL_PORT_T *port)
350{
351 MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
352
353 if (mmal_clock_is_active(priv_clock->clock))
354 mmal_clock_active_set(priv_clock->clock, MMAL_FALSE);
355
356 mmal_port_clock_flush(port);
357
358 return MMAL_SUCCESS;
359}
360
361static MMAL_STATUS_T mmal_port_clock_set_format(MMAL_PORT_T *port)
362{
363 MMAL_PARAM_UNUSED(port);
364 return MMAL_SUCCESS;
365}
366
367static MMAL_STATUS_T mmal_port_clock_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
368{
369 MMAL_PARAM_UNUSED(port);
370 MMAL_PARAM_UNUSED(other_port);
371 return MMAL_ENOSYS;
372}
373
374/* Send an event buffer to a connected port */
375static MMAL_STATUS_T mmal_port_clock_forward_event(MMAL_PORT_T *port, const MMAL_CLOCK_EVENT_T *event)
376{
377 MMAL_STATUS_T status;
378 MMAL_BUFFER_HEADER_T *buffer;
379
380 buffer = mmal_queue_get(port->priv->clock->queue);
381 if (!buffer)
382 {
383 LOG_INFO("%s: no free event buffers available for event %4.4s", port->name, (const char*)&event->id);
384 return MMAL_ENOSPC;
385 }
386
387 status = mmal_buffer_header_mem_lock(buffer);
388 if (status != MMAL_SUCCESS)
389 {
390 LOG_ERROR("failed to lock buffer %s", mmal_status_to_string(status));
391 mmal_queue_put_back(port->priv->clock->queue, buffer);
392 goto end;
393 }
394 buffer->length = sizeof(MMAL_CLOCK_EVENT_T);
395 memcpy(buffer->data, event, buffer->length);
396 mmal_buffer_header_mem_unlock(buffer);
397
398 mmal_port_buffer_header_callback(port, buffer);
399
400end:
401 return status;
402}
403
404/* Send a clock active state to a connected port */
405static MMAL_STATUS_T mmal_port_clock_forward_active_state(MMAL_PORT_T *port, MMAL_BOOL_T active)
406{
407 MMAL_CLOCK_EVENT_T event;
408
409 event.id = MMAL_CLOCK_EVENT_ACTIVE;
410 event.magic = MMAL_CLOCK_EVENT_MAGIC;
411 event.data.enable = active;
412
413 return mmal_port_clock_forward_event(port, &event);
414}
415
416/* Send a clock scale update to a connected port */
417static MMAL_STATUS_T mmal_port_clock_forward_scale(MMAL_PORT_T *port, MMAL_RATIONAL_T scale)
418{
419 MMAL_CLOCK_EVENT_T event;
420
421 event.id = MMAL_CLOCK_EVENT_SCALE;
422 event.magic = MMAL_CLOCK_EVENT_MAGIC;
423 event.data.scale = scale;
424
425 return mmal_port_clock_forward_event(port, &event);
426}
427
428/* Send a clock time update to a connected port */
429static MMAL_STATUS_T mmal_port_clock_forward_media_time(MMAL_PORT_T *port, int64_t media_time)
430{
431 MMAL_CLOCK_EVENT_T event;
432
433 event.id = MMAL_CLOCK_EVENT_TIME;
434 event.magic = MMAL_CLOCK_EVENT_MAGIC;
435 event.data.media_time = media_time;
436
437 return mmal_port_clock_forward_event(port, &event);
438}
439
440/* Send a clock update threshold to a connected port */
441static MMAL_STATUS_T mmal_port_clock_forward_update_threshold(MMAL_PORT_T *port,
442 const MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold)
443{
444 MMAL_CLOCK_EVENT_T event;
445
446 event.id = MMAL_CLOCK_EVENT_UPDATE_THRESHOLD;
447 event.magic = MMAL_CLOCK_EVENT_MAGIC;
448 event.data.update_threshold = *threshold;
449
450 return mmal_port_clock_forward_event(port, &event);
451}
452
453/* Send a clock discontinuity threshold to a connected port */
454static MMAL_STATUS_T mmal_port_clock_forward_discont_threshold(MMAL_PORT_T *port,
455 const MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold)
456{
457 MMAL_CLOCK_EVENT_T event;
458
459 event.id = MMAL_CLOCK_EVENT_DISCONT_THRESHOLD;
460 event.magic = MMAL_CLOCK_EVENT_MAGIC;
461 event.data.discont_threshold = *threshold;
462
463 return mmal_port_clock_forward_event(port, &event);
464}
465
466/* Send a clock request threshold to a connected port */
467static MMAL_STATUS_T mmal_port_clock_forward_request_threshold(MMAL_PORT_T *port,
468 const MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold)
469{
470 MMAL_CLOCK_EVENT_T event;
471
472 event.id = MMAL_CLOCK_EVENT_REQUEST_THRESHOLD;
473 event.magic = MMAL_CLOCK_EVENT_MAGIC;
474 event.data.request_threshold = *threshold;
475
476 return mmal_port_clock_forward_event(port, &event);
477}
478
479/* Send information regarding an input buffer to connected port */
480static MMAL_STATUS_T mmal_port_clock_forward_input_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
481{
482 MMAL_CLOCK_EVENT_T event;
483
484 event.id = MMAL_CLOCK_EVENT_INPUT_BUFFER_INFO;
485 event.magic = MMAL_CLOCK_EVENT_MAGIC;
486 event.data.buffer = *info;
487
488 return mmal_port_clock_forward_event(port, &event);
489}
490
491/* Send information regarding an output buffer to connected port */
492static MMAL_STATUS_T mmal_port_clock_forward_output_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
493{
494 MMAL_CLOCK_EVENT_T event;
495
496 event.id = MMAL_CLOCK_EVENT_OUTPUT_BUFFER_INFO;
497 event.magic = MMAL_CLOCK_EVENT_MAGIC;
498 event.data.buffer = *info;
499
500 return mmal_port_clock_forward_event(port, &event);
501}
502
503/* Initialise all callbacks and setup internal resources */
504static MMAL_STATUS_T mmal_port_clock_setup(MMAL_PORT_T *port, unsigned int extra_size,
505 MMAL_PORT_CLOCK_EVENT_CB event_cb)
506{
507 MMAL_STATUS_T status;
508
509 port->priv->clock = (MMAL_PORT_CLOCK_T*)((char*)(port->priv->module) + extra_size);
510
511 status = mmal_clock_create(&port->priv->clock->clock);
512 if (status != MMAL_SUCCESS)
513 {
514 LOG_ERROR("failed to create clock module on port %s (%s)",
515 port->name, mmal_status_to_string(status));
516 return status;
517 }
518 port->priv->clock->clock->user_data = port;
519
520 port->buffer_size = sizeof(MMAL_CLOCK_EVENT_T);
521 port->buffer_size_min = sizeof(MMAL_CLOCK_EVENT_T);
522 port->buffer_num_min = MMAL_PORT_CLOCK_BUFFERS_MIN;
523 port->buffer_num_recommended = MMAL_PORT_CLOCK_BUFFERS_MIN;
524
525 port->priv->clock->event_cb = event_cb;
526 port->priv->clock->queue = mmal_queue_create();
527 if (!port->priv->clock->queue)
528 {
529 mmal_clock_destroy(port->priv->clock->clock);
530 return MMAL_ENOMEM;
531 }
532
533 port->priv->pf_set_format = mmal_port_clock_set_format;
534 port->priv->pf_enable = mmal_port_clock_enable;
535 port->priv->pf_disable = mmal_port_clock_disable;
536 port->priv->pf_send = mmal_port_clock_send;
537 port->priv->pf_flush = mmal_port_clock_flush;
538 port->priv->pf_parameter_set = mmal_port_clock_parameter_set;
539 port->priv->pf_parameter_get = mmal_port_clock_parameter_get;
540 port->priv->pf_connect = mmal_port_clock_connect;
541#ifdef __VIDEOCORE__
542 port->priv->pf_payload_alloc = mmal_port_clock_payload_alloc;
543 port->priv->pf_payload_free = mmal_port_clock_payload_free;
544 port->capabilities = MMAL_PORT_CAPABILITY_ALLOCATION;
545#endif
546
547 return status;
548}
549
550/* Release all internal resources */
551static void mmal_port_clock_teardown(MMAL_PORT_T *port)
552{
553 if (!port)
554 return;
555 mmal_queue_destroy(port->priv->clock->queue);
556 mmal_clock_destroy(port->priv->clock->clock);
557}
558
559/*****************************************************************************
560 * Public functions
561 *****************************************************************************/
562/* Allocate a clock port */
563MMAL_PORT_T* mmal_port_clock_alloc(MMAL_COMPONENT_T *component, unsigned int extra_size,
564 MMAL_PORT_CLOCK_EVENT_CB event_cb)
565{
566 MMAL_PORT_T *port;
567
568 port = mmal_port_alloc(component, MMAL_PORT_TYPE_CLOCK,
569 extra_size + sizeof(MMAL_PORT_CLOCK_T));
570 if (!port)
571 return NULL;
572
573 if (mmal_port_clock_setup(port, extra_size, event_cb) != MMAL_SUCCESS)
574 {
575 mmal_port_free(port);
576 return NULL;
577 }
578
579 return port;
580}
581
582/* Free a clock port */
583void mmal_port_clock_free(MMAL_PORT_T *port)
584{
585 mmal_port_clock_teardown(port);
586 mmal_port_free(port);
587}
588
589/* Allocate an array of clock ports */
590MMAL_PORT_T **mmal_ports_clock_alloc(MMAL_COMPONENT_T *component, unsigned int ports_num,
591 unsigned int extra_size, MMAL_PORT_CLOCK_EVENT_CB event_cb)
592{
593 unsigned int i;
594 MMAL_PORT_T **ports;
595
596 ports = mmal_ports_alloc(component, ports_num, MMAL_PORT_TYPE_CLOCK,
597 extra_size + sizeof(MMAL_PORT_CLOCK_T));
598 if (!ports)
599 return NULL;
600
601 for (i = 0; i < ports_num; i++)
602 {
603 if (mmal_port_clock_setup(ports[i], extra_size, event_cb) != MMAL_SUCCESS)
604 break;
605 }
606
607 if (i != ports_num)
608 {
609 for (ports_num = i, i = 0; i < ports_num; i++)
610 mmal_port_clock_free(ports[i]);
611 vcos_free(ports);
612 return NULL;
613 }
614
615 return ports;
616}
617
618/* Free an array of clock ports */
619void mmal_ports_clock_free(MMAL_PORT_T **ports, unsigned int ports_num)
620{
621 unsigned int i;
622
623 for (i = 0; i < ports_num; i++)
624 mmal_port_clock_free(ports[i]);
625 vcos_free(ports);
626}
627
628/* Register a callback request */
629MMAL_STATUS_T mmal_port_clock_request_add(MMAL_PORT_T *port, int64_t media_time,
630 MMAL_PORT_CLOCK_REQUEST_CB cb, void *cb_data)
631{
632 return mmal_clock_request_add(port->priv->clock->clock, media_time,
633 mmal_port_clock_request_cb, cb_data, (MMAL_CLOCK_VOID_FP)cb);
634}
635
636/* Flush all pending clock requests */
637MMAL_STATUS_T mmal_port_clock_request_flush(MMAL_PORT_T *port)
638{
639 return mmal_clock_request_flush(port->priv->clock->clock);
640}
641
642/* Set the clock port's reference state */
643MMAL_STATUS_T mmal_port_clock_reference_set(MMAL_PORT_T *port, MMAL_BOOL_T reference)
644{
645 port->priv->clock->is_reference = reference;
646 return MMAL_SUCCESS;
647}
648
649/* Get the clock port's reference state */
650MMAL_BOOL_T mmal_port_clock_reference_get(MMAL_PORT_T *port)
651{
652 return port->priv->clock->is_reference;
653}
654
655/* Set the clock port's active state */
656MMAL_STATUS_T mmal_port_clock_active_set(MMAL_PORT_T *port, MMAL_BOOL_T active)
657{
658 MMAL_STATUS_T status;
659
660 status = mmal_clock_active_set(port->priv->clock->clock, active);
661 if (status != MMAL_SUCCESS)
662 return status;
663
664 if (port->priv->clock->is_reference)
665 status = mmal_port_clock_forward_active_state(port, active);
666
667 return status;
668}
669
670/* Get the clock port's active state */
671MMAL_BOOL_T mmal_port_clock_active_get(MMAL_PORT_T *port)
672{
673 return mmal_clock_is_active(port->priv->clock->clock);
674}
675
676/* Set the clock port's scale */
677MMAL_STATUS_T mmal_port_clock_scale_set(MMAL_PORT_T *port, MMAL_RATIONAL_T scale)
678{
679 MMAL_STATUS_T status;
680
681 status = mmal_clock_scale_set(port->priv->clock->clock, scale);
682 if (status != MMAL_SUCCESS)
683 return status;
684
685 if (port->priv->clock->is_reference)
686 status = mmal_port_clock_forward_scale(port, scale);
687
688 return status;
689}
690
691/* Get the clock port's scale */
692MMAL_RATIONAL_T mmal_port_clock_scale_get(MMAL_PORT_T *port)
693{
694 return mmal_clock_scale_get(port->priv->clock->clock);
695}
696
697/* Set the clock port's media-time */
698MMAL_STATUS_T mmal_port_clock_media_time_set(MMAL_PORT_T *port, int64_t media_time)
699{
700 MMAL_STATUS_T status;
701
702 status = mmal_clock_media_time_set(port->priv->clock->clock, media_time);
703 if (status != MMAL_SUCCESS)
704 {
705 LOG_DEBUG("clock media-time update ignored");
706 return status;
707 }
708
709 if (port->priv->clock->is_reference)
710 status = mmal_port_clock_forward_media_time(port, media_time);
711
712 return status;
713}
714
715/* Get the clock port's media-time */
716int64_t mmal_port_clock_media_time_get(MMAL_PORT_T *port)
717{
718 return mmal_clock_media_time_get(port->priv->clock->clock);
719}
720
721/* Set the clock port's update threshold */
722MMAL_STATUS_T mmal_port_clock_update_threshold_set(MMAL_PORT_T *port,
723 const MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold)
724{
725 MMAL_STATUS_T status;
726
727 status = mmal_clock_update_threshold_set(port->priv->clock->clock, threshold);
728 if (status != MMAL_SUCCESS)
729 return status;
730
731 if (port->priv->clock->is_reference)
732 status = mmal_port_clock_forward_update_threshold(port, threshold);
733
734 return status;
735}
736
737/* Get the clock port's update threshold */
738MMAL_STATUS_T mmal_port_clock_update_threshold_get(MMAL_PORT_T *port,
739 MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold)
740{
741 return mmal_clock_update_threshold_get(port->priv->clock->clock, threshold);
742}
743
744/* Set the clock port's discontinuity threshold */
745MMAL_STATUS_T mmal_port_clock_discont_threshold_set(MMAL_PORT_T *port,
746 const MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold)
747{
748 MMAL_STATUS_T status;
749
750 status = mmal_clock_discont_threshold_set(port->priv->clock->clock, threshold);
751 if (status != MMAL_SUCCESS)
752 return status;
753
754 if (port->priv->clock->is_reference)
755 status = mmal_port_clock_forward_discont_threshold(port, threshold);
756
757 return status;
758}
759
760/* Get the clock port's discontinuity threshold */
761MMAL_STATUS_T mmal_port_clock_discont_threshold_get(MMAL_PORT_T *port,
762 MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold)
763{
764 return mmal_clock_discont_threshold_get(port->priv->clock->clock, threshold);
765}
766
767/* Set the clock port's request threshold */
768MMAL_STATUS_T mmal_port_clock_request_threshold_set(MMAL_PORT_T *port,
769 const MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold)
770{
771 MMAL_STATUS_T status;
772
773 status = mmal_clock_request_threshold_set(port->priv->clock->clock, threshold);
774 if (status != MMAL_SUCCESS)
775 return status;
776
777 if (port->priv->clock->is_reference)
778 status = mmal_port_clock_forward_request_threshold(port, threshold);
779
780 return status;
781}
782
783/* Get the clock port's request threshold */
784MMAL_STATUS_T mmal_port_clock_request_threshold_get(MMAL_PORT_T *port,
785 MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold)
786{
787 return mmal_clock_request_threshold_get(port->priv->clock->clock, threshold);
788}
789
790/* Provide input buffer information */
791void mmal_port_clock_input_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
792{
793 if (port->priv->clock->buffer_info_reporting)
794 mmal_port_clock_forward_input_buffer_info(port, info);
795}
796
797/* Provide output buffer information */
798void mmal_port_clock_output_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
799{
800 if (port->priv->clock->buffer_info_reporting)
801 mmal_port_clock_forward_output_buffer_info(port, info);
802}
803
804