/** Send a buffer header to a port */ MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_STATUS_T status; if (!port || !port->priv) { LOG_ERROR("invalid port"); return MMAL_EINVAL; } #ifdef ENABLE_MMAL_EXTRA_LOGGING LOG_TRACE("%s(%i:%i) port %p, buffer %p (%p,%i,%i)", port->component->name, (int)port->type, (int)port->index, port, buffer, buffer ? buffer->data: 0, buffer ? (int)buffer->offset : 0, buffer ? (int)buffer->length : 0); #endif if (!buffer->data && !(port->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH)) { LOG_ERROR("%s(%p) received invalid buffer header", port->name, port); return MMAL_EINVAL; } if (!port->priv->pf_send) return MMAL_ENOSYS; LOCK_SENDING(port); if (!port->is_enabled) { UNLOCK_SENDING(port); return MMAL_EINVAL; } if (port->type == MMAL_PORT_TYPE_OUTPUT && buffer->length) { LOG_DEBUG("given an output buffer with length != 0"); buffer->length = 0; } IN_TRANSIT_INCREMENT(port); status = port->priv->pf_send(port, buffer); if (status != MMAL_SUCCESS) { IN_TRANSIT_DECREMENT(port); LOG_ERROR("%s: send failed: %s", port->name, mmal_status_to_string(status)); } else { mmal_port_update_port_stats(port, MMAL_CORE_STATS_RX); } UNLOCK_SENDING(port); return status; }
static MMAL_STATUS_T mmal_port_disable_internal(MMAL_PORT_T *port) { MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_BUFFER_HEADER_T *buffer; LOCK_PORT(port); if (!port->is_enabled) goto end; LOCK_SENDING(port); port->is_enabled = 0; UNLOCK_SENDING(port); mmal_component_action_lock(port->component); if (core->pool_for_connection) mmal_pool_callback_set(core->pool_for_connection, NULL, NULL); status = port->priv->pf_disable(port); mmal_component_action_unlock(port->component); if (status != MMAL_SUCCESS) { LOG_ERROR("port %p could not be disabled (%s)", port->name, mmal_status_to_string(status)); LOCK_SENDING(port); port->is_enabled = 1; UNLOCK_SENDING(port); goto end; } /* Flush our internal queue */ buffer = port->priv->core->queue_first; while (buffer) { MMAL_BUFFER_HEADER_T *next = buffer->next; mmal_port_buffer_header_callback(port, buffer); buffer = next; } port->priv->core->queue_first = 0; port->priv->core->queue_last = &port->priv->core->queue_first; /* Wait for all the buffers to have come back from the component */ LOG_DEBUG("%s waiting for %i buffers left in transit", port->name, (int)IN_TRANSIT_COUNT(port)); IN_TRANSIT_WAIT(port); LOG_DEBUG("%s has no buffers left in transit", port->name); port->priv->core->buffer_header_callback = NULL; end: UNLOCK_PORT(port); return status; }
/** Flush a port */ MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port) { MMAL_BUFFER_HEADER_T *buffer = 0; MMAL_STATUS_T status; if (!port || !port->priv) return MMAL_EINVAL; LOG_TRACE("%s(%i:%i) port %p", port->component->name, (int)port->type, (int)port->index, port); if (!port->priv->pf_flush) return MMAL_ENOSYS; mmal_component_action_lock(port->component); LOCK_SENDING(port); status = port->priv->pf_flush(port); if (status == MMAL_SUCCESS) { /* Flush our internal queue */ buffer = port->priv->core->queue_first; port->priv->core->queue_first = 0; port->priv->core->queue_last = &port->priv->core->queue_first; } UNLOCK_SENDING(port); mmal_component_action_unlock(port->component); while (buffer) { MMAL_BUFFER_HEADER_T *next = buffer->next; mmal_port_buffer_header_callback(port, buffer); buffer = next; } return status; }
static MMAL_STATUS_T mmal_port_disable_locked(MMAL_PORT_T *port) { MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core; MMAL_STATUS_T status; if (!port->is_enabled) { LOG_ERROR("port %p is not enabled", port); return MMAL_EINVAL; } LOCK_SENDING(port); port->is_enabled = 0; UNLOCK_SENDING(port); mmal_component_action_lock(port->component); if (core->pool_for_connection) mmal_pool_callback_set(core->pool_for_connection, NULL, NULL); status = port->priv->pf_disable(port); mmal_component_action_unlock(port->component); if (status != MMAL_SUCCESS) { LOG_ERROR("port %p could not be disabled (%s)", port->name, mmal_status_to_string(status)); LOCK_SENDING(port); port->is_enabled = 1; UNLOCK_SENDING(port); return status; } /* Wait for all the buffers to have come back from the component */ LOG_DEBUG("%s waiting for %i buffers left in transit", port->name, (int)IN_TRANSIT_COUNT(port)); IN_TRANSIT_WAIT(port); LOG_DEBUG("%s has no buffers left in transit", port->name); port->priv->core->buffer_header_callback = NULL; if (core->connected_port && port->type == MMAL_PORT_TYPE_OUTPUT) mmal_port_disable(core->connected_port); return status; }
/** Flush a port */ MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port) { MMAL_STATUS_T status; if (!port || !port->priv) return MMAL_EINVAL; LOG_TRACE("%s(%i:%i) port %p", port->component->name, (int)port->type, (int)port->index, port); if (!port->priv->pf_flush) return MMAL_ENOSYS; LOCK_SENDING(port); status = port->priv->pf_flush(port); UNLOCK_SENDING(port); return status; }
MMAL_STATUS_T mmal_port_pause(MMAL_PORT_T *port, MMAL_BOOL_T pause) { MMAL_STATUS_T status = MMAL_SUCCESS; LOCK_SENDING(port); /* When resuming from pause, we send all our queued buffers to the port */ if (!pause && port->is_enabled) { MMAL_BUFFER_HEADER_T *buffer = port->priv->core->queue_first; while (buffer) { MMAL_BUFFER_HEADER_T *next = buffer->next; status = port->priv->pf_send(port, buffer); if (status != MMAL_SUCCESS) { buffer->next = next; break; } buffer = next; } /* If for some reason we could not send one of the buffers, we just * leave all the buffers in our internal queue and return an error. */ if (status != MMAL_SUCCESS) { port->priv->core->queue_first = buffer; } else { port->priv->core->queue_first = 0; port->priv->core->queue_last = &port->priv->core->queue_first; } } if (status == MMAL_SUCCESS) port->priv->core->is_paused = pause; UNLOCK_SENDING(port); return status; }
static MMAL_STATUS_T mmal_port_enable_internal(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) { MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core; MMAL_STATUS_T status = MMAL_SUCCESS; LOCK_PORT(port); if (port->is_enabled) goto end; /* Sanity check the buffer requirements */ if (port->buffer_num < port->buffer_num_min) { LOG_ERROR("buffer_num too small (%i/%i)", (int)port->buffer_num, (int)port->buffer_num_min); status = MMAL_EINVAL; goto end; } if (port->buffer_size < port->buffer_size_min) { LOG_ERROR("buffer_size too small (%i/%i)", (int)port->buffer_size, (int)port->buffer_size_min); status = MMAL_EINVAL; goto end; } core->buffer_header_callback = cb; status = port->priv->pf_enable(port, cb); if (status != MMAL_SUCCESS) goto end; LOCK_SENDING(port); port->is_enabled = 1; UNLOCK_SENDING(port); end: UNLOCK_PORT(port); return status; }
/** Send a buffer header to a port */ MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_STATUS_T status = MMAL_SUCCESS; if (!port || !port->priv) { LOG_ERROR("invalid port"); return MMAL_EINVAL; } #ifdef ENABLE_MMAL_EXTRA_LOGGING LOG_TRACE("%s(%i:%i) port %p, buffer %p (%p,%i,%i)", port->component->name, (int)port->type, (int)port->index, port, buffer, buffer ? buffer->data: 0, buffer ? (int)buffer->offset : 0, buffer ? (int)buffer->length : 0); #endif if (!buffer->data && !(port->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH)) { LOG_ERROR("%s(%p) received invalid buffer header", port->name, port); return MMAL_EINVAL; } if (!port->priv->pf_send) return MMAL_ENOSYS; LOCK_SENDING(port); if (!port->is_enabled) { UNLOCK_SENDING(port); return MMAL_EINVAL; } if (port->type == MMAL_PORT_TYPE_OUTPUT && buffer->length) { LOG_DEBUG("given an output buffer with length != 0"); buffer->length = 0; } /* coverity[lock] transit_sema is used for signalling, and is not a lock */ /* coverity[lock_order] since transit_sema is not a lock, there is no ordering conflict */ IN_TRANSIT_INCREMENT(port); if (port->priv->core->is_paused) { /* Add buffer to our internal queue */ buffer->next = NULL; *port->priv->core->queue_last = buffer; port->priv->core->queue_last = &buffer->next; } else { /* Send buffer to component */ status = port->priv->pf_send(port, buffer); } if (status != MMAL_SUCCESS) { IN_TRANSIT_DECREMENT(port); LOG_ERROR("%s: send failed: %s", port->name, mmal_status_to_string(status)); } else { mmal_port_update_port_stats(port, MMAL_CORE_STATS_RX); } UNLOCK_SENDING(port); return status; }
static MMAL_STATUS_T mmal_port_enable_locked(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) { MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core; MMAL_PORT_T* connected_port = core->connected_port; MMAL_STATUS_T status; if (port->is_enabled) { LOG_DEBUG("already enabled"); return MMAL_EINVAL; } /* Ensure that the buffer numbers and sizes used are the maxima between connected ports. */ if (connected_port && port->type == MMAL_PORT_TYPE_OUTPUT) { LOCK_PORT(connected_port); if (connected_port->buffer_num > port->buffer_num) port->buffer_num = connected_port->buffer_num; if (connected_port->buffer_size > port->buffer_size) port->buffer_size = connected_port->buffer_size; UNLOCK_PORT(connected_port); } /* Sanity check the buffer requirements */ if (port->buffer_num < port->buffer_num_min) { LOG_ERROR("buffer_num too small (%i/%i)", (int)port->buffer_num, (int)port->buffer_num_min); return MMAL_EINVAL; } if (port->buffer_size < port->buffer_size_min) { LOG_ERROR("buffer_size too small (%i/%i)", (int)port->buffer_size, (int)port->buffer_size_min); return MMAL_EINVAL; } if (!connected_port == !cb) { /* Callback must be NULL if connected port is not NULL */ LOG_ERROR("connected port %p, callback %p not allowed", connected_port, cb); return MMAL_EINVAL; } core->buffer_header_callback = cb; status = port->priv->pf_enable(port, cb); if (status != MMAL_SUCCESS) return status; LOCK_SENDING(port); port->is_enabled = 1; UNLOCK_SENDING(port); //FIXME: move before is_enabled is set ? if (connected_port) { if (port->type == MMAL_PORT_TYPE_INPUT) core->buffer_header_callback = mmal_port_connected_input_cb; else status = mmal_port_enable_locked_connected(port, connected_port); } return status; }