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