blob: 79d756490c7f76bc1d55c0b63c0b6024f9eb61c6 [file] [log] [blame]
/* Copyright (c) 2012-2014, 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 <fcntl.h>
#include <poll.h>
#include <cam_semaphore.h>
#include "mm_camera_dbg.h"
#include "mm_camera_interface.h"
#include "mm_camera.h"
extern mm_camera_obj_t* mm_camera_util_get_camera_by_handler(uint32_t cam_handler);
extern mm_channel_t * mm_camera_util_get_channel_by_handler(mm_camera_obj_t * cam_obj,
uint32_t handler);
/* internal function declare goes here */
int32_t mm_channel_qbuf(mm_channel_t *my_obj,
mm_camera_buf_def_t *buf);
int32_t mm_channel_init(mm_channel_t *my_obj,
mm_camera_channel_attr_t *attr,
mm_camera_buf_notify_t channel_cb,
void *userdata);
void mm_channel_release(mm_channel_t *my_obj);
uint32_t mm_channel_add_stream(mm_channel_t *my_obj);
int32_t mm_channel_del_stream(mm_channel_t *my_obj,
uint32_t stream_id);
int32_t mm_channel_config_stream(mm_channel_t *my_obj,
uint32_t stream_id,
mm_camera_stream_config_t *config);
int32_t mm_channel_get_bundle_info(mm_channel_t *my_obj,
cam_bundle_config_t *bundle_info);
int32_t mm_channel_start(mm_channel_t *my_obj);
int32_t mm_channel_stop(mm_channel_t *my_obj);
int32_t mm_channel_request_super_buf(mm_channel_t *my_obj,
uint32_t num_buf_requested, uint32_t num_reto_buf_requested);
int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj);
int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj,
uint32_t frame_idx);
int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
mm_camera_super_buf_notify_mode_t notify_mode);
int32_t mm_channel_start_zsl_snapshot(mm_channel_t *my_obj);
int32_t mm_channel_stop_zsl_snapshot(mm_channel_t *my_obj);
int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj, mm_channel_queue_t * queue);
int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
mm_evt_paylod_set_get_stream_parms_t *payload);
int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
mm_evt_paylod_set_get_stream_parms_t *payload);
int32_t mm_channel_do_stream_action(mm_channel_t *my_obj,
mm_evt_paylod_do_stream_action_t *payload);
int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj,
mm_evt_paylod_map_stream_buf_t *payload);
int32_t mm_channel_unmap_stream_buf(mm_channel_t *my_obj,
mm_evt_paylod_unmap_stream_buf_t *payload);
/* state machine function declare */
int32_t mm_channel_fsm_fn_notused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_channel_fsm_fn_stopped(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_channel_fsm_fn_active(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_channel_fsm_fn_paused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
/* channel super queue functions */
int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_comp_and_enqueue(mm_channel_t *ch_obj,
mm_channel_queue_t * queue,
mm_camera_buf_info_t *buf);
mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t *my_obj,
mm_channel_queue_t *queue);
int32_t mm_channel_superbuf_skip(mm_channel_t *my_obj,
mm_channel_queue_t *queue);
static int32_t mm_channel_proc_general_cmd(mm_channel_t *my_obj,
mm_camera_generic_cmd_t *p_gen_cmd);
int32_t mm_channel_superbuf_flush_matched(mm_channel_t* my_obj,
mm_channel_queue_t * queue);
/*===========================================================================
* FUNCTION : mm_channel_util_get_stream_by_handler
*
* DESCRIPTION: utility function to get a stream object from its handle
*
* PARAMETERS :
* @cam_obj: ptr to a channel object
* @handler: stream handle
*
* RETURN : ptr to a stream object.
* NULL if failed.
*==========================================================================*/
mm_stream_t * mm_channel_util_get_stream_by_handler(
mm_channel_t * ch_obj,
uint32_t handler)
{
int i;
mm_stream_t *s_obj = NULL;
for(i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
if ((MM_STREAM_STATE_NOTUSED != ch_obj->streams[i].state) &&
(handler == ch_obj->streams[i].my_hdl)) {
s_obj = &ch_obj->streams[i];
break;
}
}
return s_obj;
}
/*===========================================================================
* FUNCTION : mm_channel_dispatch_super_buf
*
* DESCRIPTION: dispatch super buffer of bundle to registered user
*
* PARAMETERS :
* @cmd_cb : ptr storing matched super buf information
* @userdata: user data ptr
*
* RETURN : none
*==========================================================================*/
static void mm_channel_dispatch_super_buf(mm_camera_cmdcb_t *cmd_cb,
void* user_data)
{
mm_camera_cmd_thread_name("mm_cam_cb");
mm_channel_t * my_obj = (mm_channel_t *)user_data;
if (NULL == my_obj) {
return;
}
if (MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB != cmd_cb->cmd_type) {
CDBG_ERROR("%s: Wrong cmd_type (%d) for super buf dataCB",
__func__, cmd_cb->cmd_type);
return;
}
if (my_obj->bundle.super_buf_notify_cb) {
my_obj->bundle.super_buf_notify_cb(&cmd_cb->u.superbuf, my_obj->bundle.user_data);
}
}
/*===========================================================================
* FUNCTION : mm_channel_process_stream_buf
*
* DESCRIPTION: handle incoming buffer from stream in a bundle. In this function,
* matching logic will be performed on incoming stream frames.
* Will depends on the bundle attribute, either storing matched frames
* in the superbuf queue, or sending matched superbuf frames to upper
* layer through registered callback.
*
* PARAMETERS :
* @cmd_cb : ptr storing matched super buf information
* @userdata: user data ptr
*
* RETURN : none
*==========================================================================*/
static void mm_channel_process_stream_buf(mm_camera_cmdcb_t * cmd_cb,
void *user_data)
{
mm_camera_cmd_thread_name("mm_cam_cmd");
mm_camera_super_buf_notify_mode_t notify_mode;
mm_channel_queue_node_t *node = NULL;
mm_channel_t *ch_obj = (mm_channel_t *)user_data;
if (NULL == ch_obj) {
return;
}
if (MM_CAMERA_CMD_TYPE_DATA_CB == cmd_cb->cmd_type) {
/* comp_and_enqueue */
mm_channel_superbuf_comp_and_enqueue(
ch_obj,
&ch_obj->bundle.superbuf_queue,
&cmd_cb->u.buf);
} else if (MM_CAMERA_CMD_TYPE_REQ_DATA_CB == cmd_cb->cmd_type) {
/* skip frames if needed */
ch_obj->pending_cnt = cmd_cb->u.req_buf.num_buf_requested;
ch_obj->pending_retro_cnt = cmd_cb->u.req_buf.num_retro_buf_requested;
ch_obj->bWaitForPrepSnapshotDone = 0;
ALOGV("%s:[ZSL Retro] pending cnt (%d), retro count (%d)",
__func__, ch_obj->pending_cnt, ch_obj->pending_retro_cnt);
if (!ch_obj->pending_cnt || (ch_obj->pending_retro_cnt > ch_obj->pending_cnt)) {
ch_obj->pending_retro_cnt = ch_obj->pending_cnt;
}
if (ch_obj->pending_retro_cnt > 0) {
ALOGV("%s: [ZSL Retro] Resetting need Led Flash!!!",
__func__);
ch_obj->needLEDFlash = 0;
}
ch_obj->stopZslSnapshot = 0;
ch_obj->unLockAEC = 0;
mm_channel_superbuf_skip(ch_obj, &ch_obj->bundle.superbuf_queue);
} else if (MM_CAMERA_CMD_TYPE_START_ZSL == cmd_cb->cmd_type) {
ch_obj->manualZSLSnapshot = TRUE;
mm_camera_start_zsl_snapshot(ch_obj->cam_obj);
} else if (MM_CAMERA_CMD_TYPE_STOP_ZSL == cmd_cb->cmd_type) {
ch_obj->manualZSLSnapshot = FALSE;
mm_camera_stop_zsl_snapshot(ch_obj->cam_obj);
} else if (MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY == cmd_cb->cmd_type) {
ch_obj->bundle.superbuf_queue.attr.notify_mode = cmd_cb->u.notify_mode;
} else if (MM_CAMERA_CMD_TYPE_FLUSH_QUEUE == cmd_cb->cmd_type) {
ch_obj->bundle.superbuf_queue.expected_frame_id = cmd_cb->u.frame_idx;
mm_channel_superbuf_flush(ch_obj, &ch_obj->bundle.superbuf_queue);
return;
} else if (MM_CAMERA_CMD_TYPE_GENERAL == cmd_cb->cmd_type) {
CDBG_HIGH("%s:%d] MM_CAMERA_CMD_TYPE_GENERAL", __func__, __LINE__);
switch (cmd_cb->u.gen_cmd.type) {
case MM_CAMERA_GENERIC_CMD_TYPE_AE_BRACKETING:
case MM_CAMERA_GENERIC_CMD_TYPE_AF_BRACKETING: {
int8_t start = cmd_cb->u.gen_cmd.payload[0];
CDBG_HIGH("%s:%d] MM_CAMERA_GENERIC_CMDTYPE_AF_BRACKETING %d",
__func__, __LINE__, start);
mm_channel_superbuf_flush(ch_obj,
&ch_obj->bundle.superbuf_queue);
if (start) {
CDBG_HIGH("%s:%d] need AE bracketing, start zsl snapshot",
__func__, __LINE__);
ch_obj->need3ABracketing = TRUE;
} else {
ch_obj->need3ABracketing = FALSE;
}
}
break;
case MM_CAMERA_GENERIC_CMD_TYPE_FLASH_BRACKETING: {
int8_t start = cmd_cb->u.gen_cmd.payload[0];
CDBG_HIGH("%s:%d] MM_CAMERA_GENERIC_CMDTYPE_FLASH_BRACKETING %d",
__func__, __LINE__, start);
if (start) {
CDBG_HIGH("%s:%d] need flash bracketing",
__func__, __LINE__);
ch_obj->isFlashBracketingEnabled = TRUE;
} else {
ch_obj->isFlashBracketingEnabled = FALSE;
}
}
break;
case MM_CAMERA_GENERIC_CMD_TYPE_ZOOM_1X: {
int8_t start = cmd_cb->u.gen_cmd.payload[0];
CDBG_HIGH("%s:%d] MM_CAMERA_GENERIC_CMD_TYPE_ZOOM_1X %d",
__func__, __LINE__, start);
if (start) {
CDBG_HIGH("%s:%d] need zoom 1x frame",
__func__, __LINE__);
ch_obj->isZoom1xFrameRequested = TRUE;
} else {
ch_obj->isZoom1xFrameRequested = FALSE;
}
}
break;
default:
CDBG_ERROR("%s:%d] Error: Invalid command", __func__, __LINE__);
break;
}
}
notify_mode = ch_obj->bundle.superbuf_queue.attr.notify_mode;
if ((ch_obj->pending_cnt > 0)
&& (ch_obj->needLEDFlash == TRUE || ch_obj->need3ABracketing == TRUE)
&& (ch_obj->manualZSLSnapshot == FALSE)
&& ch_obj->startZSlSnapshotCalled == FALSE) {
CDBG_HIGH("%s: need flash, start zsl snapshot", __func__);
mm_camera_start_zsl_snapshot(ch_obj->cam_obj);
ch_obj->startZSlSnapshotCalled = TRUE;
ch_obj->burstSnapNum = ch_obj->pending_cnt;
ch_obj->bWaitForPrepSnapshotDone = 0;
ch_obj->needLEDFlash = FALSE;
} else if (((ch_obj->pending_cnt == 0) || (ch_obj->stopZslSnapshot == 1))
&& (ch_obj->manualZSLSnapshot == FALSE)
&& (ch_obj->startZSlSnapshotCalled == TRUE)) {
CDBG_HIGH("%s: Got picture cancelled, stop zsl snapshot", __func__);
mm_camera_stop_zsl_snapshot(ch_obj->cam_obj);
// Unlock AEC
ch_obj->startZSlSnapshotCalled = FALSE;
ch_obj->needLEDFlash = FALSE;
ch_obj->burstSnapNum = 0;
ch_obj->stopZslSnapshot = 0;
ch_obj->bWaitForPrepSnapshotDone = 0;
ch_obj->unLockAEC = 1;
ch_obj->need3ABracketing = FALSE;
}
/* bufdone for overflowed bufs */
mm_channel_superbuf_bufdone_overflow(ch_obj, &ch_obj->bundle.superbuf_queue);
CDBG("%s: Super Buffer received, pending_cnt=%d",
__func__, ch_obj->pending_cnt);
/* dispatch frame if pending_cnt>0 or is in continuous streaming mode */
CDBG("%s: [ZSL Retro] Out loop pending cnt (%d), retro count (%d)",
__func__, ch_obj->pending_cnt, ch_obj->pending_retro_cnt);
while (((ch_obj->pending_cnt > 0) ||
(MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == notify_mode)) &&
(!ch_obj->bWaitForPrepSnapshotDone)) {
CDBG("%s: [ZSL Retro] In loop pending cnt (%d), retro count (%d)",
__func__, ch_obj->pending_cnt, ch_obj->pending_retro_cnt);
/* dequeue */
node = mm_channel_superbuf_dequeue(&ch_obj->bundle.superbuf_queue);
if (NULL != node) {
uint32_t bReady = 0;
/* decrease pending_cnt */
if (MM_CAMERA_SUPER_BUF_NOTIFY_BURST == notify_mode) {
ch_obj->pending_cnt--;
if (ch_obj->pending_retro_cnt > 0) {
if (ch_obj->pending_retro_cnt == 1) {
ch_obj->bWaitForPrepSnapshotDone = 1;
// Retro Snaps are done..
bReady = 1;
}
ch_obj->pending_retro_cnt--;
}
CDBG("%s: [ZSL Retro] Super Buffer received, Call client callback,"
"pending_cnt=%d", __func__, ch_obj->pending_cnt);
if (((ch_obj->pending_cnt == 0) ||
(ch_obj->stopZslSnapshot == 1)) &&
(ch_obj->manualZSLSnapshot == FALSE) &&
ch_obj->startZSlSnapshotCalled == TRUE) {
CDBG("%s: [ZSL Retro] Received all frames requested, stop zsl snapshot", __func__);
mm_camera_stop_zsl_snapshot(ch_obj->cam_obj);
ch_obj->startZSlSnapshotCalled = FALSE;
ch_obj->burstSnapNum = 0;
ch_obj->stopZslSnapshot = 0;
ch_obj->unLockAEC = 1;
}
}
/* dispatch superbuf */
if (NULL != ch_obj->bundle.super_buf_notify_cb) {
uint8_t i;
mm_camera_cmdcb_t* cb_node = NULL;
CDBG("%s: Send superbuf to HAL, pending_cnt=%d",
__func__, ch_obj->pending_cnt);
/* send cam_sem_post to wake up cb thread to dispatch super buffer */
cb_node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != cb_node) {
memset(cb_node, 0, sizeof(mm_camera_cmdcb_t));
cb_node->cmd_type = MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB;
cb_node->u.superbuf.num_bufs = node->num_of_bufs;
for (i=0; i<node->num_of_bufs; i++) {
cb_node->u.superbuf.bufs[i] = node->super_buf[i].buf;
}
cb_node->u.superbuf.camera_handle = ch_obj->cam_obj->my_hdl;
cb_node->u.superbuf.ch_id = ch_obj->my_hdl;
cb_node->u.superbuf.bReadyForPrepareSnapshot = bReady;
if (ch_obj->unLockAEC == 1) {
cb_node->u.superbuf.bUnlockAEC = 1;
ALOGE("%s:[ZSL Retro] Unlocking AEC", __func__);
ch_obj->unLockAEC = 0;
}
/* enqueue to cb thread */
cam_queue_enq(&(ch_obj->cb_thread.cmd_queue), cb_node);
/* wake up cb thread */
cam_sem_post(&(ch_obj->cb_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
/* buf done with the nonuse super buf */
for (i=0; i<node->num_of_bufs; i++) {
mm_channel_qbuf(ch_obj, node->super_buf[i].buf);
}
}
} else {
/* buf done with the nonuse super buf */
uint8_t i;
for (i=0; i<node->num_of_bufs; i++) {
mm_channel_qbuf(ch_obj, node->super_buf[i].buf);
}
}
free(node);
} else {
/* no superbuf avail, break the loop */
break;
}
}
}
/*===========================================================================
* FUNCTION : mm_channel_fsm_fn
*
* DESCRIPTION: channel finite state machine entry function. Depends on channel
* state, incoming event will be handled differently.
*
* PARAMETERS :
* @my_obj : ptr to a channel object
* @evt : channel event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_fsm_fn(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
CDBG("%s : E state = %d", __func__, my_obj->state);
switch (my_obj->state) {
case MM_CHANNEL_STATE_NOTUSED:
rc = mm_channel_fsm_fn_notused(my_obj, evt, in_val, out_val);
break;
case MM_CHANNEL_STATE_STOPPED:
rc = mm_channel_fsm_fn_stopped(my_obj, evt, in_val, out_val);
break;
case MM_CHANNEL_STATE_ACTIVE:
rc = mm_channel_fsm_fn_active(my_obj, evt, in_val, out_val);
break;
case MM_CHANNEL_STATE_PAUSED:
rc = mm_channel_fsm_fn_paused(my_obj, evt, in_val, out_val);
break;
default:
CDBG("%s: Not a valid state (%d)", __func__, my_obj->state);
break;
}
/* unlock ch_lock */
pthread_mutex_unlock(&my_obj->ch_lock);
CDBG("%s : X rc = %d", __func__, rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_fsm_fn_notused
*
* DESCRIPTION: channel finite state machine function to handle event
* in NOT_USED state.
*
* PARAMETERS :
* @my_obj : ptr to a channel object
* @evt : channel event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_fsm_fn_notused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
switch (evt) {
default:
CDBG_ERROR("%s: invalid state (%d) for evt (%d), in(%p), out(%p)",
__func__, my_obj->state, evt, in_val, out_val);
break;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_fsm_fn_stopped
*
* DESCRIPTION: channel finite state machine function to handle event
* in STOPPED state.
*
* PARAMETERS :
* @my_obj : ptr to a channel object
* @evt : channel event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_fsm_fn_stopped(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
CDBG("%s : E evt = %d", __func__, evt);
switch (evt) {
case MM_CHANNEL_EVT_ADD_STREAM:
{
uint32_t s_hdl = 0;
s_hdl = mm_channel_add_stream(my_obj);
*((uint32_t*)out_val) = s_hdl;
rc = 0;
}
break;
case MM_CHANNEL_EVT_DEL_STREAM:
{
uint32_t s_id = (uint32_t)in_val;
rc = mm_channel_del_stream(my_obj, s_id);
}
break;
case MM_CHANNEL_EVT_START:
{
rc = mm_channel_start(my_obj);
/* first stream started in stopped state
* move to active state */
if (0 == rc) {
my_obj->state = MM_CHANNEL_STATE_ACTIVE;
}
}
break;
case MM_CHANNEL_EVT_CONFIG_STREAM:
{
mm_evt_paylod_config_stream_t *payload =
(mm_evt_paylod_config_stream_t *)in_val;
rc = mm_channel_config_stream(my_obj,
payload->stream_id,
payload->config);
}
break;
case MM_CHANNEL_EVT_GET_BUNDLE_INFO:
{
cam_bundle_config_t *payload =
(cam_bundle_config_t *)in_val;
rc = mm_channel_get_bundle_info(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_DELETE:
{
mm_channel_release(my_obj);
rc = 0;
}
break;
case MM_CHANNEL_EVT_SET_STREAM_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_channel_set_stream_parm(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_GET_STREAM_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_channel_get_stream_parm(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_DO_STREAM_ACTION:
{
mm_evt_paylod_do_stream_action_t *payload =
(mm_evt_paylod_do_stream_action_t *)in_val;
rc = mm_channel_do_stream_action(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_MAP_STREAM_BUF:
{
mm_evt_paylod_map_stream_buf_t *payload =
(mm_evt_paylod_map_stream_buf_t *)in_val;
rc = mm_channel_map_stream_buf(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_UNMAP_STREAM_BUF:
{
mm_evt_paylod_unmap_stream_buf_t *payload =
(mm_evt_paylod_unmap_stream_buf_t *)in_val;
rc = mm_channel_unmap_stream_buf(my_obj, payload);
}
break;
default:
CDBG_ERROR("%s: invalid state (%d) for evt (%d)",
__func__, my_obj->state, evt);
break;
}
CDBG("%s : E rc = %d", __func__, rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_fsm_fn_active
*
* DESCRIPTION: channel finite state machine function to handle event
* in ACTIVE state.
*
* PARAMETERS :
* @my_obj : ptr to a channel object
* @evt : channel event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_fsm_fn_active(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
CDBG("%s : E evt = %d", __func__, evt);
switch (evt) {
case MM_CHANNEL_EVT_STOP:
{
rc = mm_channel_stop(my_obj);
my_obj->state = MM_CHANNEL_STATE_STOPPED;
}
break;
case MM_CHANNEL_EVT_REQUEST_SUPER_BUF:
{
uint32_t num_buf_requested = (uint32_t)in_val;
uint32_t num_retro_buf_requested = (uint32_t)out_val;
rc = mm_channel_request_super_buf(my_obj,
num_buf_requested, num_retro_buf_requested);
}
break;
case MM_CHANNEL_EVT_CANCEL_REQUEST_SUPER_BUF:
{
rc = mm_channel_cancel_super_buf_request(my_obj);
}
break;
case MM_CHANNEL_EVT_FLUSH_SUPER_BUF_QUEUE:
{
uint32_t frame_idx = (uint32_t)in_val;
rc = mm_channel_flush_super_buf_queue(my_obj, frame_idx);
}
break;
case MM_CHANNEL_EVT_START_ZSL_SNAPSHOT:
{
rc = mm_channel_start_zsl_snapshot(my_obj);
}
break;
case MM_CHANNEL_EVT_STOP_ZSL_SNAPSHOT:
{
rc = mm_channel_stop_zsl_snapshot(my_obj);
}
break;
case MM_CHANNEL_EVT_CONFIG_NOTIFY_MODE:
{
mm_camera_super_buf_notify_mode_t notify_mode = ( mm_camera_super_buf_notify_mode_t ) in_val;
rc = mm_channel_config_notify_mode(my_obj, notify_mode);
}
break;
case MM_CHANNEL_EVT_SET_STREAM_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_channel_set_stream_parm(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_GET_STREAM_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_channel_get_stream_parm(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_DO_STREAM_ACTION:
{
mm_evt_paylod_do_stream_action_t *payload =
(mm_evt_paylod_do_stream_action_t *)in_val;
rc = mm_channel_do_stream_action(my_obj, payload);
}
break;
case MM_CHANNEL_EVT_MAP_STREAM_BUF:
{
mm_evt_paylod_map_stream_buf_t *payload =
(mm_evt_paylod_map_stream_buf_t *)in_val;
if (payload != NULL) {
uint8_t type = payload->buf_type;
if ((type == CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF) ||
(type == CAM_MAPPING_BUF_TYPE_OFFLINE_META_BUF)) {
rc = mm_channel_map_stream_buf(my_obj, payload);
}
} else {
CDBG_ERROR("%s: cannot map regualr stream buf in active state", __func__);
}
}
break;
case MM_CHANNEL_EVT_UNMAP_STREAM_BUF:
{
mm_evt_paylod_unmap_stream_buf_t *payload =
(mm_evt_paylod_unmap_stream_buf_t *)in_val;
if (payload != NULL) {
uint8_t type = payload->buf_type;
if ((type == CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF) ||
(type == CAM_MAPPING_BUF_TYPE_OFFLINE_META_BUF)) {
rc = mm_channel_unmap_stream_buf(my_obj, payload);
}
} else {
CDBG_ERROR("%s: cannot unmap regualr stream buf in active state", __func__);
}
}
break;
case MM_CHANNEL_EVT_AF_BRACKETING:
{
CDBG_HIGH("MM_CHANNEL_EVT_AF_BRACKETING");
int32_t start_flag = ( int32_t ) in_val;
mm_camera_generic_cmd_t gen_cmd;
gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_AF_BRACKETING;
gen_cmd.payload[0] = start_flag;
rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd);
}
break;
case MM_CHANNEL_EVT_AE_BRACKETING:
{
CDBG_HIGH("MM_CHANNEL_EVT_AE_BRACKETING");
int32_t start_flag = ( int32_t ) in_val;
mm_camera_generic_cmd_t gen_cmd;
gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_AE_BRACKETING;
gen_cmd.payload[0] = start_flag;
rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd);
}
break;
case MM_CHANNEL_EVT_FLASH_BRACKETING:
{
CDBG_HIGH("MM_CHANNEL_EVT_FLASH_BRACKETING");
int32_t start_flag = ( int32_t ) in_val;
mm_camera_generic_cmd_t gen_cmd;
gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_FLASH_BRACKETING;
gen_cmd.payload[0] = start_flag;
rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd);
}
break;
case MM_CHANNEL_EVT_ZOOM_1X:
{
CDBG_HIGH("MM_CHANNEL_EVT_ZOOM_1X");
int32_t start_flag = ( int32_t ) in_val;
mm_camera_generic_cmd_t gen_cmd;
gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_ZOOM_1X;
gen_cmd.payload[0] = start_flag;
rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd);
}
break;
default:
CDBG_ERROR("%s: invalid state (%d) for evt (%d), in(%p), out(%p)",
__func__, my_obj->state, evt, in_val, out_val);
break;
}
CDBG("%s : X rc = %d", __func__, rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_fsm_fn_paused
*
* DESCRIPTION: channel finite state machine function to handle event
* in PAUSED state.
*
* PARAMETERS :
* @my_obj : ptr to a channel object
* @evt : channel event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_fsm_fn_paused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
/* currently we are not supporting pause/resume channel */
CDBG_ERROR("%s: invalid state (%d) for evt (%d), in(%p), out(%p)",
__func__, my_obj->state, evt, in_val, out_val);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_init
*
* DESCRIPTION: initialize a channel
*
* PARAMETERS :
* @my_obj : channel object be to initialized
* @attr : bundle attribute of the channel if needed
* @channel_cb : callback function for bundle data notify
* @userdata : user data ptr
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : if no bundle data notify is needed, meaning each stream in the
* channel will have its own stream data notify callback, then
* attr, channel_cb, and userdata can be NULL. In this case,
* no matching logic will be performed in channel for the bundling.
*==========================================================================*/
int32_t mm_channel_init(mm_channel_t *my_obj,
mm_camera_channel_attr_t *attr,
mm_camera_buf_notify_t channel_cb,
void *userdata)
{
int32_t rc = 0;
my_obj->bundle.super_buf_notify_cb = channel_cb;
my_obj->bundle.user_data = userdata;
if (NULL != attr) {
my_obj->bundle.superbuf_queue.attr = *attr;
}
CDBG("%s : Launch data poll thread in channel open", __func__);
mm_camera_poll_thread_launch(&my_obj->poll_thread[0],
MM_CAMERA_POLL_TYPE_DATA);
/* change state to stopped state */
my_obj->state = MM_CHANNEL_STATE_STOPPED;
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_release
*
* DESCRIPTION: release a channel resource. Channel state will move to UNUSED
* state after this call.
*
* PARAMETERS :
* @my_obj : channel object
*
* RETURN : none
*==========================================================================*/
void mm_channel_release(mm_channel_t *my_obj)
{
/* stop data poll thread */
mm_camera_poll_thread_release(&my_obj->poll_thread[0]);
/* change state to notused state */
my_obj->state = MM_CHANNEL_STATE_NOTUSED;
}
/*===========================================================================
* FUNCTION : mm_channel_add_stream
*
* DESCRIPTION: add a stream into the channel
*
* PARAMETERS :
* @my_obj : channel object
*
* RETURN : uint32_t type of stream handle
* 0 -- invalid stream handle, meaning the op failed
* >0 -- successfully added a stream with a valid handle
*==========================================================================*/
uint32_t mm_channel_add_stream(mm_channel_t *my_obj)
{
int32_t rc = 0;
uint8_t idx = 0;
uint32_t s_hdl = 0;
mm_stream_t *stream_obj = NULL;
CDBG("%s : E", __func__);
/* check available stream */
for (idx = 0; idx < MAX_STREAM_NUM_IN_BUNDLE; idx++) {
if (MM_STREAM_STATE_NOTUSED == my_obj->streams[idx].state) {
stream_obj = &my_obj->streams[idx];
break;
}
}
if (NULL == stream_obj) {
CDBG_ERROR("%s: streams reach max, no more stream allowed to add", __func__);
return s_hdl;
}
/* initialize stream object */
memset(stream_obj, 0, sizeof(mm_stream_t));
stream_obj->fd = -1;
stream_obj->my_hdl = mm_camera_util_generate_handler(idx);
stream_obj->ch_obj = my_obj;
pthread_mutex_init(&stream_obj->buf_lock, NULL);
pthread_mutex_init(&stream_obj->cb_lock, NULL);
stream_obj->state = MM_STREAM_STATE_INITED;
/* acquire stream */
rc = mm_stream_fsm_fn(stream_obj, MM_STREAM_EVT_ACQUIRE, NULL, NULL);
if (0 == rc) {
s_hdl = stream_obj->my_hdl;
} else {
/* error during acquire, de-init */
pthread_mutex_destroy(&stream_obj->buf_lock);
pthread_mutex_destroy(&stream_obj->cb_lock);
memset(stream_obj, 0, sizeof(mm_stream_t));
}
CDBG("%s : stream handle = %d", __func__, s_hdl);
return s_hdl;
}
/*===========================================================================
* FUNCTION : mm_channel_del_stream
*
* DESCRIPTION: delete a stream from the channel bu its handle
*
* PARAMETERS :
* @my_obj : channel object
* @stream_id : stream handle
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : assume steam is stooped before it can be deleted
*==========================================================================*/
int32_t mm_channel_del_stream(mm_channel_t *my_obj,
uint32_t stream_id)
{
int rc = -1;
mm_stream_t * stream_obj = NULL;
stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
if (NULL == stream_obj) {
CDBG_ERROR("%s :Invalid Stream Object for stream_id = %d",
__func__, stream_id);
return rc;
}
rc = mm_stream_fsm_fn(stream_obj,
MM_STREAM_EVT_RELEASE,
NULL,
NULL);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_config_stream
*
* DESCRIPTION: configure a stream
*
* PARAMETERS :
* @my_obj : channel object
* @stream_id : stream handle
* @config : stream configuration
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_config_stream(mm_channel_t *my_obj,
uint32_t stream_id,
mm_camera_stream_config_t *config)
{
int rc = -1;
mm_stream_t * stream_obj = NULL;
CDBG("%s : E stream ID = %d", __func__, stream_id);
stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
if (NULL == stream_obj) {
CDBG_ERROR("%s :Invalid Stream Object for stream_id = %d", __func__, stream_id);
return rc;
}
/* set stream fmt */
rc = mm_stream_fsm_fn(stream_obj,
MM_STREAM_EVT_SET_FMT,
(void *)config,
NULL);
CDBG("%s : X rc = %d",__func__,rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_get_bundle_info
*
* DESCRIPTION: query bundle info of the channel, which should include all
* streams within this channel
*
* PARAMETERS :
* @my_obj : channel object
* @bundle_info : bundle info to be filled in
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_get_bundle_info(mm_channel_t *my_obj,
cam_bundle_config_t *bundle_info)
{
int i;
mm_stream_t *s_obj = NULL;
int32_t rc = 0;
memset(bundle_info, 0, sizeof(cam_bundle_config_t));
bundle_info->bundle_id = my_obj->my_hdl;
bundle_info->num_of_streams = 0;
for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
if (my_obj->streams[i].my_hdl > 0) {
s_obj = mm_channel_util_get_stream_by_handler(my_obj,
my_obj->streams[i].my_hdl);
if (NULL != s_obj) {
if (CAM_STREAM_TYPE_METADATA != s_obj->stream_info->stream_type) {
bundle_info->stream_ids[bundle_info->num_of_streams++] =
s_obj->server_stream_id;
}
} else {
CDBG_ERROR("%s: cannot find stream obj (%d) by handler (%d)",
__func__, i, my_obj->streams[i].my_hdl);
rc = -1;
break;
}
}
}
if (rc != 0) {
/* error, reset to 0 */
memset(bundle_info, 0, sizeof(cam_bundle_config_t));
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_start
*
* DESCRIPTION: start a channel, which will start all streams in the channel
*
* PARAMETERS :
* @my_obj : channel object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_start(mm_channel_t *my_obj)
{
int32_t rc = 0;
int i, j;
mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL};
uint8_t num_streams_to_start = 0;
mm_stream_t *s_obj = NULL;
int meta_stream_idx = 0;
for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
if (my_obj->streams[i].my_hdl > 0) {
s_obj = mm_channel_util_get_stream_by_handler(my_obj,
my_obj->streams[i].my_hdl);
if (NULL != s_obj) {
/* remember meta data stream index */
if (s_obj->stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
meta_stream_idx = num_streams_to_start;
}
s_objs[num_streams_to_start++] = s_obj;
}
}
}
if (meta_stream_idx > 0 ) {
/* always start meta data stream first, so switch the stream object with the first one */
s_obj = s_objs[0];
s_objs[0] = s_objs[meta_stream_idx];
s_objs[meta_stream_idx] = s_obj;
}
if (NULL != my_obj->bundle.super_buf_notify_cb) {
/* need to send up cb, therefore launch thread */
/* init superbuf queue */
mm_channel_superbuf_queue_init(&my_obj->bundle.superbuf_queue);
my_obj->bundle.superbuf_queue.num_streams = num_streams_to_start;
my_obj->bundle.superbuf_queue.expected_frame_id = 0;
my_obj->bundle.superbuf_queue.expected_frame_id_without_led = 0;
my_obj->bundle.superbuf_queue.led_off_start_frame_id = 0;
my_obj->bundle.superbuf_queue.led_on_start_frame_id = 0;
my_obj->bundle.superbuf_queue.led_on_num_frames = 0;
for (i = 0; i < num_streams_to_start; i++) {
/* set bundled flag to streams */
s_objs[i]->is_bundled = 1;
/* init bundled streams to invalid value -1 */
my_obj->bundle.superbuf_queue.bundled_streams[i] = s_objs[i]->my_hdl;
}
/* launch cb thread for dispatching super buf through cb */
mm_camera_cmd_thread_launch(&my_obj->cb_thread,
mm_channel_dispatch_super_buf,
(void*)my_obj);
/* launch cmd thread for super buf dataCB */
mm_camera_cmd_thread_launch(&my_obj->cmd_thread,
mm_channel_process_stream_buf,
(void*)my_obj);
/* set flag to TRUE */
my_obj->bundle.is_active = TRUE;
}
for (i = 0; i < num_streams_to_start; i++) {
/* all streams within a channel should be started at the same time */
if (s_objs[i]->state == MM_STREAM_STATE_ACTIVE) {
CDBG_ERROR("%s: stream already started idx(%d)", __func__, i);
rc = -1;
break;
}
/* allocate buf */
rc = mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_GET_BUF,
NULL,
NULL);
if (0 != rc) {
CDBG_ERROR("%s: get buf failed at idx(%d)", __func__, i);
break;
}
/* reg buf */
rc = mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_REG_BUF,
NULL,
NULL);
if (0 != rc) {
CDBG_ERROR("%s: reg buf failed at idx(%d)", __func__, i);
break;
}
/* start stream */
rc = mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_START,
NULL,
NULL);
if (0 != rc) {
CDBG_ERROR("%s: start stream failed at idx(%d)", __func__, i);
break;
}
}
/* error handling */
if (0 != rc) {
for (j=0; j<=i; j++) {
/* stop streams*/
mm_stream_fsm_fn(s_objs[j],
MM_STREAM_EVT_STOP,
NULL,
NULL);
/* unreg buf */
mm_stream_fsm_fn(s_objs[j],
MM_STREAM_EVT_UNREG_BUF,
NULL,
NULL);
/* put buf back */
mm_stream_fsm_fn(s_objs[j],
MM_STREAM_EVT_PUT_BUF,
NULL,
NULL);
}
/* destroy super buf cmd thread */
if (TRUE == my_obj->bundle.is_active) {
/* first stop bundle thread */
mm_camera_cmd_thread_release(&my_obj->cmd_thread);
mm_camera_cmd_thread_release(&my_obj->cb_thread);
/* deinit superbuf queue */
mm_channel_superbuf_queue_deinit(&my_obj->bundle.superbuf_queue);
/* memset bundle info */
memset(&my_obj->bundle, 0, sizeof(mm_channel_bundle_t));
}
}
my_obj->bWaitForPrepSnapshotDone = 0;
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_stop
*
* DESCRIPTION: stop a channel, which will stop all streams in the channel
*
* PARAMETERS :
* @my_obj : channel object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_stop(mm_channel_t *my_obj)
{
int32_t rc = 0;
int i;
mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL};
uint8_t num_streams_to_stop = 0;
mm_stream_t *s_obj = NULL;
int meta_stream_idx = 0;
for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
if (my_obj->streams[i].my_hdl > 0) {
s_obj = mm_channel_util_get_stream_by_handler(my_obj,
my_obj->streams[i].my_hdl);
if (NULL != s_obj) {
/* remember meta data stream index */
if (s_obj->stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
meta_stream_idx = num_streams_to_stop;
}
s_objs[num_streams_to_stop++] = s_obj;
}
}
}
if (meta_stream_idx < num_streams_to_stop - 1 ) {
/* always stop meta data stream last, so switch the stream object with the last one */
s_obj = s_objs[num_streams_to_stop - 1];
s_objs[num_streams_to_stop - 1] = s_objs[meta_stream_idx];
s_objs[meta_stream_idx] = s_obj;
}
for (i = 0; i < num_streams_to_stop; i++) {
/* stream off */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_STOP,
NULL,
NULL);
/* unreg buf at kernel */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_UNREG_BUF,
NULL,
NULL);
}
/* destroy super buf cmd thread */
if (TRUE == my_obj->bundle.is_active) {
/* first stop bundle thread */
mm_camera_cmd_thread_release(&my_obj->cmd_thread);
mm_camera_cmd_thread_release(&my_obj->cb_thread);
/* deinit superbuf queue */
mm_channel_superbuf_queue_deinit(&my_obj->bundle.superbuf_queue);
/* memset bundle info */
memset(&my_obj->bundle, 0, sizeof(mm_channel_bundle_t));
}
/* since all streams are stopped, we are safe to
* release all buffers allocated in stream */
for (i = 0; i < num_streams_to_stop; i++) {
/* put buf back */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_PUT_BUF,
NULL,
NULL);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_request_super_buf
*
* DESCRIPTION: for burst mode in bundle, reuqest certain amount of matched
* frames from superbuf queue
*
* PARAMETERS :
* @my_obj : channel object
* @num_buf_requested : number of matched frames needed
* @num_retro_buf_requested : number of retro frames needed
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_request_super_buf(mm_channel_t *my_obj,
uint32_t num_buf_requested, uint32_t num_retro_buf_requested)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
/* set pending_cnt
* will trigger dispatching super frames if pending_cnt > 0 */
/* send cam_sem_post to wake up cmd thread to dispatch super buffer */
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->cmd_type = MM_CAMERA_CMD_TYPE_REQ_DATA_CB;
node->u.req_buf.num_buf_requested = num_buf_requested;
node->u.req_buf.num_retro_buf_requested = num_retro_buf_requested;
/* enqueue to cmd thread */
cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
rc = -1;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_cancel_super_buf_request
*
* DESCRIPTION: for burst mode in bundle, cancel the reuqest for certain amount
* of matched frames from superbuf queue
*
* PARAMETERS :
* @my_obj : channel object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj)
{
int32_t rc = 0;
/* reset pending_cnt */
rc = mm_channel_request_super_buf(my_obj, 0, 0);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_flush_super_buf_queue
*
* DESCRIPTION: flush superbuf queue
*
* PARAMETERS :
* @my_obj : channel object
* @frame_idx : frame idx until which to flush all superbufs
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj, uint32_t frame_idx)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->cmd_type = MM_CAMERA_CMD_TYPE_FLUSH_QUEUE;
node->u.frame_idx = frame_idx;
/* enqueue to cmd thread */
cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
rc = -1;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_config_notify_mode
*
* DESCRIPTION: configure notification mode
*
* PARAMETERS :
* @my_obj : channel object
* @notify_mode : notification mode
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
mm_camera_super_buf_notify_mode_t notify_mode)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->u.notify_mode = notify_mode;
node->cmd_type = MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY;
/* enqueue to cmd thread */
cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
rc = -1;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_start_zsl_snapshot
*
* DESCRIPTION: start zsl snapshot
*
* PARAMETERS :
* @my_obj : channel object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_start_zsl_snapshot(mm_channel_t *my_obj)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->cmd_type = MM_CAMERA_CMD_TYPE_START_ZSL;
/* enqueue to cmd thread */
cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
rc = -1;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_stop_zsl_snapshot
*
* DESCRIPTION: stop zsl snapshot
*
* PARAMETERS :
* @my_obj : channel object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_stop_zsl_snapshot(mm_channel_t *my_obj)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->cmd_type = MM_CAMERA_CMD_TYPE_STOP_ZSL;
/* enqueue to cmd thread */
cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
rc = -1;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_qbuf
*
* DESCRIPTION: enqueue buffer back to kernel
*
* PARAMETERS :
* @my_obj : channel object
* @buf : buf ptr to be enqueued
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_qbuf(mm_channel_t *my_obj,
mm_camera_buf_def_t *buf)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, buf->stream_id);
if (NULL != s_obj) {
rc = mm_stream_fsm_fn(s_obj,
MM_STREAM_EVT_QBUF,
(void *)buf,
NULL);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_set_stream_parms
*
* DESCRIPTION: set parameters per stream
*
* PARAMETERS :
* @my_obj : channel object
* @s_id : stream handle
* @parms : ptr to a param struct to be set to server
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : Assume the parms struct buf is already mapped to server via
* domain socket. Corresponding fields of parameters to be set
* are already filled in by upper layer caller.
*==========================================================================*/
int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
mm_evt_paylod_set_get_stream_parms_t *payload)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
payload->stream_id);
if (NULL != s_obj) {
rc = mm_stream_fsm_fn(s_obj,
MM_STREAM_EVT_SET_PARM,
(void *)payload,
NULL);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_get_stream_parms
*
* DESCRIPTION: get parameters per stream
*
* PARAMETERS :
* @my_obj : channel object
* @s_id : stream handle
* @parms : ptr to a param struct to be get from server
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : Assume the parms struct buf is already mapped to server via
* domain socket. Parameters to be get from server are already
* filled in by upper layer caller. After this call, corresponding
* fields of requested parameters will be filled in by server with
* detailed information.
*==========================================================================*/
int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
mm_evt_paylod_set_get_stream_parms_t *payload)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
payload->stream_id);
if (NULL != s_obj) {
rc = mm_stream_fsm_fn(s_obj,
MM_STREAM_EVT_GET_PARM,
(void *)payload,
NULL);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_do_stream_action
*
* DESCRIPTION: request server to perform stream based action. Maybe removed later
* if the functionality is included in mm_camera_set_parms
*
* PARAMETERS :
* @my_obj : channel object
* @s_id : stream handle
* @actions : ptr to an action struct buf to be performed by server
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : Assume the action struct buf is already mapped to server via
* domain socket. Actions to be performed by server are already
* filled in by upper layer caller.
*==========================================================================*/
int32_t mm_channel_do_stream_action(mm_channel_t *my_obj,
mm_evt_paylod_do_stream_action_t *payload)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
payload->stream_id);
if (NULL != s_obj) {
rc = mm_stream_fsm_fn(s_obj,
MM_STREAM_EVT_DO_ACTION,
(void *)payload,
NULL);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_map_stream_buf
*
* DESCRIPTION: mapping stream buffer via domain socket to server
*
* PARAMETERS :
* @my_obj : channel object
* @payload : ptr to payload for mapping
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj,
mm_evt_paylod_map_stream_buf_t *payload)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
payload->stream_id);
if (NULL != s_obj) {
rc = mm_stream_map_buf(s_obj,
payload->buf_type,
payload->buf_idx,
payload->plane_idx,
payload->fd,
payload->size);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_unmap_stream_buf
*
* DESCRIPTION: unmapping stream buffer via domain socket to server
*
* PARAMETERS :
* @my_obj : channel object
* @payload : ptr to unmap payload
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_unmap_stream_buf(mm_channel_t *my_obj,
mm_evt_paylod_unmap_stream_buf_t *payload)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
payload->stream_id);
if (NULL != s_obj) {
rc = mm_stream_unmap_buf(s_obj, payload->buf_type,
payload->buf_idx, payload->plane_idx);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_queue_init
*
* DESCRIPTION: initialize superbuf queue in the channel
*
* PARAMETERS :
* @queue : ptr to superbuf queue to be initialized
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue)
{
return cam_queue_init(&queue->que);
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_queue_deinit
*
* DESCRIPTION: deinitialize superbuf queue in the channel
*
* PARAMETERS :
* @queue : ptr to superbuf queue to be deinitialized
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue)
{
return cam_queue_deinit(&queue->que);
}
/*===========================================================================
* FUNCTION : mm_channel_util_seq_comp_w_rollover
*
* DESCRIPTION: utility function to handle sequence number comparison with rollover
*
* PARAMETERS :
* @v1 : first value to be compared
* @v2 : second value to be compared
*
* RETURN : int8_t type of comparison result
* >0 -- v1 larger than v2
* =0 -- vi equal to v2
* <0 -- v1 smaller than v2
*==========================================================================*/
int8_t mm_channel_util_seq_comp_w_rollover(uint32_t v1,
uint32_t v2)
{
int8_t ret = 0;
/* TODO: need to handle the case if v2 roll over to 0 */
if (v1 > v2) {
ret = 1;
} else if (v1 < v2) {
ret = -1;
}
return ret;
}
/*===========================================================================
* FUNCTION : mm_channel_handle_metadata
*
* DESCRIPTION: Handle frame matching logic change due to metadata
*
* PARAMETERS :
* @ch_obj : channel object
* @queue : superbuf queue
* @buf_info: new buffer from stream
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_handle_metadata(
mm_channel_t* ch_obj,
mm_channel_queue_t * queue,
mm_camera_buf_info_t *buf_info)
{
int rc = 0 ;
mm_stream_t* stream_obj = NULL;
stream_obj = mm_channel_util_get_stream_by_handler(ch_obj,
buf_info->stream_id);
uint8_t is_prep_snapshot_done_valid = 0;
uint8_t is_good_frame_idx_range_valid = 0;
int32_t prep_snapshot_done_state;
cam_frame_idx_range_t good_frame_idx_range;
uint8_t is_crop_1x_found = 0;
uint32_t snapshot_stream_id = 0;
uint32_t i;
/* Set expected frame id to a future frame idx, large enough to wait
* for good_frame_idx_range, and small enough to still capture an image */
const int max_future_frame_offset = 100;
memset(&good_frame_idx_range, 0, sizeof(good_frame_idx_range));
if (NULL == stream_obj) {
CDBG_ERROR("%s: Invalid Stream Object for stream_id = %d",
__func__, buf_info->stream_id);
rc = -1;
goto end;
}
if (NULL == stream_obj->stream_info) {
CDBG_ERROR("%s: NULL stream info for stream_id = %d",
__func__, buf_info->stream_id);
rc = -1;
goto end;
}
if (CAM_STREAM_TYPE_METADATA == stream_obj->stream_info->stream_type) {
const metadata_buffer_t *metadata;
metadata = (const metadata_buffer_t *)buf_info->buf->buffer;
if (NULL == metadata) {
CDBG_ERROR("%s: NULL metadata buffer for metadata stream",
__func__);
rc = -1;
goto end;
}
CDBG("%s: E , expected frame id: %d", __func__, queue->expected_frame_id);
if (IS_META_AVAILABLE(CAM_INTF_META_PREP_SNAPSHOT_DONE, metadata)) {
prep_snapshot_done_state = *((int32_t*)
POINTER_OF_META(CAM_INTF_META_PREP_SNAPSHOT_DONE, metadata));
is_prep_snapshot_done_valid = 1;
CDBG("%s: prepare snapshot done valid ", __func__);
}
if (IS_META_AVAILABLE(CAM_INTF_META_GOOD_FRAME_IDX_RANGE, metadata)){
good_frame_idx_range = *((cam_frame_idx_range_t*)
POINTER_OF_META(CAM_INTF_META_GOOD_FRAME_IDX_RANGE, metadata));
is_good_frame_idx_range_valid = 1;
CDBG("%s: good_frame_idx_range : min: %d, max: %d , num frames = %d",
__func__, good_frame_idx_range.min_frame_idx,
good_frame_idx_range.max_frame_idx, good_frame_idx_range.num_led_on_frames);
}
if (IS_META_AVAILABLE(CAM_INTF_META_CROP_DATA, metadata)) {
cam_crop_data_t crop_data = *((cam_crop_data_t *)
POINTER_OF_META(CAM_INTF_META_CROP_DATA, metadata));
for (i=0; i<ARRAY_SIZE(ch_obj->streams); i++) {
if (CAM_STREAM_TYPE_SNAPSHOT ==
ch_obj->streams[i].stream_info->stream_type) {
snapshot_stream_id = ch_obj->streams[i].server_stream_id;
break;
}
}
for (i=0; i<crop_data.num_of_streams; i++) {
if (snapshot_stream_id == crop_data.crop_info[i].stream_id) {
if (!crop_data.crop_info[i].crop.left &&
!crop_data.crop_info[i].crop.top) {
is_crop_1x_found = 1;
break;
}
}
}
}
if (is_prep_snapshot_done_valid &&
is_good_frame_idx_range_valid) {
CDBG_ERROR("%s: prep_snapshot_done and good_idx_range shouldn't be "
"valid at the same time", __func__);
rc = -1;
goto end;
}
if (ch_obj->isZoom1xFrameRequested) {
if (is_crop_1x_found) {
ch_obj->isZoom1xFrameRequested = 0;
queue->expected_frame_id = buf_info->frame_idx + 1;
} else {
queue->expected_frame_id += max_future_frame_offset;
/* Flush unwanted frames */
mm_channel_superbuf_flush_matched(ch_obj, queue);
}
goto end;
}
if (is_prep_snapshot_done_valid) {
ch_obj->bWaitForPrepSnapshotDone = 0;
if (prep_snapshot_done_state == NEED_FUTURE_FRAME) {
queue->expected_frame_id += max_future_frame_offset;
CDBG("%s: [ZSL Retro] NEED_FUTURE_FRAME, expected frame id = %d ",
__func__, queue->expected_frame_id);
mm_channel_superbuf_flush(ch_obj, queue);
ch_obj->needLEDFlash = TRUE;
} else {
ch_obj->needLEDFlash = FALSE;
}
} else if (is_good_frame_idx_range_valid) {
if (good_frame_idx_range.min_frame_idx >
queue->expected_frame_id) {
CDBG_HIGH("%s: [ZSL Retro] min_frame_idx %d is greater than expected_frame_id %d",
__func__, good_frame_idx_range.min_frame_idx,
queue->expected_frame_id);
}
queue->expected_frame_id =
good_frame_idx_range.min_frame_idx;
if((ch_obj->needLEDFlash == TRUE) && (ch_obj->burstSnapNum > 1)) {
queue->expected_frame_id =
good_frame_idx_range.min_frame_idx;
queue->led_on_start_frame_id =
good_frame_idx_range.min_frame_idx;
queue->led_off_start_frame_id =
good_frame_idx_range.max_frame_idx;
queue->once = 0;
queue->led_on_num_frames =
good_frame_idx_range.num_led_on_frames;
queue->frame_skip_count = good_frame_idx_range.frame_skip_count;
CDBG("%s: [ZSL Retro] Need Flash, expected frame id = %d,"
" led_on start = %d, led off start = %d, led on frames = %d ",
__func__, queue->expected_frame_id, queue->led_on_start_frame_id,
queue->led_off_start_frame_id, queue->led_on_num_frames);
} else {
queue->expected_frame_id =
good_frame_idx_range.min_frame_idx;
CDBG("%s: [ZSL Retro]No flash, expected frame id = %d ",
__func__, queue->expected_frame_id);
}
} else if (ch_obj->need3ABracketing && !is_good_frame_idx_range_valid) {
/* Flush unwanted frames */
mm_channel_superbuf_flush_matched(ch_obj, queue);
queue->expected_frame_id += max_future_frame_offset;
}
if (ch_obj->isFlashBracketingEnabled &&
is_good_frame_idx_range_valid) {
/* Flash bracketing needs two frames, with & without led flash.
* in valid range min frame is with led flash and max frame is
* without led flash */
queue->expected_frame_id =
good_frame_idx_range.min_frame_idx;
/* max frame is without led flash */
queue->expected_frame_id_without_led =
good_frame_idx_range.max_frame_idx;
} else if (is_good_frame_idx_range_valid) {
if (good_frame_idx_range.min_frame_idx >
queue->expected_frame_id) {
CDBG_HIGH("%s: min_frame_idx %d is greater than expected_frame_id %d",
__func__, good_frame_idx_range.min_frame_idx,
queue->expected_frame_id);
}
queue->expected_frame_id =
good_frame_idx_range.min_frame_idx;
ch_obj->need3ABracketing = FALSE;
}
if((ch_obj->burstSnapNum > 1) && (ch_obj->needLEDFlash == TRUE) &&
!ch_obj->isFlashBracketingEnabled) {
if((buf_info->frame_idx >= queue->led_off_start_frame_id)
&& !queue->once) {
CDBG("%s: [ZSL Retro]Burst snap num = %d ",
__func__, ch_obj->burstSnapNum);
// Skip frames from LED OFF frame to get a good frame
queue->expected_frame_id = queue->led_off_start_frame_id + queue->frame_skip_count;
queue->once = 1;
ch_obj->stopZslSnapshot = 1;
CDBG("%s:[ZSL Retro]Reached max led on frames = %d , expected id = %d",
__func__, buf_info->frame_idx, queue->expected_frame_id);
}
}
}
end:
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_comp_and_enqueue
*
* DESCRIPTION: implementation for matching logic for superbuf
*
* PARAMETERS :
* @ch_obj : channel object
* @queue : superbuf queue
* @buf_info: new buffer from stream
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_comp_and_enqueue(
mm_channel_t* ch_obj,
mm_channel_queue_t *queue,
mm_camera_buf_info_t *buf_info)
{
cam_node_t* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
mm_channel_queue_node_t* super_buf = NULL;
uint8_t buf_s_idx, i, found_super_buf, unmatched_bundles;
struct cam_list *last_buf, *insert_before_buf;
CDBG("%s: E", __func__);
for (buf_s_idx = 0; buf_s_idx < queue->num_streams; buf_s_idx++) {
if (buf_info->stream_id == queue->bundled_streams[buf_s_idx]) {
break;
}
}
if (buf_s_idx == queue->num_streams) {
CDBG_ERROR("%s: buf from stream (%d) not bundled", __func__, buf_info->stream_id);
return -1;
}
if (mm_channel_handle_metadata(ch_obj, queue, buf_info) < 0) {
mm_channel_qbuf(ch_obj, buf_info->buf);
return -1;
}
#if 0
mm_stream_t* stream_obj = mm_channel_util_get_stream_by_handler(ch_obj,
buf_info->stream_id);
if (CAM_STREAM_TYPE_METADATA == stream_obj->stream_info->stream_type) {
const metadata_buffer_t *metadata;
metadata = (const metadata_buffer_t *)buf_info->buf->buffer;
int32_t is_meta_valid = *((int32_t*)POINTER_OF(CAM_INTF_META_VALID, metadata));
CDBG("%s: meta_valid: %d\n", __func__, is_meta_valid);
if (!is_meta_valid) {
mm_channel_qbuf(ch_obj, buf_info->buf);
return 0;
}
}
#endif
if (mm_channel_util_seq_comp_w_rollover(buf_info->frame_idx,
queue->expected_frame_id) < 0) {
/* incoming buf is older than expected buf id, will discard it */
mm_channel_qbuf(ch_obj, buf_info->buf);
return 0;
}
if (MM_CAMERA_SUPER_BUF_PRIORITY_NORMAL != queue->attr.priority) {
/* TODO */
/* need to decide if we want to queue the frame based on focus or exposure
* if frame not to be queued, we need to qbuf it back */
}
/* comp */
pthread_mutex_lock(&queue->que.lock);
head = &queue->que.head.list;
/* get the last one in the queue which is possibly having no matching */
pos = head->next;
found_super_buf = 0;
unmatched_bundles = 0;
last_buf = NULL;
insert_before_buf = NULL;
while (pos != head) {
node = member_of(pos, cam_node_t, list);
super_buf = (mm_channel_queue_node_t*)node->data;
if (NULL != super_buf) {
if (super_buf->matched) {
/* find a matched super buf, move to next one */
pos = pos->next;
continue;
} else if ( buf_info->frame_idx == super_buf->frame_idx ) {
/* have an unmatched super buf that matches our frame idx,
* break the loop */
found_super_buf = 1;
break;
} else {
unmatched_bundles++;
if ( NULL == last_buf ) {
if ( super_buf->frame_idx < buf_info->frame_idx ) {
last_buf = pos;
}
}
if ( NULL == insert_before_buf ) {
if ( super_buf->frame_idx > buf_info->frame_idx ) {
insert_before_buf = pos;
}
}
pos = pos->next;
}
}
}
if ( found_super_buf ) {
super_buf->super_buf[buf_s_idx] = *buf_info;
/* check if superbuf is all matched */
super_buf->matched = 1;
for (i=0; i < super_buf->num_of_bufs; i++) {
if (super_buf->super_buf[i].frame_idx == 0) {
super_buf->matched = 0;
break;
}
}
if (super_buf->matched) {
if(ch_obj->isFlashBracketingEnabled) {
queue->expected_frame_id =
queue->expected_frame_id_without_led;
if (buf_info->frame_idx >=
queue->expected_frame_id_without_led) {
ch_obj->isFlashBracketingEnabled = FALSE;
}
} else {
queue->expected_frame_id = buf_info->frame_idx
+ queue->attr.post_frame_skip;
}
CDBG("%s: curr = %d, skip = %d , Expected Frame ID: %d",
__func__, buf_info->frame_idx,
queue->attr.post_frame_skip, queue->expected_frame_id);
queue->match_cnt++;
/* Any older unmatched buffer need to be released */
if ( last_buf ) {
while ( last_buf != pos ) {
node = member_of(last_buf, cam_node_t, list);
super_buf = (mm_channel_queue_node_t*)node->data;
if (NULL != super_buf) {
for (i=0; i<super_buf->num_of_bufs; i++) {
if (super_buf->super_buf[i].frame_idx != 0) {
mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
}
}
queue->que.size--;
last_buf = last_buf->next;
cam_list_del_node(&node->list);
free(node);
free(super_buf);
} else {
CDBG_ERROR(" %s : Invalid superbuf in queue!", __func__);
break;
}
}
}
}
} else {
if ( ( queue->attr.max_unmatched_frames < unmatched_bundles ) &&
( NULL == last_buf ) ) {
/* incoming frame is older than the last bundled one */
mm_channel_qbuf(ch_obj, buf_info->buf);
} else {
if ( queue->attr.max_unmatched_frames < unmatched_bundles ) {
/* release the oldest bundled superbuf */
node = member_of(last_buf, cam_node_t, list);
super_buf = (mm_channel_queue_node_t*)node->data;
for (i=0; i<super_buf->num_of_bufs; i++) {
if (super_buf->super_buf[i].frame_idx != 0) {
mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
}
}
queue->que.size--;
node = member_of(last_buf, cam_node_t, list);
cam_list_del_node(&node->list);
free(node);
free(super_buf);
}
/* insert the new frame at the appropriate position. */
mm_channel_queue_node_t *new_buf = NULL;
cam_node_t* new_node = NULL;
new_buf = (mm_channel_queue_node_t*)malloc(sizeof(mm_channel_queue_node_t));
new_node = (cam_node_t*)malloc(sizeof(cam_node_t));
if (NULL != new_buf && NULL != new_node) {
memset(new_buf, 0, sizeof(mm_channel_queue_node_t));
memset(new_node, 0, sizeof(cam_node_t));
new_node->data = (void *)new_buf;
new_buf->num_of_bufs = queue->num_streams;
new_buf->super_buf[buf_s_idx] = *buf_info;
new_buf->frame_idx = buf_info->frame_idx;
/* enqueue */
if ( insert_before_buf ) {
cam_list_insert_before_node(&new_node->list, insert_before_buf);
} else {
cam_list_add_tail_node(&new_node->list, &queue->que.head.list);
}
queue->que.size++;
if(queue->num_streams == 1) {
new_buf->matched = 1;
queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip;
queue->match_cnt++;
}
} else {
/* No memory */
if (NULL != new_buf) {
free(new_buf);
}
if (NULL != new_node) {
free(new_node);
}
/* qbuf the new buf since we cannot enqueue */
mm_channel_qbuf(ch_obj, buf_info->buf);
}
}
}
pthread_mutex_unlock(&queue->que.lock);
CDBG("%s: X", __func__);
return 0;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_dequeue_internal
*
* DESCRIPTION: internal implementation for dequeue from the superbuf queue
*
* PARAMETERS :
* @queue : superbuf queue
* @matched_only : if dequeued buf should be matched
*
* RETURN : ptr to a node from superbuf queue
*==========================================================================*/
mm_channel_queue_node_t* mm_channel_superbuf_dequeue_internal(mm_channel_queue_t * queue,
uint8_t matched_only)
{
cam_node_t* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
mm_channel_queue_node_t* super_buf = NULL;
head = &queue->que.head.list;
pos = head->next;
if (pos != head) {
/* get the first node */
node = member_of(pos, cam_node_t, list);
super_buf = (mm_channel_queue_node_t*)node->data;
if ( (NULL != super_buf) &&
(matched_only == TRUE) &&
(super_buf->matched == FALSE) ) {
/* require to dequeue matched frame only, but this superbuf is not matched,
simply set return ptr to NULL */
super_buf = NULL;
}
if (NULL != super_buf) {
/* remove from the queue */
cam_list_del_node(&node->list);
queue->que.size--;
if (super_buf->matched == TRUE) {
queue->match_cnt--;
}
free(node);
}
}
return super_buf;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_dequeue
*
* DESCRIPTION: dequeue from the superbuf queue
*
* PARAMETERS :
* @queue : superbuf queue
*
* RETURN : ptr to a node from superbuf queue
*==========================================================================*/
mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue)
{
mm_channel_queue_node_t* super_buf = NULL;
pthread_mutex_lock(&queue->que.lock);
super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
pthread_mutex_unlock(&queue->que.lock);
return super_buf;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_bufdone_overflow
*
* DESCRIPTION: keep superbuf queue no larger than watermark set by upper layer
* via channel attribute
*
* PARAMETERS :
* @my_obj : channel object
* @queue : superbuf queue
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t* my_obj,
mm_channel_queue_t * queue)
{
int32_t rc = 0, i;
mm_channel_queue_node_t* super_buf = NULL;
if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
/* for continuous streaming mode, no overflow is needed */
return 0;
}
CDBG("%s: before match_cnt=%d, water_mark=%d",
__func__, queue->match_cnt, queue->attr.water_mark);
/* bufdone overflowed bufs */
pthread_mutex_lock(&queue->que.lock);
while (queue->match_cnt > queue->attr.water_mark) {
super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
if (NULL != super_buf) {
for (i=0; i<super_buf->num_of_bufs; i++) {
if (NULL != super_buf->super_buf[i].buf) {
mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
}
}
free(super_buf);
}
}
pthread_mutex_unlock(&queue->que.lock);
CDBG("%s: after match_cnt=%d, water_mark=%d",
__func__, queue->match_cnt, queue->attr.water_mark);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_skip
*
* DESCRIPTION: depends on the lookback configuration of the channel attribute,
* unwanted superbufs will be removed from the superbuf queue.
*
* PARAMETERS :
* @my_obj : channel object
* @queue : superbuf queue
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_skip(mm_channel_t* my_obj,
mm_channel_queue_t * queue)
{
int32_t rc = 0, i;
mm_channel_queue_node_t* super_buf = NULL;
if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
/* for continuous streaming mode, no skip is needed */
return 0;
}
/* bufdone overflowed bufs */
pthread_mutex_lock(&queue->que.lock);
while (queue->match_cnt > queue->attr.look_back) {
super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
if (NULL != super_buf) {
for (i=0; i<super_buf->num_of_bufs; i++) {
if (NULL != super_buf->super_buf[i].buf) {
mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
}
}
free(super_buf);
}
}
pthread_mutex_unlock(&queue->que.lock);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_flush
*
* DESCRIPTION: flush the superbuf queue.
*
* PARAMETERS :
* @my_obj : channel object
* @queue : superbuf queue
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj,
mm_channel_queue_t * queue)
{
int32_t rc = 0, i;
mm_channel_queue_node_t* super_buf = NULL;
/* bufdone bufs */
pthread_mutex_lock(&queue->que.lock);
super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE);
while (super_buf != NULL) {
for (i=0; i<super_buf->num_of_bufs; i++) {
if (NULL != super_buf->super_buf[i].buf) {
mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
}
}
free(super_buf);
super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE);
}
pthread_mutex_unlock(&queue->que.lock);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_proc_general_cmd
*
* DESCRIPTION: process general command
*
* PARAMETERS :
* @my_obj : channel object
* @notify_mode : notification mode
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_proc_general_cmd(mm_channel_t *my_obj,
mm_camera_generic_cmd_t *p_gen_cmd)
{
CDBG("%s: E",__func__);
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->u.gen_cmd = *p_gen_cmd;
node->cmd_type = MM_CAMERA_CMD_TYPE_GENERAL;
/* enqueue to cmd thread */
cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
rc = -1;
}
CDBG("%s: X",__func__);
return rc;
}
/*===========================================================================
* FUNCTION : mm_channel_superbuf_flush_matched
*
* DESCRIPTION: flush matched buffers from the superbuf queue.
*
* PARAMETERS :
* @my_obj : channel object
* @queue : superbuf queue
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_flush_matched(mm_channel_t* my_obj,
mm_channel_queue_t * queue)
{
int32_t rc = 0, i;
mm_channel_queue_node_t* super_buf = NULL;
/* bufdone bufs */
pthread_mutex_lock(&queue->que.lock);
super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
while (super_buf != NULL) {
for (i=0; i<super_buf->num_of_bufs; i++) {
if (NULL != super_buf->super_buf[i].buf) {
mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
}
}
free(super_buf);
super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
}
pthread_mutex_unlock(&queue->que.lock);
return rc;
}