blob: 3835f7b296957aacc49cf73b3495e1d316daffc8 [file] [log] [blame]
/* Copyright (c) 2012-2013, The Linux Foundation. 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 Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <pthread.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <poll.h>
#include <cam_semaphore.h>
#include "mm_camera_dbg.h"
#include "mm_camera_interface.h"
#include "mm_camera.h"
typedef enum {
/* poll entries updated */
MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED,
/* poll entries updated */
MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC,
/* commit updates */
MM_CAMERA_PIPE_CMD_COMMIT,
/* exit */
MM_CAMERA_PIPE_CMD_EXIT,
/* max count */
MM_CAMERA_PIPE_CMD_MAX
} mm_camera_pipe_cmd_type_t;
typedef enum {
MM_CAMERA_POLL_TASK_STATE_STOPPED,
MM_CAMERA_POLL_TASK_STATE_POLL, /* polling pid in polling state. */
MM_CAMERA_POLL_TASK_STATE_MAX
} mm_camera_poll_task_state_type_t;
typedef struct {
uint8_t cmd;
mm_camera_event_t event;
} mm_camera_sig_evt_t;
/*===========================================================================
* FUNCTION : mm_camera_poll_sig_async
*
* DESCRIPTION: Asynchoronous call to send a command through pipe.
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
* @cmd : command to be sent
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
static int32_t mm_camera_poll_sig_async(mm_camera_poll_thread_t *poll_cb,
uint32_t cmd)
{
/* send through pipe */
/* get the mutex */
mm_camera_sig_evt_t cmd_evt;
int len;
CDBG("%s: E cmd = %d", __func__,cmd);
memset(&cmd_evt, 0, sizeof(cmd_evt));
cmd_evt.cmd = cmd;
pthread_mutex_lock(&poll_cb->mutex);
/* reset the statue to false */
poll_cb->status = FALSE;
/* send cmd to worker */
len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt));
if(len < 1) {
CDBG_ERROR("%s: len = %d, errno = %d", __func__, len, errno);
/* Avoid waiting for the signal */
pthread_mutex_unlock(&poll_cb->mutex);
return 0;
}
CDBG("%s: begin IN mutex write done, len = %d", __func__, len);
pthread_mutex_unlock(&poll_cb->mutex);
CDBG("%s: X", __func__);
return 0;
}
/*===========================================================================
* FUNCTION : mm_camera_poll_sig
*
* DESCRIPTION: synchorinzed call to send a command through pipe.
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
* @cmd : command to be sent
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
static int32_t mm_camera_poll_sig(mm_camera_poll_thread_t *poll_cb,
uint32_t cmd)
{
/* send through pipe */
/* get the mutex */
mm_camera_sig_evt_t cmd_evt;
int len;
CDBG("%s: E cmd = %d", __func__,cmd);
memset(&cmd_evt, 0, sizeof(cmd_evt));
cmd_evt.cmd = cmd;
pthread_mutex_lock(&poll_cb->mutex);
/* reset the statue to false */
poll_cb->status = FALSE;
/* send cmd to worker */
len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt));
if(len < 1) {
CDBG_ERROR("%s: len = %d, errno = %d", __func__, len, errno);
/* Avoid waiting for the signal */
pthread_mutex_unlock(&poll_cb->mutex);
return 0;
}
CDBG("%s: begin IN mutex write done, len = %d", __func__, len);
/* wait till worker task gives positive signal */
if (FALSE == poll_cb->status) {
CDBG("%s: wait", __func__);
pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex);
}
/* done */
pthread_mutex_unlock(&poll_cb->mutex);
CDBG("%s: X", __func__);
return 0;
}
/*===========================================================================
* FUNCTION : mm_camera_poll_sig
*
* DESCRIPTION: signal the status of done
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
*
* RETURN : none
*==========================================================================*/
static void mm_camera_poll_sig_done(mm_camera_poll_thread_t *poll_cb)
{
pthread_mutex_lock(&poll_cb->mutex);
poll_cb->status = TRUE;
pthread_cond_signal(&poll_cb->cond_v);
CDBG("%s: done, in mutex", __func__);
pthread_mutex_unlock(&poll_cb->mutex);
}
/*===========================================================================
* FUNCTION : mm_camera_poll_set_state
*
* DESCRIPTION: set a polling state
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
* @state : polling state (stopped/polling)
*
* RETURN : none
*==========================================================================*/
static void mm_camera_poll_set_state(mm_camera_poll_thread_t *poll_cb,
mm_camera_poll_task_state_type_t state)
{
poll_cb->state = state;
}
/*===========================================================================
* FUNCTION : mm_camera_poll_proc_pipe
*
* DESCRIPTION: polling thread routine to process pipe
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
*
* RETURN : none
*==========================================================================*/
static void mm_camera_poll_proc_pipe(mm_camera_poll_thread_t *poll_cb)
{
ssize_t read_len;
int i;
mm_camera_sig_evt_t cmd_evt;
read_len = read(poll_cb->pfds[0], &cmd_evt, sizeof(cmd_evt));
CDBG("%s: read_fd = %d, read_len = %d, expect_len = %d cmd = %d",
__func__, poll_cb->pfds[0], (int)read_len, (int)sizeof(cmd_evt), cmd_evt.cmd);
switch (cmd_evt.cmd) {
case MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED:
case MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC:
/* we always have index 0 for pipe read */
poll_cb->num_fds = 0;
poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->pfds[0];
poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI;
poll_cb->num_fds++;
if (MM_CAMERA_POLL_TYPE_EVT == poll_cb->poll_type &&
poll_cb->num_fds < MAX_STREAM_NUM_IN_BUNDLE) {
if (poll_cb->poll_entries[0].fd > 0) {
/* fd is valid, we update poll_fds */
poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[0].fd;
poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI;
poll_cb->num_fds++;
}
} else if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type &&
poll_cb->num_fds <= MAX_STREAM_NUM_IN_BUNDLE) {
for(i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
if(poll_cb->poll_entries[i].fd > 0) {
/* fd is valid, we update poll_fds to this fd */
poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[i].fd;
poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI;
poll_cb->num_fds++;
} else {
/* fd is invalid, we set the entry to -1 to prevent polling.
* According to spec, polling will not poll on entry with fd=-1.
* If this is not the case, we need to skip these invalid fds
* when updating this array.
* We still keep fd=-1 in this array because this makes easier to
* map cb associated with this fd once incoming data avail by directly
* using the index-1(0 is reserved for pipe read, so need to reduce index by 1) */
poll_cb->poll_fds[poll_cb->num_fds].fd = -1;
poll_cb->poll_fds[poll_cb->num_fds].events = 0;
poll_cb->num_fds++;
}
}
}
if (cmd_evt.cmd != MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC)
mm_camera_poll_sig_done(poll_cb);
break;
case MM_CAMERA_PIPE_CMD_COMMIT:
mm_camera_poll_sig_done(poll_cb);
break;
case MM_CAMERA_PIPE_CMD_EXIT:
default:
mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_STOPPED);
mm_camera_poll_sig_done(poll_cb);
break;
}
}
/*===========================================================================
* FUNCTION : mm_camera_poll_fn
*
* DESCRIPTION: polling thread routine
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
*
* RETURN : none
*==========================================================================*/
static void *mm_camera_poll_fn(mm_camera_poll_thread_t *poll_cb)
{
int rc = 0, i;
if (NULL == poll_cb) {
CDBG_ERROR("%s: poll_cb is NULL!\n", __func__);
return NULL;
}
CDBG("%s: poll type = %d, num_fd = %d poll_cb = %p\n",
__func__, poll_cb->poll_type, poll_cb->num_fds,poll_cb);
do {
for(i = 0; i < poll_cb->num_fds; i++) {
poll_cb->poll_fds[i].events = POLLIN|POLLRDNORM|POLLPRI;
}
rc = poll(poll_cb->poll_fds, poll_cb->num_fds, poll_cb->timeoutms);
if(rc > 0) {
if ((poll_cb->poll_fds[0].revents & POLLIN) &&
(poll_cb->poll_fds[0].revents & POLLRDNORM)) {
/* if we have data on pipe, we only process pipe in this iteration */
CDBG("%s: cmd received on pipe\n", __func__);
mm_camera_poll_proc_pipe(poll_cb);
} else {
for(i=1; i<poll_cb->num_fds; i++) {
/* Checking for ctrl events */
if ((poll_cb->poll_type == MM_CAMERA_POLL_TYPE_EVT) &&
(poll_cb->poll_fds[i].revents & POLLPRI)) {
CDBG("%s: mm_camera_evt_notify\n", __func__);
if (NULL != poll_cb->poll_entries[i-1].notify_cb) {
poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data);
}
}
if ((MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) &&
(poll_cb->poll_fds[i].revents & POLLIN) &&
(poll_cb->poll_fds[i].revents & POLLRDNORM)) {
CDBG("%s: mm_stream_data_notify\n", __func__);
if (NULL != poll_cb->poll_entries[i-1].notify_cb) {
poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data);
}
}
}
}
} else {
/* in error case sleep 10 us and then continue. hard coded here */
usleep(10);
continue;
}
} while ((poll_cb != NULL) && (poll_cb->state == MM_CAMERA_POLL_TASK_STATE_POLL));
return NULL;
}
/*===========================================================================
* FUNCTION : mm_camera_poll_thread
*
* DESCRIPTION: polling thread entry function
*
* PARAMETERS :
* @data : ptr to poll thread object
*
* RETURN : none
*==========================================================================*/
static void *mm_camera_poll_thread(void *data)
{
prctl(PR_SET_NAME, (unsigned long)"mm_cam_poll_th", 0, 0, 0);
mm_camera_poll_thread_t *poll_cb = (mm_camera_poll_thread_t *)data;
/* add pipe read fd into poll first */
poll_cb->poll_fds[poll_cb->num_fds++].fd = poll_cb->pfds[0];
mm_camera_poll_sig_done(poll_cb);
mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_POLL);
return mm_camera_poll_fn(poll_cb);
}
/*===========================================================================
* FUNCTION : mm_camera_poll_thread
*
* DESCRIPTION: notify the polling thread that entries for polling fd have
* been updated
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
*
* RETURN : none
*==========================================================================*/
int32_t mm_camera_poll_thread_notify_entries_updated(mm_camera_poll_thread_t * poll_cb)
{
/* send poll entries updated signal to poll thread */
return mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED);
}
/*===========================================================================
* FUNCTION : mm_camera_poll_thread_commit_updates
*
* DESCRIPTION: sync with all previously pending async updates
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_camera_poll_thread_commit_updates(mm_camera_poll_thread_t * poll_cb)
{
return mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_COMMIT);
}
/*===========================================================================
* FUNCTION : mm_camera_poll_thread_add_poll_fd
*
* DESCRIPTION: add a new fd into polling thread
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
* @handler : stream handle if channel data polling thread,
* 0 if event polling thread
* @fd : file descriptor need to be added into polling thread
* @notify_cb : callback function to handle if any notify from fd
* @userdata : user data ptr
* @call_type : Whether its Synchronous or Asynchronous call
*
* RETURN : none
*==========================================================================*/
int32_t mm_camera_poll_thread_add_poll_fd(mm_camera_poll_thread_t * poll_cb,
uint32_t handler,
int32_t fd,
mm_camera_poll_notify_t notify_cb,
void* userdata,
mm_camera_call_type_t call_type)
{
int32_t rc = -1;
uint8_t idx = 0;
if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) {
/* get stream idx from handler if CH type */
idx = mm_camera_util_get_index_by_handler(handler);
} else {
/* for EVT type, only idx=0 is valid */
idx = 0;
}
if (MAX_STREAM_NUM_IN_BUNDLE > idx) {
poll_cb->poll_entries[idx].fd = fd;
poll_cb->poll_entries[idx].handler = handler;
poll_cb->poll_entries[idx].notify_cb = notify_cb;
poll_cb->poll_entries[idx].user_data = userdata;
/* send poll entries updated signal to poll thread */
if (call_type == mm_camera_sync_call ) {
rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED);
} else {
rc = mm_camera_poll_sig_async(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC );
}
} else {
CDBG_ERROR("%s: invalid handler %d (%d)",
__func__, handler, idx);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_camera_poll_thread_del_poll_fd
*
* DESCRIPTION: delete a fd from polling thread
*
* PARAMETERS :
* @poll_cb : ptr to poll thread object
* @handler : stream handle if channel data polling thread,
* 0 if event polling thread
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_camera_poll_thread_del_poll_fd(mm_camera_poll_thread_t * poll_cb,
uint32_t handler,
mm_camera_call_type_t call_type)
{
int32_t rc = -1;
uint8_t idx = 0;
if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) {
/* get stream idx from handler if CH type */
idx = mm_camera_util_get_index_by_handler(handler);
} else {
/* for EVT type, only idx=0 is valid */
idx = 0;
}
if ((MAX_STREAM_NUM_IN_BUNDLE > idx) &&
(handler == poll_cb->poll_entries[idx].handler)) {
/* reset poll entry */
poll_cb->poll_entries[idx].fd = -1; /* set fd to invalid */
poll_cb->poll_entries[idx].handler = 0;
poll_cb->poll_entries[idx].notify_cb = NULL;
/* send poll entries updated signal to poll thread */
if (call_type == mm_camera_sync_call ) {
rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED);
} else {
rc = mm_camera_poll_sig_async(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC );
}
} else {
CDBG_ERROR("%s: invalid handler %d (%d)",
__func__, handler, idx);
return -1;
}
return rc;
}
int32_t mm_camera_poll_thread_launch(mm_camera_poll_thread_t * poll_cb,
mm_camera_poll_thread_type_t poll_type)
{
int32_t rc = 0;
poll_cb->poll_type = poll_type;
poll_cb->pfds[0] = -1;
poll_cb->pfds[1] = -1;
rc = pipe(poll_cb->pfds);
if(rc < 0) {
CDBG_ERROR("%s: pipe open rc=%d\n", __func__, rc);
return -1;
}
poll_cb->timeoutms = -1; /* Infinite seconds */
CDBG("%s: poll_type = %d, read fd = %d, write fd = %d timeout = %d",
__func__, poll_cb->poll_type,
poll_cb->pfds[0], poll_cb->pfds[1],poll_cb->timeoutms);
pthread_mutex_init(&poll_cb->mutex, NULL);
pthread_cond_init(&poll_cb->cond_v, NULL);
/* launch the thread */
pthread_mutex_lock(&poll_cb->mutex);
poll_cb->status = 0;
pthread_create(&poll_cb->pid, NULL, mm_camera_poll_thread, (void *)poll_cb);
if(!poll_cb->status) {
pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex);
}
pthread_mutex_unlock(&poll_cb->mutex);
CDBG("%s: End",__func__);
return rc;
}
int32_t mm_camera_poll_thread_release(mm_camera_poll_thread_t *poll_cb)
{
int32_t rc = 0;
if(MM_CAMERA_POLL_TASK_STATE_STOPPED == poll_cb->state) {
CDBG_ERROR("%s: err, poll thread is not running.\n", __func__);
return rc;
}
/* send exit signal to poll thread */
mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_EXIT);
/* wait until poll thread exits */
if (pthread_join(poll_cb->pid, NULL) != 0) {
CDBG_ERROR("%s: pthread dead already\n", __func__);
}
/* close pipe */
if(poll_cb->pfds[0] >= 0) {
close(poll_cb->pfds[0]);
}
if(poll_cb->pfds[1] >= 0) {
close(poll_cb->pfds[1]);
}
pthread_mutex_destroy(&poll_cb->mutex);
pthread_cond_destroy(&poll_cb->cond_v);
memset(poll_cb, 0, sizeof(mm_camera_poll_thread_t));
poll_cb->pfds[0] = -1;
poll_cb->pfds[1] = -1;
return rc;
}
static void *mm_camera_cmd_thread(void *data)
{
int running = 1;
int ret;
mm_camera_cmd_thread_t *cmd_thread =
(mm_camera_cmd_thread_t *)data;
mm_camera_cmdcb_t* node = NULL;
do {
do {
ret = cam_sem_wait(&cmd_thread->cmd_sem);
if (ret != 0 && errno != EINVAL) {
CDBG_ERROR("%s: cam_sem_wait error (%s)",
__func__, strerror(errno));
return NULL;
}
} while (ret != 0);
/* we got notified about new cmd avail in cmd queue */
node = (mm_camera_cmdcb_t*)cam_queue_deq(&cmd_thread->cmd_queue);
while (node != NULL) {
switch (node->cmd_type) {
case MM_CAMERA_CMD_TYPE_EVT_CB:
case MM_CAMERA_CMD_TYPE_DATA_CB:
case MM_CAMERA_CMD_TYPE_REQ_DATA_CB:
case MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB:
case MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY:
case MM_CAMERA_CMD_TYPE_START_ZSL:
case MM_CAMERA_CMD_TYPE_STOP_ZSL:
case MM_CAMERA_CMD_TYPE_GENERAL:
case MM_CAMERA_CMD_TYPE_FLUSH_QUEUE:
if (NULL != cmd_thread->cb) {
cmd_thread->cb(node, cmd_thread->user_data);
}
break;
case MM_CAMERA_CMD_TYPE_EXIT:
default:
running = 0;
break;
}
free(node);
node = (mm_camera_cmdcb_t*)cam_queue_deq(&cmd_thread->cmd_queue);
} /* (node != NULL) */
} while (running);
return NULL;
}
int32_t mm_camera_cmd_thread_launch(mm_camera_cmd_thread_t * cmd_thread,
mm_camera_cmd_cb_t cb,
void* user_data)
{
int32_t rc = 0;
cam_sem_init(&cmd_thread->cmd_sem, 0);
cam_queue_init(&cmd_thread->cmd_queue);
cmd_thread->cb = cb;
cmd_thread->user_data = user_data;
/* launch the thread */
pthread_create(&cmd_thread->cmd_pid,
NULL,
mm_camera_cmd_thread,
(void *)cmd_thread);
return rc;
}
int32_t mm_camera_cmd_thread_name(const char* name)
{
int32_t rc = 0;
/* name the thread */
prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
return rc;
}
int32_t mm_camera_cmd_thread_stop(mm_camera_cmd_thread_t * cmd_thread)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL == node) {
CDBG_ERROR("%s: No memory for mm_camera_cmdcb_t", __func__);
return -1;
}
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->cmd_type = MM_CAMERA_CMD_TYPE_EXIT;
cam_queue_enq(&cmd_thread->cmd_queue, node);
cam_sem_post(&cmd_thread->cmd_sem);
/* wait until cmd thread exits */
if (pthread_join(cmd_thread->cmd_pid, NULL) != 0) {
CDBG("%s: pthread dead already\n", __func__);
}
return rc;
}
int32_t mm_camera_cmd_thread_destroy(mm_camera_cmd_thread_t * cmd_thread)
{
int32_t rc = 0;
cam_queue_deinit(&cmd_thread->cmd_queue);
cam_sem_destroy(&cmd_thread->cmd_sem);
memset(cmd_thread, 0, sizeof(mm_camera_cmd_thread_t));
return rc;
}
int32_t mm_camera_cmd_thread_release(mm_camera_cmd_thread_t * cmd_thread)
{
int32_t rc = 0;
rc = mm_camera_cmd_thread_stop(cmd_thread);
if (0 == rc) {
rc = mm_camera_cmd_thread_destroy(cmd_thread);
}
return rc;
}