1/*
2Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7    * Redistributions of source code must retain the above copyright
8      notice, this list of conditions and the following disclaimer.
9    * Redistributions in binary form must reproduce the above
10      copyright notice, this list of conditions and the following
11      disclaimer in the documentation and/or other materials provided
12      with the distribution.
13    * Neither the name of Code Aurora Forum, Inc. nor the names of its
14      contributors may be used to endorse or promote products derived
15      from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 <semaphore.h>
37
38#include "mm_camera_dbg.h"
39#include "mm_camera_interface.h"
40#include "mm_camera.h"
41
42#if 0
43#undef CDBG
44#undef LOG_TAG
45#define CDBG ALOGE
46#define LOG_TAG "NotifyLogs"
47#endif
48
49int32_t mm_camera_queue_init(mm_camera_queue_t* queue)
50{
51    pthread_mutex_init(&queue->lock, NULL);
52    cam_list_init(&queue->head.list);
53    queue->size = 0;
54    return 0;
55}
56
57int32_t mm_camera_queue_enq(mm_camera_queue_t* queue, void* data)
58{
59    mm_camera_q_node_t* node =
60        (mm_camera_q_node_t *)malloc(sizeof(mm_camera_q_node_t));
61    if (NULL == node) {
62        CDBG_ERROR("%s: No memory for mm_camera_q_node_t", __func__);
63        return -1;
64    }
65
66    memset(node, 0, sizeof(mm_camera_q_node_t));
67    node->data = data;
68
69    pthread_mutex_lock(&queue->lock);
70    cam_list_add_tail_node(&node->list, &queue->head.list);
71    queue->size++;
72    pthread_mutex_unlock(&queue->lock);
73
74    return 0;
75
76}
77
78void* mm_camera_queue_deq(mm_camera_queue_t* queue)
79{
80    mm_camera_q_node_t* node = NULL;
81    void* data = NULL;
82    struct cam_list *head = NULL;
83    struct cam_list *pos = NULL;
84
85    pthread_mutex_lock(&queue->lock);
86    head = &queue->head.list;
87    pos = head->next;
88    if (pos != head) {
89        node = member_of(pos, mm_camera_q_node_t, list);
90        cam_list_del_node(&node->list);
91        queue->size--;
92    }
93    pthread_mutex_unlock(&queue->lock);
94
95    if (NULL != node) {
96        data = node->data;
97        free(node);
98    }
99
100    return data;
101}
102
103int32_t mm_camera_queue_deinit(mm_camera_queue_t* queue)
104{
105    mm_camera_queue_flush(queue);
106    pthread_mutex_destroy(&queue->lock);
107    return 0;
108}
109
110int32_t mm_camera_queue_flush(mm_camera_queue_t* queue)
111{
112    mm_camera_q_node_t* node = NULL;
113    void* data = NULL;
114    struct cam_list *head = NULL;
115    struct cam_list *pos = NULL;
116
117    pthread_mutex_lock(&queue->lock);
118    head = &queue->head.list;
119    pos = head->next;
120
121    while(pos != head) {
122        node = member_of(pos, mm_camera_q_node_t, list);
123        cam_list_del_node(&node->list);
124        queue->size--;
125
126        /* TODO later to consider ptr inside data */
127        /* for now we only assume there is no ptr inside data
128         * so we free data directly */
129        if (NULL != node->data) {
130            free(node->data);
131        }
132        free(node);
133        pos = pos->next;
134    }
135    queue->size = 0;
136    pthread_mutex_unlock(&queue->lock);
137    return 0;
138}
139
140static void *mm_camera_cmd_thread(void *data)
141{
142    int rc = 0;
143    int running = 1;
144    int ret;
145    mm_camera_cmd_thread_t *cmd_thread =
146                (mm_camera_cmd_thread_t *)data;
147    mm_camera_cmdcb_t* node = NULL;
148
149    do {
150        do {
151            ret = sem_wait(&cmd_thread->cmd_sem);
152            if (ret != 0 && errno != EINVAL) {
153                CDBG_ERROR("%s: sem_wait error (%s)",
154                           __func__, strerror(errno));
155                return NULL;
156            }
157        } while (ret != 0);
158
159        /* we got notified about new cmd avail in cmd queue */
160        node = (mm_camera_cmdcb_t*)mm_camera_queue_deq(&cmd_thread->cmd_queue);
161        if (node != NULL) {
162            switch (node->cmd_type) {
163            case MM_CAMERA_CMD_TYPE_EVT_CB:
164            case MM_CAMERA_CMD_TYPE_DATA_CB:
165            case MM_CAMERA_CMD_TYPE_ASYNC_CB:
166            case MM_CAMERA_CMD_TYPE_REQ_DATA_CB:
167                if (NULL != cmd_thread->cb) {
168                    cmd_thread->cb(node, cmd_thread->user_data);
169                }
170                break;
171            case MM_CAMERA_CMD_TYPE_EXIT:
172            default:
173                running = 0;
174                break;
175            }
176            free(node);
177        }
178    } while (running);
179    return NULL;
180}
181
182int32_t mm_camera_cmd_thread_launch(mm_camera_cmd_thread_t * cmd_thread,
183                                    mm_camera_cmd_cb_t cb,
184                                    void* user_data)
185{
186    int32_t rc = 0;
187
188    sem_init(&cmd_thread->cmd_sem, 0, 0);
189    mm_camera_queue_init(&cmd_thread->cmd_queue);
190    cmd_thread->cb = cb;
191    cmd_thread->user_data = user_data;
192
193    /* launch the thread */
194    pthread_create(&cmd_thread->cmd_pid,
195                   NULL,
196                   mm_camera_cmd_thread,
197                   (void *)cmd_thread);
198    return rc;
199}
200
201int32_t mm_camera_cmd_thread_release(mm_camera_cmd_thread_t * cmd_thread)
202{
203    int32_t rc = 0;
204    mm_camera_buf_info_t  buf_info;
205    mm_camera_cmdcb_t* node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
206    if (NULL == node) {
207        CDBG_ERROR("%s: No memory for mm_camera_cmdcb_t", __func__);
208        return -1;
209    }
210
211    memset(node, 0, sizeof(mm_camera_cmdcb_t));
212    node->cmd_type = MM_CAMERA_CMD_TYPE_EXIT;
213
214    mm_camera_queue_enq(&cmd_thread->cmd_queue, node);
215    sem_post(&cmd_thread->cmd_sem);
216
217    /* wait until cmd thread exits */
218    if (pthread_join(cmd_thread->cmd_pid, NULL) != 0) {
219        CDBG("%s: pthread dead already\n", __func__);
220    }
221    mm_camera_queue_deinit(&cmd_thread->cmd_queue);
222
223    sem_destroy(&cmd_thread->cmd_sem);
224    memset(cmd_thread, 0, sizeof(mm_camera_cmd_thread_t));
225    return rc;
226}
227
228