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