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->fd = -1;
    712     stream_obj->my_hdl = mm_camera_util_generate_handler(idx);
    713     stream_obj->ch_obj = my_obj;
    714     pthread_mutex_init(&stream_obj->buf_lock, NULL);
    715     pthread_mutex_init(&stream_obj->cb_lock, NULL);
    716     stream_obj->state = MM_STREAM_STATE_INITED;
    717 
    718     /* acquire stream */
    719     rc = mm_stream_fsm_fn(stream_obj, MM_STREAM_EVT_ACQUIRE, NULL, NULL);
    720     if (0 == rc) {
    721         s_hdl = stream_obj->my_hdl;
    722     } else {
    723         /* error during acquire, de-init */
    724         pthread_mutex_destroy(&stream_obj->buf_lock);
    725         pthread_mutex_destroy(&stream_obj->cb_lock);
    726         memset(stream_obj, 0, sizeof(mm_stream_t));
    727     }
    728     CDBG("%s : stream handle = %d", __func__, s_hdl);
    729     return s_hdl;
    730 }
    731 
    732 /*===========================================================================
    733  * FUNCTION   : mm_channel_del_stream
    734  *
    735  * DESCRIPTION: delete a stream from the channel bu its handle
    736  *
    737  * PARAMETERS :
    738  *   @my_obj       : channel object
    739  *   @stream_id    : stream handle
    740  *
    741  * RETURN     : int32_t type of status
    742  *              0  -- success
    743  *              -1 -- failure
    744  * NOTE       : assume steam is stooped before it can be deleted
    745  *==========================================================================*/
    746 int32_t mm_channel_del_stream(mm_channel_t *my_obj,
    747                               uint32_t stream_id)
    748 {
    749     int rc = -1;
    750     mm_stream_t * stream_obj = NULL;
    751     stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
    752 
    753     if (NULL == stream_obj) {
    754         CDBG_ERROR("%s :Invalid Stream Object for stream_id = %d",
    755                    __func__, stream_id);
    756         return rc;
    757     }
    758 
    759     rc = mm_stream_fsm_fn(stream_obj,
    760                           MM_STREAM_EVT_RELEASE,
    761                           NULL,
    762                           NULL);
    763 
    764     return rc;
    765 }
    766 
    767 /*===========================================================================
    768  * FUNCTION   : mm_channel_config_stream
    769  *
    770  * DESCRIPTION: configure a stream
    771  *
    772  * PARAMETERS :
    773  *   @my_obj       : channel object
    774  *   @stream_id    : stream handle
    775  *   @config       : stream configuration
    776  *
    777  * RETURN     : int32_t type of status
    778  *              0  -- success
    779  *              -1 -- failure
    780  *==========================================================================*/
    781 int32_t mm_channel_config_stream(mm_channel_t *my_obj,
    782                                    uint32_t stream_id,
    783                                    mm_camera_stream_config_t *config)
    784 {
    785     int rc = -1;
    786     mm_stream_t * stream_obj = NULL;
    787     CDBG("%s : E stream ID = %d", __func__, stream_id);
    788     stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
    789 
    790     if (NULL == stream_obj) {
    791         CDBG_ERROR("%s :Invalid Stream Object for stream_id = %d", __func__, stream_id);
    792         return rc;
    793     }
    794 
    795     /* set stream fmt */
    796     rc = mm_stream_fsm_fn(stream_obj,
    797                           MM_STREAM_EVT_SET_FMT,
    798                           (void *)config,
    799                           NULL);
    800     CDBG("%s : X rc = %d",__func__,rc);
    801     return rc;
    802 }
    803 
    804 /*===========================================================================
    805  * FUNCTION   : mm_channel_get_bundle_info
    806  *
    807  * DESCRIPTION: query bundle info of the channel, which should include all
    808  *              streams within this channel
    809  *
    810  * PARAMETERS :
    811  *   @my_obj       : channel object
    812  *   @bundle_info  : bundle info to be filled in
    813  *
    814  * RETURN     : int32_t type of status
    815  *              0  -- success
    816  *              -1 -- failure
    817  *==========================================================================*/
    818 int32_t mm_channel_get_bundle_info(mm_channel_t *my_obj,
    819                                    cam_bundle_config_t *bundle_info)
    820 {
    821     int i;
    822     mm_stream_t *s_obj = NULL;
    823     int32_t rc = 0;
    824 
    825     memset(bundle_info, 0, sizeof(cam_bundle_config_t));
    826     bundle_info->bundle_id = my_obj->my_hdl;
    827     bundle_info->num_of_streams = 0;
    828     for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
    829         if (my_obj->streams[i].my_hdl > 0) {
    830             s_obj = mm_channel_util_get_stream_by_handler(my_obj,
    831                                                           my_obj->streams[i].my_hdl);
    832             if (NULL != s_obj) {
    833                 if (CAM_STREAM_TYPE_METADATA != s_obj->stream_info->stream_type) {
    834                     bundle_info->stream_ids[bundle_info->num_of_streams++] =
    835                                                         s_obj->server_stream_id;
    836                 }
    837             } else {
    838                 CDBG_ERROR("%s: cannot find stream obj (%d) by handler (%d)",
    839                            __func__, i, my_obj->streams[i].my_hdl);
    840                 rc = -1;
    841                 break;
    842             }
    843         }
    844     }
    845     if (rc != 0) {
    846         /* error, reset to 0 */
    847         memset(bundle_info, 0, sizeof(cam_bundle_config_t));
    848     }
    849     return rc;
    850 }
    851 
    852 /*===========================================================================
    853  * FUNCTION   : mm_channel_start
    854  *
    855  * DESCRIPTION: start a channel, which will start all streams in the channel
    856  *
    857  * PARAMETERS :
    858  *   @my_obj       : channel object
    859  *
    860  * RETURN     : int32_t type of status
    861  *              0  -- success
    862  *              -1 -- failure
    863  *==========================================================================*/
    864 int32_t mm_channel_start(mm_channel_t *my_obj)
    865 {
    866     int32_t rc = 0;
    867     int i, j;
    868     mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL};
    869     uint8_t num_streams_to_start = 0;
    870     mm_stream_t *s_obj = NULL;
    871     int meta_stream_idx = 0;
    872 
    873     for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
    874         if (my_obj->streams[i].my_hdl > 0) {
    875             s_obj = mm_channel_util_get_stream_by_handler(my_obj,
    876                                                           my_obj->streams[i].my_hdl);
    877             if (NULL != s_obj) {
    878                 /* remember meta data stream index */
    879                 if (s_obj->stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
    880                     meta_stream_idx = num_streams_to_start;
    881                 }
    882                 s_objs[num_streams_to_start++] = s_obj;
    883             }
    884         }
    885     }
    886 
    887     if (meta_stream_idx > 0 ) {
    888         /* always start meta data stream first, so switch the stream object with the first one */
    889         s_obj = s_objs[0];
    890         s_objs[0] = s_objs[meta_stream_idx];
    891         s_objs[meta_stream_idx] = s_obj;
    892     }
    893 
    894     if (NULL != my_obj->bundle.super_buf_notify_cb) {
    895         /* need to send up cb, therefore launch thread */
    896         /* init superbuf queue */
    897         mm_channel_superbuf_queue_init(&my_obj->bundle.superbuf_queue);
    898         my_obj->bundle.superbuf_queue.num_streams = num_streams_to_start;
    899         my_obj->bundle.superbuf_queue.expected_frame_id = 0;
    900 
    901         for (i = 0; i < num_streams_to_start; i++) {
    902             /* set bundled flag to streams */
    903             s_objs[i]->is_bundled = 1;
    904             /* init bundled streams to invalid value -1 */
    905             my_obj->bundle.superbuf_queue.bundled_streams[i] = s_objs[i]->my_hdl;
    906         }
    907 
    908         /* launch cb thread for dispatching super buf through cb */
    909         mm_camera_cmd_thread_launch(&my_obj->cb_thread,
    910                                     mm_channel_dispatch_super_buf,
    911                                     (void*)my_obj);
    912 
    913         /* launch cmd thread for super buf dataCB */
    914         mm_camera_cmd_thread_launch(&my_obj->cmd_thread,
    915                                     mm_channel_process_stream_buf,
    916                                     (void*)my_obj);
    917 
    918         /* set flag to TRUE */
    919         my_obj->bundle.is_active = TRUE;
    920     }
    921 
    922     for (i = 0; i < num_streams_to_start; i++) {
    923         /* all streams within a channel should be started at the same time */
    924         if (s_objs[i]->state == MM_STREAM_STATE_ACTIVE) {
    925             CDBG_ERROR("%s: stream already started idx(%d)", __func__, i);
    926             rc = -1;
    927             break;
    928         }
    929 
    930         /* allocate buf */
    931         rc = mm_stream_fsm_fn(s_objs[i],
    932                               MM_STREAM_EVT_GET_BUF,
    933                               NULL,
    934                               NULL);
    935         if (0 != rc) {
    936             CDBG_ERROR("%s: get buf failed at idx(%d)", __func__, i);
    937             break;
    938         }
    939 
    940         /* reg buf */
    941         rc = mm_stream_fsm_fn(s_objs[i],
    942                               MM_STREAM_EVT_REG_BUF,
    943                               NULL,
    944                               NULL);
    945         if (0 != rc) {
    946             CDBG_ERROR("%s: reg buf failed at idx(%d)", __func__, i);
    947             break;
    948         }
    949 
    950         /* start stream */
    951         rc = mm_stream_fsm_fn(s_objs[i],
    952                               MM_STREAM_EVT_START,
    953                               NULL,
    954                               NULL);
    955         if (0 != rc) {
    956             CDBG_ERROR("%s: start stream failed at idx(%d)", __func__, i);
    957             break;
    958         }
    959     }
    960 
    961     /* error handling */
    962     if (0 != rc) {
    963         for (j=0; j<=i; j++) {
    964             /* stop streams*/
    965             mm_stream_fsm_fn(s_objs[j],
    966                              MM_STREAM_EVT_STOP,
    967                              NULL,
    968                              NULL);
    969 
    970             /* unreg buf */
    971             mm_stream_fsm_fn(s_objs[j],
    972                              MM_STREAM_EVT_UNREG_BUF,
    973                              NULL,
    974                              NULL);
    975 
    976             /* put buf back */
    977             mm_stream_fsm_fn(s_objs[j],
    978                              MM_STREAM_EVT_PUT_BUF,
    979                              NULL,
    980                              NULL);
    981         }
    982     }
    983 
    984     return rc;
    985 }
    986 
    987 /*===========================================================================
    988  * FUNCTION   : mm_channel_stop
    989  *
    990  * DESCRIPTION: stop a channel, which will stop all streams in the channel
    991  *
    992  * PARAMETERS :
    993  *   @my_obj       : channel object
    994  *
    995  * RETURN     : int32_t type of status
    996  *              0  -- success
    997  *              -1 -- failure
    998  *==========================================================================*/
    999 int32_t mm_channel_stop(mm_channel_t *my_obj)
   1000 {
   1001     int32_t rc = 0;
   1002     int i;
   1003     mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL};
   1004     uint8_t num_streams_to_stop = 0;
   1005     mm_stream_t *s_obj = NULL;
   1006     int meta_stream_idx = 0;
   1007 
   1008     for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
   1009         if (my_obj->streams[i].my_hdl > 0) {
   1010             s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1011                                                           my_obj->streams[i].my_hdl);
   1012             if (NULL != s_obj) {
   1013                 /* remember meta data stream index */
   1014                 if (s_obj->stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
   1015                     meta_stream_idx = num_streams_to_stop;
   1016                 }
   1017                 s_objs[num_streams_to_stop++] = s_obj;
   1018             }
   1019         }
   1020     }
   1021 
   1022     if (meta_stream_idx < num_streams_to_stop - 1 ) {
   1023         /* always stop meta data stream last, so switch the stream object with the last one */
   1024         s_obj = s_objs[num_streams_to_stop - 1];
   1025         s_objs[num_streams_to_stop - 1] = s_objs[meta_stream_idx];
   1026         s_objs[meta_stream_idx] = s_obj;
   1027     }
   1028 
   1029     for (i = 0; i < num_streams_to_stop; i++) {
   1030         /* stream off */
   1031         mm_stream_fsm_fn(s_objs[i],
   1032                          MM_STREAM_EVT_STOP,
   1033                          NULL,
   1034                          NULL);
   1035 
   1036         /* unreg buf at kernel */
   1037         mm_stream_fsm_fn(s_objs[i],
   1038                          MM_STREAM_EVT_UNREG_BUF,
   1039                          NULL,
   1040                          NULL);
   1041     }
   1042 
   1043     /* destroy super buf cmd thread */
   1044     if (TRUE == my_obj->bundle.is_active) {
   1045         /* first stop bundle thread */
   1046         mm_camera_cmd_thread_release(&my_obj->cmd_thread);
   1047         mm_camera_cmd_thread_release(&my_obj->cb_thread);
   1048 
   1049         /* deinit superbuf queue */
   1050         mm_channel_superbuf_queue_deinit(&my_obj->bundle.superbuf_queue);
   1051 
   1052         /* memset bundle info */
   1053         memset(&my_obj->bundle, 0, sizeof(mm_channel_bundle_t));
   1054     }
   1055 
   1056     /* since all streams are stopped, we are safe to
   1057      * release all buffers allocated in stream */
   1058     for (i = 0; i < num_streams_to_stop; i++) {
   1059         /* put buf back */
   1060         mm_stream_fsm_fn(s_objs[i],
   1061                          MM_STREAM_EVT_PUT_BUF,
   1062                          NULL,
   1063                          NULL);
   1064     }
   1065 
   1066     return rc;
   1067 }
   1068 
   1069 /*===========================================================================
   1070  * FUNCTION   : mm_channel_request_super_buf
   1071  *
   1072  * DESCRIPTION: for burst mode in bundle, reuqest certain amount of matched
   1073  *              frames from superbuf queue
   1074  *
   1075  * PARAMETERS :
   1076  *   @my_obj       : channel object
   1077  *   @num_buf_requested : number of matched frames needed
   1078  *
   1079  * RETURN     : int32_t type of status
   1080  *              0  -- success
   1081  *              -1 -- failure
   1082  *==========================================================================*/
   1083 int32_t mm_channel_request_super_buf(mm_channel_t *my_obj, uint32_t num_buf_requested)
   1084 {
   1085     int32_t rc = 0;
   1086     mm_camera_cmdcb_t* node = NULL;
   1087 
   1088     /* set pending_cnt
   1089      * will trigger dispatching super frames if pending_cnt > 0 */
   1090     /* send cam_sem_post to wake up cmd thread to dispatch super buffer */
   1091     node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
   1092     if (NULL != node) {
   1093         memset(node, 0, sizeof(mm_camera_cmdcb_t));
   1094         node->cmd_type = MM_CAMERA_CMD_TYPE_REQ_DATA_CB;
   1095         node->u.req_buf.num_buf_requested = num_buf_requested;
   1096 
   1097         /* enqueue to cmd thread */
   1098         cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
   1099 
   1100         /* wake up cmd thread */
   1101         cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
   1102     } else {
   1103         CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
   1104         rc = -1;
   1105     }
   1106 
   1107     return rc;
   1108 }
   1109 
   1110 /*===========================================================================
   1111  * FUNCTION   : mm_channel_cancel_super_buf_request
   1112  *
   1113  * DESCRIPTION: for burst mode in bundle, cancel the reuqest for certain amount
   1114  *              of matched frames from superbuf queue
   1115  *
   1116  * PARAMETERS :
   1117  *   @my_obj       : channel object
   1118  *
   1119  * RETURN     : int32_t type of status
   1120  *              0  -- success
   1121  *              -1 -- failure
   1122  *==========================================================================*/
   1123 int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj)
   1124 {
   1125     int32_t rc = 0;
   1126     /* reset pending_cnt */
   1127     rc = mm_channel_request_super_buf(my_obj, 0);
   1128     return rc;
   1129 }
   1130 
   1131 /*===========================================================================
   1132  * FUNCTION   : mm_channel_flush_super_buf_queue
   1133  *
   1134  * DESCRIPTION: flush superbuf queue
   1135  *
   1136  * PARAMETERS :
   1137  *   @my_obj  : channel object
   1138  *   @frame_idx : frame idx until which to flush all superbufs
   1139  *
   1140  * RETURN     : int32_t type of status
   1141  *              0  -- success
   1142  *              -1 -- failure
   1143  *==========================================================================*/
   1144 int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj, uint32_t frame_idx)
   1145 {
   1146     int32_t rc = 0;
   1147     mm_camera_cmdcb_t* node = NULL;
   1148 
   1149     node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
   1150     if (NULL != node) {
   1151         memset(node, 0, sizeof(mm_camera_cmdcb_t));
   1152         node->cmd_type = MM_CAMERA_CMD_TYPE_FLUSH_QUEUE;
   1153         node->u.frame_idx = frame_idx;
   1154 
   1155         /* enqueue to cmd thread */
   1156         cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
   1157 
   1158         /* wake up cmd thread */
   1159         cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
   1160     } else {
   1161         CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
   1162         rc = -1;
   1163     }
   1164 
   1165     return rc;
   1166 }
   1167 
   1168 /*===========================================================================
   1169  * FUNCTION   : mm_channel_config_notify_mode
   1170  *
   1171  * DESCRIPTION: configure notification mode
   1172  *
   1173  * PARAMETERS :
   1174  *   @my_obj  : channel object
   1175  *   @notify_mode : notification mode
   1176  *
   1177  * RETURN     : int32_t type of status
   1178  *              0  -- success
   1179  *              -1 -- failure
   1180  *==========================================================================*/
   1181 int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
   1182                                       mm_camera_super_buf_notify_mode_t notify_mode)
   1183 {
   1184     int32_t rc = 0;
   1185     mm_camera_cmdcb_t* node = NULL;
   1186 
   1187     node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
   1188     if (NULL != node) {
   1189         memset(node, 0, sizeof(mm_camera_cmdcb_t));
   1190         node->u.notify_mode = notify_mode;
   1191         node->cmd_type = MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY;
   1192 
   1193         /* enqueue to cmd thread */
   1194         cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
   1195 
   1196         /* wake up cmd thread */
   1197         cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
   1198     } else {
   1199         CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
   1200         rc = -1;
   1201     }
   1202 
   1203     return rc;
   1204 }
   1205 
   1206 /*===========================================================================
   1207  * FUNCTION   : mm_channel_qbuf
   1208  *
   1209  * DESCRIPTION: enqueue buffer back to kernel
   1210  *
   1211  * PARAMETERS :
   1212  *   @my_obj       : channel object
   1213  *   @buf          : buf ptr to be enqueued
   1214  *
   1215  * RETURN     : int32_t type of status
   1216  *              0  -- success
   1217  *              -1 -- failure
   1218  *==========================================================================*/
   1219 int32_t mm_channel_qbuf(mm_channel_t *my_obj,
   1220                         mm_camera_buf_def_t *buf)
   1221 {
   1222     int32_t rc = -1;
   1223     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, buf->stream_id);
   1224 
   1225     if (NULL != s_obj) {
   1226         rc = mm_stream_fsm_fn(s_obj,
   1227                               MM_STREAM_EVT_QBUF,
   1228                               (void *)buf,
   1229                               NULL);
   1230     }
   1231 
   1232     return rc;
   1233 }
   1234 
   1235 /*===========================================================================
   1236  * FUNCTION   : mm_channel_set_stream_parms
   1237  *
   1238  * DESCRIPTION: set parameters per stream
   1239  *
   1240  * PARAMETERS :
   1241  *   @my_obj       : channel object
   1242  *   @s_id         : stream handle
   1243  *   @parms        : ptr to a param struct to be set to server
   1244  *
   1245  * RETURN     : int32_t type of status
   1246  *              0  -- success
   1247  *              -1 -- failure
   1248  * NOTE       : Assume the parms struct buf is already mapped to server via
   1249  *              domain socket. Corresponding fields of parameters to be set
   1250  *              are already filled in by upper layer caller.
   1251  *==========================================================================*/
   1252 int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
   1253                                    mm_evt_paylod_set_get_stream_parms_t *payload)
   1254 {
   1255     int32_t rc = -1;
   1256     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1257                                                                payload->stream_id);
   1258     if (NULL != s_obj) {
   1259         rc = mm_stream_fsm_fn(s_obj,
   1260                               MM_STREAM_EVT_SET_PARM,
   1261                               (void *)payload,
   1262                               NULL);
   1263     }
   1264 
   1265     return rc;
   1266 }
   1267 
   1268 /*===========================================================================
   1269  * FUNCTION   : mm_channel_get_stream_parms
   1270  *
   1271  * DESCRIPTION: get parameters per stream
   1272  *
   1273  * PARAMETERS :
   1274  *   @my_obj       : channel object
   1275  *   @s_id         : stream handle
   1276  *   @parms        : ptr to a param struct to be get from server
   1277  *
   1278  * RETURN     : int32_t type of status
   1279  *              0  -- success
   1280  *              -1 -- failure
   1281  * NOTE       : Assume the parms struct buf is already mapped to server via
   1282  *              domain socket. Parameters to be get from server are already
   1283  *              filled in by upper layer caller. After this call, corresponding
   1284  *              fields of requested parameters will be filled in by server with
   1285  *              detailed information.
   1286  *==========================================================================*/
   1287 int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
   1288                                    mm_evt_paylod_set_get_stream_parms_t *payload)
   1289 {
   1290     int32_t rc = -1;
   1291     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1292                                                                payload->stream_id);
   1293     if (NULL != s_obj) {
   1294         rc = mm_stream_fsm_fn(s_obj,
   1295                               MM_STREAM_EVT_GET_PARM,
   1296                               (void *)payload,
   1297                               NULL);
   1298     }
   1299 
   1300     return rc;
   1301 }
   1302 
   1303 /*===========================================================================
   1304  * FUNCTION   : mm_channel_do_stream_action
   1305  *
   1306  * DESCRIPTION: request server to perform stream based action. Maybe removed later
   1307  *              if the functionality is included in mm_camera_set_parms
   1308  *
   1309  * PARAMETERS :
   1310  *   @my_obj       : channel object
   1311  *   @s_id         : stream handle
   1312  *   @actions      : ptr to an action struct buf to be performed by server
   1313  *
   1314  * RETURN     : int32_t type of status
   1315  *              0  -- success
   1316  *              -1 -- failure
   1317  * NOTE       : Assume the action struct buf is already mapped to server via
   1318  *              domain socket. Actions to be performed by server are already
   1319  *              filled in by upper layer caller.
   1320  *==========================================================================*/
   1321 int32_t mm_channel_do_stream_action(mm_channel_t *my_obj,
   1322                                    mm_evt_paylod_do_stream_action_t *payload)
   1323 {
   1324     int32_t rc = -1;
   1325     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1326                                                                payload->stream_id);
   1327     if (NULL != s_obj) {
   1328         rc = mm_stream_fsm_fn(s_obj,
   1329                               MM_STREAM_EVT_DO_ACTION,
   1330                               (void *)payload,
   1331                               NULL);
   1332     }
   1333 
   1334     return rc;
   1335 }
   1336 
   1337 /*===========================================================================
   1338  * FUNCTION   : mm_channel_map_stream_buf
   1339  *
   1340  * DESCRIPTION: mapping stream buffer via domain socket to server
   1341  *
   1342  * PARAMETERS :
   1343  *   @my_obj       : channel object
   1344  *   @payload      : ptr to payload for mapping
   1345  *
   1346  * RETURN     : int32_t type of status
   1347  *              0  -- success
   1348  *              -1 -- failure
   1349  *==========================================================================*/
   1350 int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj,
   1351                                   mm_evt_paylod_map_stream_buf_t *payload)
   1352 {
   1353     int32_t rc = -1;
   1354     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1355                                                                payload->stream_id);
   1356     if (NULL != s_obj) {
   1357         rc = mm_stream_map_buf(s_obj,
   1358                                payload->buf_type,
   1359                                payload->buf_idx,
   1360                                payload->plane_idx,
   1361                                payload->fd,
   1362                                payload->size);
   1363     }
   1364 
   1365     return rc;
   1366 }
   1367 
   1368 /*===========================================================================
   1369  * FUNCTION   : mm_channel_unmap_stream_buf
   1370  *
   1371  * DESCRIPTION: unmapping stream buffer via domain socket to server
   1372  *
   1373  * PARAMETERS :
   1374  *   @my_obj       : channel object
   1375  *   @payload      : ptr to unmap payload
   1376  *
   1377  * RETURN     : int32_t type of status
   1378  *              0  -- success
   1379  *              -1 -- failure
   1380  *==========================================================================*/
   1381 int32_t mm_channel_unmap_stream_buf(mm_channel_t *my_obj,
   1382                                     mm_evt_paylod_unmap_stream_buf_t *payload)
   1383 {
   1384     int32_t rc = -1;
   1385     mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj,
   1386                                                                payload->stream_id);
   1387     if (NULL != s_obj) {
   1388         rc = mm_stream_unmap_buf(s_obj, payload->buf_type,
   1389                                  payload->buf_idx, payload->plane_idx);
   1390     }
   1391 
   1392     return rc;
   1393 }
   1394 
   1395 /*===========================================================================
   1396  * FUNCTION   : mm_channel_superbuf_queue_init
   1397  *
   1398  * DESCRIPTION: initialize superbuf queue in the channel
   1399  *
   1400  * PARAMETERS :
   1401  *   @queue   : ptr to superbuf queue to be initialized
   1402  *
   1403  * RETURN     : int32_t type of status
   1404  *              0  -- success
   1405  *              -1 -- failure
   1406  *==========================================================================*/
   1407 int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue)
   1408 {
   1409     return cam_queue_init(&queue->que);
   1410 }
   1411 
   1412 /*===========================================================================
   1413  * FUNCTION   : mm_channel_superbuf_queue_deinit
   1414  *
   1415  * DESCRIPTION: deinitialize superbuf queue in the channel
   1416  *
   1417  * PARAMETERS :
   1418  *   @queue   : ptr to superbuf queue to be deinitialized
   1419  *
   1420  * RETURN     : int32_t type of status
   1421  *              0  -- success
   1422  *              -1 -- failure
   1423  *==========================================================================*/
   1424 int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue)
   1425 {
   1426     return cam_queue_deinit(&queue->que);
   1427 }
   1428 
   1429 /*===========================================================================
   1430  * FUNCTION   : mm_channel_util_seq_comp_w_rollover
   1431  *
   1432  * DESCRIPTION: utility function to handle sequence number comparison with rollover
   1433  *
   1434  * PARAMETERS :
   1435  *   @v1      : first value to be compared
   1436  *   @v2      : second value to be compared
   1437  *
   1438  * RETURN     : int8_t type of comparison result
   1439  *              >0  -- v1 larger than v2
   1440  *              =0  -- vi equal to v2
   1441  *              <0  -- v1 smaller than v2
   1442  *==========================================================================*/
   1443 int8_t mm_channel_util_seq_comp_w_rollover(uint32_t v1,
   1444                                            uint32_t v2)
   1445 {
   1446     int8_t ret = 0;
   1447 
   1448     /* TODO: need to handle the case if v2 roll over to 0 */
   1449     if (v1 > v2) {
   1450         ret = 1;
   1451     } else if (v1 < v2) {
   1452         ret = -1;
   1453     }
   1454 
   1455     return ret;
   1456 }
   1457 
   1458 /*===========================================================================
   1459  * FUNCTION   : mm_channel_handle_metadata
   1460  *
   1461  * DESCRIPTION: Handle frame matching logic change due to metadata
   1462  *
   1463  * PARAMETERS :
   1464  *   @ch_obj  : channel object
   1465  *   @queue   : superbuf queue
   1466  *   @buf_info: new buffer from stream
   1467  *
   1468  * RETURN     : int32_t type of status
   1469  *              0  -- success
   1470  *              -1 -- failure
   1471  *==========================================================================*/
   1472 int32_t mm_channel_handle_metadata(
   1473                         mm_channel_t* ch_obj,
   1474                         mm_channel_queue_t * queue,
   1475                         mm_camera_buf_info_t *buf_info)
   1476 {
   1477     int rc = 0 ;
   1478     mm_stream_t* stream_obj = NULL;
   1479     stream_obj = mm_channel_util_get_stream_by_handler(ch_obj,
   1480                 buf_info->stream_id);
   1481 
   1482     if (NULL == stream_obj) {
   1483         CDBG_ERROR("%s: Invalid Stream Object for stream_id = %d",
   1484                    __func__, buf_info->stream_id);
   1485         rc = -1;
   1486         goto end;
   1487     }
   1488     if (NULL == stream_obj->stream_info) {
   1489         CDBG_ERROR("%s: NULL stream info for stream_id = %d",
   1490                     __func__, buf_info->stream_id);
   1491         rc = -1;
   1492         goto end;
   1493     }
   1494 
   1495     if (CAM_STREAM_TYPE_METADATA == stream_obj->stream_info->stream_type) {
   1496         const cam_metadata_info_t *metadata;
   1497         metadata = (const cam_metadata_info_t *)buf_info->buf->buffer;
   1498 
   1499         if (NULL == metadata) {
   1500             CDBG_ERROR("%s: NULL metadata buffer for metadata stream",
   1501                        __func__);
   1502             rc = -1;
   1503             goto end;
   1504         }
   1505 
   1506         if (metadata->is_prep_snapshot_done_valid &&
   1507                 metadata->is_good_frame_idx_range_valid) {
   1508             CDBG_ERROR("%s: prep_snapshot_done and good_idx_range shouldn't be valid at the same time", __func__);
   1509             rc = -1;
   1510             goto end;
   1511         }
   1512 
   1513         if (metadata->is_prep_snapshot_done_valid &&
   1514             metadata->prep_snapshot_done_state == NEED_FUTURE_FRAME) {
   1515 
   1516             /* Set expected frame id to a future frame idx, large enough to wait
   1517              * for good_frame_idx_range, and small enough to still capture an image */
   1518             const int max_future_frame_offset = 100;
   1519             queue->expected_frame_id += max_future_frame_offset;
   1520 
   1521             mm_channel_superbuf_flush(ch_obj, queue);
   1522         } else if (metadata->is_good_frame_idx_range_valid) {
   1523             if (metadata->good_frame_idx_range.min_frame_idx >
   1524                 queue->expected_frame_id) {
   1525                 CDBG_HIGH("%s: min_frame_idx %d is greater than expected_frame_id %d",
   1526                     __func__, metadata->good_frame_idx_range.min_frame_idx,
   1527                     queue->expected_frame_id);
   1528             }
   1529             queue->expected_frame_id =
   1530                 metadata->good_frame_idx_range.min_frame_idx;
   1531         }
   1532     }
   1533 end:
   1534     return rc;
   1535 }
   1536 
   1537 /*===========================================================================
   1538  * FUNCTION   : mm_channel_superbuf_comp_and_enqueue
   1539  *
   1540  * DESCRIPTION: implementation for matching logic for superbuf
   1541  *
   1542  * PARAMETERS :
   1543  *   @ch_obj  : channel object
   1544  *   @queue   : superbuf queue
   1545  *   @buf_info: new buffer from stream
   1546  *
   1547  * RETURN     : int32_t type of status
   1548  *              0  -- success
   1549  *              -1 -- failure
   1550  *==========================================================================*/
   1551 int32_t mm_channel_superbuf_comp_and_enqueue(
   1552                         mm_channel_t* ch_obj,
   1553                         mm_channel_queue_t *queue,
   1554                         mm_camera_buf_info_t *buf_info)
   1555 {
   1556     cam_node_t* node = NULL;
   1557     struct cam_list *head = NULL;
   1558     struct cam_list *pos = NULL;
   1559     mm_channel_queue_node_t* super_buf = NULL;
   1560     uint8_t buf_s_idx, i, found_super_buf, unmatched_bundles;
   1561     struct cam_list *last_buf, *insert_before_buf;
   1562 
   1563     CDBG("%s: E", __func__);
   1564     for (buf_s_idx = 0; buf_s_idx < queue->num_streams; buf_s_idx++) {
   1565         if (buf_info->stream_id == queue->bundled_streams[buf_s_idx]) {
   1566             break;
   1567         }
   1568     }
   1569     if (buf_s_idx == queue->num_streams) {
   1570         CDBG_ERROR("%s: buf from stream (%d) not bundled", __func__, buf_info->stream_id);
   1571         return -1;
   1572     }
   1573 
   1574     if (mm_channel_handle_metadata(ch_obj, queue, buf_info) < 0) {
   1575         return -1;
   1576     }
   1577 
   1578     if (mm_channel_util_seq_comp_w_rollover(buf_info->frame_idx,
   1579                                             queue->expected_frame_id) < 0) {
   1580         /* incoming buf is older than expected buf id, will discard it */
   1581         mm_channel_qbuf(ch_obj, buf_info->buf);
   1582         return 0;
   1583     }
   1584 
   1585     if (MM_CAMERA_SUPER_BUF_PRIORITY_NORMAL != queue->attr.priority) {
   1586         /* TODO */
   1587         /* need to decide if we want to queue the frame based on focus or exposure
   1588          * if frame not to be queued, we need to qbuf it back */
   1589     }
   1590 
   1591     /* comp */
   1592     pthread_mutex_lock(&queue->que.lock);
   1593     head = &queue->que.head.list;
   1594     /* get the last one in the queue which is possibly having no matching */
   1595     pos = head->next;
   1596 
   1597     found_super_buf = 0;
   1598     unmatched_bundles = 0;
   1599     last_buf = NULL;
   1600     insert_before_buf = NULL;
   1601     while (pos != head) {
   1602         node = member_of(pos, cam_node_t, list);
   1603         super_buf = (mm_channel_queue_node_t*)node->data;
   1604         if (NULL != super_buf) {
   1605             if (super_buf->matched) {
   1606                 /* find a matched super buf, move to next one */
   1607                 pos = pos->next;
   1608                 continue;
   1609             } else if ( buf_info->frame_idx == super_buf->frame_idx ) {
   1610                 /* have an unmatched super buf that matches our frame idx,
   1611                  *  break the loop */
   1612                 found_super_buf = 1;
   1613                 break;
   1614             } else {
   1615                 unmatched_bundles++;
   1616                 if ( NULL == last_buf ) {
   1617                     if ( super_buf->frame_idx < buf_info->frame_idx ) {
   1618                         last_buf = pos;
   1619                     }
   1620                 }
   1621                 if ( NULL == insert_before_buf ) {
   1622                     if ( super_buf->frame_idx > buf_info->frame_idx ) {
   1623                         insert_before_buf = pos;
   1624                     }
   1625                 }
   1626                 pos = pos->next;
   1627             }
   1628         }
   1629     }
   1630 
   1631     if ( found_super_buf ) {
   1632             super_buf->super_buf[buf_s_idx] = *buf_info;
   1633 
   1634             /* check if superbuf is all matched */
   1635             super_buf->matched = 1;
   1636             for (i=0; i < super_buf->num_of_bufs; i++) {
   1637                 if (super_buf->super_buf[i].frame_idx == 0) {
   1638                     super_buf->matched = 0;
   1639                     break;
   1640                 }
   1641             }
   1642 
   1643             if (super_buf->matched) {
   1644                 queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip;
   1645                 queue->match_cnt++;
   1646                 /* Any older unmatched buffer need to be released */
   1647                 if ( last_buf ) {
   1648                     while ( last_buf != pos ) {
   1649                         node = member_of(last_buf, cam_node_t, list);
   1650                         super_buf = (mm_channel_queue_node_t*)node->data;
   1651                         if (NULL != super_buf) {
   1652                             for (i=0; i<super_buf->num_of_bufs; i++) {
   1653                                 if (super_buf->super_buf[i].frame_idx != 0) {
   1654                                         mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
   1655                                 }
   1656                             }
   1657                             queue->que.size--;
   1658                             last_buf = last_buf->next;
   1659                             cam_list_del_node(&node->list);
   1660                             free(node);
   1661                             free(super_buf);
   1662                         } else {
   1663                             CDBG_ERROR(" %s : Invalid superbuf in queue!", __func__);
   1664                             break;
   1665                         }
   1666                     }
   1667                 }
   1668             }
   1669     } else {
   1670         if (  ( queue->attr.max_unmatched_frames < unmatched_bundles ) &&
   1671               ( NULL == last_buf ) ) {
   1672             /* incoming frame is older than the last bundled one */
   1673             mm_channel_qbuf(ch_obj, buf_info->buf);
   1674         } else {
   1675             if ( queue->attr.max_unmatched_frames < unmatched_bundles ) {
   1676                 /* release the oldest bundled superbuf */
   1677                 node = member_of(last_buf, cam_node_t, list);
   1678                 super_buf = (mm_channel_queue_node_t*)node->data;
   1679                 for (i=0; i<super_buf->num_of_bufs; i++) {
   1680                     if (super_buf->super_buf[i].frame_idx != 0) {
   1681                             mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
   1682                     }
   1683                 }
   1684                 queue->que.size--;
   1685                 node = member_of(last_buf, cam_node_t, list);
   1686                 cam_list_del_node(&node->list);
   1687                 free(node);
   1688                 free(super_buf);
   1689             }
   1690             /* insert the new frame at the appropriate position. */
   1691 
   1692             mm_channel_queue_node_t *new_buf = NULL;
   1693             cam_node_t* new_node = NULL;
   1694 
   1695             new_buf = (mm_channel_queue_node_t*)malloc(sizeof(mm_channel_queue_node_t));
   1696             new_node = (cam_node_t*)malloc(sizeof(cam_node_t));
   1697             if (NULL != new_buf && NULL != new_node) {
   1698                 memset(new_buf, 0, sizeof(mm_channel_queue_node_t));
   1699                 memset(new_node, 0, sizeof(cam_node_t));
   1700                 new_node->data = (void *)new_buf;
   1701                 new_buf->num_of_bufs = queue->num_streams;
   1702                 new_buf->super_buf[buf_s_idx] = *buf_info;
   1703                 new_buf->frame_idx = buf_info->frame_idx;
   1704 
   1705                 /* enqueue */
   1706                 if ( insert_before_buf ) {
   1707                     cam_list_insert_before_node(&new_node->list, insert_before_buf);
   1708                 } else {
   1709                     cam_list_add_tail_node(&new_node->list, &queue->que.head.list);
   1710                 }
   1711                 queue->que.size++;
   1712 
   1713                 if(queue->num_streams == 1) {
   1714                     new_buf->matched = 1;
   1715 
   1716                     queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip;
   1717                     queue->match_cnt++;
   1718                 }
   1719             } else {
   1720                 /* No memory */
   1721                 if (NULL != new_buf) {
   1722                     free(new_buf);
   1723                 }
   1724                 if (NULL != new_node) {
   1725                     free(new_node);
   1726                 }
   1727                 /* qbuf the new buf since we cannot enqueue */
   1728                 mm_channel_qbuf(ch_obj, buf_info->buf);
   1729             }
   1730         }
   1731     }
   1732 
   1733     pthread_mutex_unlock(&queue->que.lock);
   1734 
   1735     CDBG("%s: X", __func__);
   1736     return 0;
   1737 }
   1738 
   1739 /*===========================================================================
   1740  * FUNCTION   : mm_channel_superbuf_dequeue_internal
   1741  *
   1742  * DESCRIPTION: internal implementation for dequeue from the superbuf queue
   1743  *
   1744  * PARAMETERS :
   1745  *   @queue   : superbuf queue
   1746  *   @matched_only : if dequeued buf should be matched
   1747  *
   1748  * RETURN     : ptr to a node from superbuf queue
   1749  *==========================================================================*/
   1750 mm_channel_queue_node_t* mm_channel_superbuf_dequeue_internal(mm_channel_queue_t * queue,
   1751                                                               uint8_t matched_only)
   1752 {
   1753     cam_node_t* node = NULL;
   1754     struct cam_list *head = NULL;
   1755     struct cam_list *pos = NULL;
   1756     mm_channel_queue_node_t* super_buf = NULL;
   1757 
   1758     head = &queue->que.head.list;
   1759     pos = head->next;
   1760     if (pos != head) {
   1761         /* get the first node */
   1762         node = member_of(pos, cam_node_t, list);
   1763         super_buf = (mm_channel_queue_node_t*)node->data;
   1764         if ( (NULL != super_buf) &&
   1765              (matched_only == TRUE) &&
   1766              (super_buf->matched == FALSE) ) {
   1767             /* require to dequeue matched frame only, but this superbuf is not matched,
   1768                simply set return ptr to NULL */
   1769             super_buf = NULL;
   1770         }
   1771         if (NULL != super_buf) {
   1772             /* remove from the queue */
   1773             cam_list_del_node(&node->list);
   1774             queue->que.size--;
   1775             if (super_buf->matched == TRUE) {
   1776                 queue->match_cnt--;
   1777             }
   1778             free(node);
   1779         }
   1780     }
   1781 
   1782     return super_buf;
   1783 }
   1784 
   1785 /*===========================================================================
   1786  * FUNCTION   : mm_channel_superbuf_dequeue
   1787  *
   1788  * DESCRIPTION: dequeue from the superbuf queue
   1789  *
   1790  * PARAMETERS :
   1791  *   @queue   : superbuf queue
   1792  *
   1793  * RETURN     : ptr to a node from superbuf queue
   1794  *==========================================================================*/
   1795 mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue)
   1796 {
   1797     mm_channel_queue_node_t* super_buf = NULL;
   1798 
   1799     pthread_mutex_lock(&queue->que.lock);
   1800     super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
   1801     pthread_mutex_unlock(&queue->que.lock);
   1802 
   1803     return super_buf;
   1804 }
   1805 
   1806 /*===========================================================================
   1807  * FUNCTION   : mm_channel_superbuf_bufdone_overflow
   1808  *
   1809  * DESCRIPTION: keep superbuf queue no larger than watermark set by upper layer
   1810  *              via channel attribute
   1811  *
   1812  * PARAMETERS :
   1813  *   @my_obj  : channel object
   1814  *   @queue   : superbuf queue
   1815  *
   1816  * RETURN     : int32_t type of status
   1817  *              0  -- success
   1818  *              -1 -- failure
   1819  *==========================================================================*/
   1820 int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t* my_obj,
   1821                                              mm_channel_queue_t * queue)
   1822 {
   1823     int32_t rc = 0, i;
   1824     mm_channel_queue_node_t* super_buf = NULL;
   1825     if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
   1826         /* for continuous streaming mode, no overflow is needed */
   1827         return 0;
   1828     }
   1829 
   1830     CDBG("%s: before match_cnt=%d, water_mark=%d",
   1831          __func__, queue->match_cnt, queue->attr.water_mark);
   1832     /* bufdone overflowed bufs */
   1833     pthread_mutex_lock(&queue->que.lock);
   1834     while (queue->match_cnt > queue->attr.water_mark) {
   1835         super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
   1836         if (NULL != super_buf) {
   1837             for (i=0; i<super_buf->num_of_bufs; i++) {
   1838                 if (NULL != super_buf->super_buf[i].buf) {
   1839                     mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
   1840                 }
   1841             }
   1842             free(super_buf);
   1843         }
   1844     }
   1845     pthread_mutex_unlock(&queue->que.lock);
   1846     CDBG("%s: after match_cnt=%d, water_mark=%d",
   1847          __func__, queue->match_cnt, queue->attr.water_mark);
   1848 
   1849     return rc;
   1850 }
   1851 
   1852 /*===========================================================================
   1853  * FUNCTION   : mm_channel_superbuf_skip
   1854  *
   1855  * DESCRIPTION: depends on the lookback configuration of the channel attribute,
   1856  *              unwanted superbufs will be removed from the superbuf queue.
   1857  *
   1858  * PARAMETERS :
   1859  *   @my_obj  : channel object
   1860  *   @queue   : superbuf queue
   1861  *
   1862  * RETURN     : int32_t type of status
   1863  *              0  -- success
   1864  *              -1 -- failure
   1865  *==========================================================================*/
   1866 int32_t mm_channel_superbuf_skip(mm_channel_t* my_obj,
   1867                                  mm_channel_queue_t * queue)
   1868 {
   1869     int32_t rc = 0, i;
   1870     mm_channel_queue_node_t* super_buf = NULL;
   1871     if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
   1872         /* for continuous streaming mode, no skip is needed */
   1873         return 0;
   1874     }
   1875 
   1876     /* bufdone overflowed bufs */
   1877     pthread_mutex_lock(&queue->que.lock);
   1878     while (queue->match_cnt > queue->attr.look_back) {
   1879         super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE);
   1880         if (NULL != super_buf) {
   1881             for (i=0; i<super_buf->num_of_bufs; i++) {
   1882                 if (NULL != super_buf->super_buf[i].buf) {
   1883                     mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
   1884                 }
   1885             }
   1886             free(super_buf);
   1887         }
   1888     }
   1889     pthread_mutex_unlock(&queue->que.lock);
   1890 
   1891     return rc;
   1892 }
   1893 
   1894 /*===========================================================================
   1895  * FUNCTION   : mm_channel_superbuf_flush
   1896  *
   1897  * DESCRIPTION: flush the superbuf queue.
   1898  *
   1899  * PARAMETERS :
   1900  *   @my_obj  : channel object
   1901  *   @queue   : superbuf queue
   1902  *
   1903  * RETURN     : int32_t type of status
   1904  *              0  -- success
   1905  *              -1 -- failure
   1906  *==========================================================================*/
   1907 int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj,
   1908                                   mm_channel_queue_t * queue)
   1909 {
   1910     int32_t rc = 0, i;
   1911     mm_channel_queue_node_t* super_buf = NULL;
   1912 
   1913     /* bufdone bufs */
   1914     pthread_mutex_lock(&queue->que.lock);
   1915     super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE);
   1916     while (super_buf != NULL) {
   1917         for (i=0; i<super_buf->num_of_bufs; i++) {
   1918             if (NULL != super_buf->super_buf[i].buf) {
   1919                 mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
   1920             }
   1921         }
   1922         free(super_buf);
   1923         super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE);
   1924     }
   1925     pthread_mutex_unlock(&queue->que.lock);
   1926 
   1927     return rc;
   1928 }
   1929