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_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 */ |
42 | typedef 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. */ |
61 | static 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 | |
79 | static 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 */ |
88 | static 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 */ |
97 | static 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 | |
170 | static 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 | |
183 | static 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 | |
198 | static 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 | |
279 | static 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 | |
342 | static 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 | |
349 | static 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 | |
361 | static MMAL_STATUS_T mmal_port_clock_set_format(MMAL_PORT_T *port) |
362 | { |
363 | MMAL_PARAM_UNUSED(port); |
364 | return MMAL_SUCCESS; |
365 | } |
366 | |
367 | static 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 */ |
375 | static 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 | |
400 | end: |
401 | return status; |
402 | } |
403 | |
404 | /* Send a clock active state to a connected port */ |
405 | static 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 */ |
417 | static 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 */ |
429 | static 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 */ |
441 | static 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 */ |
454 | static 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 */ |
467 | static 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 */ |
480 | static 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 */ |
492 | static 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 */ |
504 | static MMAL_STATUS_T mmal_port_clock_setup(MMAL_PORT_T *port, unsigned int , |
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 */ |
551 | static 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 */ |
563 | MMAL_PORT_T* mmal_port_clock_alloc(MMAL_COMPONENT_T *component, unsigned int , |
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 */ |
583 | void 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 */ |
590 | MMAL_PORT_T **mmal_ports_clock_alloc(MMAL_COMPONENT_T *component, unsigned int ports_num, |
591 | unsigned int , 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 */ |
619 | void 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 */ |
629 | MMAL_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 */ |
637 | MMAL_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 */ |
643 | MMAL_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 */ |
650 | MMAL_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 */ |
656 | MMAL_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 */ |
671 | MMAL_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 */ |
677 | MMAL_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 */ |
692 | MMAL_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 */ |
698 | MMAL_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 */ |
716 | int64_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 */ |
722 | MMAL_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 */ |
738 | MMAL_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 */ |
745 | MMAL_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 */ |
761 | MMAL_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 */ |
768 | MMAL_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 */ |
784 | MMAL_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 */ |
791 | void 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 */ |
798 | void 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 | |