Merge "msm: camera: Fix memory leak with stats buffers" into msm-3.4
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 67e7c02..bb7db54 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -673,7 +673,6 @@
 	}
 	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF: {
 		struct msm_stats_buf_info buf_info;
-
 		if (copy_from_user(&buf_info, arg,
 			sizeof(struct msm_stats_buf_info))) {
 			ERR_COPY_FROM_USER();
@@ -687,18 +686,30 @@
 	}
 	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ: {
 		struct msm_stats_flush_bufq bufq_info;
-
 		if (copy_from_user(&bufq_info, arg,
 			sizeof(struct msm_stats_flush_bufq))) {
 			ERR_COPY_FROM_USER();
 			return -EFAULT;
-	}
+		}
 	cfgcmd.cmd_type = VFE_CMD_STATS_FLUSH_BUFQ;
 	cfgcmd.value = (void *)&bufq_info;
 	cfgcmd.length = sizeof(struct msm_stats_flush_bufq);
 	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
 	break;
 	}
+	case MSM_CAM_IOCTL_STATS_UNREG_BUF: {
+		struct msm_stats_reqbuf reqbuf;
+		if (copy_from_user(&reqbuf, arg,
+			sizeof(struct msm_stats_reqbuf))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	cfgcmd.cmd_type = VFE_CMD_STATS_UNREGBUF;
+	cfgcmd.value = (void *)&reqbuf;
+	cfgcmd.length = sizeof(struct msm_stats_reqbuf);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, (void *)mctl->client);
+	break;
+	}
 	default:
 		rc = -1;
 	break;
@@ -734,6 +745,7 @@
 	case MSM_CAM_IOCTL_STATS_REQBUF:
 	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF:
 	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ:
+	case MSM_CAM_IOCTL_STATS_UNREG_BUF:
 		rc = msm_vfe_stats_buf_ioctl(sd, cmd, pmctl, argp);
 		break;
 
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index 18168ee..a22a09f 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -417,6 +417,25 @@
 	return 0L;
 }
 
+static unsigned long vfe31_stats_unregbuf(
+	struct msm_stats_reqbuf *req_buf)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe31_ctrl->stats_ops.buf_unprepare(
+			vfe31_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe31_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
+
 static int vfe_stats_awb_buf_init(
 	struct vfe_cmd_stats_buf *in)
 {
@@ -3334,6 +3353,22 @@
 				vfe31_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe31_stats_unregbuf(req_buf);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported", __func__,
@@ -3583,6 +3618,7 @@
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_ENQUEUEBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
 		return rc;
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index aa2b19d..f748b8d 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -216,6 +216,26 @@
 		{VFE_CMD_GET_RGB_G_TABLE},
 		{VFE_CMD_GET_LA_TABLE},
 		{VFE_CMD_DEMOSAICV3_UPDATE},
+		{VFE_CMD_ACTIVE_REGION_CFG},
+/*130*/ {VFE_CMD_COLOR_PROCESSING_CONFIG},
+		{VFE_CMD_STATS_WB_AEC_CONFIG},
+		{VFE_CMD_STATS_WB_AEC_UPDATE},
+		{VFE_CMD_Y_GAMMA_CONFIG},
+		{VFE_CMD_SCALE_OUTPUT1_CONFIG},
+/*135*/ {VFE_CMD_SCALE_OUTPUT2_CONFIG},
+		{VFE_CMD_CAPTURE_RAW},
+		{VFE_CMD_STOP_LIVESHOT},
+		{VFE_CMD_RECONFIG_VFE},
+		{VFE_CMD_STATS_REQBUF},
+/*140*/	{VFE_CMD_STATS_ENQUEUEBUF},
+		{VFE_CMD_STATS_FLUSH_BUFQ},
+		{VFE_CMD_STATS_UNREGBUF},
+
+
+
+
+
+
 };
 
 uint32_t vfe32_AXI_WM_CFG[] = {
@@ -677,6 +697,26 @@
 	return 0L;
 }
 
+
+static unsigned long vfe32_stats_unregbuf(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct msm_stats_reqbuf *req_buf)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe32_ctrl->stats_ops.buf_unprepare(
+			vfe32_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe32_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
 static int vfe_stats_awb_buf_init(
 	struct vfe32_ctrl_type *vfe32_ctrl,
 	struct vfe_cmd_stats_buf *in)
@@ -4521,6 +4561,22 @@
 			vfe_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe32_stats_unregbuf(vfe_ctrl, req_buf);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported", __func__,
@@ -4570,6 +4626,7 @@
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_ENQUEUEBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
 				cmd, vfe_params->data);
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 64e0385..59c5d7d 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -404,6 +404,25 @@
 	return 0L;
 }
 
+static unsigned long vfe2x_stats_unregbuf(
+	struct msm_stats_reqbuf *req_buf)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe2x_ctrl->stats_ops.buf_unprepare(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe2x_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
+
 static int vfe2x_stats_buf_init(enum msm_stats_enum_type type)
 {
 	unsigned long flags;
@@ -556,6 +575,22 @@
 				vfe2x_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe2x_stats_unregbuf(req_buf);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported",
@@ -1228,6 +1263,7 @@
 		cmd->cmd_type != CMD_VFE_BUFFER_RELEASE &&
 		cmd->cmd_type != VFE_CMD_STATS_REQBUF &&
 		cmd->cmd_type != VFE_CMD_STATS_FLUSH_BUFQ &&
+		cmd->cmd_type != VFE_CMD_STATS_UNREGBUF &&
 		cmd->cmd_type != VFE_CMD_STATS_ENQUEUEBUF) {
 		if (copy_from_user(&vfecmd,
 			   (void __user *)(cmd->value),
@@ -1239,6 +1275,7 @@
 	switch (cmd->cmd_type) {
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe2x_stats_bufq_sub_ioctl(cmd, vfe_params->data);
 		return rc;
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index ae81dcd..a7ae2cc 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -213,6 +213,10 @@
 #define MSM_CAM_IOCTL_GET_INST_HANDLE \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 60, uint32_t *)
 
+#define MSM_CAM_IOCTL_STATS_UNREG_BUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 61, struct msm_stats_flush_bufq *)
+
+
 struct msm_stats_reqbuf {
 	int num_buf;		/* how many buffers requested */
 	int stats_type;	/* stats type */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 3df6ded..8de8c37 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -206,6 +206,7 @@
 #define VFE_CMD_STATS_REQBUF                            139
 #define VFE_CMD_STATS_ENQUEUEBUF                        140
 #define VFE_CMD_STATS_FLUSH_BUFQ                        141
+#define VFE_CMD_STATS_UNREGBUF                          142
 
 struct msm_isp_cmd {
 	int32_t  id;