1 /* 2 Copyright (c) 2012, The Linux Foundation. All rights reserved. 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions are 6 met: 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 The Linux Foundation 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 17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <pthread.h> 31 #include <errno.h> 32 #include <stdbool.h> 33 #include <sys/ioctl.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <poll.h> 38 #include <semaphore.h> 39 40 #include "mm_camera_dbg.h" 41 #include "mm_camera_interface.h" 42 #include "mm_camera.h" 43 44 typedef enum { 45 /* poll entries updated */ 46 MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED, 47 /* exit */ 48 MM_CAMERA_PIPE_CMD_EXIT, 49 /* max count */ 50 MM_CAMERA_PIPE_CMD_MAX 51 } mm_camera_pipe_cmd_type_t; 52 53 typedef enum { 54 MM_CAMERA_POLL_TASK_STATE_STOPPED, 55 MM_CAMERA_POLL_TASK_STATE_POLL, /* polling pid in polling state. */ 56 MM_CAMERA_POLL_TASK_STATE_MAX 57 } mm_camera_poll_task_state_type_t; 58 59 typedef struct { 60 uint8_t cmd; 61 mm_camera_event_t event; 62 } mm_camera_sig_evt_t; 63 64 static int32_t mm_camera_poll_sig(mm_camera_poll_thread_t *poll_cb, 65 uint32_t cmd) 66 { 67 /* send through pipe */ 68 /* get the mutex */ 69 mm_camera_sig_evt_t cmd_evt; 70 int len; 71 72 CDBG("%s: E cmd = %d", __func__,cmd); 73 memset(&cmd_evt, 0, sizeof(cmd_evt)); 74 cmd_evt.cmd = cmd; 75 pthread_mutex_lock(&poll_cb->mutex); 76 /* reset the statue to false */ 77 poll_cb->status = false; 78 /* send cmd to worker */ 79 80 len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt)); 81 if(len < 1) { 82 CDBG_ERROR("%s: len = %d, errno = %d", __func__, len, errno); 83 } 84 CDBG("%s: begin IN mutex write done, len = %d", __func__, len); 85 /* wait till worker task gives positive signal */ 86 if (false == poll_cb->status) { 87 CDBG("%s: wait", __func__); 88 pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex); 89 } 90 /* done */ 91 pthread_mutex_unlock(&poll_cb->mutex); 92 CDBG("%s: X", __func__); 93 return 0; 94 } 95 96 static void mm_camera_poll_sig_done(mm_camera_poll_thread_t *poll_cb) 97 { 98 pthread_mutex_lock(&poll_cb->mutex); 99 poll_cb->status = true; 100 pthread_cond_signal(&poll_cb->cond_v); 101 CDBG("%s: done, in mutex", __func__); 102 pthread_mutex_unlock(&poll_cb->mutex); 103 } 104 105 static void mm_camera_poll_set_state(mm_camera_poll_thread_t *poll_cb, 106 mm_camera_poll_task_state_type_t state) 107 { 108 poll_cb->state = state; 109 } 110 111 static void mm_camera_poll_proc_pipe(mm_camera_poll_thread_t *poll_cb) 112 { 113 ssize_t read_len; 114 int i; 115 mm_camera_sig_evt_t cmd_evt; 116 read_len = read(poll_cb->pfds[0], &cmd_evt, sizeof(cmd_evt)); 117 CDBG("%s: read_fd = %d, read_len = %d, expect_len = %d cmd = %d", 118 __func__, poll_cb->pfds[0], (int)read_len, (int)sizeof(cmd_evt), cmd_evt.cmd); 119 switch (cmd_evt.cmd) { 120 case MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED: 121 /* we always have index 0 for pipe read */ 122 poll_cb->num_fds = 0; 123 poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->pfds[0]; 124 poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI; 125 poll_cb->num_fds++; 126 127 if (MM_CAMERA_POLL_TYPE_EVT == poll_cb->poll_type) { 128 if (poll_cb->poll_entries[0].fd > 0) { 129 /* fd is valid, we update poll_fds */ 130 poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[0].fd; 131 poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI; 132 poll_cb->num_fds++; 133 } 134 } else if (MM_CAMERA_POLL_TYPE_CH == poll_cb->poll_type) { 135 for(i = 0; i < MM_CAMEAR_STRAEM_NUM_MAX; i++) { 136 if(poll_cb->poll_entries[i].fd > 0) { 137 /* fd is valid, we update poll_fds to this fd */ 138 poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[i].fd; 139 poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI; 140 poll_cb->num_fds++; 141 } else { 142 /* fd is invalid, we set the entry to -1 to prevent polling. 143 * According to spec, polling will not poll on entry with fd=-1. 144 * If this is not the case, we need to skip these invalid fds 145 * when updating this array. 146 * We still keep fd=-1 in this array because this makes easier to 147 * map cb associated with this fd once incoming data avail by directly 148 * using the index-1(0 is reserved for pipe read, so need to reduce index by 1) */ 149 poll_cb->poll_fds[poll_cb->num_fds].fd = -1; 150 poll_cb->poll_fds[poll_cb->num_fds].events = 0; 151 poll_cb->num_fds++; 152 } 153 } 154 } 155 mm_camera_poll_sig_done(poll_cb); 156 break; 157 158 case MM_CAMERA_PIPE_CMD_EXIT: 159 default: 160 mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_STOPPED); 161 mm_camera_poll_sig_done(poll_cb); 162 break; 163 } 164 } 165 166 static void *mm_camera_poll_fn(mm_camera_poll_thread_t *poll_cb) 167 { 168 int rc = 0, i; 169 170 CDBG("%s: poll type = %d, num_fd = %d poll_cb = %p\n", 171 __func__, poll_cb->poll_type, poll_cb->num_fds,poll_cb); 172 do { 173 for(i = 0; i < poll_cb->num_fds; i++) { 174 poll_cb->poll_fds[i].events = POLLIN|POLLRDNORM|POLLPRI; 175 } 176 177 rc = poll(poll_cb->poll_fds, poll_cb->num_fds, poll_cb->timeoutms); 178 if(rc > 0) { 179 if ((poll_cb->poll_fds[0].revents & POLLIN) && 180 (poll_cb->poll_fds[0].revents & POLLRDNORM)) { 181 /* if we have data on pipe, we only process pipe in this iteration */ 182 CDBG("%s: cmd received on pipe\n", __func__); 183 mm_camera_poll_proc_pipe(poll_cb); 184 } else { 185 for(i=1; i<poll_cb->num_fds; i++) { 186 /* Checking for ctrl events */ 187 if ((poll_cb->poll_type == MM_CAMERA_POLL_TYPE_EVT) && 188 (poll_cb->poll_fds[i].revents & POLLPRI)) { 189 CDBG("%s: mm_camera_evt_notify\n", __func__); 190 if (NULL != poll_cb->poll_entries[i-1].notify_cb) { 191 poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data); 192 } 193 } 194 195 if ((poll_cb->poll_type == MM_CAMERA_POLL_TYPE_CH) && 196 (poll_cb->poll_fds[i].revents & POLLIN) && 197 (poll_cb->poll_fds[i].revents & POLLRDNORM)) { 198 CDBG("%s: mm_stream_data_notify\n", __func__); 199 if (NULL != poll_cb->poll_entries[i-1].notify_cb) { 200 poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data); 201 } 202 } 203 } 204 } 205 } else { 206 /* in error case sleep 10 us and then continue. hard coded here */ 207 usleep(10); 208 continue; 209 } 210 } while (poll_cb->state == MM_CAMERA_POLL_TASK_STATE_POLL); 211 return NULL; 212 } 213 214 static void *mm_camera_poll_thread(void *data) 215 { 216 int rc = 0; 217 int i; 218 void *ret = NULL; 219 mm_camera_poll_thread_t *poll_cb = (mm_camera_poll_thread_t *)data; 220 221 /* add pipe read fd into poll first */ 222 poll_cb->poll_fds[poll_cb->num_fds++].fd = poll_cb->pfds[0]; 223 224 //poll_cb->poll_fds[poll_cb->num_fds++].fd = (((mm_camera_obj_t *)poll_cb->my_obj)->ctrl_fd); 225 226 mm_camera_poll_sig_done(poll_cb); 227 mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_POLL); 228 ret = mm_camera_poll_fn(poll_cb); 229 return ret; 230 } 231 232 int32_t mm_camera_poll_thread_notify_entries_updated(mm_camera_poll_thread_t * poll_cb) 233 { 234 /* send poll entries updated signal to poll thread */ 235 return mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED); 236 } 237 238 int32_t mm_camera_poll_thread_add_poll_fd(mm_camera_poll_thread_t * poll_cb, 239 uint32_t handler, 240 int32_t fd, 241 mm_camera_poll_notify_t notify_cb, 242 void* userdata) 243 { 244 int32_t rc = -1; 245 uint8_t idx = 0; 246 247 if (MM_CAMERA_POLL_TYPE_CH == poll_cb->poll_type) { 248 /* get stream idx from handler if CH type */ 249 idx = mm_camera_util_get_index_by_handler(handler); 250 } else { 251 /* for EVT type, only idx=0 is valid */ 252 idx = 0; 253 } 254 255 if (MM_CAMEAR_STRAEM_NUM_MAX > idx) { 256 poll_cb->poll_entries[idx].fd = fd; 257 poll_cb->poll_entries[idx].handler = handler; 258 poll_cb->poll_entries[idx].notify_cb = notify_cb; 259 poll_cb->poll_entries[idx].user_data = userdata; 260 /* send poll entries updated signal to poll thread */ 261 rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED); 262 } else { 263 CDBG_ERROR("%s: invalid handler %d (%d)", 264 __func__, handler, idx); 265 } 266 return rc; 267 } 268 269 int32_t mm_camera_poll_thread_del_poll_fd(mm_camera_poll_thread_t * poll_cb, 270 uint32_t handler) 271 { 272 int32_t rc = -1; 273 uint8_t idx = 0; 274 275 if (MM_CAMERA_POLL_TYPE_CH == poll_cb->poll_type) { 276 /* get stream idx from handler if CH type */ 277 idx = mm_camera_util_get_index_by_handler(handler); 278 } else { 279 /* for EVT type, only idx=0 is valid */ 280 idx = 0; 281 } 282 283 if ((MM_CAMEAR_STRAEM_NUM_MAX > idx) && 284 (handler == poll_cb->poll_entries[idx].handler)) { 285 /* reset poll entry */ 286 poll_cb->poll_entries[idx].fd = -1; /* set fd to invalid */ 287 poll_cb->poll_entries[idx].handler = 0; 288 poll_cb->poll_entries[idx].notify_cb = NULL; 289 290 /* send poll entries updated signal to poll thread */ 291 rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED); 292 } else { 293 CDBG_ERROR("%s: invalid handler %d (%d)", 294 __func__, handler, idx); 295 } 296 297 return rc; 298 } 299 300 int32_t mm_camera_poll_thread_launch(mm_camera_poll_thread_t * poll_cb, 301 mm_camera_poll_thread_type_t poll_type) 302 { 303 int32_t rc = 0; 304 poll_cb->poll_type = poll_type; 305 306 poll_cb->pfds[0] = 0; 307 poll_cb->pfds[1] = 0; 308 rc = pipe(poll_cb->pfds); 309 if(rc < 0) { 310 CDBG_ERROR("%s: pipe open rc=%d\n", __func__, rc); 311 return -1; 312 } 313 314 poll_cb->timeoutms = -1; /* Infinite seconds */ 315 316 CDBG("%s: poll_type = %d, read fd = %d, write fd = %d timeout = %d", 317 __func__, poll_cb->poll_type, 318 poll_cb->pfds[0], poll_cb->pfds[1],poll_cb->timeoutms); 319 320 pthread_mutex_init(&poll_cb->mutex, NULL); 321 pthread_cond_init(&poll_cb->cond_v, NULL); 322 323 /* launch the thread */ 324 pthread_mutex_lock(&poll_cb->mutex); 325 poll_cb->status = 0; 326 pthread_create(&poll_cb->pid, NULL, mm_camera_poll_thread, (void *)poll_cb); 327 if(!poll_cb->status) { 328 pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex); 329 } 330 pthread_mutex_unlock(&poll_cb->mutex); 331 CDBG("%s: End",__func__); 332 return rc; 333 } 334 335 int32_t mm_camera_poll_thread_release(mm_camera_poll_thread_t *poll_cb) 336 { 337 int32_t rc = 0; 338 if(MM_CAMERA_POLL_TASK_STATE_STOPPED == poll_cb->state) { 339 CDBG_ERROR("%s: err, poll thread is not running.\n", __func__); 340 return rc; 341 } 342 343 /* send exit signal to poll thread */ 344 mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_EXIT); 345 /* wait until poll thread exits */ 346 if (pthread_join(poll_cb->pid, NULL) != 0) { 347 CDBG_ERROR("%s: pthread dead already\n", __func__); 348 } 349 350 /* close pipe */ 351 if(poll_cb->pfds[0]) { 352 close(poll_cb->pfds[0]); 353 } 354 if(poll_cb->pfds[1]) { 355 close(poll_cb->pfds[1]); 356 } 357 358 pthread_mutex_destroy(&poll_cb->mutex); 359 pthread_cond_destroy(&poll_cb->cond_v); 360 memset(poll_cb, 0, sizeof(mm_camera_poll_thread_t)); 361 return rc; 362 } 363