int32_t mm_camera_close(mm_camera_obj_t *my_obj)
{
    int i, rc = 0;

    for(i = 0; i < MM_CAMERA_CH_MAX; i++){
        mm_camera_ch_fn(my_obj, (mm_camera_channel_type_t)i,
                                MM_CAMERA_STATE_EVT_RELEASE, NULL);
    }

    CDBG("%s : Close Threads in Cam Close",__func__);
    for(i = 0; i < MM_CAMERA_CH_MAX; i++) {
        mm_camera_poll_thread_release(my_obj,(mm_camera_channel_type_t)i);
    }
    mm_camera_poll_threads_deinit(my_obj);
    my_obj->op_mode = MM_CAMERA_OP_MODE_NOTUSED;
    if(my_obj->ctrl_fd > 0) {
        mm_camera_histo_mmap(my_obj, NULL);
        rc = close(my_obj->ctrl_fd);
        if(rc < 0) {
            /* this is a dead end. */
            CDBG("%s: !!!!FATAL ERROR!!!! ctrl_fd = %d, rc = %d",
                 __func__, my_obj->ctrl_fd, rc);
        }
        my_obj->ctrl_fd = 0;
    }
    if(my_obj->ds_fd > 0) {
        mm_camera_socket_close(my_obj->ds_fd);
        my_obj->ds_fd = 0;
    }
    return MM_CAMERA_OK;
}
static int mm_camera_evt_sub(mm_camera_obj_t * my_obj,
                             mm_camera_event_type_t evt_type, int reg_count)
{
    int rc = MM_CAMERA_OK;
    struct v4l2_event_subscription sub;

    memset(&sub, 0, sizeof(sub));
    sub.type = V4L2_EVENT_PRIVATE_START+MSM_CAM_APP_NOTIFY_EVENT;
    if(reg_count == 0) {
        /* unsubscribe */
        if(my_obj->evt_type_mask == (uint32_t)(1 << evt_type)) {
            rc = ioctl(my_obj->ctrl_fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
            CDBG("%s: unsubscribe event 0x%x, rc = %d", __func__, sub.type, rc);
            sub.type = V4L2_EVENT_PRIVATE_START+MSM_CAM_APP_NOTIFY_ERROR_EVENT;
            rc = ioctl(my_obj->ctrl_fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
            CDBG("%s: unsubscribe event 0x%x, rc = %d", __func__, sub.type, rc);
        }
        my_obj->evt_type_mask &= ~(1 << evt_type);
        if(my_obj->evt_type_mask == 0) {
            /* kill the polling thraed when unreg the last event */
            mm_camera_poll_thread_release(my_obj, MM_CAMERA_CH_MAX);
        }
    } else {
        if(!my_obj->evt_type_mask) {
            /* this is the first reg event */
            rc = ioctl(my_obj->ctrl_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
            CDBG("%s: subscribe event 0x%x, rc = %d", __func__, sub.type, rc);
            if (rc < 0)
                goto end;
            sub.type = V4L2_EVENT_PRIVATE_START+MSM_CAM_APP_NOTIFY_ERROR_EVENT;
            rc = ioctl(my_obj->ctrl_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
            CDBG("%s: subscribe event 0x%x, rc = %d", __func__, sub.type, rc);
            if (rc < 0)
                goto end;
        }
        my_obj->evt_type_mask |= (1 << evt_type);
        if(my_obj->evt_type_mask == (uint32_t)(1 << evt_type)) {
            /* launch event polling when subscribe the first event */
            rc = mm_camera_poll_thread_launch(my_obj, MM_CAMERA_CH_MAX);
        }
    }
end:
    return rc;
}
int32_t mm_camera_ch_fn(mm_camera_obj_t * my_obj,
        mm_camera_channel_type_t ch_type,
        mm_camera_state_evt_type_t evt, void *val)
{
    int32_t rc = MM_CAMERA_OK;

    CDBG("%s:ch = %d, evt=%d\n", __func__, ch_type, evt);
    switch(evt) {
    case MM_CAMERA_STATE_EVT_ACQUIRE:
        rc = mm_camera_ch_util_acquire(my_obj, ch_type);
        break;
    case MM_CAMERA_STATE_EVT_RELEASE:
      /* safe code in case no stream off before release. */
        //mm_camera_poll_thread_release(my_obj, ch_type);
        rc = mm_camera_ch_util_release(my_obj, ch_type, evt);
        break;
    case MM_CAMERA_STATE_EVT_ATTR:
        rc = mm_camera_ch_util_attr(my_obj, ch_type,
                                    (mm_camera_channel_attr_t *)val);
        break;
    case MM_CAMERA_STATE_EVT_REG_BUF_CB:
        rc = mm_camera_ch_util_reg_buf_cb(my_obj, ch_type,
                                          (mm_camera_buf_cb_t *)val);
        break;
    case MM_CAMERA_STATE_EVT_SET_FMT:
        rc = mm_camera_ch_util_set_fmt(my_obj, ch_type,
                                       (mm_camera_ch_image_fmt_parm_t *)val);
        break;
    case MM_CAMERA_STATE_EVT_REG_BUF:
    case MM_CAMERA_STATE_EVT_REQUEST_BUF:
    case MM_CAMERA_STATE_EVT_ENQUEUE_BUF:
        rc = mm_camera_ch_util_reg_buf(my_obj, ch_type, evt, val);
        break;
    case MM_CAMERA_STATE_EVT_UNREG_BUF:
        rc = mm_camera_ch_util_stream_null_val(my_obj, ch_type, evt, NULL);
        break;
    case MM_CAMERA_STATE_EVT_STREAM_ON: {
        if(ch_type == MM_CAMERA_CH_RAW &&
             my_obj->ch[ch_type].raw.mode == MM_CAMERA_RAW_STREAMING_CAPTURE_SINGLE) {
            if( MM_CAMERA_OK != (rc = mm_camera_util_s_ctrl(my_obj->ctrl_fd,
                MSM_V4L2_PID_CAM_MODE, MSM_V4L2_CAM_OP_RAW))) {
                CDBG("%s:set MM_CAMERA_RAW_STREAMING_CAPTURE_SINGLE err=%d\n", __func__, rc);
                break;
            }
        }
        mm_camera_poll_thread_add_ch(my_obj, ch_type);
        rc = mm_camera_ch_util_stream_null_val(my_obj, ch_type, evt, NULL);
        if(rc < 0) {
          CDBG_ERROR("%s: Failed in STREAM ON", __func__);
          mm_camera_poll_thread_release(my_obj, ch_type);
        }
        break;
    }
    case MM_CAMERA_STATE_EVT_STREAM_OFF: {
        mm_camera_poll_thread_del_ch(my_obj, ch_type);
        rc = mm_camera_ch_util_stream_null_val(my_obj, ch_type, evt, NULL);
        break;
    }
    case MM_CAMERA_STATE_EVT_QBUF:
        rc = mm_camera_ch_util_qbuf(my_obj, ch_type, evt,
                                    (mm_camera_ch_data_buf_t *)val);
        break;
    case MM_CAMERA_STATE_EVT_GET_CROP:
      rc = mm_camera_ch_util_get_crop(my_obj, ch_type, evt,
                                  (mm_camera_ch_crop_t *)val);
      break;
    case MM_CAMERA_STATE_EVT_DISPATCH_BUFFERED_FRAME:
      rc = mm_camera_ch_util_dispatch_buffered_frame(my_obj, ch_type);
      break;
    default:
        break;
    }
    return rc;
}