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