msm: camera: send error to HAL if daemon crashed
When camera userspace daemon crashes, the server fd
will be close, which trigger the msm_server_close
function, we will check if there is an active camera
session. If camera is active, we will send a v4l2
event to HAL layer to signal an error. Application
will exit gracefully and close other open fds and
exit camera session.
Change-Id: I14ebc864d6cace7ca6f4dbfb935623a76eeccaa8
Signed-off-by: Kevin Chan <ktchan@codeaurora.org>
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 84d441d..4598b31 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -163,6 +163,10 @@
if (!rc)
rc = -ETIMEDOUT;
if (rc < 0) {
+ rcmd = msm_dequeue(queue, list_control);
+ if (!rcmd)
+ free_qcmd(rcmd);
+ kfree(isp_event);
pr_err("%s: wait_event error %d\n", __func__, rc);
return rc;
}
@@ -943,7 +947,8 @@
not in use when we free the buffers */
mutex_lock(&pcam->vid_lock);
pcam_inst->streamon = 0;
- rc = msm_server_streamoff(pcam, pcam_inst->my_index);
+ if (g_server_dev.use_count > 0)
+ rc = msm_server_streamoff(pcam, pcam_inst->my_index);
mutex_unlock(&pcam->vid_lock);
if (rc < 0)
pr_err("%s: hw failed to stop streaming\n", __func__);
@@ -1448,6 +1453,7 @@
}
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
pcam->mctl.client = msm_ion_client_create(-1, "camera");
+ kref_init(&pcam->mctl.refcount);
#endif
/* Should be set to sensor ops if any but right now its OK!! */
if (!pcam->mctl.mctl_open) {
@@ -1502,6 +1508,7 @@
if (pcam->use_count == 1) {
+ msm_queue_init(&g_server_dev.ctrl_q, "control");
rc = msm_send_open_server(pcam->vnode_id);
if (rc < 0) {
mutex_unlock(&pcam->vid_lock);
@@ -1573,6 +1580,14 @@
return rc;
}
+void msm_release_ion_client(struct kref *ref)
+{
+ struct msm_cam_media_controller *mctl = container_of(ref,
+ struct msm_cam_media_controller, refcount);
+ pr_err("%s Calling ion_client_destroy ", __func__);
+ ion_client_destroy(mctl->client);
+}
+
static int msm_close(struct file *f)
{
int rc = 0;
@@ -1581,13 +1596,11 @@
pcam_inst = container_of(f->private_data,
struct msm_cam_v4l2_dev_inst, eventHandle);
pcam = pcam_inst->pcam;
- D("%s\n", __func__);
if (!pcam) {
pr_err("%s NULL pointer of camera device!\n", __func__);
return -EINVAL;
}
-
mutex_lock(&pcam->vid_lock);
pcam_inst->streamon = 0;
pcam->use_count--;
@@ -1610,17 +1623,21 @@
if (rc < 0)
pr_err("msm_cam_server_close_session fails %d\n", rc);
- rc = msm_send_close_server(pcam->vnode_id);
- if (rc < 0)
- pr_err("msm_send_close_server failed %d\n", rc);
+ if (g_server_dev.use_count > 0) {
+ rc = msm_send_close_server(pcam->vnode_id);
+ if (rc < 0)
+ pr_err("msm_send_close_server failed %d\n", rc);
+ }
if (pcam->mctl.mctl_release) {
rc = pcam->mctl.mctl_release(&(pcam->mctl));
if (rc < 0)
pr_err("mctl_release fails %d\n", rc);
}
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_client_destroy(pcam->mctl.client);
+ kref_put(&pcam->mctl.refcount, msm_release_ion_client);
#endif
+ if (g_server_dev.use_count == 0)
+ mutex_unlock(&g_server_dev.server_lock);
}
mutex_unlock(&pcam->vid_lock);
return rc;
@@ -1879,16 +1896,17 @@
{
int rc;
D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
-
+ mutex_lock(&g_server_dev.server_lock);
rc = nonseekable_open(inode, fp);
if (rc < 0) {
pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+ mutex_unlock(&g_server_dev.server_lock);
return rc;
}
g_server_dev.use_count++;
if (g_server_dev.use_count == 1)
msm_queue_init(&g_server_dev.ctrl_q, "control");
-
+ mutex_unlock(&g_server_dev.server_lock);
return rc;
}
@@ -1909,6 +1927,29 @@
return rc;
}
+static int msm_close_server(struct inode *inode, struct file *fp)
+{
+ mutex_lock(&g_server_dev.server_lock);
+ if (g_server_dev.use_count > 0)
+ g_server_dev.use_count--;
+ mutex_unlock(&g_server_dev.server_lock);
+ if (g_server_dev.use_count == 0) {
+ if (g_server_dev.pcam_active) {
+ struct v4l2_event v4l2_ev;
+ mutex_lock(&g_server_dev.server_lock);
+
+ v4l2_ev.type = V4L2_EVENT_PRIVATE_START
+ + MSM_CAM_APP_NOTIFY_ERROR_EVENT;
+ ktime_get_ts(&v4l2_ev.timestamp);
+ v4l2_event_queue(
+ g_server_dev.pcam_active->pvdev, &v4l2_ev);
+ }
+ msm_queue_drain(&g_server_dev.ctrl_q, list_control);
+ }
+ return 0;
+}
+
+
static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
unsigned int cmd, unsigned long evt)
{
@@ -2147,10 +2188,19 @@
spin_lock_init(&config_cam->p_mctl->sync.pmem_stats_spinlock);
config_cam->p_mctl->config_device = config_cam;
+ kref_get(&config_cam->p_mctl->refcount);
fp->private_data = config_cam;
return rc;
}
+static int msm_close_config(struct inode *node, struct file *f)
+{
+ struct msm_cam_config_dev *config_cam = f->private_data;
+ D("%s Decrementing ref count of config node ", __func__);
+ kref_put(&config_cam->p_mctl->refcount, msm_release_ion_client);
+ return 0;
+}
+
static struct v4l2_file_operations g_msm_fops = {
.owner = THIS_MODULE,
.open = msm_open,
@@ -2169,6 +2219,7 @@
.open = msm_open_server,
.poll = msm_poll_server,
.unlocked_ioctl = msm_ioctl_server,
+ .release = msm_close_server,
};
static const struct file_operations msm_fops_config = {
@@ -2177,6 +2228,7 @@
.poll = msm_poll_config,
.unlocked_ioctl = msm_ioctl_config,
.mmap = msm_mmap_config,
+ .release = msm_close_config,
};
int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
@@ -2294,6 +2346,7 @@
return rc;
}
+ mutex_init(&g_server_dev.server_lock);
g_server_dev.pcam_active = NULL;
g_server_dev.camera_info.num_cameras = 0;
atomic_set(&g_server_dev.number_pcam_active, 0);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 55c0da1..c90ab44 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -239,6 +239,7 @@
struct pm_qos_request_list pm_qos_req_list;
struct msm_mctl_pp_info pp_info;
struct ion_client *client;
+ struct kref refcount;
/* VFE output mode.
* Used to interpret the Primary/Secondary messages
* to preview/video/main/thumbnail image types*/
@@ -409,6 +410,7 @@
struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
/* info of MCTL nodes successfully probed*/
struct msm_mctl_node_info mctl_node_info;
+ struct mutex server_lock;
};
/* camera server related functions */
@@ -525,6 +527,7 @@
int image_mode, struct msm_frame_buffer *buf);
int msm_mctl_pp_mctl_divert_done(struct msm_cam_media_controller *p_mctl,
void __user *arg);
+void msm_release_ion_client(struct kref *ref);
#endif /* __KERNEL__ */
#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 54458d1..492bcce 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -890,7 +890,7 @@
return rc;
}
pcam_inst->vbqueue_initialized = 0;
-
+ kref_get(&pcam->mctl.refcount);
f->private_data = &pcam_inst->eventHandle;
D("f->private_data = 0x%x, pcam = 0x%x\n",
@@ -961,6 +961,7 @@
v4l2_fh_exit(&pcam_inst->eventHandle);
kfree(pcam_inst);
+ kref_put(&pcam->mctl.refcount, msm_release_ion_client);
f->private_data = NULL;
mutex_unlock(&pcam->mctl_node.dev_lock);
D("%s : X ", __func__);
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 867bd8a..6a7f99b 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -342,6 +342,7 @@
#define MSM_CAM_RESP_MAX 8
#define MSM_CAM_APP_NOTIFY_EVENT 0
+#define MSM_CAM_APP_NOTIFY_ERROR_EVENT 1
/* this one is used to send ctrl/status up to config thread */