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