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