1/* Copyright (c) 2012-2016, 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// System dependencies
31#include <string.h>
32#include <utils/Errors.h>
33#define PRCTL_H <SYSTEM_HEADER_PREFIX/prctl.h>
34#include PRCTL_H
35
36// Camera dependencies
37#include "QCameraCmdThread.h"
38
39extern "C" {
40#include "mm_camera_dbg.h"
41}
42
43using namespace android;
44
45namespace qcamera {
46
47/*===========================================================================
48 * FUNCTION   : QCameraCmdThread
49 *
50 * DESCRIPTION: default constructor of QCameraCmdThread
51 *
52 * PARAMETERS : None
53 *
54 * RETURN     : None
55 *==========================================================================*/
56QCameraCmdThread::QCameraCmdThread() :
57    cmd_queue()
58{
59    cmd_pid = 0;
60    cam_sem_init(&sync_sem, 0);
61    cam_sem_init(&cmd_sem, 0);
62}
63
64/*===========================================================================
65 * FUNCTION   : ~QCameraCmdThread
66 *
67 * DESCRIPTION: deconstructor of QCameraCmdThread
68 *
69 * PARAMETERS : None
70 *
71 * RETURN     : None
72 *==========================================================================*/
73QCameraCmdThread::~QCameraCmdThread()
74{
75    exit();
76    cam_sem_destroy(&sync_sem);
77    cam_sem_destroy(&cmd_sem);
78}
79
80/*===========================================================================
81 * FUNCTION   : launch
82 *
83 * DESCRIPTION: launch Cmd Thread
84 *
85 * PARAMETERS :
86 *   @start_routine : thread routine function ptr
87 *   @user_data     : user data ptr
88 *
89 * RETURN     : int32_t type of status
90 *              NO_ERROR  -- success
91 *              none-zero failure code
92 *==========================================================================*/
93int32_t QCameraCmdThread::launch(void *(*start_routine)(void *),
94                                 void* user_data)
95{
96    /* launch the thread */
97    pthread_create(&cmd_pid,
98                   NULL,
99                   start_routine,
100                   user_data);
101    return NO_ERROR;
102}
103
104/*===========================================================================
105 * FUNCTION   : setName
106 *
107 * DESCRIPTION: name the cmd thread
108 *
109 * PARAMETERS :
110 *   @name : desired name for the thread
111 *
112 * RETURN     : int32_t type of status
113 *              NO_ERROR  -- success
114 *              none-zero failure code
115 *==========================================================================*/
116int32_t QCameraCmdThread::setName(const char* name)
117{
118    /* name the thread */
119    prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
120    return NO_ERROR;
121}
122
123/*===========================================================================
124 * FUNCTION   : sendCmd
125 *
126 * DESCRIPTION: send a command to the Cmd Thread
127 *
128 * PARAMETERS :
129 *   @cmd     : command to be executed.
130 *   @sync_cmd: flag to indicate if this is a synchorinzed cmd. If true, this call
131 *              will wait until signal is set after the command is completed.
132 *   @priority: flag to indicate if this is a cmd with priority. If true, the cmd
133 *              will be enqueued to the head with priority.
134 *
135 * RETURN     : int32_t type of status
136 *              NO_ERROR  -- success
137 *              none-zero failure code
138 *==========================================================================*/
139int32_t QCameraCmdThread::sendCmd(camera_cmd_type_t cmd, uint8_t sync_cmd, uint8_t priority)
140{
141    camera_cmd_t *node = (camera_cmd_t *)malloc(sizeof(camera_cmd_t));
142    if (NULL == node) {
143        LOGE("No memory for camera_cmd_t");
144        return NO_MEMORY;
145    }
146    memset(node, 0, sizeof(camera_cmd_t));
147    node->cmd = cmd;
148
149    if (priority) {
150        if (!cmd_queue.enqueueWithPriority((void *)node)) {
151            free(node);
152            node = NULL;
153        }
154    } else {
155        if (!cmd_queue.enqueue((void *)node)) {
156            free(node);
157            node = NULL;
158        }
159    }
160    cam_sem_post(&cmd_sem);
161
162    /* if is a sync call, need to wait until it returns */
163    if (sync_cmd) {
164        cam_sem_wait(&sync_sem);
165    }
166    return NO_ERROR;
167}
168
169/*===========================================================================
170 * FUNCTION   : getCmd
171 *
172 * DESCRIPTION: dequeue a cmommand from cmd queue
173 *
174 * PARAMETERS : None
175 *
176 * RETURN     : cmd dequeued
177 *==========================================================================*/
178camera_cmd_type_t QCameraCmdThread::getCmd()
179{
180    camera_cmd_type_t cmd = CAMERA_CMD_TYPE_NONE;
181    camera_cmd_t *node = (camera_cmd_t *)cmd_queue.dequeue();
182    if (NULL == node) {
183        LOGD("No notify avail");
184        return CAMERA_CMD_TYPE_NONE;
185    } else {
186        cmd = node->cmd;
187        free(node);
188    }
189    return cmd;
190}
191
192/*===========================================================================
193 * FUNCTION   : exit
194 *
195 * DESCRIPTION: exit the CMD thread
196 *
197 * PARAMETERS : None
198 *
199 * RETURN     : int32_t type of status
200 *              NO_ERROR  -- success
201 *              none-zero failure code
202 *==========================================================================*/
203int32_t QCameraCmdThread::exit()
204{
205    int32_t rc = NO_ERROR;
206
207    if (cmd_pid == 0) {
208        return rc;
209    }
210
211    rc = sendCmd(CAMERA_CMD_TYPE_EXIT, 0, 1);
212    if (NO_ERROR != rc) {
213        LOGE("Error during exit, rc = %d", rc);
214        return rc;
215    }
216
217    /* wait until cmd thread exits */
218    if (pthread_join(cmd_pid, NULL) != 0) {
219        LOGD("pthread dead already\n");
220    }
221    cmd_pid = 0;
222    return rc;
223}
224
225}; // namespace qcamera
226