From: ddl <ddl@rock-chips.com>
Date: Tue, 21 Sep 2010 10:15:08 +0000 (+0800)
Subject: camera:fix camera client connect error,because capture videobuf queue may be not... 
X-Git-Tag: firefly_0821_release~11118
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=f42f806991dd5a6c3c17b09d57d3c3e126918aa7;p=firefly-linux-kernel-4.4.55.git

camera:fix camera client connect error,because capture videobuf queue may be not dequeue before camera is closed. Add stream control for vip
---

diff --git a/drivers/media/video/rk2818_camera.c b/drivers/media/video/rk2818_camera.c
index 935e299513ef..99c22951e612 100644
--- a/drivers/media/video/rk2818_camera.c
+++ b/drivers/media/video/rk2818_camera.c
@@ -308,7 +308,14 @@ static void rk28_videobuf_queue(struct videobuf_queue *vq,
 
     vb->state = VIDEOBUF_ACTIVE;
     spin_lock_irqsave(&pcdev->lock, flags);
-    list_add_tail(&vb->queue, &pcdev->capture);
+	if (!list_empty(&pcdev->capture)) {
+		list_add_tail(&vb->queue, &pcdev->capture);
+	} else {
+		if (list_entry(pcdev->capture.next, struct videobuf_buffer, queue) != vb)
+			list_add_tail(&vb->queue, &pcdev->capture);
+		else
+			BUG();    /* ddl@rock-chips.com : The same videobuffer queue again */
+	}
 
     if (!pcdev->active) {
         pcdev->active = vb;
@@ -327,10 +334,16 @@ static irqreturn_t rk28_camera_irq(int irq, void *data)
     /* ddl@rock-chps.com : Current VIP is run in One Frame Mode, Frame 1 is validate */
     if (read_vip_reg(RK28_VIP_FB_SR) & 0x01) {
 
-        if (pcdev->frame_inval) {
+		if (!pcdev->active)
+			goto RK28_CAMERA_IRQ_END;
+
+        if ((pcdev->frame_inval>0) && (pcdev->frame_inval<=RK28_CAM_FRAME_INVAL)) {
             pcdev->frame_inval--;
             rk28_videobuf_capture(pcdev->active);
-            return IRQ_HANDLED;
+            goto RK28_CAMERA_IRQ_END;
+        } else if (pcdev->frame_inval) {
+        	printk("frame_inval : %0x",pcdev->frame_inval);
+            pcdev->frame_inval = 0;
         }
 
         vb = pcdev->active;
@@ -350,6 +363,7 @@ static irqreturn_t rk28_camera_irq(int irq, void *data)
         wake_up(&vb->done);
     }
 
+RK28_CAMERA_IRQ_END:
     return IRQ_HANDLED;
 }
 
@@ -486,6 +500,14 @@ static int rk28_camera_add_device(struct soc_camera_device *icd)
     dev_info(&icd->dev, "RK28 Camera driver attached to camera %d\n",
              icd->devnum);
 
+	pcdev->frame_inval = RK28_CAM_FRAME_INVAL;
+    pcdev->active = NULL;
+    pcdev->icd = NULL;
+	/* ddl@rock-chips.com: capture list must be reset, because this list may be not empty,
+     * if app havn't dequeue all videobuf before close camera device;
+	*/
+    INIT_LIST_HEAD(&pcdev->capture);
+
     ret = rk28_camera_activate(pcdev,icd);
     if (ret)
         goto ebusy;
@@ -500,8 +522,6 @@ static int rk28_camera_add_device(struct soc_camera_device *icd)
 
     pcdev->icd = icd;
 
-    pcdev->frame_inval = RK28_CAM_FRAME_INVAL;
-
 ebusy:
     mutex_unlock(&camera_lock);
 
@@ -517,16 +537,22 @@ static void rk28_camera_remove_device(struct soc_camera_device *icd)
     dev_info(&icd->dev, "RK28 Camera driver detached from camera %d\n",
              icd->devnum);
 
+	rk28_camera_deactivate(pcdev);
+
 	/* ddl@rock-chips.com: Call videobuf_mmap_free here for free the struct video_buffer which malloc in videobuf_alloc */
 	if (pcdev->vb_vidq_ptr) {
 		videobuf_mmap_free(pcdev->vb_vidq_ptr);
 		pcdev->vb_vidq_ptr = NULL;
 	}
 
-
-    rk28_camera_deactivate(pcdev);
-
+	pcdev->active = NULL;
     pcdev->icd = NULL;
+	/* ddl@rock-chips.com: capture list must be reset, because this list may be not empty,
+     * if app havn't dequeue all videobuf before close camera device;
+	*/
+    INIT_LIST_HEAD(&pcdev->capture);
+
+	return;
 }
 
 static int rk28_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
@@ -560,7 +586,8 @@ static int rk28_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt
     if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH)
         set_vip_vsp(VSY_HIGH_ACTIVE);
 
-    vip_ctrl_val |= ENABLE_CAPTURE;
+    /* ddl@rock-chips.com : Don't enable capture here, enable in stream_on */
+    //vip_ctrl_val |= ENABLE_CAPTURE;
 
     write_vip_reg(RK28_VIP_CTRL, vip_ctrl_val);
     RK28CAMERA_DG("\n%s..CtrReg=%x  \n",__FUNCTION__,read_vip_reg(RK28_VIP_CTRL));
@@ -909,6 +936,26 @@ static int rk28_camera_resume(struct soc_camera_device *icd)
     return ret;
 }
 
+static int rk28_camera_s_stream(struct soc_camera_device *icd, int enable)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+    struct rk28_camera_dev *pcdev = ici->priv;
+    int vip_ctrl_val;
+
+	WARN_ON(pcdev->icd != icd);
+
+	vip_ctrl_val = read_vip_reg(RK28_VIP_CTRL);
+	if (enable) {
+		vip_ctrl_val |= ENABLE_CAPTURE;
+	} else {
+        vip_ctrl_val &= ~ENABLE_CAPTURE;
+	}
+	write_vip_reg(RK28_VIP_CTRL, vip_ctrl_val);
+
+	RK28CAMERA_DG("%s.. enable : %d\n", __FUNCTION__, enable);
+	return 0;
+}
+
 static struct soc_camera_host_ops rk28_soc_camera_host_ops =
 {
     .owner		= THIS_MODULE,
@@ -926,6 +973,7 @@ static struct soc_camera_host_ops rk28_soc_camera_host_ops =
     .poll		= rk28_camera_poll,
     .querycap	= rk28_camera_querycap,
     .set_bus_param	= rk28_camera_set_bus_param,
+    .s_stream = rk28_camera_s_stream   /* ddl@rock-chips.com : Add stream control for host */
 };
 static int rk28_camera_probe(struct platform_device *pdev)
 {
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 0ecbf6b4f36e..93269b551e32 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -523,7 +523,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
 	}
 	#else
 
-	/* ddl@rock-chips.com :  
+	/* ddl@rock-chips.com :
 	     Judge queue  initialised by Judge icf->vb_vidq.bufs[0] whether is NULL , it is error.    */
 
 	i = 0;
@@ -535,7 +535,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
 		}
 		i++;
 	}
-	
+
 	#endif
 
 	ret = soc_camera_set_fmt(icf, f);
@@ -605,6 +605,8 @@ static int soc_camera_streamon(struct file *file, void *priv,
 	struct soc_camera_file *icf = file->private_data;
 	struct soc_camera_device *icd = icf->icd;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici =
+                    to_soc_camera_host(icd->dev.parent);
 	int ret;
 
 	WARN_ON(priv != file->private_data);
@@ -615,7 +617,8 @@ static int soc_camera_streamon(struct file *file, void *priv,
 	mutex_lock(&icd->video_lock);
 
 	v4l2_subdev_call(sd, video, s_stream, 1);
-
+    if (ici->ops->s_stream)
+	    ici->ops->s_stream(icd, 1);				/* ddl@rock-chips.com : Add stream control for host */
 	/* This calls buf_queue from host driver's videobuf_queue_ops */
 	ret = videobuf_streamon(&icf->vb_vidq);
 
@@ -630,6 +633,8 @@ static int soc_camera_streamoff(struct file *file, void *priv,
 	struct soc_camera_file *icf = file->private_data;
 	struct soc_camera_device *icd = icf->icd;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+    struct soc_camera_host *ici =
+                    to_soc_camera_host(icd->dev.parent);
 
 	WARN_ON(priv != file->private_data);
 
@@ -643,6 +648,8 @@ static int soc_camera_streamoff(struct file *file, void *priv,
 	videobuf_streamoff(&icf->vb_vidq);
 
 	v4l2_subdev_call(sd, video, s_stream, 0);
+    if (ici->ops->s_stream)
+		ici->ops->s_stream(icd, 0);				/* ddl@rock-chips.com : Add stream control for host */
 
 	mutex_unlock(&icd->video_lock);
 
@@ -689,14 +696,14 @@ static int soc_camera_querymenu(struct file *file, void *priv,
     struct soc_camera_device *icd = icf->icd;
     struct v4l2_queryctrl qctrl;
     int i,j;
-    
+
     qctrl.id = qm->id;
 
     if (soc_camera_queryctrl(file,priv, &qctrl) == 0) {
         for (i = 0; i < icd->ops->num_menus; i++) {
             if (qm->id == icd->ops->menus[i].id) {
                 for (j=0; j<=(qctrl.maximum - qctrl.minimum); j++) {
-                
+
                     if (qm->index == icd->ops->menus[i].index) {
                         snprintf(qm->name, sizeof(qm->name), icd->ops->menus[i].name);
                         qm->reserved = 0;
@@ -705,13 +712,13 @@ static int soc_camera_querymenu(struct file *file, void *priv,
                     } else {
                         i++;
                         if ( i >= icd->ops->num_menus)
-                            return -EINVAL;    
-                    }                    
-                }                
+                            return -EINVAL;
+                    }
+                }
             }
         }
     }
-    
+
     return -EINVAL;
 }
 
@@ -762,15 +769,15 @@ static int soc_camera_try_ext_ctrl(struct file *file, void *priv,
 {
     struct soc_camera_file *icf = file->private_data;
     struct soc_camera_device *icd = icf->icd;
-    const struct v4l2_queryctrl *qctrl;   
+    const struct v4l2_queryctrl *qctrl;
     int i;
-    
+
     WARN_ON(priv != file->private_data);
 
     if (ctrl->ctrl_class != V4L2_CTRL_CLASS_CAMERA)
         return -EINVAL;
 
-    for (i=0; i<ctrl->count; i++) {     
+    for (i=0; i<ctrl->count; i++) {
         qctrl = soc_camera_find_qctrl(icd->ops, ctrl->controls[i].id);
         if (!qctrl)
             return -EINVAL;
@@ -778,7 +785,7 @@ static int soc_camera_try_ext_ctrl(struct file *file, void *priv,
         if ((ctrl->controls[i].value < qctrl->minimum) ||(ctrl->controls[i].value > qctrl->minimum))
             return -ERANGE;
     }
-    
+
     return 0;
 }
  /* ddl@rock-chips.com : Add ioctrl -VIDIOC_XXX_ext_ctrl for soc-camera */
@@ -788,13 +795,13 @@ static int soc_camera_g_ext_ctrl(struct file *file, void *priv,
     struct soc_camera_file *icf = file->private_data;
     struct soc_camera_device *icd = icf->icd;
     struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-    
+
     WARN_ON(priv != file->private_data);
 
     if (ctrl->ctrl_class != V4L2_CTRL_CLASS_CAMERA)
         return -EINVAL;
-    
-    return v4l2_subdev_call(sd, core, g_ext_ctrls, ctrl);    
+
+    return v4l2_subdev_call(sd, core, g_ext_ctrls, ctrl);
 }
  /* ddl@rock-chips.com : Add ioctrl -VIDIOC_XXX_ext_ctrl for soc-camera */
 static int soc_camera_s_ext_ctrl(struct file *file, void *priv,
@@ -803,13 +810,13 @@ static int soc_camera_s_ext_ctrl(struct file *file, void *priv,
     struct soc_camera_file *icf = file->private_data;
     struct soc_camera_device *icd = icf->icd;
     struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-    
+
     WARN_ON(priv != file->private_data);
 
     if (ctrl->ctrl_class != V4L2_CTRL_CLASS_CAMERA)
         return -EINVAL;
-    
-    return v4l2_subdev_call(sd, core, s_ext_ctrls, ctrl);    
+
+    return v4l2_subdev_call(sd, core, s_ext_ctrls, ctrl);
 }
 
 
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index b7227075f6cd..705c44b33b19 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -89,6 +89,9 @@ struct soc_camera_host_ops {
 	unsigned int (*poll)(struct file *, poll_table *);
 	const struct v4l2_queryctrl *controls;
 	int num_controls;
+
+    int (*s_stream)(struct soc_camera_device *, int enable);	/* ddl@rock-chips.com : Add stream control for host */
+
 };
 
 #define SOCAM_SENSOR_INVERT_PCLK	(1 << 0)
@@ -196,8 +199,8 @@ struct soc_camera_ops {
 	int (*resume)(struct soc_camera_device *);
 	unsigned long (*query_bus_param)(struct soc_camera_device *);
 	int (*set_bus_param)(struct soc_camera_device *, unsigned long);
-	int (*enum_input)(struct soc_camera_device *, struct v4l2_input *);	
-	
+	int (*enum_input)(struct soc_camera_device *, struct v4l2_input *);
+
 	const struct v4l2_queryctrl *controls;
 	const struct v4l2_querymenu *menus;                /* ddl@rock-chips.com : Add ioctrl -VIDIOC_QUERYMENU */
 	int num_controls;
@@ -259,7 +262,7 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
 #define SOCAM_DATA_ACTIVE_HIGH		(1 << 14)
 #define SOCAM_DATA_ACTIVE_LOW		(1 << 15)
 
-#define SOCAM_MCLK_24MHZ   (1<<29)                                      /* ddl@rock-chips.com : add  */ 
+#define SOCAM_MCLK_24MHZ   (1<<29)                                      /* ddl@rock-chips.com : add  */
 #define SOCAM_MCLK_27MHZ   (1<<30)
 #define SOCAM_MCLK_48MHZ   (1<<31)