Änderungen Gruppe 30_10_2022 V2

This commit is contained in:
2022-10-30 20:01:47 +01:00
parent 269f807b31
commit 2517e52e59
239 changed files with 54983 additions and 9 deletions
@@ -0,0 +1,29 @@
# MMAL can use VCSM to allow zero copy for ARM accessible buffers.
# This is not enabled by default right now because VCSM on RPI is still
# experimental.
# add_definitions(-DENABLE_MMAL_VCSM)
add_library(mmal_vc_client ${LIBRARY_TYPE} mmal_vc_client.c mmal_vc_shm.c mmal_vc_api.c mmal_vc_opaque_alloc.c mmal_vc_msgnames.c mmal_vc_api_drm.c)
target_link_libraries(mmal_vc_client vchiq_arm vcos)
# target_link_libraries(mmal_vc_client vchiq_arm vcos vcsm)
if(BUILD_MMAL_APPS)
add_executable(mmal_vc_diag mmal_vc_diag.c)
target_link_libraries(mmal_vc_diag mmal mmal_vc_client debug_sym vcos)
install(TARGETS mmal_vc_diag RUNTIME DESTINATION bin)
endif(BUILD_MMAL_APPS)
include_directories ( ../../../host_applications/linux/libs/sm )
install(TARGETS mmal_vc_client DESTINATION lib)
install(FILES
mmal_vc_api.h
mmal_vc_api_drm.h
mmal_vc_client_priv.h
mmal_vc_msgnames.h
mmal_vc_msgs.h
mmal_vc_opaque_alloc.h
mmal_vc_shm.h
DESTINATION include/interface/mmal/vc
)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,219 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMAL_VC_API_H
#define MMAL_VC_API_H
/** @file
*
* Public API for MMAL VC client. Most functionality is exposed
* via MMAL itself.
*/
#include "interface/mmal/mmal_types.h"
#include "interface/mmal/mmal_parameters.h"
#include "interface/mmal/mmal_port.h"
#ifdef __cplusplus
extern "C" {
#endif
/** State of components created by the VC adaptation layer, used for
* statistics reporting.
*/
typedef enum {
MMAL_STATS_COMP_IDLE,
MMAL_STATS_COMP_CREATED,
MMAL_STATS_COMP_DESTROYING,
MMAL_STATS_COMP_DESTROYED,
MMAL_STATS_COMP_UNUSED = 0xffffffff /* force 32bit */
} MMAL_STATS_COMP_STATE_T;
/** Per-component statistics collected by the VC adaptation layer.
*/
struct MMAL_VC_COMP_STATS_T {
struct MMAL_DRIVER_COMPONENT_T *comp;
MMAL_STATS_COMP_STATE_T state;
uint32_t pid;
uint32_t pool_mem_alloc_size;
char name[20];
};
/** VC adaptation layer statistics.
*/
struct MMAL_VC_STATS_T
{
struct
{
uint32_t rx; /**< Count of data buffers received */
uint32_t rx_zero_copy; /**< Count of zero-copy data buffers received */
uint32_t rx_empty; /**< Empty data buffers (to be filled) */
uint32_t rx_fails; /**< Gave up partway through */
uint32_t tx; /**< Count of data buffers sent */
uint32_t tx_zero_copy; /**< Count of zero-copy data buffers sent */
uint32_t tx_empty; /**< Count of empty data buffers sent */
uint32_t tx_fails; /**< Gave up partway through */
uint32_t tx_short_msg; /**< Messages sent directly in the control message */
uint32_t rx_short_msg; /**< Messages received directly in the control message */
} buffers;
struct service
{
uint32_t created; /**< How many services created */
uint32_t pending_destroy; /**< How many destroyed */
uint32_t destroyed; /**< How many destroyed */
uint32_t failures; /**< Failures to create a service */
} service;
struct commands
{
uint32_t bad_messages;
uint32_t executed;
uint32_t failed;
uint32_t replies;
uint32_t reply_fails;
} commands;
struct
{
uint32_t tx; /**< Count of events sent */
uint32_t tx_fails; /**< Count of events not fully sent */
} events;
struct
{
uint32_t created;
uint32_t destroyed;
uint32_t destroying;
uint32_t failed;
uint32_t list_size;
struct MMAL_VC_COMP_STATS_T component_list[8];
} components;
struct
{
uint32_t enqueued_messages;
uint32_t dequeued_messages;
uint32_t max_parameter_set_delay;
uint32_t max_messages_waiting;
} worker;
};
typedef struct MMAL_VC_STATS_T MMAL_VC_STATS_T;
/* Simple circular text buffer used to store 'interesting' data
* from MMAL clients. e.g. settings for each picture taken */
struct MMAL_VC_HOST_LOG_T
{
/** Simple circular buffer of plain text log messages separated by NUL */
char buffer[16 << 10];
/** For VCDBG validation and to help detect buffer overflow */
uint32_t magic;
/** Write offset into buffer */
int32_t offset;
/** Counter of host messages logged since boot */
unsigned count;
};
typedef struct MMAL_VC_HOST_LOG_T MMAL_VC_HOST_LOG_T;
/** Status from querying MMAL core statistics.
*/
typedef enum
{
MMAL_STATS_FOUND,
MMAL_STATS_COMPONENT_NOT_FOUND,
MMAL_STATS_PORT_NOT_FOUND,
MMAL_STATS_INVALID = 0x7fffffff
} MMAL_STATS_RESULT_T;
MMAL_STATUS_T mmal_vc_init(void);
void mmal_vc_deinit(void);
MMAL_STATUS_T mmal_vc_use(void);
MMAL_STATUS_T mmal_vc_release(void);
MMAL_STATUS_T mmal_vc_get_version(uint32_t *major, uint32_t *minor, uint32_t *minimum);
MMAL_STATUS_T mmal_vc_get_stats(MMAL_VC_STATS_T *stats, int reset);
/** Return the MMAL core statistics for a given component/port.
*
* @param stats Updated with given port statistics
* @param result Whether the port/component was found
* @param name Filled in with the name of the port
* @param namelen Length of name
* @param component Which component (indexed from zero)
* @param port_type Which type of port
* @param port Which port (index from zero)
* @param reset Reset the stats.
*/
MMAL_STATUS_T mmal_vc_get_core_stats(MMAL_CORE_STATISTICS_T *stats,
MMAL_STATS_RESULT_T *result,
char *name,
size_t namelen,
MMAL_PORT_TYPE_T type,
unsigned component,
unsigned port,
MMAL_CORE_STATS_DIR dir,
MMAL_BOOL_T reset);
/**
* Stores an arbitrary text message in a circular buffer inside the MMAL VC server.
* The purpose of this message is to log high level events from the host in order
* to diagnose problems that require multiple actions to reproduce. e.g. taking
* multiple pictures with different settings.
*
* @param msg The message text.
* @return MMAL_SUCCESS if the message was logged or MMAL_ENOSYS if the API
* if not supported.
*/
MMAL_STATUS_T mmal_vc_host_log(const char *msg);
/* For backwards compatibility in builds */
#define MMAL_VC_API_HAVE_HOST_LOG
/* VC DEBUG ONLY ************************************************************/
/** Consumes memory in the relocatable heap.
*
* The existing reserved memory is freed first then the new chunk is allocated.
* If zero is specified for the size then the previously reserved memory
* is freed and no allocation occurs.
*
* At startup no memory is reserved.
*
* @param size Size of memory to consume in bytes.
* @param handle Set to the mem handle for the reserved memory or zero
* if no memory was allocated.
* @return MMAL_SUCCESS if memory was reserved (or size zero requested),
* MMAL_ENOSPC if the allocation failed or MMAL_ENOSYS if the
* API is not supported e.g in release mode VC images.
* @internal
*/
MMAL_STATUS_T mmal_vc_consume_mem(size_t size, uint32_t *handle);
/** Trigger LMK action from VC, for diagnostics.
* @internal
*/
MMAL_STATUS_T mmal_vc_lmk(uint32_t alloc_size);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,77 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mmal_vc_api_drm.h"
#include "mmal_vc_api.h"
#include "interface/mmal/mmal_logging.h"
#include "interface/mmal/mmal.h"
#include "mmal_vc_api.h"
#include "mmal_vc_msgs.h"
#include "mmal_vc_client_priv.h"
#include "mmal_vc_opaque_alloc.h"
#include "mmal_vc_shm.h"
#include "interface/mmal/util/mmal_util.h"
#include "interface/mmal/core/mmal_component_private.h"
#include "interface/mmal/core/mmal_port_private.h"
#include "interface/mmal/core/mmal_buffer_private.h"
#include "interface/vcos/vcos.h"
int mmal_vc_drm_get_time(unsigned int * time)
{
MMAL_STATUS_T status;
mmal_worker_msg_header req;
mmal_worker_drm_get_time_reply reply;
size_t len = sizeof(reply);
status = mmal_vc_init();
if (status != MMAL_SUCCESS) return status;
status = mmal_vc_sendwait_message(mmal_vc_get_client(),
&req, sizeof(req),
MMAL_WORKER_DRM_GET_TIME,
&reply, &len, MMAL_FALSE);
*time = reply.time;
mmal_vc_deinit();
return status;
}
int mmal_vc_drm_get_lhs32(unsigned char * into)
{
MMAL_STATUS_T status;
mmal_worker_msg_header req;
mmal_worker_drm_get_lhs32_reply reply;
size_t len = sizeof(reply);
status = mmal_vc_init();
if (status != MMAL_SUCCESS) return status;
status = mmal_vc_sendwait_message(mmal_vc_get_client(),
&req, sizeof(req),
MMAL_WORKER_DRM_GET_LHS32,
&reply, &len, MMAL_FALSE);
memcpy(into, reply.secret, 32);
mmal_vc_deinit();
return status;
}
@@ -0,0 +1,55 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMAL_VC_API_DRM_H
#define MMAL_VC_API_DRM_H
/** @file
*
* Public API for MMAL VC client. (Divx DRM part)
*/
#ifdef __cplusplus
extern "C" {
#endif
// Reads the current clock (in microseconds) into the "time" variable.
// Returns zero on success, nonszero on failure
int mmal_vc_drm_get_time(unsigned int * time);
// Reads the local hardware secret into the "into" variable (needs to be 32 bytes of space for this)
// Returns 0 on success, nonzero on failure
// Usage:
// unsigned char buffer[32];
// success = mmal_vc_divx_drm_get_lhs(buffer);
int mmal_vc_drm_get_lhs32(unsigned char * into);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,822 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mmal.h"
#include "mmal_vc_msgs.h"
#include "mmal_vc_api.h"
#include "mmal_vc_client_priv.h"
#include "interface/vcos/vcos.h"
#include "vchiq_util.h"
#include "interface/mmal/core/mmal_buffer_private.h"
#include "interface/mmal/core/mmal_component_private.h"
#include "interface/mmal/core/mmal_port_private.h"
#include "interface/mmal/util/mmal_list.h"
#include "interface/mmal/util/mmal_util.h"
#define VCOS_LOG_CATEGORY (&mmal_ipc_log_category)
#include "interface/mmal/mmal_logging.h"
#include <stdio.h>
#define MAX_WAITERS 16
static VCOS_ONCE_T once = VCOS_ONCE_INIT;
static VCHIQ_INSTANCE_T mmal_vchiq_instance;
static VCOS_LOG_CAT_T mmal_ipc_log_category;
/** Client threads use one of these to wait for
* a reply from VideoCore.
*/
typedef struct MMAL_WAITER_T
{
VCOS_SEMAPHORE_T sem;
unsigned inuse;
void *dest; /**< Where to write reply */
size_t destlen; /**< Max length for reply */
} MMAL_WAITER_T;
/** We have an array of waiters and allocate them to waiting
* threads. They can be released back to the pool in any order.
* If there are none free, the calling thread will block until
* one becomes available.
*/
typedef struct
{
MMAL_WAITER_T waiters[MAX_WAITERS];
VCOS_SEMAPHORE_T sem;
} MMAL_WAITPOOL_T;
struct MMAL_CLIENT_T
{
int refcount;
int usecount;
VCOS_MUTEX_T lock;
VCHIQ_SERVICE_HANDLE_T service;
MMAL_WAITPOOL_T waitpool;
VCOS_MUTEX_T bulk_lock;
MMAL_BOOL_T inited;
};
/* One client per process/VC connection. Multiple threads may
* be using a single client.
*/
static MMAL_CLIENT_T client;
static void init_once(void)
{
vcos_mutex_create(&client.lock, VCOS_FUNCTION);
}
/** Create a pool of wait-structures.
*/
static MMAL_STATUS_T create_waitpool(MMAL_WAITPOOL_T *waitpool)
{
MMAL_STATUS_T status;
int i;
status = vcos_semaphore_create(&waitpool->sem, VCOS_FUNCTION,
MAX_WAITERS);
if (status != MMAL_SUCCESS)
return status;
for (i=0; i<MAX_WAITERS; i++)
{
waitpool->waiters[i].inuse = 0;
status = vcos_semaphore_create(&waitpool->waiters[i].sem,
"mmal waiter", 0);
if (status != MMAL_SUCCESS)
break;
}
if (status != MMAL_SUCCESS)
{
/* clean up */
i--;
while (i>=0)
{
vcos_semaphore_delete(&waitpool->waiters[i].sem);
i--;
}
vcos_semaphore_delete(&waitpool->sem);
}
return status;
}
static void destroy_waitpool(MMAL_WAITPOOL_T *waitpool)
{
int i;
for (i=0; i<MAX_WAITERS; i++)
vcos_semaphore_delete(&waitpool->waiters[i].sem);
vcos_semaphore_delete(&waitpool->sem);
}
/** Grab a waiter from the pool. Return immediately if one already
* available, or wait for one to become available.
*/
static MMAL_WAITER_T *get_waiter(MMAL_CLIENT_T *client)
{
int i;
MMAL_WAITER_T *waiter = NULL;
vcos_semaphore_wait(&client->waitpool.sem);
vcos_mutex_lock(&client->lock);
for (i=0; i<MAX_WAITERS; i++)
{
if (client->waitpool.waiters[i].inuse == 0)
break;
}
/* If this fails, the semaphore is not working */
if (vcos_verify(i != MAX_WAITERS))
{
waiter = client->waitpool.waiters+i;
waiter->inuse = 1;
}
vcos_mutex_unlock(&client->lock);
return waiter;
}
/** Return a waiter to the pool.
*/
static void release_waiter(MMAL_CLIENT_T *client, MMAL_WAITER_T *waiter)
{
LOG_TRACE("at %p", waiter);
vcos_assert(waiter);
vcos_assert(waiter->inuse);
waiter->inuse = 0;
vcos_semaphore_post(&client->waitpool.sem);
}
static MMAL_PORT_T *mmal_vc_port_by_number(MMAL_COMPONENT_T *component, uint32_t type, uint32_t number)
{
switch (type)
{
case MMAL_PORT_TYPE_CONTROL:
vcos_assert(number == 0);
return component->control;
case MMAL_PORT_TYPE_INPUT:
vcos_assert(number < component->input_num);
return component->input[number];
case MMAL_PORT_TYPE_OUTPUT:
vcos_assert(number < component->output_num);
return component->output[number];
case MMAL_PORT_TYPE_CLOCK:
vcos_assert(number < component->clock_num);
return component->clock[number];
}
return NULL;
}
static void mmal_vc_handle_event_msg(VCHIQ_HEADER_T *vchiq_header,
VCHIQ_SERVICE_HANDLE_T service,
void *context)
{
mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)vchiq_header->data;
MMAL_COMPONENT_T *component = msg->client_component;
MMAL_BUFFER_HEADER_T *buffer;
MMAL_STATUS_T status;
MMAL_PORT_T *port;
LOG_DEBUG("event to host, cmd 0x%08x len %d to component %p port (%d,%d)",
msg->cmd, msg->length, msg->client_component, msg->port_type, msg->port_num);
(void)context;
port = mmal_vc_port_by_number(component, msg->port_type, msg->port_num);
if (!vcos_verify(port))
{
LOG_ERROR("port (%i,%i) doesn't exist", (int)msg->port_type, (int)msg->port_num);
goto error;
}
status = mmal_port_event_get(port, &buffer, msg->cmd);
if (status != MMAL_SUCCESS)
{
LOG_ERROR("no event buffer available to receive event (%i)", (int)status);
goto error;
}
if (!vcos_verify(msg->length <= buffer->alloc_size))
{
LOG_ERROR("event buffer to small to receive event (%i/%i)",
(int)buffer->alloc_size, (int)msg->length);
goto error;
}
buffer->length = msg->length;
/* Sanity check that the event buffers have the proper vc client context */
if (!vcos_verify(mmal_buffer_header_driver_data(buffer)->magic == MMAL_MAGIC &&
mmal_buffer_header_driver_data(buffer)->client_context &&
mmal_buffer_header_driver_data(buffer)->client_context->magic == MMAL_MAGIC &&
mmal_buffer_header_driver_data(buffer)->client_context->callback_event))
{
LOG_ERROR("event buffers not configured properly by component");
goto error;
}
if (buffer->length > MMAL_WORKER_EVENT_SPACE)
{
/* a buffer full of data for us to process */
int len = buffer->length;
len = (len+3) & (~3);
LOG_DEBUG("queue event bulk rx: %p, %d", buffer->data, buffer->length);
msg->delayed_buffer = buffer;
VCHIQ_STATUS_T vst = vchiq_queue_bulk_receive(service, buffer->data, len, vchiq_header);
if (vst != VCHIQ_SUCCESS)
{
LOG_TRACE("queue event bulk rx len %d failed to start", buffer->length);
mmal_buffer_header_release(buffer);
goto error;
}
}
else
{
if (msg->length)
memcpy(buffer->data, msg->data, msg->length);
mmal_buffer_header_driver_data(buffer)->client_context->callback_event(port, buffer);
LOG_DEBUG("done callback back to client");
vchiq_release_message(service, vchiq_header);
}
return;
error:
/* FIXME: How to abort bulk receive if necessary? */
msg->length = 0; /* FIXME: set a buffer flag to signal error */
vchiq_release_message(service, vchiq_header);
}
static MMAL_STATUS_T mmal_vc_use_internal(MMAL_CLIENT_T *client)
{
MMAL_STATUS_T status = MMAL_SUCCESS;
vcos_mutex_lock(&client->lock);
if(client->usecount++ == 0)
{
if(vchiq_use_service(client->service) != VCHIQ_SUCCESS)
{
client->usecount--;
status = MMAL_EIO;
}
}
vcos_mutex_unlock(&client->lock);
return status;
}
static MMAL_STATUS_T mmal_vc_release_internal(MMAL_CLIENT_T *client)
{
MMAL_STATUS_T status = MMAL_SUCCESS;
vcos_mutex_lock(&client->lock);
if(--client->usecount == 0)
{
if(vchiq_release_service(client->service) != VCHIQ_SUCCESS)
{
client->usecount++;
status = MMAL_EIO;
}
}
vcos_mutex_unlock(&client->lock);
return status;
}
/** Callback invoked by VCHIQ
*/
static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
VCHIQ_HEADER_T *vchiq_header,
VCHIQ_SERVICE_HANDLE_T service,
void *context)
{
LOG_TRACE("reason %d", reason);
switch (reason)
{
case VCHIQ_MESSAGE_AVAILABLE:
{
mmal_worker_msg_header *msg = (mmal_worker_msg_header*)vchiq_header->data;
vcos_assert(msg->magic == MMAL_MAGIC);
if (msg->msgid == MMAL_WORKER_BUFFER_TO_HOST)
{
LOG_TRACE("buffer to host");
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)vchiq_header->data;
LOG_TRACE("len %d context %p", msg->buffer_header.length, msg->drvbuf.client_context);
vcos_assert(msg->drvbuf.client_context);
vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
/* If the buffer is referencing another, need to replicate it here
* in order to use the reference buffer's payload and ensure the
* reference is not released prematurely */
if (msg->has_reference)
mmal_buffer_header_replicate(msg->drvbuf.client_context->buffer,
msg->drvbuf_ref.client_context->buffer);
/* Sanity check the size of the transfer so we don't overrun our buffer */
if (!vcos_verify(msg->buffer_header.offset + msg->buffer_header.length <=
msg->drvbuf.client_context->buffer->alloc_size))
{
LOG_TRACE("buffer too small (%i, %i)",
msg->buffer_header.offset + msg->buffer_header.length,
msg->drvbuf.client_context->buffer->alloc_size);
msg->buffer_header.length = 0; /* FIXME: set a buffer flag to signal error */
msg->drvbuf.client_context->callback(msg);
vchiq_release_message(service, vchiq_header);
break;
}
/*To handle VC to HOST filled buffer callback of EOS buffer to receive in sync with data buffers*/
if (!msg->is_zero_copy &&
(msg->buffer_header.length != 0 ||
(msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS)))
{
/* a buffer full of data for us to process */
VCHIQ_STATUS_T vst = VCHIQ_SUCCESS;
LOG_TRACE("queue bulk rx: %p, %d", msg->drvbuf.client_context->buffer->data +
msg->buffer_header.offset, msg->buffer_header.length);
int len = msg->buffer_header.length;
len = (len+3) & (~3);
if (!len && (msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS))
{
len = 8;
}
if (!msg->payload_in_message)
{
/* buffer transferred using vchiq bulk xfer */
vst = vchiq_queue_bulk_receive(service,
msg->drvbuf.client_context->buffer->data + msg->buffer_header.offset,
len, vchiq_header);
if (vst != VCHIQ_SUCCESS)
{
LOG_TRACE("queue bulk rx len %d failed to start", msg->buffer_header.length);
msg->buffer_header.length = 0; /* FIXME: set a buffer flag to signal error */
msg->drvbuf.client_context->callback(msg);
vchiq_release_message(service, vchiq_header);
}
}
else if (msg->payload_in_message <= MMAL_VC_SHORT_DATA)
{
/* we have already received the buffer data in the message! */
MMAL_BUFFER_HEADER_T *dst = msg->drvbuf.client_context->buffer;
LOG_TRACE("short data: dst = %p, dst->data = %p, len %d short len %d", dst, dst? dst->data : 0, msg->buffer_header.length, msg->payload_in_message);
memcpy(dst->data, msg->short_data, msg->payload_in_message);
dst->offset = 0;
dst->length = msg->payload_in_message;
vchiq_release_message(service, vchiq_header);
msg->drvbuf.client_context->callback(msg);
}
else
{
/* impossible short data length */
LOG_ERROR("Message with invalid short payload length %d",
msg->payload_in_message);
vcos_assert(0);
}
}
else
{
/* Message received from videocore; the client_context should have
* been passed all the way through by videocore back to us, and will
* be picked up in the callback to complete the sequence.
*/
LOG_TRACE("doing cb (%p) context %p",
msg->drvbuf.client_context, msg->drvbuf.client_context ?
msg->drvbuf.client_context->callback : 0);
msg->drvbuf.client_context->callback(msg);
LOG_TRACE("done callback back to client");
vchiq_release_message(service, vchiq_header);
}
}
else if (msg->msgid == MMAL_WORKER_EVENT_TO_HOST)
{
mmal_vc_handle_event_msg(vchiq_header, service, context);
}
else
{
MMAL_WAITER_T *waiter = msg->u.waiter;
LOG_TRACE("waking up waiter at %p", waiter);
vcos_assert(waiter->inuse);
int len = vcos_min(waiter->destlen, vchiq_header->size);
waiter->destlen = len;
LOG_TRACE("copying payload @%p to %p len %d", waiter->dest, msg, len);
memcpy(waiter->dest, msg, len);
vchiq_release_message(service, vchiq_header);
vcos_semaphore_post(&waiter->sem);
}
}
break;
case VCHIQ_BULK_TRANSMIT_DONE:
{
/* nothing to do here, need to wait for the copro to tell us it
* has emptied the buffer before we can recycle it, otherwise we
* end up feeding the copro with buffers it cannot handle.
*/
#ifdef VCOS_LOGGING_ENABLED
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
#endif
LOG_TRACE("bulk tx done: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
}
break;
case VCHIQ_BULK_RECEIVE_DONE:
{
VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)context;
mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)header->data;
if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
{
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
msg->drvbuf.client_context->callback(msg);
LOG_TRACE("bulk rx done: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
}
else
{
mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)msg_hdr;
MMAL_PORT_T *port = mmal_vc_port_by_number(msg->client_component, msg->port_type, msg->port_num);
vcos_assert(port);
mmal_buffer_header_driver_data(msg->delayed_buffer)->
client_context->callback_event(port, msg->delayed_buffer);
LOG_DEBUG("event bulk rx done, length %d", msg->length);
}
vchiq_release_message(service, header);
}
break;
case VCHIQ_BULK_RECEIVE_ABORTED:
{
VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)context;
mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)header->data;
if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
{
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
LOG_TRACE("bulk rx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
msg->buffer_header.flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
msg->drvbuf.client_context->callback(msg);
}
else
{
mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)msg_hdr;
MMAL_PORT_T *port = mmal_vc_port_by_number(msg->client_component, msg->port_type, msg->port_num);
vcos_assert(port);
LOG_DEBUG("event bulk rx aborted");
msg->delayed_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
mmal_buffer_header_driver_data(msg->delayed_buffer)->
client_context->callback_event(port, msg->delayed_buffer);
}
vchiq_release_message(service, header);
}
break;
case VCHIQ_BULK_TRANSMIT_ABORTED:
{
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
LOG_INFO("bulk tx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
/* Nothing to do as the VC side will release the buffer and notify us of the error */
}
break;
default:
break;
}
return VCHIQ_SUCCESS;
}
/** Send a message and wait for a reply.
*
* @param client client to send message for
* @param msg_header message vchiq_header to send
* @param size length of message, including header
* @param msgid message id
* @param dest destination for reply
* @param destlen size of destination, updated with actual length
* @param send_dummy_bulk whether to send a dummy bulk transfer
*/
MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
mmal_worker_msg_header *msg_header,
size_t size,
uint32_t msgid,
void *dest,
size_t *destlen,
MMAL_BOOL_T send_dummy_bulk)
{
MMAL_STATUS_T ret;
MMAL_WAITER_T *waiter;
VCHIQ_STATUS_T vst;
VCHIQ_ELEMENT_T elems[] = {{msg_header, size}};
vcos_assert(size >= sizeof(mmal_worker_msg_header));
vcos_assert(dest);
if (!client->inited)
{
vcos_assert(0);
return MMAL_EINVAL;
}
if (send_dummy_bulk)
vcos_mutex_lock(&client->bulk_lock);
waiter = get_waiter(client);
msg_header->msgid = msgid;
msg_header->u.waiter = waiter;
msg_header->magic = MMAL_MAGIC;
waiter->dest = dest;
waiter->destlen = *destlen;
LOG_TRACE("wait %p, reply to %p", waiter, dest);
mmal_vc_use_internal(client);
vst = vchiq_queue_message(client->service, elems, 1);
if (vst != VCHIQ_SUCCESS)
{
ret = MMAL_EIO;
if (send_dummy_bulk)
vcos_mutex_unlock(&client->bulk_lock);
goto fail_msg;
}
if (send_dummy_bulk)
{
uint32_t data_size = 8;
/* The data is just some dummy bytes so it's fine for it to be static */
static uint8_t data[8];
vst = vchiq_queue_bulk_transmit(client->service, data, data_size, msg_header);
vcos_mutex_unlock(&client->bulk_lock);
if (!vcos_verify(vst == VCHIQ_SUCCESS))
{
LOG_ERROR("failed bulk transmit");
/* This really should not happen and if it does, things will go wrong as
* we've already queued the vchiq message above. */
vcos_assert(0);
ret = MMAL_EIO;
goto fail_msg;
}
}
/* now wait for the reply...
*
* FIXME: we could do with a timeout here. Need to be careful to cancel
* the semaphore on a timeout.
*/
/* coverity[lock] This semaphore isn't being used as a mutex */
vcos_semaphore_wait(&waiter->sem);
mmal_vc_release_internal(client);
LOG_TRACE("got reply (len %i/%i)", (int)*destlen, (int)waiter->destlen);
*destlen = waiter->destlen;
release_waiter(client, waiter);
return MMAL_SUCCESS;
fail_msg:
mmal_vc_release_internal(client);
release_waiter(client, waiter);
return ret;
}
/** Send a message and do not wait for a reply.
*
* @note
* This function should only be called from within a mmal component, so
* vchiq_use/release_service calls aren't required (dealt with at higher level).
*
* @param client client to send message for
* @param msg_header message header to send
* @param size length of message, including header
* @param msgid message id
*/
MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
mmal_worker_msg_header *msg_header, size_t size,
uint8_t *data, size_t data_size,
uint32_t msgid)
{
VCHIQ_STATUS_T vst;
VCHIQ_ELEMENT_T elems[] = {{msg_header, size}};
MMAL_BOOL_T using_bulk_transfer = (data_size != 0);
LOG_TRACE("len %d", data_size);
vcos_assert(size >= sizeof(mmal_worker_msg_header));
if (!client->inited)
{
vcos_assert(0);
return MMAL_EINVAL;
}
if (using_bulk_transfer)
vcos_mutex_lock(&client->bulk_lock);
msg_header->msgid = msgid;
msg_header->magic = MMAL_MAGIC;
vst = vchiq_queue_message(client->service, elems, 1);
if (vst != VCHIQ_SUCCESS)
{
if (using_bulk_transfer)
vcos_mutex_unlock(&client->bulk_lock);
LOG_ERROR("failed");
goto error;
}
if (using_bulk_transfer)
{
LOG_TRACE("bulk transmit: %p, %i", data, data_size);
data_size = (data_size + 3) & ~3;
vst = vchiq_queue_bulk_transmit(client->service, data, data_size, msg_header);
vcos_mutex_unlock(&client->bulk_lock);
if (!vcos_verify(vst == VCHIQ_SUCCESS))
{
LOG_ERROR("failed bulk transmit");
/* This really should not happen and if it does, things will go wrong as
* we've already queued the vchiq message above. */
vcos_assert(0);
goto error;
}
}
return MMAL_SUCCESS;
error:
return MMAL_EIO;
}
MMAL_STATUS_T mmal_vc_use(void)
{
MMAL_STATUS_T status = MMAL_ENOTCONN;
if(client.inited)
status = mmal_vc_use_internal(&client);
return status;
}
MMAL_STATUS_T mmal_vc_release(void)
{
MMAL_STATUS_T status = MMAL_ENOTCONN;
if(client.inited)
status = mmal_vc_release_internal(&client);
return status;
}
MMAL_STATUS_T mmal_vc_init(void)
{
VCHIQ_SERVICE_PARAMS_T vchiq_params;
MMAL_BOOL_T vchiq_initialised = 0, waitpool_initialised = 0;
MMAL_BOOL_T service_initialised = 0;
MMAL_STATUS_T status = MMAL_EIO;
VCHIQ_STATUS_T vchiq_status;
int count;
vcos_once(&once, init_once);
vcos_mutex_lock(&client.lock);
count = client.refcount++;
if (count > 0)
{
/* Already initialised so nothing to do */
vcos_mutex_unlock(&client.lock);
return MMAL_SUCCESS;
}
vcos_log_register("mmalipc", VCOS_LOG_CATEGORY);
/* Initialise a VCHIQ instance */
vchiq_status = vchiq_initialise(&mmal_vchiq_instance);
if (vchiq_status != VCHIQ_SUCCESS)
{
LOG_ERROR("failed to initialise vchiq");
status = MMAL_EIO;
goto error;
}
vchiq_initialised = 1;
vchiq_status = vchiq_connect(mmal_vchiq_instance);
if (vchiq_status != VCHIQ_SUCCESS)
{
LOG_ERROR("failed to connect to vchiq");
status = MMAL_EIO;
goto error;
}
memset(&vchiq_params,0,sizeof(vchiq_params));
vchiq_params.fourcc = MMAL_CONTROL_FOURCC();
vchiq_params.callback = mmal_vc_vchiq_callback;
vchiq_params.userdata = &client;
vchiq_params.version = WORKER_VER_MAJOR;
vchiq_params.version_min = WORKER_VER_MINIMUM;
vchiq_status = vchiq_open_service(mmal_vchiq_instance, &vchiq_params, &client.service);
if (vchiq_status != VCHIQ_SUCCESS)
{
LOG_ERROR("could not open vchiq service");
status = MMAL_EIO;
goto error;
}
client.usecount = 1; /* usecount set to 1 by the open call. */
service_initialised = 1;
status = create_waitpool(&client.waitpool);
if (status != MMAL_SUCCESS)
{
LOG_ERROR("could not create wait pool");
goto error;
}
waitpool_initialised = 1;
if (vcos_mutex_create(&client.bulk_lock, "mmal client bulk lock") != VCOS_SUCCESS)
{
LOG_ERROR("could not create bulk lock");
status = MMAL_ENOSPC;
goto error;
}
client.inited = 1;
vcos_mutex_unlock(&client.lock);
/* assume we're not using VC immediately. Do this outside the lock */
mmal_vc_release();
return MMAL_SUCCESS;
error:
if (waitpool_initialised)
destroy_waitpool(&client.waitpool);
if (service_initialised)
{
client.usecount = 0;
vchiq_close_service(client.service);
}
if (vchiq_initialised)
vchiq_shutdown(mmal_vchiq_instance);
vcos_log_unregister(VCOS_LOG_CATEGORY);
client.refcount--;
vcos_mutex_unlock(&client.lock);
return status;
}
void mmal_vc_deinit(void)
{
int count;
vcos_mutex_lock(&client.lock);
count = --client.refcount;
if (count != 0)
{
/* Still in use so don't do anything */
vcos_mutex_unlock(&client.lock);
return;
}
vcos_mutex_delete(&client.bulk_lock);
destroy_waitpool(&client.waitpool);
vchiq_close_service(client.service);
vchiq_shutdown(mmal_vchiq_instance);
vcos_log_unregister(VCOS_LOG_CATEGORY);
client.service = VCHIQ_SERVICE_HANDLE_INVALID;
client.inited = 0;
vcos_mutex_unlock(&client.lock);
}
MMAL_CLIENT_T *mmal_vc_get_client(void)
{
return &client;
}
@@ -0,0 +1,80 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMAL_VC_CLIENT_H
#define MMAL_VC_CLIENT_H
/** @file mmal_vc_client_priv.h
*
* Internal API for vchiq_arm MMAL client.
*/
struct MMAL_CLIENT_T;
typedef struct MMAL_CLIENT_T MMAL_CLIENT_T;
void mmal_vc_client_init(void);
/** Hold the context required when sending a buffer to the copro.
*/
typedef struct MMAL_VC_CLIENT_BUFFER_CONTEXT_T
{
uint32_t magic;
/** Called when VC is done with the buffer */
void (*callback)(struct mmal_worker_buffer_from_host *);
/** Called when VC sends an event */
void (*callback_event)(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *event);
/** The port this buffer was sent to */
MMAL_PORT_T *port;
/** The original buffer from the host. */
MMAL_BUFFER_HEADER_T *buffer;
/** The actual message sent to the host */
struct mmal_worker_buffer_from_host msg;
} MMAL_VC_CLIENT_BUFFER_CONTEXT_T;
MMAL_CLIENT_T *mmal_vc_get_client(void);
MMAL_STATUS_T mmal_vc_sendwait_message(MMAL_CLIENT_T *client,
mmal_worker_msg_header *header,
size_t size,
uint32_t msgid,
void *dest,
size_t *destlen,
MMAL_BOOL_T send_dummy_bulk);
MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
mmal_worker_msg_header *header, size_t size,
uint8_t *data, size_t data_size,
uint32_t msgid);
#endif
@@ -0,0 +1,160 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* Multi-Media Abstraction Layer API
*/
#ifndef MMAL_VC_DBGLOG_H
#define MMAL_VC_DBGLOG_H
#include "interface/mmal/mmal.h"
#include "mmal_vc_msgs.h"
/* Debug log for MMAL messages going past */
typedef enum {
MMAL_DBG_MSG,
MMAL_DBG_BULK,
MMAL_DBG_OPENED,
MMAL_DBG_CLOSED,
MMAL_DBG_BULK_ACK,
MMAL_DBG_BULK_TX,
MMAL_DBG_BULK_RX,
} MMAL_DBG_EVENT_TYPE_T;
/** Debug log data. */
typedef union
{
struct {
mmal_worker_msg_header header;
uint32_t msg[4]; /**< Snarf this much message data */
} msg;
struct {
uint32_t len; /**< Length of transfer */
uint32_t data[4]; /**< Snarf this much payload data */
} bulk;
uint32_t uint;
uint32_t arr[15]; /** Pad complete DBG_ENTRY_T to 64 bytes per line */
} MMAL_DBG_DATA_T;
/** One entry in the debug log */
typedef struct
{
uint32_t time;
uint32_t event_type;
MMAL_DBG_DATA_T u;
} MMAL_DBG_ENTRY_T;
#define MMAL_DBG_ENTRIES_MAX 64
#define MMAL_DBG_ENTRIES_MASK (MMAL_DBG_ENTRIES_MAX-1)
#define MMAL_DBG_VERSION 1
/** The debug log itself. This is currently allocated in uncached
* memory so that the ARM can easily access it.
*/
typedef struct
{
uint32_t version;
uint32_t magic;
uint32_t num_entries;
uint32_t index;
uint32_t size;
uint32_t elemsize;
uint32_t pad[2];
MMAL_DBG_ENTRY_T entries[MMAL_DBG_ENTRIES_MAX];
} MMAL_DBG_LOG_T;
extern VCOS_MUTEX_T mmal_dbg_lock;
extern MMAL_DBG_LOG_T *mmal_dbg_log;
/** Get the next event and hold the lock. Should only be
* accessed by the macros below.
*/
static inline MMAL_DBG_ENTRY_T *mmal_log_lock_event(MMAL_DBG_EVENT_TYPE_T event_type ) {
uint32_t index;
MMAL_DBG_ENTRY_T *entry;
vcos_mutex_lock(&mmal_dbg_lock);
index = mmal_dbg_log->index++;
entry = mmal_dbg_log->entries + (index & MMAL_DBG_ENTRIES_MASK);
entry->time = vcos_getmicrosecs();
entry->event_type = event_type;
return entry;
}
/** Release the lock. Should only be accessed by the macros below. */
static inline void mmal_log_unlock_event(void) {
vcos_mutex_unlock(&mmal_dbg_lock);
}
/** Initialise the logging module. */
MMAL_STATUS_T mmal_vc_dbglog_init(void);
/** Deinitialise the logging module. */
void mmal_vc_dbglog_deinit(void);
/** Put an entry into the log.
*
* @param short_type type of event, e.g. OPENED
* @param name union entry name, e.g. uint.
* @param event event data
*/
#define MMAL_LOG_EVENT(short_type, name, value) {\
MMAL_DBG_ENTRY_T *entry = mmal_log_lock_event(MMAL_DBG_##short_type); \
entry->u.name = value;\
mmal_log_unlock_event(); \
}
/** Log an uint event (i.e. all just the fact that it occurred */
#define LOG_EVENT_UINT(short_type,u) MMAL_LOG_EVENT(short_type, uint, u)
#define LOG_EVENT_OPENED() LOG_EVENT_UINT(OPENED,0)
#define LOG_EVENT_CLOSED() LOG_EVENT_UINT(CLOSED,0)
#define LOG_EVENT_BULK_ACK(reason) LOG_EVENT_UINT(BULK_ACK,reason)
/** Log a message. Grabs part of the message data.
*/
#define LOG_EVENT_MSG(header) {\
MMAL_DBG_ENTRY_T *entry = mmal_log_lock_event(MMAL_DBG_MSG); \
memcpy(&entry->u.msg, header, sizeof(entry->u.msg)); \
mmal_log_unlock_event(); \
}
/** Log bulk data. For now, do not grab the actual data itself */
#define LOG_EVENT_BULK(type, len, data) {\
MMAL_DBG_ENTRY_T *entry = mmal_log_lock_event(MMAL_DBG_BULK_##type); \
entry->u.bulk.len = len; \
mmal_log_unlock_event(); \
}
#endif
@@ -0,0 +1,843 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "interface/mmal/mmal.h"
#include "interface/mmal/util/mmal_util.h"
#include "mmal_vc_api.h"
#include <stdio.h>
#include <stddef.h>
#include <sys/time.h>
#include <limits.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
#include "host_applications/linux/libs/debug_sym/debug_sym.h"
#include "mmal_vc_msgnames.h"
#include "mmal_vc_dbglog.h"
#include "vchiq.h"
#include "interface/vmcs_host/vc_imageconv_defs.h"
/** Command-line diagnostics at the VC MMAL API level.
*
* @fixme: how does this work with multiple videocores?
*/
struct cmd {
const char *name;
int (*pfn)(int argc, const char **argv);
const char *descr;
int flags;
};
#define CONNECT 1
static int do_commands(int argc, const char **argv);
static int do_version(int argc, const char **argv);
static int do_stats(int argc, const char **argv);
static int do_usage(int argc, const char **argv);
static int do_create(int argc, const char **argv);
static int do_eventlog(int argc, const char **argv);
static int do_components(int argc, const char **argv);
static int do_mmal_stats(int argc, const char **argv);
static int do_imageconv_stats(int argc, const char **argv);
static int do_autosusptest(int argc, const char **argv);
static int do_camerainfo(int argc, const char **argv);
static int do_host_log(int argc, const char **argv);
static int do_host_log_write(int argc, const char **argv);
static struct cmd cmds[] = {
{ "help", do_usage, "give this help", 0 },
{ "version", do_version, "report VC MMAL server version number", CONNECT },
{ "stats", do_stats, "report VC MMAL statistics", CONNECT },
{ "reset", do_stats, "reset VC MMAL statistics", CONNECT },
{ "commands", do_commands, "list available commands", CONNECT },
{ "create", do_create, "create a component", CONNECT },
{ "eventlog", do_eventlog, "display event log", 0 },
{ "components", do_components, "[update] list components", 0 },
{ "mmal-stats", do_mmal_stats, "list mmal core stats", CONNECT },
{ "ic-stats", do_imageconv_stats, "[reset] list imageconv stats", CONNECT },
{ "autosusp", do_autosusptest, "test out auto-suspend/resume", CONNECT },
{ "camerainfo", do_camerainfo, "get camera info", CONNECT },
{ "host_log", do_host_log, "dumps the MMAL VC log", CONNECT },
{ "host_log_write", do_host_log_write, "appends a message to the MMAL VC log of host messages", CONNECT },
{ NULL, NULL, NULL, 0},
};
static void do_connect(void)
{
/* this command needs a vchiq connection */
MMAL_STATUS_T st;
if ((st = mmal_vc_init()) != MMAL_SUCCESS)
{
fprintf(stderr, "failed to initialize mmal vc library (%i:%s)\n",
st, mmal_status_to_string(st));
exit(1);
}
}
int main(int argc, const char **argv)
{
int i;
if (argc < 2)
{
do_usage(argc, argv);
exit(1);
}
for (i = 0; cmds[i].name; i++)
{
if (strcasecmp(cmds[i].name, argv[1]) == 0)
{
int rc;
if (cmds[i].flags & CONNECT)
{
do_connect();
}
rc = cmds[i].pfn(argc, argv);
if (cmds[i].flags & CONNECT)
mmal_vc_deinit();
return rc;
}
}
fprintf(stderr,"unknown command %s\n", argv[1]);
return -1;
}
static int do_commands(int argc, const char **argv)
{
int i = 0;
(void)argc; (void)argv;
while (cmds[i].name)
{
printf("%-20s %s\n", cmds[i].name, cmds[i].descr);
i++;
}
return 0;
}
static int do_create(int argc, const char **argv)
{
MMAL_COMPONENT_T *comp;
MMAL_STATUS_T st;
if (argc != 3)
{
printf("usage: mmal-vc-diag create <name>\n");
printf(" e.g. vc.camera\n");
exit(1);
}
st = mmal_component_create(argv[2], &comp);
if (comp)
printf("Created component\n");
else
printf("Failed to create %s: %d\n", argv[2], st);
return 0;
}
static int do_version(int argc, const char **argv)
{
uint32_t maj = UINT_MAX, min = UINT_MAX, minimum;
MMAL_STATUS_T st = mmal_vc_get_version(&maj, &min, &minimum);
(void)argc; (void)argv;
if (st == MMAL_SUCCESS)
{
printf("version %d.%02d (min %d)\n", maj, min, minimum);
return 0;
}
else
{
fprintf(stderr, "error getting version (%i:%s)\n", st, mmal_status_to_string(st));
return -1;
}
}
#define STATS_FIELD(x) { #x, offsetof(MMAL_VC_STATS_T, x) }
static struct {
const char *name;
unsigned offset;
} stats_fields [] = {
STATS_FIELD(buffers.rx),
STATS_FIELD(buffers.rx_zero_copy),
STATS_FIELD(buffers.rx_empty),
STATS_FIELD(buffers.rx_fails),
STATS_FIELD(buffers.tx),
STATS_FIELD(buffers.tx_zero_copy),
STATS_FIELD(buffers.tx_empty),
STATS_FIELD(buffers.tx_fails),
STATS_FIELD(buffers.tx_short_msg),
STATS_FIELD(buffers.rx_short_msg),
STATS_FIELD(service.created),
STATS_FIELD(service.pending_destroy),
STATS_FIELD(service.destroyed),
STATS_FIELD(service.failures),
STATS_FIELD(commands.bad_messages),
STATS_FIELD(commands.executed),
STATS_FIELD(commands.failed),
STATS_FIELD(commands.replies),
STATS_FIELD(commands.reply_fails),
STATS_FIELD(events.tx),
STATS_FIELD(events.tx_fails),
STATS_FIELD(worker.enqueued_messages),
STATS_FIELD(worker.dequeued_messages),
STATS_FIELD(worker.max_parameter_set_delay),
STATS_FIELD(worker.max_messages_waiting)
};
static int do_stats(int argc, const char **argv)
{
MMAL_VC_STATS_T stats;
int reset_stats = strcasecmp(argv[1], "reset") == 0;
MMAL_STATUS_T st = mmal_vc_get_stats(&stats, reset_stats);
int ret;
(void)argc; (void)argv;
if (st != MMAL_SUCCESS)
{
fprintf(stderr, "error getting status (%i,%s)\n", st, mmal_status_to_string(st));
ret = -1;
}
else
{
unsigned i;
uint32_t *ptr = (uint32_t*)&stats;
for (i=0; i<vcos_countof(stats_fields); i++)
{
printf("%-32s: %u\n", stats_fields[i].name, ptr[stats_fields[i].offset/sizeof(uint32_t)]);
}
ret = 0;
}
return ret;
}
static int do_usage(int argc, const char **argv)
{
const char *last_slash = strrchr(argv[0], '/');
const char *progname = last_slash ? last_slash+1:argv[0];
(void)argc;
printf("usage: %s [command [args]]\n", progname);
printf(" %s commands - list available commands\n", progname);
return 0;
}
/*
* Print out the event log
*/
struct event_handler
{
MMAL_DBG_EVENT_TYPE_T type;
void (*handler)(MMAL_DBG_ENTRY_T *entry, char *, size_t);
};
static void on_openclose(MMAL_DBG_ENTRY_T *entry,
char *buf,
size_t buflen)
{
switch (entry->event_type) {
case MMAL_DBG_OPENED: snprintf(buf,buflen,"opened"); break;
case MMAL_DBG_CLOSED: snprintf(buf,buflen,"closed"); break;
default: break;
}
}
static void on_bulk_ack(MMAL_DBG_ENTRY_T *entry,
char *buf,
size_t buflen)
{
switch (entry->u.uint)
{
case VCHIQ_BULK_RECEIVE_ABORTED: snprintf(buf,buflen,"vchiq bulk rx abort"); break;
case VCHIQ_BULK_TRANSMIT_ABORTED: snprintf(buf,buflen,"vchiq bulk tx abort"); break;
case VCHIQ_BULK_TRANSMIT_DONE: snprintf(buf,buflen,"vchiq bulk tx done"); break;
case VCHIQ_BULK_RECEIVE_DONE: snprintf(buf,buflen,"vchiq bulk rx done"); break;
default: snprintf(buf,buflen,"vchiq unknown reason %d", entry->u.uint); break;
}
}
static void on_msg(MMAL_DBG_ENTRY_T *entry,
char *buf,
size_t buflen)
{
uint32_t id = entry->u.msg.header.msgid;
snprintf(buf,buflen,"msgid %d (%s)", id, mmal_msgname(id));
}
static void on_bulk(MMAL_DBG_ENTRY_T *entry,
char *buf,
size_t buflen)
{
const char *name = entry->event_type == MMAL_DBG_BULK_TX ? "tx" : "rx";
snprintf(buf,buflen,"bulk %s len %d", name, entry->u.bulk.len);
}
static struct event_handler handlers[] = {
{ MMAL_DBG_OPENED, on_openclose },
{ MMAL_DBG_CLOSED, on_openclose },
{ MMAL_DBG_BULK_ACK, on_bulk_ack },
{ MMAL_DBG_MSG, on_msg },
{ MMAL_DBG_BULK_TX, on_bulk },
{ MMAL_DBG_BULK_RX, on_bulk },
};
static int n_handlers = sizeof(handlers)/sizeof(handlers[0]);
static void print_mmal_event_log(VC_MEM_ACCESS_HANDLE_T vc, MMAL_DBG_LOG_T *log)
{
uint32_t i;
uint32_t n = vcos_min(log->num_entries, log->index);
uint32_t mask = log->num_entries-1;
uint32_t start = log->index < log->num_entries ?
0 : log->index & mask;
uint32_t last_t = 0;
(void)vc;
for (i=0; i<n; i++)
{
MMAL_DBG_ENTRY_T *e = &log->entries[(start+i) & mask];
char buf[256];
int j;
uint32_t t = e->time;
printf("[%08u]: ", t-last_t);
last_t = t;
for (j=0; j<n_handlers; j++)
{
if (handlers[j].type == e->event_type)
{
handlers[j].handler(e, buf, sizeof(buf));
printf("%s\n", buf);
break;
}
}
if (j == n_handlers )
printf("Unknown event type %d\n", e->event_type);
}
}
static int do_eventlog(int argc, const char **argv)
{
VC_MEM_ACCESS_HANDLE_T vc;
VC_MEM_ADDR_T addr; /** The address of the pointer to the log */
size_t size;
VC_MEM_ADDR_T logaddr; /** The address of the log itself */
MMAL_DBG_LOG_T log;
(void)argc; (void)argv;
int rc;
if ((rc = OpenVideoCoreMemory(&vc)) < 0)
{
fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
return -1;
}
if (!LookupVideoCoreSymbol(vc, "mmal_dbg_log", &addr, &size))
{
fprintf(stderr,"Could not get MMAL log address\n");
goto fail;
}
if (!ReadVideoCoreUInt32(vc, &logaddr, addr))
{
fprintf(stderr,"Could not read MMAL log pointer at address 0x%x\n",
addr);
goto fail;
}
if (!ReadVideoCoreMemory(vc, &log, logaddr, sizeof(log)))
{
fprintf(stderr,"Could not read MMAL log at address 0x%x\n",
logaddr);
goto fail;
}
if (log.magic != MMAL_MAGIC)
{
fprintf(stderr,"Bad magic 0x%08x in log at 0x%x\n", log.magic, logaddr);
goto fail;
}
if (log.size != sizeof(log))
{
fprintf(stderr,"MMAL Log size mismatch (got %d, expected %d)\n",
log.size, sizeof(log));
goto fail;
}
if (log.elemsize != sizeof(MMAL_DBG_ENTRY_T))
{
fprintf(stderr,"MMAL log element size mismatch (got %d, expected %d)\n",
log.elemsize, sizeof(MMAL_DBG_ENTRY_T));
goto fail;
}
printf("reading MMAL log at 0x%x version %d magic %x\n",
logaddr, log.version, log.magic);
printf("%d events, %d entries each size %d\n", log.index, log.num_entries,
log.elemsize);
print_mmal_event_log(vc, &log);
CloseVideoCoreMemory(vc);
return 0;
fail:
CloseVideoCoreMemory(vc);
return -1;
}
static int print_component_stats(const MMAL_VC_STATS_T *stats)
{
size_t i;
if (stats->components.list_size > 64)
{
fprintf(stderr,"component array looks corrupt (list size %d\n",
stats->components.list_size);
goto fail;
}
printf("%d created, %d destroyed (%d destroying), %d create failures\n",
stats->components.created,
stats->components.destroyed,
stats->components.destroying,
stats->components.failed);
for (i=0; i < stats->components.list_size; i++)
{
const struct MMAL_VC_COMP_STATS_T *cs = stats->components.component_list+i;
const char *state;
/* coverity[overrun-local] */
if (cs->state != MMAL_STATS_COMP_IDLE)
{
switch (cs->state)
{
case MMAL_STATS_COMP_CREATED: state = "created"; break;
case MMAL_STATS_COMP_DESTROYING: state = "destroying"; break;
case MMAL_STATS_COMP_DESTROYED: state = "destroyed"; break;
default: state = "corrupt"; break;
}
printf("%-32s: %s: pid %d address %p pool mem alloc size %d\n",
cs->name, state, cs->pid, cs->comp, cs->pool_mem_alloc_size);
}
}
return 0;
fail:
return -1;
}
static int do_components(int argc, const char **argv)
{
VC_MEM_ACCESS_HANDLE_T vc;
VC_MEM_ADDR_T addr, statsaddr;
size_t size;
MMAL_VC_STATS_T stats;
int rc;
if (argc > 2 && (strcasecmp(argv[2], "update") == 0))
{
MMAL_STATUS_T status;
do_connect();
status = mmal_vc_get_stats(&stats, 0);
if (status != MMAL_SUCCESS)
{
fprintf(stderr, "Failed to update MMAL stats. error %s",
mmal_status_to_string(status));
return -1;
}
}
else
{
if ((rc = OpenVideoCoreMemory(&vc)) < 0)
{
fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
return -1;
}
if (!LookupVideoCoreSymbol(vc, "mmal_vc_stats", &addr, &size))
{
fprintf(stderr,"Could not get MMAL stats address\n");
goto fail;
}
if (!ReadVideoCoreUInt32(vc, &statsaddr, addr))
{
fprintf(stderr,"Could not read MMAL stats pointer at address 0x%x\n",
addr);
goto fail;
}
if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
{
fprintf(stderr,"Could not read MMAL stats at address 0x%x\n", addr);
goto fail;
}
CloseVideoCoreMemory(vc);
}
rc = print_component_stats(&stats);
return rc;
fail:
CloseVideoCoreMemory(vc);
return -1;
}
static int do_mmal_stats(int argc, const char **argv)
{
unsigned comp_index = 0;
MMAL_BOOL_T more_ports = MMAL_TRUE, reset = MMAL_FALSE;
unsigned port_index = 0;
MMAL_PORT_TYPE_T type = MMAL_PORT_TYPE_INPUT;
if (argc >= 3)
reset = strcasecmp(argv[2], "reset") == 0;
printf("component\t\tport\t\tbuffers\t\tfps\tdelay\n");
while (more_ports)
{
int dir;
const char *dirnames[] = {"rx","tx"};
MMAL_STATS_RESULT_T result;
for (dir = MMAL_CORE_STATS_RX; dir <= MMAL_CORE_STATS_TX; dir++)
{
double framerate;
MMAL_CORE_STATISTICS_T stats;
char name[32];
MMAL_STATUS_T status = mmal_vc_get_core_stats(&stats,
&result,
name, sizeof(name),
type,
comp_index,
port_index,
dir,
reset);
if (status != MMAL_SUCCESS)
{
fprintf(stderr, "could not get core stats: %s\n",
mmal_status_to_string(status));
exit(1);
}
if (result == MMAL_STATS_FOUND)
{
if (stats.first_buffer_time == stats.last_buffer_time)
framerate = 0;
else
framerate = 1.0e6*(1+stats.buffer_count)/(stats.last_buffer_time-stats.first_buffer_time);
printf("%-20s\t%d [%s]%2s\t%-10d\t%4.1f\t%d\n",
name, port_index,
type == MMAL_PORT_TYPE_INPUT ? "in " : "out",
dirnames[dir],
stats.buffer_count, framerate, stats.max_delay);
}
}
switch (result)
{
case MMAL_STATS_FOUND:
port_index++;
break;
case MMAL_STATS_COMPONENT_NOT_FOUND:
more_ports = MMAL_FALSE;
break;
case MMAL_STATS_PORT_NOT_FOUND:
port_index = 0;
if (type == MMAL_PORT_TYPE_INPUT)
{
type = MMAL_PORT_TYPE_OUTPUT;
}
else
{
type = MMAL_PORT_TYPE_INPUT;
comp_index++;
}
break;
default:
fprintf(stderr, "bad result from query: %d\n", result);
vcos_assert(0);
exit(1);
}
}
return 0;
}
static int do_imageconv_stats(int argc, const char **argv)
{
VC_MEM_ACCESS_HANDLE_T vc;
VC_MEM_ADDR_T addr, statsaddr;
size_t size;
IMAGECONV_STATS_T stats;
long convert_time;
double frame_rate;
int rc;
int reset_stats = 0;
if (argc > 2)
reset_stats = strcasecmp(argv[2], "reset") == 0;
if ((rc = OpenVideoCoreMemory(&vc)) < 0)
{
fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
return -1;
}
if (!LookupVideoCoreSymbol(vc, "imageconv_stats", &addr, &size))
{
fprintf(stderr,"Could not get imageconv stats address\n");
goto fail;
}
if (!ReadVideoCoreUInt32(vc, &statsaddr, addr))
{
fprintf(stderr, "Could not read imageconv stats address\n");
goto fail;
}
if (reset_stats)
{
memset(&stats, 0, sizeof(stats));
stats.magic = IMAGECONV_STATS_MAGIC;
if (!WriteVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
{
fprintf(stderr, "Could not write stats at 0x%x\n", statsaddr);
goto fail;
}
}
if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
{
fprintf(stderr, "Could not read stats at 0x%x\n", statsaddr);
goto fail;
}
if (stats.magic != IMAGECONV_STATS_MAGIC)
{
fprintf(stderr, "Bad magic 0x%x\n", stats.magic);
goto fail;
}
if (stats.conversions)
convert_time = stats.time_spent / stats.conversions;
else
convert_time = 0;
if (stats.conversions)
frame_rate = 1000000.0 * stats.conversions /
(stats.last_image_ts - stats.first_image_ts);
else
frame_rate = 0;
printf("%-25s:\t%d\n", "conversions", stats.conversions);
printf("%-25s:\t%d\n", "size requests", stats.size_requests);
printf("%-25s:\t%d\n", "max vrf delay", stats.max_vrf_delay);
printf("%-25s:\t%d\n", "vrf wait time", stats.vrf_wait_time);
printf("%-25s:\t%d\n", "duplicate conversions", stats.duplicate_conversions);
printf("%-25s:\t%d\n", "failures", stats.failures);
printf("%-25s:\t%ld\n", "convert time / image (us)", convert_time);
printf("%-25s:\t%.1f\n", "client frame_rate", frame_rate);
printf("%-25s:\t%d us\n", "max delay to consume", stats.max_delay);
CloseVideoCoreMemory(vc);
return 0;
fail:
CloseVideoCoreMemory(vc);
return -1;
}
/* Autosuspend test. Create a component, but kill process
* shortly after startup.
*/
static int autosusp_signal;
static void autosusp_timeout_handler(int cause, siginfo_t *how, void *ucontext)
{
(void)how; (void)ucontext; (void)cause;
printf("Sending signal %d\n", autosusp_signal);
kill(getpid(), autosusp_signal);
}
static int do_autosusptest(int argc, const char **argv)
{
long timeout;
struct timeval interval;
MMAL_STATUS_T status;
if (argc != 4)
{
printf("usage: %s autosusp <timeout-ms> <signal>\n",
argv[0]);
printf(" e.g. 650 9\n");
exit(1);
}
timeout = 1000 * atoi(argv[2]);
autosusp_signal = atoi(argv[3]);
if ((status=mmal_vc_use()) != MMAL_SUCCESS)
{
fprintf(stderr,"mmal_vc_use failed: %d\n", status);
exit(1);
}
/* install a signal handler for the alarm */
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = autosusp_timeout_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGALRM, &sa, 0))
{
perror("sigaction");
exit(1);
}
/* when to expire */
interval.tv_sec = timeout / 1000000;
interval.tv_usec = timeout % 1000000;
struct itimerval alarm_spec = {
.it_interval = {0,0},
.it_value = interval
};
int rc = setitimer(ITIMER_REAL, &alarm_spec, NULL);
if (rc < 0)
{
perror("setitimer failed");
exit(1);
}
usleep(timeout + 1000000);
printf("%s: not killed by timer\n", argv[0]);
mmal_vc_release();
return 0;
}
static int do_camerainfo(int argc, const char **argv)
{
MMAL_COMPONENT_T *comp;
MMAL_STATUS_T st;
MMAL_PARAMETER_CAMERA_INFO_T mmal_camera_config_info;
unsigned i;
(void)argc;
(void)argv;
st = mmal_component_create("vc.camera_info", &comp);
if (st != MMAL_SUCCESS)
{
fprintf(stderr, "Failed to create camera_info: %d\n", st);
exit(1);
}
mmal_camera_config_info.hdr.id = MMAL_PARAMETER_CAMERA_INFO;
mmal_camera_config_info.hdr.size = sizeof(mmal_camera_config_info);
st = mmal_port_parameter_get(comp->control, &mmal_camera_config_info.hdr);
if (st != MMAL_SUCCESS)
{
fprintf(stderr, "%s: get param failed:%d", __FUNCTION__, st);
exit(1);
}
printf("cameras : %d\n", mmal_camera_config_info.num_cameras);
printf("flashes : %d\n", mmal_camera_config_info.num_flashes);
for (i=0; i<mmal_camera_config_info.num_cameras; i++)
{
printf("camera %u : port %u: %u x %u lens %s\n",
i,
mmal_camera_config_info.cameras[i].port_id,
mmal_camera_config_info.cameras[i].max_width,
mmal_camera_config_info.cameras[i].max_height,
mmal_camera_config_info.cameras[i].lens_present ? "present" : "absent");
}
for (i=0; i<mmal_camera_config_info.num_flashes; i++)
{
const char *flash_type;
switch (mmal_camera_config_info.flashes[i].flash_type)
{
case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON:
flash_type = "Xenon";
break;
case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED:
flash_type = "LED";
break;
case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER:
flash_type = "Other";
break;
default:
flash_type = "invalid";
}
printf("flash %u : flash type %s\n", i, flash_type);
}
mmal_component_destroy(comp);
return 0;
}
static int do_host_log(int argc, const char **argv)
{
VC_MEM_ACCESS_HANDLE_T vc;
VC_MEM_ADDR_T log_addr;
MMAL_VC_HOST_LOG_T log;
const char *msg = &log.buffer[0];
const char *log_end = &log.buffer[sizeof(log.buffer)];
int rc;
(void) argc;
(void) argv;
if ((rc = OpenVideoCoreMemory(&vc)) < 0)
{
fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
return -1;
}
if (!ReadVideoCoreUInt32BySymbol(vc, "mmal_host_log", &log_addr))
{
fprintf(stderr, "Could not read mmal_host_log address\n");
goto fail;
}
if (!ReadVideoCoreMemory(vc, &log, log_addr, sizeof(log)))
{
fprintf(stderr, "Could not read log at 0x%x\n", log_addr);
goto fail;
}
while (msg < log_end)
{
if (*msg)
msg += printf("%s", msg);
/* Skip multiple null characters */
while (msg < log_end && *msg == 0) ++msg;
}
CloseVideoCoreMemory(vc);
return 0;
fail:
CloseVideoCoreMemory(vc);
return -1;
}
static int do_host_log_write(int argc, const char **argv)
{
if (argc > 2)
mmal_vc_host_log(argv[2]);
return 0;
}
@@ -0,0 +1,77 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mmal_vc_msgnames.h"
#include "mmal_vc_msgs.h"
/** Convert a message id to a name.
*/
const char *mmal_msgname(uint32_t id)
{
#define MSGNAME(x) { MMAL_WORKER_##x, #x }
static struct {
uint32_t id;
const char *name;
} msgnames[] = {
MSGNAME(QUIT),
MSGNAME(SERVICE_CLOSED),
MSGNAME(GET_VERSION),
MSGNAME(COMPONENT_CREATE),
MSGNAME(COMPONENT_DESTROY),
MSGNAME(COMPONENT_ENABLE),
MSGNAME(COMPONENT_DISABLE),
MSGNAME(PORT_INFO_GET),
MSGNAME(PORT_INFO_SET),
MSGNAME(PORT_ACTION),
MSGNAME(BUFFER_FROM_HOST),
MSGNAME(BUFFER_TO_HOST),
MSGNAME(GET_STATS),
MSGNAME(PORT_PARAMETER_SET),
MSGNAME(PORT_PARAMETER_GET),
MSGNAME(EVENT_TO_HOST),
MSGNAME(GET_CORE_STATS_FOR_PORT),
MSGNAME(OPAQUE_ALLOCATOR),
MSGNAME(CONSUME_MEM),
MSGNAME(LMK),
MSGNAME(OPAQUE_ALLOCATOR_DESC),
MSGNAME(DRM_GET_LHS32),
MSGNAME(DRM_GET_TIME),
MSGNAME(BUFFER_FROM_HOST_ZEROLEN),
MSGNAME(PORT_FLUSH),
MSGNAME(HOST_LOG),
{ 0, NULL },
};
vcos_static_assert(sizeof(msgnames)/sizeof(msgnames[0]) == MMAL_WORKER_MSG_LAST);
int i = 0;
while (msgnames[i].name)
{
if (msgnames[i].id == id)
return msgnames[i].name;
i++;
}
return "unknown-message";
}
@@ -0,0 +1,37 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMAL_VC_MSGNAMES_H
#define MMAL_VC_MSGNAMES_H
#include "interface/vcos/vcos.h"
/** Convert a message id to a name.
*/
const char *mmal_msgname(uint32_t id);
#endif
@@ -0,0 +1,525 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMAL_VC_MSGS_H
#define MMAL_VC_MSGS_H
/** @file mmal_vc_msgs.h
*
* Private message definitions, defining the message API between
* the host and VideoCore.
*/
#include "interface/vcos/vcos.h"
#include "interface/mmal/mmal.h"
#include "mmal_vc_api.h"
#define MMAL_CONTROL_FOURCC() VCHIQ_MAKE_FOURCC('m','m','a','l')
/* Major version indicates binary backwards compatiblity */
#define WORKER_VER_MAJOR 16
#define WORKER_VER_MINIMUM 10
/* Minor version is not used normally.
*/
#define WORKER_VER_MINOR 1
#ifndef WORKER_VER_MINIMUM
#endif
#define VIDEOCORE_PREFIX "vc"
#define MMAL_MAX_PORTS 8 /**< Max ports per component */
#define MMAL_WORKER_MAX_MSG_LEN 512
#define MMAL_VC_CORE_STATS_NAME_MAX 32 /**< Length of the name in the core stats message */
/** A MMAL_CONTROL_SERVICE_T gets space for a single message. This
* is the space allocated for these messages.
*/
#define MMAL_WORKER_MSG_LEN 28
/** Maximum size of the format extradata.
* FIXME: should probably be made bigger and maybe be passed separately from the info.
*/
#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
/** Size of space reserved in a buffer message for short messages.
*/
#define MMAL_VC_SHORT_DATA 128
/** Message ids sent to worker thread.
*/
/* Please update the array in mmal_vc_msgnames.c if this is updated.
*/
typedef enum {
MMAL_WORKER_QUIT = 1,
MMAL_WORKER_SERVICE_CLOSED,
MMAL_WORKER_GET_VERSION,
MMAL_WORKER_COMPONENT_CREATE,
MMAL_WORKER_COMPONENT_DESTROY,
MMAL_WORKER_COMPONENT_ENABLE,
MMAL_WORKER_COMPONENT_DISABLE,
MMAL_WORKER_PORT_INFO_GET,
MMAL_WORKER_PORT_INFO_SET,
MMAL_WORKER_PORT_ACTION,
MMAL_WORKER_BUFFER_FROM_HOST,
MMAL_WORKER_BUFFER_TO_HOST,
MMAL_WORKER_GET_STATS,
MMAL_WORKER_PORT_PARAMETER_SET,
MMAL_WORKER_PORT_PARAMETER_GET,
MMAL_WORKER_EVENT_TO_HOST,
MMAL_WORKER_GET_CORE_STATS_FOR_PORT,
MMAL_WORKER_OPAQUE_ALLOCATOR,
/* VC debug mode only - due to security, denial of service implications */
MMAL_WORKER_CONSUME_MEM,
MMAL_WORKER_LMK,
MMAL_WORKER_OPAQUE_ALLOCATOR_DESC,
MMAL_WORKER_DRM_GET_LHS32,
MMAL_WORKER_DRM_GET_TIME,
MMAL_WORKER_BUFFER_FROM_HOST_ZEROLEN,
MMAL_WORKER_PORT_FLUSH,
MMAL_WORKER_HOST_LOG,
MMAL_WORKER_MSG_LAST
} MMAL_WORKER_CMD_T;
/** Every message has one of these at the start.
*/
typedef struct
{
uint32_t magic;
uint32_t msgid;
struct MMAL_CONTROL_SERVICE_T *control_service; /** Handle to the control service */
union {
struct MMAL_WAITER_T *waiter; /** User-land wait structure, passed back */
} u;
MMAL_STATUS_T status; /** Result code, passed back */
/* Make sure this structure is 64 bit aligned */
uint32_t dummy;
} mmal_worker_msg_header;
/* Make sure mmal_worker_msg_header will preserve 64 bits alignment */
vcos_static_assert(!(sizeof(mmal_worker_msg_header) & 0x7));
/* Message structures sent to worker thread.
*/
/** Tell the worker a service has closed. It should start to delete
* the associated components.
*/
typedef struct
{
mmal_worker_msg_header header;
} mmal_worker_service_closed;
vcos_static_assert(sizeof(mmal_worker_service_closed) <= MMAL_WORKER_MSG_LEN);
/** Send from VC to host to report our version */
typedef struct
{
mmal_worker_msg_header header;
uint32_t flags;
uint32_t major;
uint32_t minor;
uint32_t minimum;
} mmal_worker_version;
/** Request component creation */
typedef struct
{
mmal_worker_msg_header header;
void *client_component; /** Client component */
char name[128];
uint32_t pid; /**< For debug */
} mmal_worker_component_create;
/** Reply to component-creation message. Reports back
* the number of ports.
*/
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status;
uint32_t component_handle; /** Handle on VideoCore for component */
uint32_t input_num; /**< Number of input ports */
uint32_t output_num; /**< Number of output ports */
uint32_t clock_num; /**< Number of clock ports */
} mmal_worker_component_create_reply;
vcos_static_assert(sizeof(mmal_worker_component_create_reply) <= MMAL_WORKER_MAX_MSG_LEN);
/** Destroys a component
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< which component */
} mmal_worker_component_destroy;
/** Enables a component
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< which component */
} mmal_worker_component_enable;
/** Disable a component
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< Which component */
} mmal_worker_component_disable;
/** Component port info. Used to get port info.
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< Which component */
MMAL_PORT_TYPE_T port_type; /**< Type of port */
uint32_t index; /**< Which port of given type to get */
} mmal_worker_port_info_get;
vcos_static_assert(sizeof(mmal_worker_port_info_get) <= MMAL_WORKER_MAX_MSG_LEN);
/** Component port info. Used to set port info.
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< Which component */
MMAL_PORT_TYPE_T port_type; /**< Type of port */
uint32_t index; /**< Which port of given type to get */
MMAL_PORT_T port;
MMAL_ES_FORMAT_T format;
MMAL_ES_SPECIFIC_FORMAT_T es;
uint8_t extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
} mmal_worker_port_info_set;
vcos_static_assert(sizeof(mmal_worker_port_info_set) <= MMAL_WORKER_MAX_MSG_LEN);
/** Report port info back in response to a get / set. */
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status; /**< Result of query */
uint32_t component_handle; /**< Which component */
MMAL_PORT_TYPE_T port_type; /**< Type of port */
uint32_t index; /**< Which port of given type to get */
int32_t found; /**< Did we find anything? */
uint32_t port_handle; /**< Handle to use for this port */
MMAL_PORT_T port;
MMAL_ES_FORMAT_T format;
MMAL_ES_SPECIFIC_FORMAT_T es;
uint8_t extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
} mmal_worker_port_info;
vcos_static_assert(sizeof(mmal_worker_port_info) <= MMAL_WORKER_MAX_MSG_LEN);
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status;
} mmal_worker_reply;
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status;
uint8_t secret[32];
} mmal_worker_drm_get_lhs32_reply;
vcos_static_assert(sizeof(mmal_worker_drm_get_lhs32_reply) <= MMAL_WORKER_MAX_MSG_LEN);
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status;
uint32_t time;
} mmal_worker_drm_get_time_reply;
vcos_static_assert(sizeof(mmal_worker_drm_get_time_reply) <= MMAL_WORKER_MAX_MSG_LEN);
/** List of actions for a port */
enum MMAL_WORKER_PORT_ACTIONS
{
MMAL_WORKER_PORT_ACTION_UNKNOWN = 0, /**< Unkown action */
MMAL_WORKER_PORT_ACTION_ENABLE, /**< Enable a port */
MMAL_WORKER_PORT_ACTION_DISABLE, /**< Disable a port */
MMAL_WORKER_PORT_ACTION_FLUSH, /**< Flush a port */
MMAL_WORKER_PORT_ACTION_CONNECT, /**< Connect 2 ports together */
MMAL_WORKER_PORT_ACTION_DISCONNECT, /**< Disconnect 2 ports connected together */
MMAL_WORKER_PORT_ACTION_SET_REQUIREMENTS, /**< Set buffer requirements */
MMAL_WORKER_PORT_ACTION_MAX = 0x7fffffff /**< Make the enum 32bits */
};
/** Trigger an action on a port.
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle;
uint32_t port_handle;
enum MMAL_WORKER_PORT_ACTIONS action;
/** Action parameter */
union {
struct {
MMAL_PORT_T port;
} enable;
struct {
uint32_t component_handle;
uint32_t port_handle;
} connect;
} param;
} mmal_worker_port_action;
vcos_static_assert(sizeof(mmal_worker_port_action) <= MMAL_WORKER_MAX_MSG_LEN);
#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
#define MMAL_WORKER_PORT_PARAMETER_SET_MAX \
(MMAL_WORKER_PORT_PARAMETER_SPACE*sizeof(uint32_t)+sizeof(MMAL_PARAMETER_HEADER_T))
#define MMAL_WORKER_PORT_PARAMETER_GET_MAX MMAL_WORKER_PORT_PARAMETER_SET_MAX
/** Component port parameter set. Doesn't include space for the parameter data.
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< Which component */
uint32_t port_handle; /**< Which port */
MMAL_PARAMETER_HEADER_T param; /**< Parameter ID and size */
uint32_t space[MMAL_WORKER_PORT_PARAMETER_SPACE];
} mmal_worker_port_param_set;
vcos_static_assert(sizeof(mmal_worker_port_param_set) <= MMAL_WORKER_MAX_MSG_LEN);
/** Component port parameter get.
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< Which component */
uint32_t port_handle; /**< Which port */
MMAL_PARAMETER_HEADER_T param; /**< Parameter ID and size */
uint32_t space[MMAL_WORKER_PORT_PARAMETER_SPACE];
} mmal_worker_port_param_get;
vcos_static_assert(sizeof(mmal_worker_port_param_get) <= MMAL_WORKER_MAX_MSG_LEN);
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_handle; /**< Which component */
uint32_t port_handle; /**< Which port */
MMAL_PARAMETER_HEADER_T param; /**< Parameter ID and size */
} mmal_worker_port_param_get_old;
/** Component port parameter get reply. Doesn't include space for the parameter data.
*/
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status; /**< Status of mmal_port_parameter_get call */
MMAL_PARAMETER_HEADER_T param; /**< Parameter ID and size */
uint32_t space[MMAL_WORKER_PORT_PARAMETER_SPACE];
} mmal_worker_port_param_get_reply;
vcos_static_assert(sizeof(mmal_worker_port_param_get_reply) <= MMAL_WORKER_MAX_MSG_LEN);
/** Buffer header driver area structure. In the private area
* of a buffer header there is a driver area where we can
* put values. This structure defines the layout of that.
*/
struct MMAL_DRIVER_BUFFER_T
{
uint32_t magic;
uint32_t component_handle; /**< The component this buffer is from */
uint32_t port_handle; /**< Index into array of ports for this component */
/** Client side uses this to get back to its context structure. */
struct MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context;
};
/** Receive a buffer from the host.
*
* @sa mmal_port_send_buffer()
*/
typedef struct mmal_worker_buffer_from_host
{
mmal_worker_msg_header header;
/** Our control data, copied from the buffer header "driver area"
* @sa mmal_buffer_header_driver_data().
*/
struct MMAL_DRIVER_BUFFER_T drvbuf;
/** Referenced buffer control data.
* This is set if the buffer is referencing another
* buffer as is the case with passthrough ports where
* buffers on the output port reference buffers on the
* input port. */
struct MMAL_DRIVER_BUFFER_T drvbuf_ref;
/** the buffer header itself */
MMAL_BUFFER_HEADER_T buffer_header;
MMAL_BUFFER_HEADER_TYPE_SPECIFIC_T buffer_header_type_specific;
MMAL_BOOL_T is_zero_copy;
MMAL_BOOL_T has_reference;
/** If the data is short enough, then send it in the control message rather
* than using a separate VCHIQ bulk transfer.
*/
uint32_t payload_in_message;
uint8_t short_data[MMAL_VC_SHORT_DATA];
} mmal_worker_buffer_from_host;
vcos_static_assert(sizeof(mmal_worker_buffer_from_host) <= MMAL_WORKER_MAX_MSG_LEN);
/** Maximum number of event data bytes that can be passed in the message.
* More than this and the data is passed in a bulk message.
*/
#define MMAL_WORKER_EVENT_SPACE 256
/** Send an event buffer from the host.
*
* @sa mmal_port_send_event()
*/
typedef struct mmal_worker_event_to_host
{
mmal_worker_msg_header header;
struct MMAL_COMPONENT_T *client_component;
uint32_t port_type;
uint32_t port_num;
uint32_t cmd;
uint32_t length;
uint8_t data[MMAL_WORKER_EVENT_SPACE];
MMAL_BUFFER_HEADER_T *delayed_buffer; /* Only used to remember buffer for bulk rx */
} mmal_worker_event_to_host;
vcos_static_assert(sizeof(mmal_worker_event_to_host) <= MMAL_WORKER_MAX_MSG_LEN);
typedef struct
{
mmal_worker_msg_header header;
MMAL_VC_STATS_T stats;
uint32_t reset;
} mmal_worker_stats;
vcos_static_assert(sizeof(mmal_worker_stats) <= MMAL_WORKER_MAX_MSG_LEN);
typedef enum {
MMAL_WORKER_OPAQUE_MEM_ALLOC,
MMAL_WORKER_OPAQUE_MEM_RELEASE,
MMAL_WORKER_OPAQUE_MEM_ACQUIRE,
MMAL_WORKER_OPAQUE_MEM_MAX = 0x7fffffff,
} MMAL_WORKER_OPAQUE_MEM_OP;
typedef struct
{
mmal_worker_msg_header header;
MMAL_WORKER_OPAQUE_MEM_OP op;
uint32_t handle;
MMAL_STATUS_T status;
char description[32];
} mmal_worker_opaque_allocator;
/*
* Per-port core statistics
*/
typedef struct
{
mmal_worker_msg_header header;
uint32_t component_index;
uint32_t port_index;
MMAL_PORT_TYPE_T type;
MMAL_CORE_STATS_DIR dir;
MMAL_BOOL_T reset;
} mmal_worker_get_core_stats_for_port;
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status;
MMAL_STATS_RESULT_T result;
MMAL_CORE_STATISTICS_T stats;
char component_name[MMAL_VC_CORE_STATS_NAME_MAX];
} mmal_worker_get_core_stats_for_port_reply;
typedef struct
{
mmal_worker_msg_header header;
MMAL_STATUS_T status;
/* The amount of memory to reserve */
uint32_t size;
/* Handle to newly allocated memory or MEM_HANDLE_INVALD on failure */
uint32_t handle;
} mmal_worker_consume_mem;
vcos_static_assert(sizeof(mmal_worker_consume_mem) <= MMAL_WORKER_MAX_MSG_LEN);
typedef struct
{
mmal_worker_msg_header header;
/* Message text to add to the circular buffer */
char msg[MMAL_WORKER_MAX_MSG_LEN - sizeof(mmal_worker_msg_header)];
} mmal_worker_host_log;
vcos_static_assert(sizeof(mmal_worker_host_log) <= MMAL_WORKER_MAX_MSG_LEN);
typedef struct
{
mmal_worker_msg_header header;
/* The memory allocation size to pass to lmk, as if in a response to an
* allocation for this amount of memory. */
uint32_t alloc_size;
} mmal_worker_lmk;
vcos_static_assert(sizeof(mmal_worker_lmk) <= MMAL_WORKER_MAX_MSG_LEN);
static inline void mmal_vc_buffer_header_to_msg(mmal_worker_buffer_from_host *msg,
MMAL_BUFFER_HEADER_T *header)
{
msg->buffer_header.cmd = header->cmd;
msg->buffer_header.offset = header->offset;
msg->buffer_header.length = header->length;
msg->buffer_header.flags = header->flags;
msg->buffer_header.pts = header->pts;
msg->buffer_header.dts = header->dts;
msg->buffer_header.alloc_size = header->alloc_size;
msg->buffer_header.data = header->data;
msg->buffer_header_type_specific = *header->type;
}
static inline void mmal_vc_msg_to_buffer_header(MMAL_BUFFER_HEADER_T *header,
mmal_worker_buffer_from_host *msg)
{
header->cmd = msg->buffer_header.cmd;
header->offset = msg->buffer_header.offset;
header->length = msg->buffer_header.length;
header->flags = msg->buffer_header.flags;
header->pts = msg->buffer_header.pts;
header->dts = msg->buffer_header.dts;
*header->type = msg->buffer_header_type_specific;
}
#endif
@@ -0,0 +1,87 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "interface/mmal/vc/mmal_vc_opaque_alloc.h"
#include "mmal_vc_msgs.h"
#include "mmal_vc_client_priv.h"
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc_desc(const char *description)
{
MMAL_STATUS_T ret;
MMAL_OPAQUE_IMAGE_HANDLE_T h = 0;
mmal_worker_opaque_allocator msg;
size_t len = sizeof(msg);
msg.op = MMAL_WORKER_OPAQUE_MEM_ALLOC;
vcos_safe_strcpy(msg.description, description, sizeof(msg.description), 0);
ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
&msg.header, sizeof(msg),
MMAL_WORKER_OPAQUE_ALLOCATOR_DESC,
&msg, &len, MMAL_FALSE);
if (ret == MMAL_SUCCESS)
{
h = msg.handle;
}
return h;
}
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void)
{
return mmal_vc_opaque_alloc_desc("?");
}
MMAL_STATUS_T mmal_vc_opaque_acquire(unsigned int handle)
{
MMAL_STATUS_T ret;
mmal_worker_opaque_allocator msg;
size_t len = sizeof(msg);
msg.handle = handle;
msg.op = MMAL_WORKER_OPAQUE_MEM_ACQUIRE;
ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
&msg.header, sizeof(msg),
MMAL_WORKER_OPAQUE_ALLOCATOR,
&msg, &len, MMAL_FALSE);
if (ret == MMAL_SUCCESS)
ret = msg.status;
return ret;
}
MMAL_STATUS_T mmal_vc_opaque_release(unsigned int handle)
{
MMAL_STATUS_T ret;
mmal_worker_opaque_allocator msg;
size_t len = sizeof(msg);
msg.handle = handle;
msg.op = MMAL_WORKER_OPAQUE_MEM_RELEASE;
ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
&msg.header, sizeof(msg),
MMAL_WORKER_OPAQUE_ALLOCATOR,
&msg, &len, MMAL_FALSE);
if (ret == MMAL_SUCCESS)
ret = msg.status;
return ret;
}
@@ -0,0 +1,73 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMAL_VC_OPAQUE_ALLOC_H
#define MMAL_VC_OPAQUE_ALLOC_H
#include <stdint.h>
#include "interface/mmal/mmal.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t MMAL_OPAQUE_IMAGE_HANDLE_T;
/** Allocate an opaque image on VideoCore.
*
* @return allocated handle, or zero if allocation failed.
*/
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void);
/** Allocate an opaque image on VideoCore, providing a description.
* @return allocated handle, or zero if allocation failed.
*/
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc_desc(const char *description);
/** Release an opaque image.
*
* @param handle handle allocated earlier
* @return MMAL_SUCCESS or error code if handle not found
*/
MMAL_STATUS_T mmal_vc_opaque_release(MMAL_OPAQUE_IMAGE_HANDLE_T h);
/** Acquire an additional reference to an opaque image.
*
* @param handle handle allocated earlier
* @return MMAL_SUCCESS or error code if handle not found
*/
MMAL_STATUS_T mmal_vc_opaque_acquire(MMAL_OPAQUE_IMAGE_HANDLE_T h);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,235 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "interface/mmal/mmal_logging.h"
#include "interface/mmal/mmal.h"
#include "interface/vcos/vcos.h"
#include "interface/mmal/vc/mmal_vc_shm.h"
#ifdef ENABLE_MMAL_VCSM
# include "user-vcsm.h"
#endif /* ENABLE_MMAL_VCSM */
#define MMAL_VC_PAYLOAD_ELEM_MAX 512
typedef struct MMAL_VC_PAYLOAD_ELEM_T
{
struct MMAL_VC_PAYLOAD_ELEM_T *next;
void *handle;
void *vc_handle;
uint8_t *mem;
MMAL_BOOL_T in_use;
} MMAL_VC_PAYLOAD_ELEM_T;
typedef struct MMAL_VC_PAYLOAD_LIST_T
{
MMAL_VC_PAYLOAD_ELEM_T list[MMAL_VC_PAYLOAD_ELEM_MAX];
VCOS_MUTEX_T lock;
} MMAL_VC_PAYLOAD_LIST_T;
static MMAL_VC_PAYLOAD_LIST_T mmal_vc_payload_list;
static void mmal_vc_payload_list_init()
{
vcos_mutex_create(&mmal_vc_payload_list.lock, "mmal_vc_payload_list");
}
static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_get()
{
MMAL_VC_PAYLOAD_ELEM_T *elem = 0;
unsigned int i;
vcos_mutex_lock(&mmal_vc_payload_list.lock);
for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++)
{
if (mmal_vc_payload_list.list[i].in_use)
continue;
elem = &mmal_vc_payload_list.list[i];
elem->in_use = 1;
break;
}
vcos_mutex_unlock(&mmal_vc_payload_list.lock);
return elem;
}
static void mmal_vc_payload_list_release(MMAL_VC_PAYLOAD_ELEM_T *elem)
{
vcos_mutex_lock(&mmal_vc_payload_list.lock);
elem->handle = elem->vc_handle = 0;
elem->mem = 0;
elem->in_use = 0;
vcos_mutex_unlock(&mmal_vc_payload_list.lock);
}
static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_find_mem(uint8_t *mem)
{
MMAL_VC_PAYLOAD_ELEM_T *elem = 0;
unsigned int i;
vcos_mutex_lock(&mmal_vc_payload_list.lock);
for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++)
{
if (!mmal_vc_payload_list.list[i].in_use)
continue;
if (mmal_vc_payload_list.list[i].mem != mem)
continue;
elem = &mmal_vc_payload_list.list[i];
break;
}
vcos_mutex_unlock(&mmal_vc_payload_list.lock);
return elem;
}
static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_find_handle(uint8_t *mem)
{
MMAL_VC_PAYLOAD_ELEM_T *elem = 0;
unsigned int i;
vcos_mutex_lock(&mmal_vc_payload_list.lock);
for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++)
{
if (!mmal_vc_payload_list.list[i].in_use)
continue;
if (mmal_vc_payload_list.list[i].vc_handle != (void *)mem)
continue;
elem = &mmal_vc_payload_list.list[i];
break;
}
vcos_mutex_unlock(&mmal_vc_payload_list.lock);
return elem;
}
/** Initialise the shared memory system */
MMAL_STATUS_T mmal_vc_shm_init(void)
{
#ifdef ENABLE_MMAL_VCSM
if (vcsm_init() != 0)
{
LOG_ERROR("could not initialize vc shared memory service");
return MMAL_EIO;
}
#endif /* ENABLE_MMAL_VCSM */
mmal_vc_payload_list_init();
return MMAL_SUCCESS;
}
/** Allocate a shared memory buffer */
uint8_t *mmal_vc_shm_alloc(uint32_t size)
{
uint8_t *mem = NULL;
MMAL_VC_PAYLOAD_ELEM_T *payload_elem = mmal_vc_payload_list_get();
if (!payload_elem)
{
LOG_ERROR("could not get a free slot in the payload list");
return NULL;
}
#ifdef ENABLE_MMAL_VCSM
unsigned int vcsm_handle = vcsm_malloc_cache(size, VCSM_CACHE_TYPE_HOST, "mmal_vc_port buffer");
unsigned int vc_handle = vcsm_vc_hdl_from_hdl(vcsm_handle);
mem = (uint8_t *)vcsm_lock( vcsm_handle );
if (!mem || !vc_handle)
{
LOG_ERROR("could not allocate %i bytes of shared memory (handle %x)",
(int)size, vcsm_handle);
if (mem)
vcsm_unlock_hdl(vcsm_handle);
if (vcsm_handle)
vcsm_free(vcsm_handle);
mmal_vc_payload_list_release(payload_elem);
return NULL;
}
/* The memory area is automatically mem-locked by vcsm's fault
* handler when it is next used. So leave it unlocked until it
* is needed.
*/
vcsm_unlock_hdl(vcsm_handle);
payload_elem->mem = mem;
payload_elem->handle = (void *)vcsm_handle;
payload_elem->vc_handle = (void *)vc_handle;
#else /* ENABLE_MMAL_VCSM */
MMAL_PARAM_UNUSED(size);
mmal_vc_payload_list_release(payload_elem);
#endif /* ENABLE_MMAL_VCSM */
return mem;
}
/** Free a shared memory buffer */
MMAL_STATUS_T mmal_vc_shm_free(uint8_t *mem)
{
MMAL_VC_PAYLOAD_ELEM_T *payload_elem = mmal_vc_payload_list_find_mem(mem);
if (payload_elem)
{
#ifdef ENABLE_MMAL_VCSM
vcsm_free((unsigned int)payload_elem->handle);
#endif /* ENABLE_MMAL_VCSM */
mmal_vc_payload_list_release(payload_elem);
return MMAL_SUCCESS;
}
return MMAL_EINVAL;
}
/** Lock a shared memory buffer */
uint8_t *mmal_vc_shm_lock(uint8_t *mem, uint32_t workaround)
{
/* Zero copy stuff */
MMAL_VC_PAYLOAD_ELEM_T *elem = mmal_vc_payload_list_find_handle(mem);
MMAL_PARAM_UNUSED(workaround);
if (elem)
mem = elem->mem;
return mem;
}
/** Unlock a shared memory buffer */
uint8_t *mmal_vc_shm_unlock(uint8_t *mem, uint32_t *length, uint32_t workaround)
{
/* Zero copy stuff */
MMAL_VC_PAYLOAD_ELEM_T *elem = mmal_vc_payload_list_find_mem(mem);
MMAL_PARAM_UNUSED(workaround);
if (elem)
{
*length = 0;
mem = (uint8_t *)elem->vc_handle;
#ifdef ENABLE_MMAL_VCSM
vcsm_unlock_ptr(elem->mem);
#endif /* ENABLE_MMAL_VCSM */
}
return mem;
}
@@ -0,0 +1,62 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMAL_VC_SHM_H
#define MMAL_VC_SHM_H
/** @file
*
* Abstraction layer for MMAL VC shared memory.
* This API is only used by the MMAL VC component.
*/
#include "mmal_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Initialise the shared memory system */
MMAL_STATUS_T mmal_vc_shm_init(void);
/** Allocate a shared memory buffer */
uint8_t *mmal_vc_shm_alloc(uint32_t size);
/** Free a shared memory buffer */
MMAL_STATUS_T mmal_vc_shm_free(uint8_t *mem);
/** Lock a shared memory buffer */
uint8_t *mmal_vc_shm_lock(uint8_t *mem, uint32_t workaround);
/** Unlock a shared memory buffer */
uint8_t *mmal_vc_shm_unlock(uint8_t *mem, uint32_t *length, uint32_t workaround);
#ifdef __cplusplus
}
#endif
#endif /* MMAL_VC_SHM_H */