Home | History | Annotate | Download | only in src
      1 /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions are
      5  * met:
      6  *     * Redistributions of source code must retain the above copyright
      7  *       notice, this list of conditions and the following disclaimer.
      8  *     * Redistributions in binary form must reproduce the above
      9  *       copyright notice, this list of conditions and the following
     10  *       disclaimer in the documentation and/or other materials provided
     11  *       with the distribution.
     12  *     * Neither the name of The Linux Foundation nor the names of its
     13  *       contributors may be used to endorse or promote products derived
     14  *       from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  *
     28  */
     29 
     30 #include <pthread.h>
     31 #include <errno.h>
     32 #include <sys/ioctl.h>
     33 #include <sys/types.h>
     34 #include <sys/stat.h>
     35 #include <fcntl.h>
     36 #include <poll.h>
     37 #include <cam_semaphore.h>
     38 
     39 #include "mm_camera_dbg.h"
     40 #include "mm_camera_interface.h"
     41 #include "mm_camera.h"
     42 
     43 extern mm_camera_obj_t* mm_camera_util_get_camera_by_handler(uint32_t cam_handler);
     44 extern mm_channel_t * mm_camera_util_get_channel_by_handler(mm_camera_obj_t * cam_obj,
     45                                                             uint32_t handler);
     46 
     47 /* internal function declare goes here */
     48 int32_t mm_channel_qbuf(mm_channel_t *my_obj,
     49                         mm_camera_buf_def_t *buf);
     50 int32_t mm_channel_init(mm_channel_t *my_obj,
     51                         mm_camera_channel_attr_t *attr,
     52                         mm_camera_buf_notify_t channel_cb,
     53                         void *userdata);
     54 void mm_channel_release(mm_channel_t *my_obj);
     55 uint32_t mm_channel_add_stream(mm_channel_t *my_obj);
     56 int32_t mm_channel_del_stream(mm_channel_t *my_obj,
     57                                    uint32_t stream_id);
     58 int32_t mm_channel_config_stream(mm_channel_t *my_obj,
     59                                  uint32_t stream_id,
     60                                  mm_camera_stream_config_t *config);
     61 int32_t mm_channel_get_bundle_info(mm_channel_t *my_obj,
     62                                    cam_bundle_config_t *bundle_info);
     63 int32_t mm_channel_start(mm_channel_t *my_obj);
     64 int32_t mm_channel_stop(mm_channel_t *my_obj);
     65 int32_t mm_channel_request_super_buf(mm_channel_t *my_obj,
     66                                      uint32_t num_buf_requested);
     67 int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj);
     68 int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj,
     69                                          uint32_t frame_idx);
     70 int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
     71                                       mm_camera_super_buf_notify_mode_t notify_mode);
     72 int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj, mm_channel_queue_t * queue);
     73 int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
     74                                    mm_evt_paylod_set_get_stream_parms_t *payload);
     75 int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
     76                                    mm_evt_paylod_set_get_stream_parms_t *payload);
     77 int32_t mm_channel_do_stream_action(mm_channel_t *my_obj,
     78                                     mm_evt_paylod_do_stream_action_t *payload);
     79 int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj,
     80                                   mm_evt_paylod_map_stream_buf_t *payload);
     81 int32_t mm_channel_unmap_stream_buf(mm_channel_t *my_obj,
     82                                     mm_evt_paylod_unmap_stream_buf_t *payload);
     83 
     84 /* state machine function declare */
     85 int32_t mm_channel_fsm_fn_notused(mm_channel_t *my_obj,
     86                           mm_channel_evt_type_t evt,
     87                           void * in_val,
     88                           void * out_val);
     89 int32_t mm_channel_fsm_fn_stopped(mm_channel_t *my_obj,
     90                           mm_channel_evt_type_t evt,
     91                           void * in_val,
     92                           void * out_val);
     93 int32_t mm_channel_fsm_fn_active(mm_channel_t *my_obj,
     94                           mm_channel_evt_type_t evt,
     95                           void * in_val,
     96                           void * out_val);
     97 int32_t mm_channel_fsm_fn_paused(mm_channel_t *my_obj,
     98                           mm_channel_evt_type_t evt,
     99                           void * in_val,
    100                           void * out_val);
    101 
    102 /* channel super queue functions */
    103 int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue);
    104 int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue);
    105 int32_t mm_channel_superbuf_comp_and_enqueue(mm_channel_t *ch_obj,
    106                                              mm_channel_queue_t * queue,
    107                                              mm_camera_buf_info_t *buf);
    108 mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue);
    109 int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t *my_obj,
    110                                              mm_channel_queue_t *queue);
    111 int32_t mm_channel_superbuf_skip(mm_channel_t *my_obj,
    112                                  mm_channel_queue_t *queue);
    113 
    114 /*===========================================================================
    115  * FUNCTION   : mm_channel_util_get_stream_by_handler
    116  *
    117  * DESCRIPTION: utility function to get a stream object from its handle
    118  *
    119  * PARAMETERS :
    120  *   @cam_obj: ptr to a channel object
    121  *   @handler: stream handle
    122  *
    123  * RETURN     : ptr to a stream object.
    124  *              NULL if failed.
    125  *==========================================================================*/
    126 mm_stream_t * mm_channel_util_get_stream_by_handler(
    127                                     mm_channel_t * ch_obj,
    128                                     uint32_t handler)
    129 {
    130     int i;
    131     mm_stream_t *s_obj = NULL;
    132     for(i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
    133         if ((MM_STREAM_STATE_NOTUSED != ch_obj->streams[i].state) &&
    134             (handler == ch_obj->streams[i].my_hdl)) {
    135             s_obj = &ch_obj->streams[i];
    136             break;
    137         }
    138     }
    139     return s_obj;
    140 }
    141 
    142 /*===========================================================================
    143  * FUNCTION   : mm_channel_dispatch_super_buf
    144  *
    145  * DESCRIPTION: dispatch super buffer of bundle to registered user
    146  *
    147  * PARAMETERS :
    148  *   @cmd_cb  : ptr storing matched super buf information
    149  *   @userdata: user data ptr
    150  *
    151  * RETURN     : none
    152  *==========================================================================*/
    153 static void mm_channel_dispatch_super_buf(mm_camera_cmdcb_t *cmd_cb,
    154                                           void* user_data)
    155 {
    156     mm_camera_cmd_thread_name("mm_cam_cb");
    157     mm_channel_t * my_obj = (mm_channel_t *)user_data;
    158 
    159     if (NULL == my_obj) {
    160         return;
    161     }
    162 
    163     if (MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB != cmd_cb->cmd_type) {
    164         CDBG_ERROR("%s: Wrong cmd_type (%d) for super buf dataCB",
    165                    __func__, cmd_cb->cmd_type);
    166         return;
    167     }
    168 
    169     if (my_obj->bundle.super_buf_notify_cb) {
    170         my_obj->bundle.super_buf_notify_cb(&cmd_cb->u.superbuf, my_obj->bundle.user_data);
    171     }
    172 }
    173 
    174 /*===========================================================================
    175  * FUNCTION   : mm_channel_process_stream_buf
    176  *
    177  * DESCRIPTION: handle incoming buffer from stream in a bundle. In this function,
    178  *              matching logic will be performed on incoming stream frames.
    179  *              Will depends on the bundle attribute, either storing matched frames
    180  *              in the superbuf queue, or sending matched superbuf frames to upper
    181  *              layer through registered callback.
    182  *
    183  * PARAMETERS :
    184  *   @cmd_cb  : ptr storing matched super buf information
    185  *   @userdata: user data ptr
    186  *
    187  * RETURN     : none
    188  *==========================================================================*/
    189 static void mm_channel_process_stream_buf(mm_camera_cmdcb_t * cmd_cb,
    190                                           void *user_data)
    191 {
    192     mm_camera_cmd_thread_name("mm_cam_cmd");
    193     mm_camera_super_buf_notify_mode_t notify_mode;
    194     mm_channel_queue_node_t *node = NULL;
    195     mm_channel_t *ch_obj = (mm_channel_t *)user_data;
    196     if (NULL == ch_obj) {
    197         return;
    198     }
    199 
    200     if (MM_CAMERA_CMD_TYPE_DATA_CB  == cmd_cb->cmd_type) {
    201         /* comp_and_enqueue */
    202         mm_channel_superbuf_comp_and_enqueue(
    203                         ch_obj,
    204                         &ch_obj->bundle.superbuf_queue,
    205                         &cmd_cb->u.buf);
    206     } else if (MM_CAMERA_CMD_TYPE_REQ_DATA_CB  == cmd_cb->cmd_type) {
    207         /* skip frames if needed */
    208         ch_obj->pending_cnt = cmd_cb->u.req_buf.num_buf_requested;
    209         mm_channel_superbuf_skip(ch_obj, &ch_obj->bundle.superbuf_queue);
    210     } else if (MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY == cmd_cb->cmd_type) {
    211            ch_obj->bundle.superbuf_queue.attr.notify_mode = cmd_cb->u.notify_mode;
    212     } else if (MM_CAMERA_CMD_TYPE_FLUSH_QUEUE  == cmd_cb->cmd_type) {
    213         ch_obj->bundle.superbuf_queue.expected_frame_id = cmd_cb->u.frame_idx;
    214         mm_channel_superbuf_flush(ch_obj, &ch_obj->bundle.superbuf_queue);
    215         return;
    216     }
    217     notify_mode = ch_obj->bundle.superbuf_queue.attr.notify_mode;
    218 
    219     /* bufdone for overflowed bufs */
    220     mm_channel_superbuf_bufdone_overflow(ch_obj, &ch_obj->bundle.superbuf_queue);
    221 
    222     /* dispatch frame if pending_cnt>0 or is in continuous streaming mode */
    223     while ( (ch_obj->pending_cnt > 0) ||
    224             (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == notify_mode) ) {
    225 
    226         /* dequeue */
    227         node = mm_channel_superbuf_dequeue(&ch_obj->bundle.superbuf_queue);
    228         if (NULL != node) {
    229             /* decrease pending_cnt */
    230             CDBG("%s: Super Buffer received, Call client callback, pending_cnt=%d",
    231                  __func__, ch_obj->pending_cnt);
    232             if (MM_CAMERA_SUPER_BUF_NOTIFY_BURST == notify_mode) {
    233                 ch_obj->pending_cnt--;
    234             }
    235 
    236             /* dispatch superbuf */
    237             if (NULL != ch_obj->bundle.super_buf_notify_cb) {
    238                 uint8_t i;
    239                 mm_camera_cmdcb_t* cb_node = NULL;
    240 
    241                 CDBG("%s: Send superbuf to HAL, pending_cnt=%d",
    242                      __func__, ch_obj->pending_cnt);
    243 
    244                 /* send cam_sem_post to wake up cb thread to dispatch super buffer */
    245                 cb_node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
    246                 if (NULL != cb_node) {
    247                     memset(cb_node, 0, sizeof(mm_camera_cmdcb_t));
    248                     cb_node->cmd_type = MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB;
    249                     cb_node->u.superbuf.num_bufs = node->num_of_bufs;
    250                     for (i=0; i<node->num_of_bufs; i++) {
    251                         cb_node->u.superbuf.bufs[i] = node->super_buf[i].buf;
    252                     }
    253                     cb_node->u.superbuf.camera_handle = ch_obj->cam_obj->my_hdl;
    254                     cb_node->u.superbuf.ch_id = ch_obj->my_hdl;
    255 
    256                     /* enqueue to cb thread */
    257                     cam_queue_enq(&(ch_obj->cb_thread.cmd_queue), cb_node);
    258 
    259                     /* wake up cb thread */
    260                     cam_sem_post(&(ch_obj->cb_thread.cmd_sem));
    261                 } else {
    262                     CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
    263                     /* buf done with the nonuse super buf */
    264                     for (i=0; i<node->num_of_bufs; i++) {
    265                         mm_channel_qbuf(ch_obj, node->super_buf[i].buf);
    266                     }
    267                 }
    268             } else {
    269                 /* buf done with the nonuse super buf */
    270                 uint8_t i;
    271                 for (i=0; i<node->num_of_bufs; i++) {
    272                     mm_channel_qbuf(ch_obj, node->super_buf[i].buf);
    273                 }
    274             }
    275             free(node);
    276         } else {
    277             /* no superbuf avail, break the loop */
    278             break;
    279         }
    280     }
    281 }
    282 
    283 /*===========================================================================
    284  * FUNCTION   : mm_channel_fsm_fn
    285  *
    286  * DESCRIPTION: channel finite state machine entry function. Depends on channel
    287  *              state, incoming event will be handled differently.
    288  *
    289  * PARAMETERS :
    290  *   @my_obj   : ptr to a channel object
    291  *   @evt      : channel event to be processed
    292  *   @in_val   : input event payload. Can be NULL if not needed.
    293  *   @out_val  : output payload, Can be NULL if not needed.
    294  *
    295  * RETURN     : int32_t type of status
    296  *              0  -- success
    297  *              -1 -- failure
    298  *==========================================================================*/
    299 int32_t mm_channel_fsm_fn(mm_channel_t *my_obj,
    300                           mm_channel_evt_type_t evt,
    301                           void * in_val,
    302                           void * out_val)
    303 {
    304     int32_t rc = -1;
    305 
    306     CDBG("%s : E state = %d", __func__, my_obj->state);
    307     switch (my_obj->state) {
    308     case MM_CHANNEL_STATE_NOTUSED:
    309         rc = mm_channel_fsm_fn_notused(my_obj, evt, in_val, out_val);
    310         break;
    311     case MM_CHANNEL_STATE_STOPPED:
    312         rc = mm_channel_fsm_fn_stopped(my_obj, evt, in_val, out_val);
    313         break;
    314     case MM_CHANNEL_STATE_ACTIVE:
    315         rc = mm_channel_fsm_fn_active(my_obj, evt, in_val, out_val);
    316         break;
    317     case MM_CHANNEL_STATE_PAUSED:
    318         rc = mm_channel_fsm_fn_paused(my_obj, evt, in_val, out_val);
    319         break;
    320     default:
    321         CDBG("%s: Not a valid state (%d)", __func__, my_obj->state);
    322         break;
    323     }
    324 
    325     /* unlock ch_lock */
    326     pthread_mutex_unlock(&my_obj->ch_lock);
    327     CDBG("%s : X rc = %d", __func__, rc);
    328     return rc;
    329 }
    330 
    331 /*===========================================================================
    332  * FUNCTION   : mm_channel_fsm_fn_notused
    333  *
    334  * DESCRIPTION: channel finite state machine function to handle event
    335  *              in NOT_USED state.
    336  *
    337  * PARAMETERS :
    338  *   @my_obj   : ptr to a channel object
    339  *   @evt      : channel event to be processed
    340  *   @in_val   : input event payload. Can be NULL if not needed.
    341  *   @out_val  : output payload, Can be NULL if not needed.
    342  *
    343  * RETURN     : int32_t type of status
    344  *              0  -- success
    345  *              -1 -- failure
    346  *==========================================================================*/
    347 int32_t mm_channel_fsm_fn_notused(mm_channel_t *my_obj,
    348                                   mm_channel_evt_type_t evt,
    349                                   void * in_val,
    350                                   void * out_val)
    351 {
    352     int32_t rc = -1;
    353 
    354     switch (evt) {
    355     default:
    356         CDBG_ERROR("%s: invalid state (%d) for evt (%d), in(%p), out(%p)",
    357                    __func__, my_obj->state, evt, in_val, out_val);
    358         break;
    359     }
    360 
    361     return rc;
    362 }
    363 
    364 /*===========================================================================
    365  * FUNCTION   : mm_channel_fsm_fn_stopped
    366  *
    367  * DESCRIPTION: channel finite state machine function to handle event
    368  *              in STOPPED state.
    369  *
    370  * PARAMETERS :
    371  *   @my_obj   : ptr to a channel object
    372  *   @evt      : channel event to be processed
    373  *   @in_val   : input event payload. Can be NULL if not needed.
    374  *   @out_val  : output payload, Can be NULL if not needed.
    375  *
    376  * RETURN     : int32_t type of status
    377  *              0  -- success
    378  *              -1 -- failure
    379  *==========================================================================*/
    380 int32_t mm_channel_fsm_fn_stopped(mm_channel_t *my_obj,
    381                                   mm_channel_evt_type_t evt,
    382                                   void * in_val,
    383                                   void * out_val)
    384 {
    385     int32_t rc = 0;
    386     CDBG("%s : E evt = %d", __func__, evt);
    387     switch (evt) {
    388     case MM_CHANNEL_EVT_ADD_STREAM:
    389         {
    390             uint32_t s_hdl = 0;
    391             s_hdl = mm_channel_add_stream(my_obj);
    392             *((uint32_t*)out_val) = s_hdl;
    393             rc = 0;
    394         }
    395         break;
    396     case MM_CHANNEL_EVT_DEL_STREAM:
    397         {
    398             uint32_t s_id = (uint32_t)in_val;
    399             rc = mm_channel_del_stream(my_obj, s_id);
    400         }
    401         break;
    402     case MM_CHANNEL_EVT_START:
    403         {
    404             rc = mm_channel_start(my_obj);
    405             /* first stream started in stopped state
    406              * move to active state */
    407             if (0 == rc) {
    408                 my_obj->state = MM_CHANNEL_STATE_ACTIVE;
    409             }
    410         }
    411         break;
    412     case MM_CHANNEL_EVT_CONFIG_STREAM:
    413         {
    414             mm_evt_paylod_config_stream_t *payload =
    415                 (mm_evt_paylod_config_stream_t *)in_val;
    416             rc = mm_channel_config_stream(my_obj,
    417                                           payload->stream_id,
    418                                           payload->config);
    419         }
    420         break;
    421     case MM_CHANNEL_EVT_GET_BUNDLE_INFO:
    422         {
    423             cam_bundle_config_t *payload =
    424                 (cam_bundle_config_t *)in_val;
    425             rc = mm_channel_get_bundle_info(my_obj, payload);
    426         }
    427         break;
    428     case MM_CHANNEL_EVT_DELETE:
    429         {
    430             mm_channel_release(my_obj);
    431             rc = 0;
    432         }
    433         break;
    434     case MM_CHANNEL_EVT_SET_STREAM_PARM:
    435         {
    436             mm_evt_paylod_set_get_stream_parms_t *payload =
    437                 (mm_evt_paylod_set_get_stream_parms_t *)in_val;
    438             rc = mm_channel_set_stream_parm(my_obj, payload);
    439         }
    440         break;
    441     case MM_CHANNEL_EVT_GET_STREAM_PARM:
    442         {
    443             mm_evt_paylod_set_get_stream_parms_t *payload =
    444                 (mm_evt_paylod_set_get_stream_parms_t *)in_val;
    445             rc = mm_channel_get_stream_parm(my_obj, payload);
    446         }
    447         break;
    448     case MM_CHANNEL_EVT_DO_STREAM_ACTION:
    449         {
    450             mm_evt_paylod_do_stream_action_t *payload =
    451                 (mm_evt_paylod_do_stream_action_t *)in_val;
    452             rc = mm_channel_do_stream_action(my_obj, payload);
    453         }
    454         break;
    455     case MM_CHANNEL_EVT_MAP_STREAM_BUF:
    456         {
    457             mm_evt_paylod_map_stream_buf_t *payload =
    458                 (mm_evt_paylod_map_stream_buf_t *)in_val;
    459             rc = mm_channel_map_stream_buf(my_obj, payload);
    460         }
    461         break;
    462     case MM_CHANNEL_EVT_UNMAP_STREAM_BUF:
    463         {
    464             mm_evt_paylod_unmap_stream_buf_t *payload =
    465                 (mm_evt_paylod_unmap_stream_buf_t *)in_val;
    466             rc = mm_channel_unmap_stream_buf(my_obj, payload);
    467         }
    468         break;
    469     default:
    470         CDBG_ERROR("%s: invalid state (%d) for evt (%d)",
    471                    __func__, my_obj->state, evt);
    472         break;
    473     }
    474     CDBG("%s : E rc = %d", __func__, rc);
    475     return rc;
    476 }
    477 
    478 /*===========================================================================
    479  * FUNCTION   : mm_channel_fsm_fn_active
    480  *
    481  * DESCRIPTION: channel finite state machine function to handle event
    482  *              in ACTIVE state.
    483  *
    484  * PARAMETERS :
    485  *   @my_obj   : ptr to a channel object
    486  *   @evt      : channel event to be processed
    487  *   @in_val   : input event payload. Can be NULL if not needed.
    488  *   @out_val  : output payload, Can be NULL if not needed.
    489  *
    490  * RETURN     : int32_t type of status
    491  *              0  -- success
    492  *              -1 -- failure
    493  *==========================================================================*/
    494 int32_t mm_channel_fsm_fn_active(mm_channel_t *my_obj,
    495                           mm_channel_evt_type_t evt,
    496                           void * in_val,
    497                           void * out_val)
    498 {
    499     int32_t rc = 0;
    500 
    501     CDBG("%s : E evt = %d", __func__, evt);
    502     switch (evt) {
    503     case MM_CHANNEL_EVT_STOP:
    504         {
    505             rc = mm_channel_stop(my_obj);
    506             my_obj->state = MM_CHANNEL_STATE_STOPPED;
    507         }
    508         break;
    509     case MM_CHANNEL_EVT_REQUEST_SUPER_BUF:
    510         {
    511             uint32_t num_buf_requested = (uint32_t)in_val;
    512             rc = mm_channel_request_super_buf(my_obj, num_buf_requested);
    513         }
    514         break;
    515     case MM_CHANNEL_EVT_CANCEL_REQUEST_SUPER_BUF:
    516         {
    517             rc = mm_channel_cancel_super_buf_request(my_obj);
    518         }
    519         break;
    520     case MM_CHANNEL_EVT_FLUSH_SUPER_BUF_QUEUE:
    521         {
    522             uint32_t frame_idx = (uint32_t)in_val;
    523             rc = mm_channel_flush_super_buf_queue(my_obj, frame_idx);
    524         }
    525         break;
    526     case MM_CHANNEL_EVT_CONFIG_NOTIFY_MODE:
    527         {
    528             mm_camera_super_buf_notify_mode_t notify_mode = ( mm_camera_super_buf_notify_mode_t ) in_val;
    529             rc = mm_channel_config_notify_mode(my_obj, notify_mode);
    530         }
    531         break;
    532     case MM_CHANNEL_EVT_SET_STREAM_PARM:
    533         {
    534             mm_evt_paylod_set_get_stream_parms_t *payload =
    535                 (mm_evt_paylod_set_get_stream_parms_t *)in_val;
    536             rc = mm_channel_set_stream_parm(my_obj, payload);
    537         }
    538         break;
    539     case MM_CHANNEL_EVT_GET_STREAM_PARM:
    540         {
    541             mm_evt_paylod_set_get_stream_parms_t *payload =
    542                 (mm_evt_paylod_set_get_stream_parms_t *)in_val;
    543             rc = mm_channel_get_stream_parm(my_obj, payload);
    544         }
    545         break;
    546     case MM_CHANNEL_EVT_DO_STREAM_ACTION:
    547         {
    548             mm_evt_paylod_do_stream_action_t *payload =
    549                 (mm_evt_paylod_do_stream_action_t *)in_val;
    550             rc = mm_channel_do_stream_action(my_obj, payload);
    551         }
    552         break;
    553     case MM_CHANNEL_EVT_MAP_STREAM_BUF:
    554         {
    555             mm_evt_paylod_map_stream_buf_t *payload =
    556                 (mm_evt_paylod_map_stream_buf_t *)in_val;
    557             if (payload != NULL &&
    558                 payload->buf_type == CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF) {
    559                 rc = mm_channel_map_stream_buf(my_obj, payload);
    560             } else {
    561                 CDBG_ERROR("%s: cannot map regualr stream buf in active state", __func__);
    562             }
    563         }
    564         break;
    565     case MM_CHANNEL_EVT_UNMAP_STREAM_BUF:
    566         {
    567             mm_evt_paylod_unmap_stream_buf_t *payload =
    568                 (mm_evt_paylod_unmap_stream_buf_t *)in_val;
    569             if (payload != NULL &&
    570                 payload->buf_type == CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF) {
    571                 rc = mm_channel_unmap_stream_buf(my_obj, payload);
    572             } else {
    573                 CDBG_ERROR("%s: cannot unmap regualr stream buf in active state", __func__);
    574             }
    575         }
    576         break;
    577     default:
    578         CDBG_ERROR("%s: invalid state (%d) for evt (%d), in(%p), out(%p)",
    579                    __func__, my_obj->state, evt, in_val, out_val);
    580         break;
    581     }
    582     CDBG("%s : X rc = %d", __func__, rc);
    583     return rc;
    584 }
    585 
    586 /*===========================================================================
    587  * FUNCTION   : mm_channel_fsm_fn_paused
    588  *
    589  * DESCRIPTION: channel finite state machine function to handle event
    590  *              in PAUSED state.
    591  *
    592  * PARAMETERS :
    593  *   @my_obj   : ptr to a channel object
    594  *   @evt      : channel event to be processed
    595  *   @in_val   : input event payload. Can be NULL if not needed.
    596  *   @out_val  : output payload, Can be NULL if not needed.
    597  *
    598  * RETURN     : int32_t type of status
    599  *              0  -- success
    600  *              -1 -- failure
    601  *==========================================================================*/
    602 int32_t mm_channel_fsm_fn_paused(mm_channel_t *my_obj,
    603                           mm_channel_evt_type_t evt,
    604                           void * in_val,
    605                           void * out_val)
    606 {
    607     int32_t rc = 0;
    608 
    609     /* currently we are not supporting pause/resume channel */
    610     CDBG_ERROR("%s: invalid state (%d) for evt (%d), in(%p), out(%p)",
    611                __func__, my_obj->state, evt, in_val, out_val);
    612 
    613     return rc;
    614 }
    615 
    616 /*===========================================================================
    617  * FUNCTION   : mm_channel_init
    618  *
    619  * DESCRIPTION: initialize a channel
    620  *
    621  * PARAMETERS :
    622  *   @my_obj       : channel object be to initialized
    623  *   @attr         : bundle attribute of the channel if needed
    624  *   @channel_cb   : callback function for bundle data notify
    625  *   @userdata     : user data ptr
    626  *
    627  * RETURN     : int32_t type of status
    628  *              0  -- success
    629  *              -1 -- failure
    630  * NOTE       : if no bundle data notify is needed, meaning each stream in the
    631  *              channel will have its own stream data notify callback, then
    632  *              attr, channel_cb, and userdata can be NULL. In this case,
    633  *              no matching logic will be performed in channel for the bundling.
    634  *==========================================================================*/
    635 int32_t mm_channel_init(mm_channel_t *my_obj,
    636                         mm_camera_channel_attr_t *attr,
    637                         mm_camera_buf_notify_t channel_cb,
    638                         void *userdata)
    639 {
    640     int32_t rc = 0;
    641 
    642     my_obj->bundle.super_buf_notify_cb = channel_cb;
    643     my_obj->bundle.user_data = userdata;
    644     if (NULL != attr) {
    645         my_obj->bundle.superbuf_queue.attr = *attr;
    646     }
    647 
    648     CDBG("%s : Launch data poll thread in channel open", __func__);
    649     mm_camera_poll_thread_launch(&my_obj->poll_thread[0],
    650                                  MM_CAMERA_POLL_TYPE_DATA);
    651 
    652     /* change state to stopped state */
    653     my_obj->state = MM_CHANNEL_STATE_STOPPED;
    654     return rc;
    655 }
    656 
    657 /*===========================================================================
    658  * FUNCTION   : mm_channel_release
    659  *
    660  * DESCRIPTION: release a channel resource. Channel state will move to UNUSED
    661  *              state after this call.
    662  *
    663  * PARAMETERS :
    664  *   @my_obj       : channel object
    665  *
    666  * RETURN     : none
    667  *==========================================================================*/
    668 void mm_channel_release(mm_channel_t *my_obj)
    669 {
    670     /* stop data poll thread */
    671     mm_camera_poll_thread_release(&my_obj->poll_thread[0]);
    672 
    673     /* change state to notused state */
    674     my_obj->state = MM_CHANNEL_STATE_NOTUSED;
    675 }
    676 
    677 /*===========================================================================
    678  * FUNCTION   : mm_channel_add_stream
    679  *
    680  * DESCRIPTION: add a stream into the channel
    681  *
    682  * PARAMETERS :
    683  *   @my_obj       : channel object
    684  *
    685  * RETURN     : uint32_t type of stream handle
    686  *              0  -- invalid stream handle, meaning the op failed
    687  *              >0 -- successfully added a stream with a valid handle
    688  *==========================================================================*/
    689 uint32_t mm_channel_add_stream(mm_channel_t *my_obj)
    690 {
    691     int32_t rc = 0;
    692     uint8_t idx = 0;
    693     uint32_t s_hdl = 0;
    694     mm_stream_t *stream_obj = NULL;
    695 
    696     CDBG("%s : E", __func__);
    697     /* check available stream */
    698     for (idx = 0; idx < MAX_STREAM_NUM_IN_BUNDLE; idx++) {
    699         if (MM_STREAM_STATE_NOTUSED == my_obj->streams[idx].state) {
    700             stream_obj = &my_obj->streams[idx];
    701             break;
    702         }
    703     }
    704     if (NULL == stream_obj) {
    705         CDBG_ERROR("%s: streams reach max, no more stream allowed to add", __func__);
    706         return s_hdl;
    707     }
    708 
    709     /* initialize stream object */
    710     memset(stream_obj, 0, sizeof(mm_stream_t));
    711     stream_obj->my_hdl = mm_camera_util_generate_handler(idx);
    712     stream_obj->ch_obj = my_obj;
    713     pthread_mutex_init(&stream_obj->buf_lock, NULL);
    714     pthread_mutex_init(&stream_obj->cb_lock, NULL);
    715     stream_obj->state = MM_STREAM_STATE_INITED;
    716 
    717     /* acquire stream */
    718     rc = mm_stream_fsm_fn(stream_obj, MM_STREAM_EVT_ACQUIRE, NULL, NULL);
    719     if (0 == rc) {
    720         s_hdl = stream_obj->my_hdl;
    721     } else {
    722         /* error during acquire, de-init */
    723         pthread_mutex_destroy(&stream_obj->buf_lock);
    724         pthread_mutex_destroy(&stream_obj->cb_lock);
    725         memset(stream_obj, 0, sizeof(mm_stream_t));
    726     }
    727     CDBG("%s : stream handle = %d", __func__, s_hdl);
    728     return s_hdl;
    729 }
    730 
    731 /*===========================================================================
    732  * FUNCTION   : mm_channel_del_stream
    733  *
    734  * DESCRIPTION: delete a stream from the channel bu its handle
    735  *
    736  * PARAMETERS :
    737  *   @my_obj       : channel object
    738  *   @stream_id    : stream handle
    739  *
    740  * RETURN     : int32_t type of status
    741  *              0  -- success
    742  *              -1 -- failure
    743  * NOTE       : assume steam is stooped before it can be deleted
    744  *==========================================================================*/
    745 int32_t mm_channel_del_stream(mm_channel_t *my_obj,
    746                               uint32_t stream_id)
    747 {
    748     int rc = -1;
    749     mm_stream_t * stream_obj = NULL;
    750     stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
    751 
    752     if (NULL == stream_obj) {
    753         CDBG_ERROR("%s :Invalid Stream Object for stream_id = %d",
    754                    __func__, stream_id);
    755         return rc;
    756     }
    757 
    758     rc = mm_stream_fsm_fn(stream_obj,
    759                           MM_STREAM_EVT_RELEASE,
    760                           NULL,
    761                           NULL);
    762 
    763     return rc;
    764 }
    765 
    766 /*===========================================================================
    767  * FUNCTION   : mm_channel_config_stream
    768  *
    769  * DESCRIPTION: configure a stream
    770  *
    771  * PARAMETERS :
    772  *   @my_obj       : channel object
    773  *   @stream_id    : stream handle
    774  *   @config       : stream configuration
    775  *
    776  * RETURN     : int32_t type of status
    777  *              0  -- success
    778  *              -1 -- failure
    779  *==========================================================================*/
    780 int32_t mm_channel_config_stream(mm_channel_t *my_obj,
    781                                    uint32_t stream_id,
    782                                    mm_camera_stream_config_t *config)
    783 {
    784     int rc = -1;
    785     mm_stream_t * stream_obj = NULL;
    786     CDBG("%s : E stream ID = %d", __func__, stream_id);
    787     stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
    788 
    789     if (NULL == stream_obj) {
    790         CDBG_ERROR("%s :Invalid Stream Object for stream_id = %d", __func__, stream_id);
    791         return rc;
    792     }
    793 
    794     /* set stream fmt */
    795     rc = mm_stream_fsm_fn(stream_obj,
    796                           MM_STREAM_EVT_SET_FMT,
    797                           (void *)config,
    798                           NULL);
    799     CDBG("%s : X rc = %d",__func__,rc);
    800     return rc;
    801 }
    802 
    803 /*===========================================================================
    804  * FUNCTION   : mm_channel_get_bundle_info
    805  *
    806  * DESCRIPTION: query bundle info of the channel, which should include all
    807  *              streams within this channel
    808  *
    809  * PARAMETERS :
    810  *   @my_obj       : channel object
    811  *   @bundle_info  : bundle info to be filled in
    812  *
    813  * RETURN     : int32_t type of status
    814  *              0  -- success
    815  *              -1 -- failure
    816  *==========================================================================*/
    817 int32_t mm_channel_get_bundle_info(mm_channel_t *my_obj,
    818                                    cam_bundle_config_t *bundle_info)
    819 {
    820     int i;
    821     mm_stream_t *s_obj = NULL;
    822     int32_t rc = 0;
    823 
    824     memset(bundle_info, 0, sizeof(cam_bundle_config_t));
    825     bundle_info->bundle_id = my_obj->my_hdl;
    826     bundle_info->num_of_streams = 0;
    827     for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
    828         if (my_obj->streams[i].my_hdl > 0) {
    829             s_obj = mm_channel_util_get_stream_by_handler(my_obj,
    830                                                           my_obj->streams[i].my_hdl);
    831             if (NULL != s_obj) {
    832                 if (CAM_STREAM_TYPE_METADATA != s_obj->stream_info->stream_type) {
    833                     bundle_info->stream_ids[bundle_info->num_of_streams++] =
    834                                                         s_obj->server_stream_id;
    835                 }
    836             } else {
    837                 CDBG_ERROR("%s: cannot find stream obj (%d) by handler (%d)",
    838                            __func__, i, my_obj->streams[i].my_hdl);
    839                 rc = -1;
    840                 break;
    841             }
    842         }
    843     }
    844     if (rc != 0) {
    845         /* error, reset to 0 */
    846         memset(bundle_info, 0, sizeof(cam_bundle_config_t));
    847     }
    848     return rc;
    849 }
    850 
    851 /*===========================================================================
    852  * FUNCTION   : mm_channel_start
    853  *
    854  * DESCRIPTION: start a channel, which will start all streams in the channel
    855  *
    856  * PARAMETERS :
    857  *   @my_obj       : channel object
    858  *
    859  * RETURN     : int32_t type of status
    860  *              0  -- success
    861  *              -1 -- failure
    862  *==========================================================================*/
    863 int32_t mm_channel_start(mm_channel_t *my_obj)
    864 {
    865     int32_t rc = 0;
    866     int i, j;
    867     mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL};
    868     uint8_t num_streams_to_start = 0;
    869     mm_stream_t *s_obj = NULL;
    870     int meta_stream_idx = 0;
    871 
    872     for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
    873         if (my_obj->streams[i].my_hdl > 0) {
    874             s_obj = mm_channel_util_get_stream_by_handler(my_obj,
    875                                                           my_obj->streams[i].my_hdl);
    876             if (NULL != s_obj) {
    877                 /* remember meta data stream index */
    878                 if (s_obj->stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
    879                     meta_stream_idx = num_streams_to_start;
    880                 }
    881                 s_objs[num_streams_to_start++] = s_obj;
    882             }
    883         }
    884     }
    885 
    886     if (meta_stream_idx > 0 ) {
    887         /* always start meta data stream first, so switch the stream object with the first one */
    888         s_obj = s_objs[0];
    889         s_objs[0] = s_objs[meta_stream_idx];
    890         s_objs[meta_stream_idx] = s_obj;
    891     }
    892 
    893     if (NULL != my_obj->bundle.super_buf_notify_cb) {
    894         /* need to send up cb, therefore launch thread */
    895         /* init superbuf queue */
    896         mm_channel_superbuf_queue_init(&my_obj->bundle.superbuf_queue);
    897         my_obj->bundle.superbuf_queue.num_streams = num_streams_to_start;
    898         my_obj->bundle.superbuf_queue.expected_frame_id = 0;
    899 
    900         for (i = 0; i < num_streams_to_start; i++) {
    901             /* set bundled flag to streams */
    902             s_objs[i]->is_bundled = 1;
    903             /* init bundled streams to invalid value -1 */
    904             my_obj->bundle.superbuf_queue.bundled_streams[i] = s_objs[i]->my_hdl;
    905         }
    906 
    907         /* launch cb thread for dispatching super buf through cb */
    908         mm_camera_cmd_thread_launch(&my_obj->cb_thread,
    909                                     mm_channel_dispatch_super_buf,
    910                                     (void*)my_obj);
    911 
    912         /* launch cmd thread for super buf dataCB */
    913         mm_camera_cmd_thread_launch(&my_obj->cmd_thread,
    914                                     mm_channel_process_stream_buf,
    915                                     (void*)my_obj);
    916 
    917         /* set flag to TRUE */
    918         my_obj->bundle.is_active = TRUE;
    919     }
    920 
    921     for (i = 0; i < num_streams_to_start; i++) {
    922         /* all streams within a channel should be started at the same time */
    923         if (s_objs[i]->state == MM_STREAM_STATE_ACTIVE) {
    924             CDBG_ERROR("%s: stream already started idx(%d)", __func__, i);
    925             rc = -1;
    926             break;
    927         }
    928 
    929         /* allocate buf */
    930         rc = mm_stream_fsm_fn(s_objs[i],
    931                               MM_STREAM_EVT_GET_BUF,
    932                               NULL,
    933                               NULL);
    934         if (0 != rc) {
    935             CDBG_ERROR("%s: get buf failed at idx(%d)", __func__, i);
    936             break;
    937         }
    938 
    939         /* reg buf */
    940         rc = mm_stream_fsm_fn(s_objs[i],
    941                               MM_STREAM_EVT_REG_BUF,
    942                               NULL,
    943                               NULL);
    944         if (0 != rc) {
    945             CDBG_ERROR("%s: reg buf failed at idx(%d)", __func__, i);
    946             break;
    947         }
    948 
    949         /* start stream */
    950         rc = mm_stream_fsm_fn(s_objs[i],
    951                               MM_STREAM_EVT_START,
    952                               NULL,
    953                               NULL);
    954         if (0 != rc) {
    955             CDBG_ERROR("%s: start stream failed at idx(%d)", __func__, i);
    956             break;
    957         }
    958     }
    959 
    960     /* error handling */
    961     if (0 != rc) {
    962         for (j=0; j<=i; j++) {
    963             /* stop streams*/
    964             mm_stream_fsm_fn(s_objs[j],
    965                              MM_STREAM_EVT_STOP,
    966                              NULL,
    967                              NULL);
    968 
    969             /* unreg buf */
    970             mm_stream_fsm_fn(s_objs[j],
    971                              MM_STREAM_EVT_UNREG_BUF,
    972                              NULL,
    973                              NULL);
    974 
    975             /* put buf back */
    976             mm_stream_fsm_fn(s_objs[j],
    977                              MM_STREAM_EVT_PUT_BUF,
    978                              NULL,
    979                              NULL);
    980         }
    981     }
    982 
    983     return rc;
    984 }
    985 
    986 /*===========================================================================
    987  * FUNCTION   : mm_channel_stop
    988  *
    989  * DESCRIPTION: stop a channel, which will stop all streams in the channel
    990  *
    991  * PARAMETERS :
    992  *   @my_obj       : channel object
    993  *
    994  * RETURN     : int32_t type of status
    995  *              0  -- success
    996  *              -1 -- failure
    997  *==========================================================================*/
    998 int32_t mm_channel_stop(mm_channel_t *my_obj)
    999 {
   1000     int32_t rc = 0;
   1001     int i;
   1002     mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL};
   1003     uint8_t num_streams_to_stop = 0;
   1004     mm_stream_t *s_obj = NULL;
   1005     int meta_stream_idx = 0;
   1006 
   1007     for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
   1008         if (my_obj->streams[i].my_hdl > 0) {
   1009             s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1010                                                           my_obj->streams[i].my_hdl);
   1011             if (NULL != s_obj) {
   1012                 /* remember meta data stream index */
   1013                 if (s_obj->stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
   1014                     meta_stream_idx = num_streams_to_stop;
   1015                 }
   1016                 s_objs[num_streams_to_stop++] = s_obj;
   1017             }
   1018         }
   1019     }
   1020 
   1021     if (meta_stream_idx < num_streams_to_stop - 1 ) {
   1022         /* always stop meta data stream last, so switch the stream object with the last one */
   1023         s_obj = s_objs[num_streams_to_stop - 1];
   1024         s_objs[num_streams_to_stop - 1] = s_objs[meta_stream_idx];
   1025         s_objs[meta_stream_idx] = s_obj;
   1026     }
   1027 
   1028     for (i = 0; i < num_streams_to_stop; i++) {
   1029         /* stream off */
   1030         mm_stream_fsm_fn(s_objs[i],
   1031                          MM_STREAM_EVT_STOP,
   1032                          NULL,
   1033                          NULL);
   1034 
   1035         /* unreg buf at kernel */
   1036         mm_stream_fsm_fn(s_objs[i],
   1037                          MM_STREAM_EVT_UNREG_BUF,
   1038                          NULL,
   1039                          NULL);
   1040     }
   1041 
   1042     /* destroy super buf cmd thread */
   1043     if (TRUE == my_obj->bundle.is_active) {
   1044         /* first stop bundle thread */
   1045         mm_camera_cmd_thread_release(&my_obj->cmd_thread);
   1046         mm_camera_cmd_thread_release(&my_obj->cb_thread);
   1047 
   1048         /* deinit superbuf queue */
   1049         mm_channel_superbuf_queue_deinit(&my_obj->bundle.superbuf_queue);
   1050 
   1051         /* memset bundle info */
   1052         memset(&my_obj->bundle, 0, sizeof(mm_channel_bundle_t));
   1053     }
   1054 
   1055     /* since all streams are stopped, we are safe to
   1056      * release all buffers allocated in stream */
   1057     for (i = 0; i < num_streams_to_stop; i++) {
   1058         /* put buf back */
   1059         mm_stream_fsm_fn(s_objs[i],
   1060                          MM_STREAM_EVT_PUT_BUF,
   1061                          NULL,
   1062                          NULL);
   1063     }
   1064 
   1065     return rc;
   1066 }
   1067 
   1068 /*===========================================================================
   1069  * FUNCTION   : mm_channel_request_super_buf
   1070  *
   1071  * DESCRIPTION: for burst mode in bundle, reuqest certain amount of matched
   1072  *              frames from superbuf queue
   1073  *
   1074  * PARAMETERS :
   1075  *   @my_obj       : channel object
   1076  *   @num_buf_requested : number of matched frames needed
   1077  *
   1078  * RETURN     : int32_t type of status
   1079  *              0  -- success
   1080  *              -1 -- failure
   1081  *==========================================================================*/
   1082 int32_t mm_channel_request_super_buf(mm_channel_t *my_obj, uint32_t num_buf_requested)
   1083 {
   1084     int32_t rc = 0;
   1085     mm_camera_cmdcb_t* node = NULL;
   1086 
   1087     /* set pending_cnt
   1088      * will trigger dispatching super frames if pending_cnt > 0 */
   1089     /* send cam_sem_post to wake up cmd thread to dispatch super buffer */
   1090     node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
   1091     if (NULL != node) {
   1092         memset(node, 0, sizeof(mm_camera_cmdcb_t));
   1093         node->cmd_type = MM_CAMERA_CMD_TYPE_REQ_DATA_CB;
   1094         node->u.req_buf.num_buf_requested = num_buf_requested;
   1095 
   1096         /* enqueue to cmd thread */
   1097         cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
   1098 
   1099         /* wake up cmd thread */
   1100         cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
   1101     } else {
   1102         CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
   1103         rc = -1;
   1104     }
   1105 
   1106     return rc;
   1107 }
   1108 
   1109 /*===========================================================================
   1110  * FUNCTION   : mm_channel_cancel_super_buf_request
   1111  *
   1112  * DESCRIPTION: for burst mode in bundle, cancel the reuqest for certain amount
   1113  *              of matched frames from superbuf queue
   1114  *
   1115  * PARAMETERS :
   1116  *   @my_obj       : channel object
   1117  *
   1118  * RETURN     : int32_t type of status
   1119  *              0  -- success
   1120  *              -1 -- failure
   1121  *==========================================================================*/
   1122 int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj)
   1123 {
   1124     int32_t rc = 0;
   1125     /* reset pending_cnt */
   1126     rc = mm_channel_request_super_buf(my_obj, 0);
   1127     return rc;
   1128 }
   1129 
   1130 /*===========================================================================
   1131  * FUNCTION   : mm_channel_flush_super_buf_queue
   1132  *
   1133  * DESCRIPTION: flush superbuf queue
   1134  *
   1135  * PARAMETERS :
   1136  *   @my_obj  : channel object
   1137  *   @frame_idx : frame idx until which to flush all superbufs
   1138  *
   1139  * RETURN     : int32_t type of status
   1140  *              0  -- success
   1141  *              -1 -- failure
   1142  *==========================================================================*/
   1143 int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj, uint32_t frame_idx)
   1144 {
   1145     int32_t rc = 0;
   1146     mm_camera_cmdcb_t* node = NULL;
   1147 
   1148     node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
   1149     if (NULL != node) {
   1150         memset(node, 0, sizeof(mm_camera_cmdcb_t));
   1151         node->cmd_type = MM_CAMERA_CMD_TYPE_FLUSH_QUEUE;
   1152         node->u.frame_idx = frame_idx;
   1153 
   1154         /* enqueue to cmd thread */
   1155         cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
   1156 
   1157         /* wake up cmd thread */
   1158         cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
   1159     } else {
   1160         CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
   1161         rc = -1;
   1162     }
   1163 
   1164     return rc;
   1165 }
   1166 
   1167 /*===========================================================================
   1168  * FUNCTION   : mm_channel_config_notify_mode
   1169  *
   1170  * DESCRIPTION: configure notification mode
   1171  *
   1172  * PARAMETERS :
   1173  *   @my_obj  : channel object
   1174  *   @notify_mode : notification mode
   1175  *
   1176  * RETURN     : int32_t type of status
   1177  *              0  -- success
   1178  *              -1 -- failure
   1179  *==========================================================================*/
   1180 int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
   1181                                       mm_camera_super_buf_notify_mode_t notify_mode)
   1182 {
   1183     int32_t rc = 0;
   1184     mm_camera_cmdcb_t* node = NULL;
   1185 
   1186     node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
   1187     if (NULL != node) {
   1188         memset(node, 0, sizeof(mm_camera_cmdcb_t));
   1189         node->u.notify_mode = notify_mode;
   1190         node->cmd_type = MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY;
   1191 
   1192         /* enqueue to cmd thread */
   1193         cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
   1194 
   1195         /* wake up cmd thread */
   1196         cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
   1197     } else {
   1198         CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
   1199         rc = -1;
   1200     }
   1201 
   1202     return rc;
   1203 }
   1204 
   1205 /*===========================================================================
   1206  * FUNCTION   : mm_channel_qbuf
   1207  *
   1208  * DESCRIPTION: enqueue buffer back to kernel
   1209  *
   1210  * PARAMETERS :
   1211  *   @my_obj       : channel object
   1212  *   @buf          : buf ptr to be enqueued
   1213  *
   1214  * RETURN     : int32_t type of status
   1215  *              0  -- success
   1216  *              -1 -- failure
   1217  *==========================================================================*/
   1218 int32_t mm_channel_qbuf(mm_channel_t *my_obj,
   1219                         mm_camera_buf_def_t *buf)
   1220 {
   1221     int32_t rc = -1;
   1222     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, buf->stream_id);
   1223 
   1224     if (NULL != s_obj) {
   1225         rc = mm_stream_fsm_fn(s_obj,
   1226                               MM_STREAM_EVT_QBUF,
   1227                               (void *)buf,
   1228                               NULL);
   1229     }
   1230 
   1231     return rc;
   1232 }
   1233 
   1234 /*===========================================================================
   1235  * FUNCTION   : mm_channel_set_stream_parms
   1236  *
   1237  * DESCRIPTION: set parameters per stream
   1238  *
   1239  * PARAMETERS :
   1240  *   @my_obj       : channel object
   1241  *   @s_id         : stream handle
   1242  *   @parms        : ptr to a param struct to be set to server
   1243  *
   1244  * RETURN     : int32_t type of status
   1245  *              0  -- success
   1246  *              -1 -- failure
   1247  * NOTE       : Assume the parms struct buf is already mapped to server via
   1248  *              domain socket. Corresponding fields of parameters to be set
   1249  *              are already filled in by upper layer caller.
   1250  *==========================================================================*/
   1251 int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
   1252                                    mm_evt_paylod_set_get_stream_parms_t *payload)
   1253 {
   1254     int32_t rc = -1;
   1255     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1256                                                                payload->stream_id);
   1257     if (NULL != s_obj) {
   1258         rc = mm_stream_fsm_fn(s_obj,
   1259                               MM_STREAM_EVT_SET_PARM,
   1260                               (void *)payload,
   1261                               NULL);
   1262     }
   1263 
   1264     return rc;
   1265 }
   1266 
   1267 /*===========================================================================
   1268  * FUNCTION   : mm_channel_get_stream_parms
   1269  *
   1270  * DESCRIPTION: get parameters per stream
   1271  *
   1272  * PARAMETERS :
   1273  *   @my_obj       : channel object
   1274  *   @s_id         : stream handle
   1275  *   @parms        : ptr to a param struct to be get from server
   1276  *
   1277  * RETURN     : int32_t type of status
   1278  *              0  -- success
   1279  *              -1 -- failure
   1280  * NOTE       : Assume the parms struct buf is already mapped to server via
   1281  *              domain socket. Parameters to be get from server are already
   1282  *              filled in by upper layer caller. After this call, corresponding
   1283  *              fields of requested parameters will be filled in by server with
   1284  *              detailed information.
   1285  *==========================================================================*/
   1286 int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
   1287                                    mm_evt_paylod_set_get_stream_parms_t *payload)
   1288 {
   1289     int32_t rc = -1;
   1290     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1291                                                                payload->stream_id);
   1292     if (NULL != s_obj) {
   1293         rc = mm_stream_fsm_fn(s_obj,
   1294                               MM_STREAM_EVT_GET_PARM,
   1295                               (void *)payload,
   1296                               NULL);
   1297     }
   1298 
   1299     return rc;
   1300 }
   1301 
   1302 /*===========================================================================
   1303  * FUNCTION   : mm_channel_do_stream_action
   1304  *
   1305  * DESCRIPTION: request server to perform stream based action. Maybe removed later
   1306  *              if the functionality is included in mm_camera_set_parms
   1307  *
   1308  * PARAMETERS :
   1309  *   @my_obj       : channel object
   1310  *   @s_id         : stream handle
   1311  *   @actions      : ptr to an action struct buf to be performed by server
   1312  *
   1313  * RETURN     : int32_t type of status
   1314  *              0  -- success
   1315  *              -1 -- failure
   1316  * NOTE       : Assume the action struct buf is already mapped to server via
   1317  *              domain socket. Actions to be performed by server are already
   1318  *              filled in by upper layer caller.
   1319  *==========================================================================*/
   1320 int32_t mm_channel_do_stream_action(mm_channel_t *my_obj,
   1321                                    mm_evt_paylod_do_stream_action_t *payload)
   1322 {
   1323     int32_t rc = -1;
   1324     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1325                                                                payload->stream_id);
   1326     if (NULL != s_obj) {
   1327         rc = mm_stream_fsm_fn(s_obj,
   1328                               MM_STREAM_EVT_DO_ACTION,
   1329                               (void *)payload,
   1330                               NULL);
   1331     }
   1332 
   1333     return rc;
   1334 }
   1335 
   1336 /*===========================================================================
   1337  * FUNCTION   : mm_channel_map_stream_buf
   1338  *
   1339  * DESCRIPTION: mapping stream buffer via domain socket to server
   1340  *
   1341  * PARAMETERS :
   1342  *   @my_obj       : channel object
   1343  *   @payload      : ptr to payload for mapping
   1344  *
   1345  * RETURN     : int32_t type of status
   1346  *              0  -- success
   1347  *              -1 -- failure
   1348  *==========================================================================*/
   1349 int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj,
   1350                                   mm_evt_paylod_map_stream_buf_t *payload)
   1351 {
   1352     int32_t rc = -1;
   1353     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1354                                                                payload->stream_id);
   1355     if (NULL != s_obj) {
   1356         rc = mm_stream_map_buf(s_obj,
   1357                                payload->buf_type,
   1358                                payload->buf_idx,
   1359                                payload->plane_idx,
   1360                                payload->fd,
   1361                                payload->size);
   1362     }
   1363 
   1364     return rc;
   1365 }
   1366 
   1367 /*===========================================================================
   1368  * FUNCTION   : mm_channel_unmap_stream_buf
   1369  *
   1370  * DESCRIPTION: unmapping stream buffer via domain socket to server
   1371  *
   1372  * PARAMETERS :
   1373  *   @my_obj       : channel object
   1374  *   @payload      : ptr to unmap payload
   1375  *
   1376  * RETURN     : int32_t type of status
   1377  *              0  -- success
   1378  *              -1 -- failure
   1379  *==========================================================================*/
   1380 int32_t mm_channel_unmap_stream_buf(mm_channel_t *my_obj,
   1381                                     mm_evt_paylod_unmap_stream_buf_t *payload)
   1382 {
   1383     int32_t rc = -1;
   1384     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1385                                                                payload->stream_id);
   1386     if (NULL != s_obj) {
   1387         rc = mm_stream_unmap_buf(s_obj, payload->buf_type,
   1388                                  payload->buf_idx, payload->plane_idx);
   1389     }
   1390 
   1391     return rc;
   1392 }
   1393 
   1394 /*===========================================================================
   1395  * FUNCTION   : mm_channel_superbuf_queue_init
   1396  *
   1397  * DESCRIPTION: initialize superbuf queue in the channel
   1398  *
   1399  * PARAMETERS :
   1400  *   @queue   : ptr to superbuf queue to be initialized
   1401  *
   1402  * RETURN     : int32_t type of status
   1403  *              0  -- success
   1404  *              -1 -- failure
   1405  *==========================================================================*/
   1406 int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue)
   1407 {
   1408     return cam_queue_init(&queue->que);
   1409 }
   1410 
   1411 /*===========================================================================
   1412  * FUNCTION   : mm_channel_superbuf_queue_deinit
   1413  *
   1414  * DESCRIPTION: deinitialize superbuf queue in the channel
   1415  *
   1416  * PARAMETERS :
   1417  *   @queue   : ptr to superbuf queue to be deinitialized
   1418  *
   1419  * RETURN     : int32_t type of status
   1420  *              0  -- success
   1421  *              -1 -- failure
   1422  *==========================================================================*/
   1423 int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue)
   1424 {
   1425     return cam_queue_deinit(&queue->que);
   1426 }
   1427 
   1428 /*===========================================================================
   1429  * FUNCTION   : mm_channel_util_seq_comp_w_rollover
   1430  *
   1431  * DESCRIPTION: utility function to handle sequence number comparison with rollover
   1432  *
   1433  * PARAMETERS :
   1434  *   @v1      : first value to be compared
   1435  *   @v2      : second value to be compared
   1436  *
   1437  * RETURN     : int8_t type of comparison result
   1438  *              >0  -- v1 larger than v2
   1439  *              =0  -- vi equal to v2
   1440  *              <0  -- v1 smaller than v2
   1441  *==========================================================================*/
   1442 int8_t mm_channel_util_seq_comp_w_rollover(uint32_t v1,
   1443                                            uint32_t v2)
   1444 {
   1445     int8_t ret = 0;
   1446 
   1447     /* TODO: need to handle the case if v2 roll over to 0 */
   1448     if (v1 > v2) {
   1449         ret = 1;
   1450     } else if (v1 < v2) {
   1451         ret = -1;
   1452     }
   1453 
   1454     return ret;
   1455 }
   1456 
   1457 /*===========================================================================
   1458  * FUNCTION   : mm_channel_handle_metadata
   1459  *
   1460  * DESCRIPTION: Handle frame matching logic change due to metadata
   1461  *
   1462  * PARAMETERS :
   1463  *   @ch_obj  : channel object
   1464  *   @queue   : superbuf queue
   1465  *   @buf_info: new buffer from stream
   1466  *
   1467  * RETURN     : int32_t type of status
   1468  *              0  -- success
   1469  *              -1 -- failure
   1470  *==========================================================================*/
   1471 int32_t mm_channel_handle_metadata(
   1472                         mm_channel_t* ch_obj,
   1473                         mm_channel_queue_t * queue,
   1474                         mm_camera_buf_info_t *buf_info)
   1475 {
   1476     int rc = 0 ;
   1477     mm_stream_t* stream_obj = NULL;
   1478     stream_obj = mm_channel_util_get_stream_by_handler(ch_obj,
   1479                 buf_info->stream_id);
   1480 
   1481     if (NULL == stream_obj) {
   1482         CDBG_ERROR("%s: Invalid Stream Object for stream_id = %d",
   1483                    __func__, buf_info->stream_id);
   1484         rc = -1;
   1485         goto end;
   1486     }
   1487     if (NULL == stream_obj->stream_info) {
   1488         CDBG_ERROR("%s: NULL stream info for stream_id = %d",
   1489                     __func__, buf_info->stream_id);
   1490         rc = -1;
   1491         goto end;
   1492     }
   1493 
   1494     if (CAM_STREAM_TYPE_METADATA == stream_obj->stream_info->stream_type) {
   1495         const cam_metadata_info_t *metadata;
   1496         metadata = (const cam_metadata_info_t *)buf_info->buf->buffer;
   1497 
   1498         if (NULL == metadata) {
   1499             CDBG_ERROR("%s: NULL metadata buffer for metadata stream",
   1500                        __func__);
   1501             rc = -1;
   1502             goto end;
   1503         }
   1504 
   1505         if (metadata->is_prep_snapshot_done_valid &&
   1506                 metadata->is_good_frame_idx_range_valid) {
   1507             CDBG_ERROR("%s: prep_snapshot_done and good_idx_range shouldn't be valid at the same time", __func__);
   1508             rc = -1;
   1509             goto end;
   1510         }
   1511 
   1512         if (metadata->is_prep_snapshot_done_valid &&
   1513             metadata->prep_snapshot_done_state == NEED_FUTURE_FRAME) {
   1514 
   1515             /* Set expected frame id to a future frame idx, large enough to wait
   1516              * for good_frame_idx_range, and small enough to still capture an image */
   1517             const int max_future_frame_offset = 100;
   1518             queue->expected_frame_id += max_future_frame_offset;
   1519 
   1520             mm_channel_superbuf_flush(ch_obj, queue);
   1521         } else if (metadata->is_good_frame_idx_range_valid) {
   1522             if (metadata->good_frame_idx_range.min_frame_idx >
   1523                 queue->expected_frame_id) {
   1524                 CDBG_HIGH("%s: min_frame_idx %d is greater than expected_frame_id %d",
   1525                     __func__, metadata->good_frame_idx_range.min_frame_idx,
   1526                     queue->expected_frame_id);
   1527             }
   1528             queue->expected_frame_id =
   1529                 metadata->good_frame_idx_range.min_frame_idx;
   1530         }
   1531     }
   1532 end:
   1533     return rc;
   1534 }
   1535 
   1536 /*===========================================================================
   1537  * FUNCTION   : mm_channel_superbuf_comp_and_enqueue
   1538  *
   1539  * DESCRIPTION: implementation for matching logic for superbuf
   1540  *
   1541  * PARAMETERS :
   1542  *   @ch_obj  : channel object
   1543  *   @queue   : superbuf queue
   1544  *   @buf_info: new buffer from stream
   1545  *
   1546  * RETURN     : int32_t type of status
   1547  *              0  -- success
   1548  *              -1 -- failure
   1549  *==========================================================================*/
   1550 int32_t mm_channel_superbuf_comp_and_enqueue(
   1551                         mm_channel_t* ch_obj,
   1552                         mm_channel_queue_t *queue,
   1553                         mm_camera_buf_info_t *buf_info)
   1554 {
   1555     cam_node_t* node = NULL;
   1556     struct cam_list *head = NULL;
   1557     struct cam_list *pos = NULL;
   1558     mm_channel_queue_node_t* super_buf = NULL;
   1559     uint8_t buf_s_idx, i, found_super_buf, unmatched_bundles;
   1560     struct cam_list *last_buf, *insert_before_buf;
   1561 
   1562     CDBG("%s: E", __func__);
   1563     for (buf_s_idx = 0; buf_s_idx < queue->num_streams; buf_s_idx++) {
   1564         if (buf_info->stream_id == queue->bundled_streams[buf_s_idx]) {
   1565             break;
   1566         }
   1567     }
   1568     if (buf_s_idx == queue->num_streams) {
   1569         CDBG_ERROR("%s: buf from stream (%d) not bundled", __func__, buf_info->stream_id);
   1570         return -1;
   1571     }
   1572 
   1573     if (mm_channel_handle_metadata(ch_obj, queue, buf_info) < 0) {
   1574         return -1;
   1575     }
   1576 
   1577     if (mm_channel_util_seq_comp_w_rollover(buf_info->frame_idx,
   1578                                             queue->expected_frame_id) < 0) {
   1579         /* incoming buf is older than expected buf id, will discard it */
   1580         mm_channel_qbuf(ch_obj, buf_info->buf);
   1581         return 0;
   1582     }
   1583 
   1584     if (MM_CAMERA_SUPER_BUF_PRIORITY_NORMAL != queue->attr.priority) {
   1585         /* TODO */
   1586         /* need to decide if we want to queue the frame based on focus or exposure
   1587          * if frame not to be queued, we need to qbuf it back */
   1588     }
   1589 
   1590     /* comp */
   1591     pthread_mutex_lock(&queue->que.lock);
   1592     head = &queue->que.head.list;
   1593     /* get the last one in the queue which is possibly having no matching */
   1594     pos = head->next;
   1595 
   1596     found_super_buf = 0;
   1597     unmatched_bundles = 0;
   1598     last_buf = NULL;
   1599     insert_before_buf = NULL;
   1600     while (pos != head) {
   1601         node = member_of(pos, cam_node_t, list);
   1602         super_buf = (mm_channel_queue_node_t*)node->data;
   1603         if (NULL != super_buf) {
   1604             if (super_buf->matched) {
   1605                 /* find a matched super buf, move to next one */
   1606                 pos = pos->next;
   1607                 continue;
   1608             } else if ( buf_info->frame_idx == super_buf->frame_idx ) {
   1609                 /* have an unmatched super buf that matches our frame idx,
   1610                  *  break the loop */
   1611                 found_super_buf = 1;
   1612                 break;
   1613             } else {
   1614                 unmatched_bundles++;
   1615                 if ( NULL == last_buf ) {
   1616                     if ( super_buf->frame_idx < buf_info->frame_idx ) {
   1617                         last_buf = pos;
   1618                     }
   1619                 }
   1620                 if ( NULL == insert_before_buf ) {
   1621                     if ( super_buf->frame_idx > buf_info->frame_idx ) {
   1622                         insert_before_buf = pos;
   1623                     }
   1624                 }
   1625                 pos = pos->next;
   1626             }
   1627         }
   1628     }
   1629 
   1630     if ( found_super_buf ) {
   1631             super_buf->super_buf[buf_s_idx] = *buf_info;
   1632 
   1633             /* check if superbuf is all matched */
   1634             super_buf->matched = 1;
   1635             for (i=0; i < super_buf->num_of_bufs; i++) {
   1636                 if (super_buf->super_buf[i].frame_idx == 0) {
   1637                     super_buf->matched = 0;
   1638                     break;
   1639                 }
   1640             }
   1641 
   1642             if (super_buf->matched) {
   1643                 queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip;
   1644                 queue->match_cnt++;
   1645                 /* Any older unmatched buffer need to be released */
   1646                 if ( last_buf ) {
   1647                     while ( last_buf != pos ) {
   1648                         node = member_of(last_buf, cam_node_t, list);
   1649                         super_buf = (mm_channel_queue_node_t*)node->data;
   1650                         if (NULL != super_buf) {
   1651                             for (i=0; i<super_buf->num_of_bufs; i++) {
   1652                                 if (super_buf->super_buf[i].frame_idx != 0) {
   1653                                         mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
   1654                                 }
   1655                             }
   1656                             queue->que.size--;
   1657                             last_buf = last_buf->next;
   1658                             cam_list_del_node(&node->list);
   1659                             free(node);
   1660                             free(super_buf);
   1661                         } else {
   1662                             CDBG_ERROR(" %s : Invalid superbuf in queue!", __func__);
   1663                             break;
   1664                         }
   1665                     }
   1666                 }
   1667             }
   1668     } else {
   1669         if (  ( queue->attr.max_unmatched_frames < unmatched_bundles ) &&
   1670               ( NULL == last_buf ) ) {
   1671             /* incoming frame is older than the last bundled one */
   1672             mm_channel_qbuf(ch_obj, buf_info->buf);
   1673         } else {
   1674             if ( queue->attr.max_unmatched_frames < unmatched_bundles ) {
   1675                 /* release the oldest bundled superbuf */
   1676                 node = member_of(last_buf, cam_node_t, list);
   1677                 super_buf = (mm_channel_queue_node_t*)node->data;
   1678                 for (i=0; i<super_buf->num_of_bufs; i++) {
   1679                     if (super_buf->super_buf[i].frame_idx != 0) {
   1680                             mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
   1681                     }
   1682                 }
   1683                 queue->que.size--;
   1684                 node = member_of(last_buf, cam_node_t, list);
   1685                 cam_list_del_node(&node->list);
   1686                 free(node);
   1687                 free(super_buf);
   1688             }
   1689             /* insert the new frame at the appropriate position. */
   1690 
   1691             mm_channel_queue_node_t *new_buf = NULL;
   1692             cam_node_t* new_node = NULL;
   1693 
   1694             new_buf = (mm_channel_queue_node_t*)malloc(sizeof(mm_channel_queue_node_t));
   1695             new_node = (cam_node_t*)malloc(sizeof(cam_node_t));
   1696             if (NULL != new_buf && NULL != new_node) {
   1697                 memset(new_buf, 0, sizeof(mm_channel_queue_node_t));
   1698                 memset(new_node, 0, sizeof(cam_node_t));
   1699                 new_node->data = (void *)new_buf;
   1700                 new_buf->num_of_bufs = queue->num_streams;
   1701                 new_buf->super_buf[buf_s_idx] = *buf_info;
   1702                 new_buf->frame_idx = buf_info->frame_idx;
   1703 
   1704                 /* enqueue */
   1705                 if ( insert_before_buf ) {
   1706                     cam_list_insert_before_node(&new_node->list, insert_before_buf);
   1707                 } else {
   1708                     cam_list_add_tail_node(&new_node->list, &queue->que.head.list);
   1709                 }
   1710                 queue->que.size++;
   1711 
   1712                 if(queue->num_streams == 1) {
   1713                     new_buf->matched = 1;
   1714 
   1715                     queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip;
   1716                     queue->match_cnt++;
   1717                 }
   1718             } else {
   1719                 /* No memory */
   1720                 if (NULL != new_buf) {
   1721                     free(new_buf);
   1722                 }
   1723                 if (NULL != new_node) {
   1724                     free(new_node);
   1725                 }
   1726                 /* qbuf the new buf since we cannot enqueue */
   1727                 mm_channel_qbuf(ch_obj, buf_info->buf);
   1728             }
   1729         }
   1730     }
   1731 
   1732     pthread_mutex_unlock(&queue->que.lock);
   1733 
   1734     CDBG("%s: X", __func__);
   1735     return 0;
   1736 }
   1737 
   1738 /*===========================================================================
   1739  * FUNCTION   : mm_channel_superbuf_dequeue_internal
   1740  *
   1741  * DESCRIPTION: internal implementation for dequeue from the superbuf queue
   1742  *
   1743  * PARAMETERS :
   1744  *   @queue   : superbuf queue
   1745  *   @matched_only : if dequeued buf should be matched
   1746  *
   1747  * RETURN     : ptr to a node from superbuf queue
   1748  *==========================================================================*/
   1749 mm_channel_queue_node_t* mm_channel_superbuf_dequeue_internal(mm_channel_queue_t * queue,
   1750                                                               uint8_t matched_only)
   1751 {
   1752     cam_node_t* node = NULL;
   1753     struct cam_list *head = NULL;
   1754     struct cam_list *pos = NULL;
   1755     mm_channel_queue_node_t* super_buf = NULL;
   1756 
   1757     head = &queue->que.head.list;
   1758     pos = head->next;
   1759     if (pos != head) {
   1760         /* get the first node */
   1761         node = member_of(pos, cam_node_t, list);
   1762         super_buf = (mm_channel_queue_node_t*)node->data;
   1763         if ( (NULL != super_buf) &&
   1764              (matched_only == TRUE) &&
   1765              (super_buf->matched == FALSE) ) {
   1766             /* require to dequeue matched frame only, but this superbuf is not matched,
   1767                simply set return ptr to NULL */
   1768             super_buf = NULL;
   1769         }
   1770         if (NULL != super_buf) {
   1771             /* remove from the queue */
   1772             cam_list_del_node(&node->list);
   1773             queue->que.size--;
   1774             if (super_buf->matched == TRUE) {
   1775                 queue->match_cnt--;
   1776             }
   1777             free(node);
   1778         }
   1779     }
   1780 
   1781     return super_buf;
   1782 }
   1783 
   1784 /*===========================================================================
   1785  * FUNCTION   : mm_channel_superbuf_dequeue
   1786  *
   1787  * DESCRIPTION: dequeue from the superbuf queue
   1788  *
   1789  * PARAMETERS :
   1790  *   @queue   : superbuf queue
   1791  *
   1792  * RETURN     : ptr to a node from superbuf queue
   1793  *==========================================================================*/
   1794 mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue)
   1795 {
   1796     mm_channel_queue_node_t* super_buf = NULL;
   1797 
   1798     pthread_mutex_lock(&queue->que.lock);
   1799     super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
   1800     pthread_mutex_unlock(&queue->que.lock);
   1801 
   1802     return super_buf;
   1803 }
   1804 
   1805 /*===========================================================================
   1806  * FUNCTION   : mm_channel_superbuf_bufdone_overflow
   1807  *
   1808  * DESCRIPTION: keep superbuf queue no larger than watermark set by upper layer
   1809  *              via channel attribute
   1810  *
   1811  * PARAMETERS :
   1812  *   @my_obj  : channel object
   1813  *   @queue   : superbuf queue
   1814  *
   1815  * RETURN     : int32_t type of status
   1816  *              0  -- success
   1817  *              -1 -- failure
   1818  *==========================================================================*/
   1819 int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t* my_obj,
   1820                                              mm_channel_queue_t * queue)
   1821 {
   1822     int32_t rc = 0, i;
   1823     mm_channel_queue_node_t* super_buf = NULL;
   1824     if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
   1825         /* for continuous streaming mode, no overflow is needed */
   1826         return 0;
   1827     }
   1828 
   1829     CDBG("%s: before match_cnt=%d, water_mark=%d",
   1830          __func__, queue->match_cnt, queue->attr.water_mark);
   1831     /* bufdone overflowed bufs */
   1832     pthread_mutex_lock(&queue->que.lock);
   1833     while (queue->match_cnt > queue->attr.water_mark) {
   1834         super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
   1835         if (NULL != super_buf) {
   1836             for (i=0; i<super_buf->num_of_bufs; i++) {
   1837                 if (NULL != super_buf->super_buf[i].buf) {
   1838                     mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
   1839                 }
   1840             }
   1841             free(super_buf);
   1842         }
   1843     }
   1844     pthread_mutex_unlock(&queue->que.lock);
   1845     CDBG("%s: after match_cnt=%d, water_mark=%d",
   1846          __func__, queue->match_cnt, queue->attr.water_mark);
   1847 
   1848     return rc;
   1849 }
   1850 
   1851 /*===========================================================================
   1852  * FUNCTION   : mm_channel_superbuf_skip
   1853  *
   1854  * DESCRIPTION: depends on the lookback configuration of the channel attribute,
   1855  *              unwanted superbufs will be removed from the superbuf queue.
   1856  *
   1857  * PARAMETERS :
   1858  *   @my_obj  : channel object
   1859  *   @queue   : superbuf queue
   1860  *
   1861  * RETURN     : int32_t type of status
   1862  *              0  -- success
   1863  *              -1 -- failure
   1864  *==========================================================================*/
   1865 int32_t mm_channel_superbuf_skip(mm_channel_t* my_obj,
   1866                                  mm_channel_queue_t * queue)
   1867 {
   1868     int32_t rc = 0, i;
   1869     mm_channel_queue_node_t* super_buf = NULL;
   1870     if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
   1871         /* for continuous streaming mode, no skip is needed */
   1872         return 0;
   1873     }
   1874 
   1875     /* bufdone overflowed bufs */
   1876     pthread_mutex_lock(&queue->que.lock);
   1877     while (queue->match_cnt > queue->attr.look_back) {
   1878         super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
   1879         if (NULL != super_buf) {
   1880             for (i=0; i<super_buf->num_of_bufs; i++) {
   1881                 if (NULL != super_buf->super_buf[i].buf) {
   1882                     mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
   1883                 }
   1884             }
   1885             free(super_buf);
   1886         }
   1887     }
   1888     pthread_mutex_unlock(&queue->que.lock);
   1889 
   1890     return rc;
   1891 }
   1892 
   1893 /*===========================================================================
   1894  * FUNCTION   : mm_channel_superbuf_flush
   1895  *
   1896  * DESCRIPTION: flush the superbuf queue.
   1897  *
   1898  * PARAMETERS :
   1899  *   @my_obj  : channel object
   1900  *   @queue   : superbuf queue
   1901  *
   1902  * RETURN     : int32_t type of status
   1903  *              0  -- success
   1904  *              -1 -- failure
   1905  *==========================================================================*/
   1906 int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj,
   1907                                   mm_channel_queue_t * queue)
   1908 {
   1909     int32_t rc = 0, i;
   1910     mm_channel_queue_node_t* super_buf = NULL;
   1911 
   1912     /* bufdone bufs */
   1913     pthread_mutex_lock(&queue->que.lock);
   1914     super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE);
   1915     while (super_buf != NULL) {
   1916         for (i=0; i<super_buf->num_of_bufs; i++) {
   1917             if (NULL != super_buf->super_buf[i].buf) {
   1918                 mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
   1919             }
   1920         }
   1921         free(super_buf);
   1922         super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE);
   1923     }
   1924     pthread_mutex_unlock(&queue->que.lock);
   1925 
   1926     return rc;
   1927 }
   1928