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 <sys/prctl.h>
36#include <fcntl.h>
37#include <poll.h>
38#include <cam_semaphore.h>
39
40#include "mm_camera_dbg.h"
41#include "mm_camera_interface.h"
42#include "mm_camera.h"
43
44typedef enum {
45    /* poll entries updated */
46    MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED,
47    /* poll entries updated */
48    MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC,
49    /* commit updates */
50    MM_CAMERA_PIPE_CMD_COMMIT,
51    /* exit */
52    MM_CAMERA_PIPE_CMD_EXIT,
53    /* max count */
54    MM_CAMERA_PIPE_CMD_MAX
55} mm_camera_pipe_cmd_type_t;
56
57typedef enum {
58    MM_CAMERA_POLL_TASK_STATE_STOPPED,
59    MM_CAMERA_POLL_TASK_STATE_POLL,     /* polling pid in polling state. */
60    MM_CAMERA_POLL_TASK_STATE_MAX
61} mm_camera_poll_task_state_type_t;
62
63typedef struct {
64    uint8_t cmd;
65    mm_camera_event_t event;
66} mm_camera_sig_evt_t;
67
68
69/*===========================================================================
70 * FUNCTION   : mm_camera_poll_sig_async
71 *
72 * DESCRIPTION: Asynchoronous call to send a command through pipe.
73 *
74 * PARAMETERS :
75 *   @poll_cb      : ptr to poll thread object
76 *   @cmd          : command to be sent
77 *
78 * RETURN     : int32_t type of status
79 *              0  -- success
80 *              -1 -- failure
81 *==========================================================================*/
82static int32_t mm_camera_poll_sig_async(mm_camera_poll_thread_t *poll_cb,
83                                  uint32_t cmd)
84{
85    /* send through pipe */
86    /* get the mutex */
87    mm_camera_sig_evt_t cmd_evt;
88    int len;
89
90    CDBG("%s: E cmd = %d", __func__,cmd);
91    memset(&cmd_evt, 0, sizeof(cmd_evt));
92    cmd_evt.cmd = cmd;
93    pthread_mutex_lock(&poll_cb->mutex);
94    /* reset the statue to false */
95    poll_cb->status = FALSE;
96    /* send cmd to worker */
97
98    len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt));
99    if(len < 1) {
100        CDBG_ERROR("%s: len = %d, errno = %d", __func__, len, errno);
101        /* Avoid waiting for the signal */
102        pthread_mutex_unlock(&poll_cb->mutex);
103        return 0;
104    }
105    CDBG("%s: begin IN mutex write done, len = %d", __func__, len);
106    pthread_mutex_unlock(&poll_cb->mutex);
107    CDBG("%s: X", __func__);
108    return 0;
109}
110
111
112
113
114/*===========================================================================
115 * FUNCTION   : mm_camera_poll_sig
116 *
117 * DESCRIPTION: synchorinzed call to send a command through pipe.
118 *
119 * PARAMETERS :
120 *   @poll_cb      : ptr to poll thread object
121 *   @cmd          : command to be sent
122 *
123 * RETURN     : int32_t type of status
124 *              0  -- success
125 *              -1 -- failure
126 *==========================================================================*/
127static int32_t mm_camera_poll_sig(mm_camera_poll_thread_t *poll_cb,
128                                  uint32_t cmd)
129{
130    /* send through pipe */
131    /* get the mutex */
132    mm_camera_sig_evt_t cmd_evt;
133    int len;
134
135    CDBG("%s: E cmd = %d", __func__,cmd);
136    memset(&cmd_evt, 0, sizeof(cmd_evt));
137    cmd_evt.cmd = cmd;
138    pthread_mutex_lock(&poll_cb->mutex);
139    /* reset the statue to false */
140    poll_cb->status = FALSE;
141    /* send cmd to worker */
142
143    len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt));
144    if(len < 1) {
145        CDBG_ERROR("%s: len = %d, errno = %d", __func__, len, errno);
146        /* Avoid waiting for the signal */
147        pthread_mutex_unlock(&poll_cb->mutex);
148        return 0;
149    }
150    CDBG("%s: begin IN mutex write done, len = %d", __func__, len);
151    /* wait till worker task gives positive signal */
152    if (FALSE == poll_cb->status) {
153        CDBG("%s: wait", __func__);
154        pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex);
155    }
156    /* done */
157    pthread_mutex_unlock(&poll_cb->mutex);
158    CDBG("%s: X", __func__);
159    return 0;
160}
161
162/*===========================================================================
163 * FUNCTION   : mm_camera_poll_sig
164 *
165 * DESCRIPTION: signal the status of done
166 *
167 * PARAMETERS :
168 *   @poll_cb : ptr to poll thread object
169 *
170 * RETURN     : none
171 *==========================================================================*/
172static void mm_camera_poll_sig_done(mm_camera_poll_thread_t *poll_cb)
173{
174    pthread_mutex_lock(&poll_cb->mutex);
175    poll_cb->status = TRUE;
176    pthread_cond_signal(&poll_cb->cond_v);
177    CDBG("%s: done, in mutex", __func__);
178    pthread_mutex_unlock(&poll_cb->mutex);
179}
180
181/*===========================================================================
182 * FUNCTION   : mm_camera_poll_set_state
183 *
184 * DESCRIPTION: set a polling state
185 *
186 * PARAMETERS :
187 *   @poll_cb : ptr to poll thread object
188 *   @state   : polling state (stopped/polling)
189 *
190 * RETURN     : none
191 *==========================================================================*/
192static void mm_camera_poll_set_state(mm_camera_poll_thread_t *poll_cb,
193                                     mm_camera_poll_task_state_type_t state)
194{
195    poll_cb->state = state;
196}
197
198/*===========================================================================
199 * FUNCTION   : mm_camera_poll_proc_pipe
200 *
201 * DESCRIPTION: polling thread routine to process pipe
202 *
203 * PARAMETERS :
204 *   @poll_cb : ptr to poll thread object
205 *
206 * RETURN     : none
207 *==========================================================================*/
208static void mm_camera_poll_proc_pipe(mm_camera_poll_thread_t *poll_cb)
209{
210    ssize_t read_len;
211    int i;
212    mm_camera_sig_evt_t cmd_evt;
213    read_len = read(poll_cb->pfds[0], &cmd_evt, sizeof(cmd_evt));
214    CDBG("%s: read_fd = %d, read_len = %d, expect_len = %d cmd = %d",
215         __func__, poll_cb->pfds[0], (int)read_len, (int)sizeof(cmd_evt), cmd_evt.cmd);
216    switch (cmd_evt.cmd) {
217    case MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED:
218    case MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC:
219        /* we always have index 0 for pipe read */
220        poll_cb->num_fds = 0;
221        poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->pfds[0];
222        poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI;
223        poll_cb->num_fds++;
224
225        if (MM_CAMERA_POLL_TYPE_EVT == poll_cb->poll_type &&
226                poll_cb->num_fds < MAX_STREAM_NUM_IN_BUNDLE) {
227            if (poll_cb->poll_entries[0].fd > 0) {
228                /* fd is valid, we update poll_fds */
229                poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[0].fd;
230                poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI;
231                poll_cb->num_fds++;
232            }
233        } else if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type &&
234                poll_cb->num_fds <= MAX_STREAM_NUM_IN_BUNDLE) {
235            for(i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
236                if(poll_cb->poll_entries[i].fd > 0) {
237                    /* fd is valid, we update poll_fds to this fd */
238                    poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[i].fd;
239                    poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI;
240                    poll_cb->num_fds++;
241                } else {
242                    /* fd is invalid, we set the entry to -1 to prevent polling.
243                     * According to spec, polling will not poll on entry with fd=-1.
244                     * If this is not the case, we need to skip these invalid fds
245                     * when updating this array.
246                     * We still keep fd=-1 in this array because this makes easier to
247                     * map cb associated with this fd once incoming data avail by directly
248                     * using the index-1(0 is reserved for pipe read, so need to reduce index by 1) */
249                    poll_cb->poll_fds[poll_cb->num_fds].fd = -1;
250                    poll_cb->poll_fds[poll_cb->num_fds].events = 0;
251                    poll_cb->num_fds++;
252                }
253            }
254        }
255        if (cmd_evt.cmd != MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC)
256            mm_camera_poll_sig_done(poll_cb);
257        break;
258
259    case MM_CAMERA_PIPE_CMD_COMMIT:
260        mm_camera_poll_sig_done(poll_cb);
261        break;
262    case MM_CAMERA_PIPE_CMD_EXIT:
263    default:
264        mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_STOPPED);
265        mm_camera_poll_sig_done(poll_cb);
266        break;
267    }
268}
269
270/*===========================================================================
271 * FUNCTION   : mm_camera_poll_fn
272 *
273 * DESCRIPTION: polling thread routine
274 *
275 * PARAMETERS :
276 *   @poll_cb : ptr to poll thread object
277 *
278 * RETURN     : none
279 *==========================================================================*/
280static void *mm_camera_poll_fn(mm_camera_poll_thread_t *poll_cb)
281{
282    int rc = 0, i;
283
284    if (NULL == poll_cb) {
285        CDBG_ERROR("%s: poll_cb is NULL!\n", __func__);
286        return NULL;
287    }
288    CDBG("%s: poll type = %d, num_fd = %d poll_cb = %p\n",
289         __func__, poll_cb->poll_type, poll_cb->num_fds,poll_cb);
290    do {
291         for(i = 0; i < poll_cb->num_fds; i++) {
292            poll_cb->poll_fds[i].events = POLLIN|POLLRDNORM|POLLPRI;
293         }
294
295         rc = poll(poll_cb->poll_fds, poll_cb->num_fds, poll_cb->timeoutms);
296         if(rc > 0) {
297            if ((poll_cb->poll_fds[0].revents & POLLIN) &&
298                (poll_cb->poll_fds[0].revents & POLLRDNORM)) {
299                /* if we have data on pipe, we only process pipe in this iteration */
300                CDBG("%s: cmd received on pipe\n", __func__);
301                mm_camera_poll_proc_pipe(poll_cb);
302            } else {
303                for(i=1; i<poll_cb->num_fds; i++) {
304                    /* Checking for ctrl events */
305                    if ((poll_cb->poll_type == MM_CAMERA_POLL_TYPE_EVT) &&
306                        (poll_cb->poll_fds[i].revents & POLLPRI)) {
307                        CDBG("%s: mm_camera_evt_notify\n", __func__);
308                        if (NULL != poll_cb->poll_entries[i-1].notify_cb) {
309                            poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data);
310                        }
311                    }
312
313                    if ((MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) &&
314                        (poll_cb->poll_fds[i].revents & POLLIN) &&
315                        (poll_cb->poll_fds[i].revents & POLLRDNORM)) {
316                        CDBG("%s: mm_stream_data_notify\n", __func__);
317                        if (NULL != poll_cb->poll_entries[i-1].notify_cb) {
318                            poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data);
319                        }
320                    }
321                }
322            }
323        } else {
324            /* in error case sleep 10 us and then continue. hard coded here */
325            usleep(10);
326            continue;
327        }
328    } while ((poll_cb != NULL) && (poll_cb->state == MM_CAMERA_POLL_TASK_STATE_POLL));
329    return NULL;
330}
331
332/*===========================================================================
333 * FUNCTION   : mm_camera_poll_thread
334 *
335 * DESCRIPTION: polling thread entry function
336 *
337 * PARAMETERS :
338 *   @data    : ptr to poll thread object
339 *
340 * RETURN     : none
341 *==========================================================================*/
342static void *mm_camera_poll_thread(void *data)
343{
344    prctl(PR_SET_NAME, (unsigned long)"mm_cam_poll_th", 0, 0, 0);
345    mm_camera_poll_thread_t *poll_cb = (mm_camera_poll_thread_t *)data;
346
347    /* add pipe read fd into poll first */
348    poll_cb->poll_fds[poll_cb->num_fds++].fd = poll_cb->pfds[0];
349
350    mm_camera_poll_sig_done(poll_cb);
351    mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_POLL);
352    return mm_camera_poll_fn(poll_cb);
353}
354
355/*===========================================================================
356 * FUNCTION   : mm_camera_poll_thread
357 *
358 * DESCRIPTION: notify the polling thread that entries for polling fd have
359 *              been updated
360 *
361 * PARAMETERS :
362 *   @poll_cb : ptr to poll thread object
363 *
364 * RETURN     : none
365 *==========================================================================*/
366int32_t mm_camera_poll_thread_notify_entries_updated(mm_camera_poll_thread_t * poll_cb)
367{
368    /* send poll entries updated signal to poll thread */
369    return mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED);
370}
371
372/*===========================================================================
373 * FUNCTION   : mm_camera_poll_thread_commit_updates
374 *
375 * DESCRIPTION: sync with all previously pending async updates
376 *
377 * PARAMETERS :
378 *   @poll_cb : ptr to poll thread object
379 *
380 * RETURN     : int32_t type of status
381 *              0  -- success
382 *              -1 -- failure
383 *==========================================================================*/
384int32_t mm_camera_poll_thread_commit_updates(mm_camera_poll_thread_t * poll_cb)
385{
386    return mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_COMMIT);
387}
388
389/*===========================================================================
390 * FUNCTION   : mm_camera_poll_thread_add_poll_fd
391 *
392 * DESCRIPTION: add a new fd into polling thread
393 *
394 * PARAMETERS :
395 *   @poll_cb   : ptr to poll thread object
396 *   @handler   : stream handle if channel data polling thread,
397 *                0 if event polling thread
398 *   @fd        : file descriptor need to be added into polling thread
399 *   @notify_cb : callback function to handle if any notify from fd
400 *   @userdata  : user data ptr
401 *   @call_type : Whether its Synchronous or Asynchronous call
402 *
403 * RETURN     : none
404 *==========================================================================*/
405int32_t mm_camera_poll_thread_add_poll_fd(mm_camera_poll_thread_t * poll_cb,
406                                          uint32_t handler,
407                                          int32_t fd,
408                                          mm_camera_poll_notify_t notify_cb,
409                                          void* userdata,
410                                          mm_camera_call_type_t call_type)
411{
412    int32_t rc = -1;
413    uint8_t idx = 0;
414
415    if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) {
416        /* get stream idx from handler if CH type */
417        idx = mm_camera_util_get_index_by_handler(handler);
418    } else {
419        /* for EVT type, only idx=0 is valid */
420        idx = 0;
421    }
422
423    if (MAX_STREAM_NUM_IN_BUNDLE > idx) {
424        poll_cb->poll_entries[idx].fd = fd;
425        poll_cb->poll_entries[idx].handler = handler;
426        poll_cb->poll_entries[idx].notify_cb = notify_cb;
427        poll_cb->poll_entries[idx].user_data = userdata;
428        /* send poll entries updated signal to poll thread */
429        if (call_type == mm_camera_sync_call ) {
430            rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED);
431        } else {
432            rc = mm_camera_poll_sig_async(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC );
433        }
434    } else {
435        CDBG_ERROR("%s: invalid handler %d (%d)",
436                   __func__, handler, idx);
437    }
438    return rc;
439}
440
441/*===========================================================================
442 * FUNCTION   : mm_camera_poll_thread_del_poll_fd
443 *
444 * DESCRIPTION: delete a fd from polling thread
445 *
446 * PARAMETERS :
447 *   @poll_cb   : ptr to poll thread object
448 *   @handler   : stream handle if channel data polling thread,
449 *                0 if event polling thread
450 *
451 * RETURN     : int32_t type of status
452 *              0  -- success
453 *              -1 -- failure
454 *==========================================================================*/
455int32_t mm_camera_poll_thread_del_poll_fd(mm_camera_poll_thread_t * poll_cb,
456                                          uint32_t handler,
457                                          mm_camera_call_type_t call_type)
458{
459    int32_t rc = -1;
460    uint8_t idx = 0;
461
462    if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) {
463        /* get stream idx from handler if CH type */
464        idx = mm_camera_util_get_index_by_handler(handler);
465    } else {
466        /* for EVT type, only idx=0 is valid */
467        idx = 0;
468    }
469
470    if ((MAX_STREAM_NUM_IN_BUNDLE > idx) &&
471        (handler == poll_cb->poll_entries[idx].handler)) {
472        /* reset poll entry */
473        poll_cb->poll_entries[idx].fd = -1; /* set fd to invalid */
474        poll_cb->poll_entries[idx].handler = 0;
475        poll_cb->poll_entries[idx].notify_cb = NULL;
476
477        /* send poll entries updated signal to poll thread */
478        if (call_type == mm_camera_sync_call ) {
479            rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED);
480        } else {
481            rc = mm_camera_poll_sig_async(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC );
482        }
483    } else {
484        CDBG_ERROR("%s: invalid handler %d (%d)",
485                   __func__, handler, idx);
486        return -1;
487    }
488
489    return rc;
490}
491
492int32_t mm_camera_poll_thread_launch(mm_camera_poll_thread_t * poll_cb,
493                                     mm_camera_poll_thread_type_t poll_type)
494{
495    int32_t rc = 0;
496    poll_cb->poll_type = poll_type;
497
498    poll_cb->pfds[0] = -1;
499    poll_cb->pfds[1] = -1;
500    rc = pipe(poll_cb->pfds);
501    if(rc < 0) {
502        CDBG_ERROR("%s: pipe open rc=%d\n", __func__, rc);
503        return -1;
504    }
505
506    poll_cb->timeoutms = -1;  /* Infinite seconds */
507
508    CDBG("%s: poll_type = %d, read fd = %d, write fd = %d timeout = %d",
509        __func__, poll_cb->poll_type,
510        poll_cb->pfds[0], poll_cb->pfds[1],poll_cb->timeoutms);
511
512    pthread_mutex_init(&poll_cb->mutex, NULL);
513    pthread_cond_init(&poll_cb->cond_v, NULL);
514
515    /* launch the thread */
516    pthread_mutex_lock(&poll_cb->mutex);
517    poll_cb->status = 0;
518    pthread_create(&poll_cb->pid, NULL, mm_camera_poll_thread, (void *)poll_cb);
519    if(!poll_cb->status) {
520        pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex);
521    }
522    pthread_mutex_unlock(&poll_cb->mutex);
523    CDBG("%s: End",__func__);
524    return rc;
525}
526
527int32_t mm_camera_poll_thread_release(mm_camera_poll_thread_t *poll_cb)
528{
529    int32_t rc = 0;
530    if(MM_CAMERA_POLL_TASK_STATE_STOPPED == poll_cb->state) {
531        CDBG_ERROR("%s: err, poll thread is not running.\n", __func__);
532        return rc;
533    }
534
535    /* send exit signal to poll thread */
536    mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_EXIT);
537    /* wait until poll thread exits */
538    if (pthread_join(poll_cb->pid, NULL) != 0) {
539        CDBG_ERROR("%s: pthread dead already\n", __func__);
540    }
541
542    /* close pipe */
543    if(poll_cb->pfds[0] >= 0) {
544        close(poll_cb->pfds[0]);
545    }
546    if(poll_cb->pfds[1] >= 0) {
547        close(poll_cb->pfds[1]);
548    }
549
550    pthread_mutex_destroy(&poll_cb->mutex);
551    pthread_cond_destroy(&poll_cb->cond_v);
552    memset(poll_cb, 0, sizeof(mm_camera_poll_thread_t));
553    poll_cb->pfds[0] = -1;
554    poll_cb->pfds[1] = -1;
555    return rc;
556}
557
558static void *mm_camera_cmd_thread(void *data)
559{
560    int running = 1;
561    int ret;
562    mm_camera_cmd_thread_t *cmd_thread =
563                (mm_camera_cmd_thread_t *)data;
564    mm_camera_cmdcb_t* node = NULL;
565
566    do {
567        do {
568            ret = cam_sem_wait(&cmd_thread->cmd_sem);
569            if (ret != 0 && errno != EINVAL) {
570                CDBG_ERROR("%s: cam_sem_wait error (%s)",
571                           __func__, strerror(errno));
572                return NULL;
573            }
574        } while (ret != 0);
575
576        /* we got notified about new cmd avail in cmd queue */
577        node = (mm_camera_cmdcb_t*)cam_queue_deq(&cmd_thread->cmd_queue);
578        while (node != NULL) {
579            switch (node->cmd_type) {
580            case MM_CAMERA_CMD_TYPE_EVT_CB:
581            case MM_CAMERA_CMD_TYPE_DATA_CB:
582            case MM_CAMERA_CMD_TYPE_REQ_DATA_CB:
583            case MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB:
584            case MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY:
585            case MM_CAMERA_CMD_TYPE_START_ZSL:
586            case MM_CAMERA_CMD_TYPE_STOP_ZSL:
587            case MM_CAMERA_CMD_TYPE_GENERAL:
588            case MM_CAMERA_CMD_TYPE_FLUSH_QUEUE:
589                if (NULL != cmd_thread->cb) {
590                    cmd_thread->cb(node, cmd_thread->user_data);
591                }
592                break;
593            case MM_CAMERA_CMD_TYPE_EXIT:
594            default:
595                running = 0;
596                break;
597            }
598            free(node);
599            node = (mm_camera_cmdcb_t*)cam_queue_deq(&cmd_thread->cmd_queue);
600        } /* (node != NULL) */
601    } while (running);
602    return NULL;
603}
604
605int32_t mm_camera_cmd_thread_launch(mm_camera_cmd_thread_t * cmd_thread,
606                                    mm_camera_cmd_cb_t cb,
607                                    void* user_data)
608{
609    int32_t rc = 0;
610
611    cam_sem_init(&cmd_thread->cmd_sem, 0);
612    cam_queue_init(&cmd_thread->cmd_queue);
613    cmd_thread->cb = cb;
614    cmd_thread->user_data = user_data;
615
616    /* launch the thread */
617    pthread_create(&cmd_thread->cmd_pid,
618                   NULL,
619                   mm_camera_cmd_thread,
620                   (void *)cmd_thread);
621    return rc;
622}
623
624int32_t mm_camera_cmd_thread_name(const char* name)
625{
626    int32_t rc = 0;
627    /* name the thread */
628    prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
629    return rc;
630}
631
632
633int32_t mm_camera_cmd_thread_stop(mm_camera_cmd_thread_t * cmd_thread)
634{
635    int32_t rc = 0;
636    mm_camera_cmdcb_t* node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
637    if (NULL == node) {
638        CDBG_ERROR("%s: No memory for mm_camera_cmdcb_t", __func__);
639        return -1;
640    }
641
642    memset(node, 0, sizeof(mm_camera_cmdcb_t));
643    node->cmd_type = MM_CAMERA_CMD_TYPE_EXIT;
644
645    cam_queue_enq(&cmd_thread->cmd_queue, node);
646    cam_sem_post(&cmd_thread->cmd_sem);
647
648    /* wait until cmd thread exits */
649    if (pthread_join(cmd_thread->cmd_pid, NULL) != 0) {
650        CDBG("%s: pthread dead already\n", __func__);
651    }
652    return rc;
653}
654
655int32_t mm_camera_cmd_thread_destroy(mm_camera_cmd_thread_t * cmd_thread)
656{
657    int32_t rc = 0;
658    cam_queue_deinit(&cmd_thread->cmd_queue);
659    cam_sem_destroy(&cmd_thread->cmd_sem);
660    memset(cmd_thread, 0, sizeof(mm_camera_cmd_thread_t));
661    return rc;
662}
663
664int32_t mm_camera_cmd_thread_release(mm_camera_cmd_thread_t * cmd_thread)
665{
666    int32_t rc = 0;
667    rc = mm_camera_cmd_thread_stop(cmd_thread);
668    if (0 == rc) {
669        rc = mm_camera_cmd_thread_destroy(cmd_thread);
670    }
671    return rc;
672}
673