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