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