From: ddl 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; icount; i++) { + for (i=0; icount; 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)