mm_camera_channel.c revision 744f5403bebb0e27140d16a5df7a341713c24a13
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
43extern mm_camera_obj_t* mm_camera_util_get_camera_by_handler(uint32_t cam_handler);
44extern 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 */
48int32_t mm_channel_qbuf(mm_channel_t *my_obj,
49                        mm_camera_buf_def_t *buf);
50int32_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);
54void mm_channel_release(mm_channel_t *my_obj);
55uint32_t mm_channel_add_stream(mm_channel_t *my_obj);
56int32_t mm_channel_del_stream(mm_channel_t *my_obj,
57                                   uint32_t stream_id);
58int32_t mm_channel_config_stream(mm_channel_t *my_obj,
59                                 uint32_t stream_id,
60                                 mm_camera_stream_config_t *config);
61int32_t mm_channel_get_bundle_info(mm_channel_t *my_obj,
62                                   cam_bundle_config_t *bundle_info);
63int32_t mm_channel_start(mm_channel_t *my_obj);
64int32_t mm_channel_stop(mm_channel_t *my_obj);
65int32_t mm_channel_request_super_buf(mm_channel_t *my_obj,
66                                     uint32_t num_buf_requested);
67int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj);
68int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj,
69                                         uint32_t frame_idx);
70int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
71                                      mm_camera_super_buf_notify_mode_t notify_mode);
72int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj, mm_channel_queue_t * queue);
73int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
74                                   mm_evt_paylod_set_get_stream_parms_t *payload);
75int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
76                                   mm_evt_paylod_set_get_stream_parms_t *payload);
77int32_t mm_channel_do_stream_action(mm_channel_t *my_obj,
78                                    mm_evt_paylod_do_stream_action_t *payload);
79int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj,
80                                  mm_evt_paylod_map_stream_buf_t *payload);
81int32_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 */
85int32_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);
89int32_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);
93int32_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);
97int32_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 */
103int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue);
104int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue);
105int32_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);
108mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue);
109int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t *my_obj,
110                                             mm_channel_queue_t *queue);
111int32_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 *==========================================================================*/
126mm_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 *==========================================================================*/
153static 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 *==========================================================================*/
188static 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 *==========================================================================*/
297int32_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 *==========================================================================*/
345int32_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 *==========================================================================*/
378int32_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 *==========================================================================*/
492int32_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 *==========================================================================*/
600int32_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 *==========================================================================*/
633int32_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 *==========================================================================*/
666void 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 *==========================================================================*/
687uint32_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 *==========================================================================*/
743int32_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 *==========================================================================*/
778int32_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 *==========================================================================*/
815int32_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 *==========================================================================*/
861int32_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 *==========================================================================*/
996int32_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 *==========================================================================*/
1080int32_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 *==========================================================================*/
1120int32_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 *==========================================================================*/
1141int32_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 *==========================================================================*/
1178int32_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 *==========================================================================*/
1216int32_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 *==========================================================================*/
1249int32_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 *==========================================================================*/
1284int32_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 *==========================================================================*/
1318int32_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 *==========================================================================*/
1347int32_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 *==========================================================================*/
1378int32_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 *==========================================================================*/
1404int32_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 *==========================================================================*/
1421int32_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 *==========================================================================*/
1440int8_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 *==========================================================================*/
1469int32_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    }
1530end:
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 *==========================================================================*/
1548int32_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 *==========================================================================*/
1747mm_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 *==========================================================================*/
1792mm_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 *==========================================================================*/
1817int32_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 *==========================================================================*/
1863int32_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 *==========================================================================*/
1904int32_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