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