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