Änderungen Gruppe 30_10_2022 V2
This commit is contained in:
@@ -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 */
|
||||
Reference in New Issue
Block a user