diff options
author | Michael Hunold <devnull@localhost> | 2004-03-12 12:47:55 +0000 |
---|---|---|
committer | Michael Hunold <devnull@localhost> | 2004-03-12 12:47:55 +0000 |
commit | 87c4e37cac037d4f59eb6a69795715ff655eb615 (patch) | |
tree | 674c2d76dc2bf5b15e8c5d44951d5878f983ed50 /linux/drivers/media/common/saa7146_video.c | |
parent | 47196b544cfc6aaee1cf3d1649c4b0745da3c401 (diff) | |
download | mediapointer-dvb-s2-87c4e37cac037d4f59eb6a69795715ff655eb615.tar.gz mediapointer-dvb-s2-87c4e37cac037d4f59eb6a69795715ff655eb615.tar.bz2 |
With the addition of the ressource management, an overlay couldn't be
interrupted by a streaming capture any more. So:
- revamp video_begin()/video_end(), saa7146_start_preview()/saa7146_stop_preview
- clean up a lot of mess around the usage of these functions
- allow overlay to be suspended by streaming capture again, if ressources are available
Diffstat (limited to 'linux/drivers/media/common/saa7146_video.c')
-rw-r--r-- | linux/drivers/media/common/saa7146_video.c | 352 |
1 files changed, 179 insertions, 173 deletions
diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index 875bfe535..9ccda048a 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -5,6 +5,12 @@ static int memory = 32; MODULE_PARM(memory,"i"); MODULE_PARM_DESC(memory, "maximum memory usage for capture buffers (default: 32Mb)"); +#define IS_CAPTURE_ACTIVE(fh) \ + (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh)) + +#define IS_OVERLAY_ACTIVE(fh) \ + (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh)) + /* format descriptions for capture and preview */ static struct saa7146_format formats[] = { { @@ -251,6 +257,7 @@ int saa7146_start_preview(struct saa7146_fh *fh) struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; int ret = 0, err = 0; + unsigned long flags; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); @@ -260,24 +267,35 @@ int saa7146_start_preview(struct saa7146_fh *fh) return -EAGAIN; } + /* check if streaming capture is running */ + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("streaming capture is active.\n")); + return -EBUSY; + } + /* check if overlay is running */ - if( 0 != vv->ov_data ) { - if( fh != vv->ov_data->fh ) { - DEB_D(("overlay is running in another open.\n")); - return -EAGAIN; + if (IS_OVERLAY_ACTIVE(fh) != 0) { + if (vv->video_fh == fh) { + DEB_D(("overlay is already active.\n")); + return 0; } - DEB_D(("overlay is already active.\n")); - return 0; - } - - if( 0 != vv->streaming ) { - DEB_D(("streaming capture is active.\n")); + DEB_D(("overlay is already active in another open.\n")); return -EBUSY; - } - + } + + spin_lock_irqsave(&dev->slock,flags); + + if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { + DEB_D(("cannot get necessary overlay resources\n")); + err = -EBUSY; + goto out; + } + err = try_win(dev,&fh->ov.win); if (0 != err) { - return err; + saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); + err = -EBUSY; + goto out; } vv->ov_data = &fh->ov; @@ -288,35 +306,55 @@ int saa7146_start_preview(struct saa7146_fh *fh) vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); if (0 != (ret = saa7146_enable_overlay(fh))) { - vv->ov_data = NULL; DEB_D(("enabling overlay failed: %d\n",ret)); - return ret; + saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); + err = ret; + goto out; } - return 0; + vv->video_status = STATUS_OVERLAY; + vv->video_fh = fh; + err = 0; + +out: + spin_unlock_irqrestore(&dev->slock,flags); + return err; } int saa7146_stop_preview(struct saa7146_fh *fh) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; + unsigned long flags; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - /* check if overlay is running */ - if( 0 == vv->ov_data ) { - DEB_D(("overlay is not active.\n")); + /* check if streaming capture is running */ + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("streaming capture is active.\n")); + return -EBUSY; + } + /* check if overlay is running at all */ + if ((vv->video_status & STATUS_OVERLAY) == 0) { + DEB_D(("no active streaming capture.\n")); return 0; } - if( fh != vv->ov_data->fh ) { - DEB_D(("overlay is active, but for another open.\n")); - return 1; + if (vv->video_fh != fh) { + DEB_D(("streaming capture is active, but in another open.\n")); + return -EBUSY; } - vv->ov_data = NULL; + spin_lock_irqsave(&dev->slock,flags); + + saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); + + vv->video_status = 0; + vv->video_fh = NULL; + saa7146_disable_overlay(fh); + spin_unlock_irqrestore(&dev->slock,flags); return 0; } @@ -325,15 +363,14 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f) struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - unsigned long flags; int err; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh)); - if( fh == vv->streaming ) { - DEB_EE(("streaming capture is active")); - return -EAGAIN; + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_EE(("streaming capture is active\n")); + return -EBUSY; } err = try_fmt(fh,f); if (0 != err) @@ -359,16 +396,13 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f) /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ fh->ov.fh = fh; - /* check if we have an active overlay */ - if( vv->ov_data != NULL ) { - if( fh == vv->ov_data->fh) { - spin_lock_irqsave(&dev->slock,flags); - saa7146_stop_preview(fh); - saa7146_start_preview(fh); - spin_unlock_irqrestore(&dev->slock,flags); - } - } up(&dev->lock); + + /* check if our current overlay is active */ + if (IS_OVERLAY_ACTIVE(fh) != 0) { + saa7146_stop_preview(fh); + saa7146_start_preview(fh); + } return 0; default: DEB_D(("unknown format type '%d'\n",f->type)); @@ -480,8 +514,6 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) struct saa7146_vv *vv = dev->vv_data; const struct v4l2_queryctrl* ctrl; - unsigned long flags; - int restart_overlay = 0; ctrl = ctrl_by_id(c->id); if (NULL == ctrl) { @@ -489,6 +521,8 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) return -EINVAL; } + down(&dev->lock); + switch (ctrl->type) { case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_MENU: @@ -528,35 +562,31 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) break; } case V4L2_CID_HFLIP: - /* fixme: we can supfhrt changing VFLIP and HFLIP here... */ - if( 0 != vv->streaming ) { + /* fixme: we can support changing VFLIP and HFLIP here... */ + if (IS_CAPTURE_ACTIVE(fh) != 0) { DEB_D(("V4L2_CID_HFLIP while active capture.\n")); + up(&dev->lock); return -EINVAL; } vv->hflip = c->value; - restart_overlay = 1; break; case V4L2_CID_VFLIP: - if( 0 != vv->streaming ) { + if (IS_CAPTURE_ACTIVE(fh) != 0) { DEB_D(("V4L2_CID_VFLIP while active capture.\n")); + up(&dev->lock); return -EINVAL; } vv->vflip = c->value; - restart_overlay = 1; break; default: { return -EINVAL; } } - if( 0 != restart_overlay ) { - if( 0 != vv->ov_data ) { - if( fh == vv->ov_data->fh ) { - spin_lock_irqsave(&dev->slock,flags); - saa7146_stop_preview(fh); - saa7146_start_preview(fh); - spin_unlock_irqrestore(&dev->slock,flags); - } - } + up(&dev->lock); + + if (IS_OVERLAY_ACTIVE(fh) != 0) { + saa7146_stop_preview(fh); + saa7146_start_preview(fh); } return 0; } @@ -689,25 +719,29 @@ static int video_begin(struct saa7146_fh *fh) struct saa7146_format *fmt = NULL; unsigned long flags; unsigned int resource; - int ret = 0; + int ret = 0, err = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - if( fh == vv->streaming ) { - DEB_S(("already capturing.\n")); + if ((vv->video_status & STATUS_CAPTURE) != 0) { + if (vv->video_fh == fh) { + DEB_S(("already capturing.\n")); + return 0; + } + DEB_S(("already capturing in another open.\n")); return -EBUSY; } - if( vv->streaming != 0 ) { - DEB_S(("already capturing, but in another open.\n")); - return -EBUSY; + if ((vv->video_status & STATUS_OVERLAY) != 0) { + DEB_S(("warning: suspending overlay video for streaming capture.\n")); + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (0 != err) { + DEB_D(("suspending video failed. aborting\n")); + return err; + } } - if( 0 != vv->ov_data ) { - DEB_S(("overlay is active. disable it first.\n")); - return -EBUSY; - } - fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); @@ -721,6 +755,10 @@ static int video_begin(struct saa7146_fh *fh) ret = saa7146_res_get(fh, resource); if (0 == ret) { DEB_S(("cannot get capture resource %d\n",resource)); + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } return -EBUSY; } @@ -732,7 +770,9 @@ static int video_begin(struct saa7146_fh *fh) /* enable rps0 irqs */ IER_ENABLE(dev, MASK_27); - vv->streaming = fh; + vv->video_fh = fh; + vv->video_status = STATUS_CAPTURE; + spin_unlock_irqrestore(&dev->slock,flags); return 0; } @@ -747,9 +787,14 @@ static int video_end(struct saa7146_fh *fh, struct file *file) u32 dmas = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - if( vv->streaming != fh ) { + if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { DEB_S(("not capturing.\n")); - return -EINVAL; + return 0; + } + + if (vv->video_fh != fh) { + DEB_S(("capturing, but in another open.\n")); + return -EBUSY; } fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); @@ -776,9 +821,15 @@ static int video_end(struct saa7146_fh *fh, struct file *file) /* shut down all used video dma transfers */ saa7146_write(dev, MC1, dmas); - vv->streaming = NULL; + vv->video_fh = NULL; + vv->video_status = 0; spin_unlock_irqrestore(&dev->slock, flags); + + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } return 0; } @@ -795,7 +846,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - unsigned long flags; int err = 0, result = 0, ee = 0; struct saa7146_use_ops *ops; @@ -872,8 +922,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int { struct v4l2_framebuffer *fb = arg; struct saa7146_format *fmt; - struct saa7146_fh *ov_fh = NULL; - int restart_overlay = 0; DEB_EE(("VIDIOC_S_FBUF\n")); /* @@ -895,10 +943,10 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int } down(&dev->lock); - if( vv->ov_data != NULL ) { - ov_fh = vv->ov_data->fh; - saa7146_stop_preview(ov_fh); - restart_overlay = 1; + if (vv->video_status != 0) { + DEB_S(("overlay video is active\n")); + up(&dev->lock); + return -EBUSY; } /* ok, accept it */ @@ -908,10 +956,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width*fmt->depth/8; - if( 0 != restart_overlay ) { - saa7146_start_preview(ov_fh); - } - up(&dev->lock); return 0; @@ -976,9 +1020,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int #endif { DEB_EE(("VIDIOC_S_CTRL\n")); - down(&dev->lock); err = set_control(fh,arg); - up(&dev->lock); return err; } case VIDIOC_G_PARM: @@ -1037,27 +1079,27 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOC_S_STD: { v4l2_std_id *id = arg; - int i; - - int restart_overlay = 0; int found = 0; + int i, err; - struct saa7146_fh *ov_fh = NULL; - DEB_EE(("VIDIOC_S_STD\n")); - if( 0 != vv->streaming ) { + if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { + DEB_D(("cannot change video standard while streaming capture is active\n")); return -EBUSY; } - down(&dev->lock); - - if( vv->ov_data != NULL ) { - ov_fh = vv->ov_data->fh; - saa7146_stop_preview(ov_fh); - restart_overlay = 1; + if ((vv->video_status & STATUS_OVERLAY) != 0) { + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (0 != err) { + DEB_D(("suspending video failed. aborting\n")); + return err; + } } + down(&dev->lock); + for(i = 0; i < dev->ext_vv_data->num_stds; i++) if (*id & dev->ext_vv_data->stds[i].id) break; @@ -1068,11 +1110,13 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int found = 1; } - if( 0 != restart_overlay ) { - saa7146_start_preview(ov_fh); - } up(&dev->lock); + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + if( 0 == found ) { DEB_EE(("VIDIOC_S_STD: standard not found.\n")); return -EINVAL; @@ -1091,41 +1135,11 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int int err = 0; DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); - - if( NULL == vv->ov_fmt && on != 0 ) { - DEB_D(("VIDIOC_OVERLAY: no framebuffer informations. call S_FBUF first!\n")); - return -EAGAIN; - } - - if( vv->ov_data != NULL ) { - if( fh != vv->ov_data->fh) { - DEB_D(("overlay already active in another open\n")); - return -EAGAIN; - } - if (on != 0) { - DEB_D(("overlay is already active.\n")); - return 0; - } - spin_lock_irqsave(&dev->slock,flags); + if (on != 0) { + err = saa7146_start_preview(fh); + } else { err = saa7146_stop_preview(fh); - spin_unlock_irqrestore(&dev->slock,flags); - /* free resources */ - saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); - return err; } - if (on == 0) { - DEB_D(("overlay not running. doing nothing.\n")); - return 0; - } - - if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { - DEB_D(("cannot get overlay resources\n")); - return -EBUSY; - } - - spin_lock_irqsave(&dev->slock,flags); - err = saa7146_start_preview(fh); - spin_unlock_irqrestore(&dev->slock,flags); return err; } case VIDIOC_REQBUFS: { @@ -1156,11 +1170,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int int *type = arg; DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); - if( fh == vv->streaming ) { - DEB_D(("already capturing.\n")); - return 0; - } - err = video_begin(fh); if( 0 != err) { return err; @@ -1173,18 +1182,26 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); - if (NULL == vv->streaming ) { - DEB_D(("not capturing\n")); + /* ugly: we need to copy some checks from video_end(), + because videobuf_streamoff() relies on the capture running. + check and fix this */ + if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { + DEB_S(("not capturing.\n")); return 0; } - if( fh != vv->streaming ) { - DEB_D(("this open is not capturing.\n")); - return -EINVAL; + if (vv->video_fh != fh) { + DEB_S(("capturing, but in another open.\n")); + return -EBUSY; } err = videobuf_streamoff(file,q); - video_end(fh, file); + if (0 != err) { + DEB_D(("warning: videobuf_streamoff() failed.\n")); + video_end(fh, file); + } else { + err = video_end(fh, file); + } return err; } case VIDIOCGMBUF: @@ -1418,20 +1435,16 @@ static void video_close(struct saa7146_dev *dev, struct file *file) { struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; struct saa7146_vv *vv = dev->vv_data; - unsigned long flags; - - if( 0 != vv->ov_data ) { - if( fh == vv->ov_data->fh ) { - spin_lock_irqsave(&dev->slock,flags); - saa7146_stop_preview(fh); - spin_unlock_irqrestore(&dev->slock,flags); - saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); - } - } + int err; - if( fh == vv->streaming ) { - video_end(fh, file); + if (IS_CAPTURE_ACTIVE(fh) != 0) { + err = video_end(fh, file); + } else if (IS_CAPTURE_ACTIVE(fh) != 0) { + err = saa7146_stop_preview(fh); } + + /* hmm, why is this function declared void? */ + /* return err */ } @@ -1459,41 +1472,34 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p struct saa7146_vv *vv = dev->vv_data; ssize_t ret = 0; - int restart_overlay = 0; - struct saa7146_fh *ov_fh = NULL; - DEB_EE(("called.\n")); - /* fixme: should we allow read() captures while streaming capture? */ - if( 0 != vv->streaming ) { - DEB_S(("already capturing.\n")); + if ((vv->video_status & STATUS_CAPTURE) != 0) { + /* fixme: should we allow read() captures while streaming capture? */ + if (vv->video_fh == fh) { + DEB_S(("already capturing.\n")); + return -EBUSY; + } + DEB_S(("already capturing in another open.\n")); return -EBUSY; } - /* stop any active overlay */ - if( vv->ov_data != NULL ) { - ov_fh = vv->ov_data->fh; - saa7146_stop_preview(ov_fh); - saa7146_res_free(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); - restart_overlay = 1; - } - ret = video_begin(fh); if( 0 != ret) { goto out; } ret = videobuf_read_one(file,&fh->video_q , data, count, ppos); - video_end(fh, file); - + if (ret != 0) { + video_end(fh, file); + } else { + ret = video_end(fh, file); + } out: /* restart overlay if it was active before */ - if( 0 != restart_overlay ) { - if (0 == saa7146_res_get(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { - DEB_D(("cannot get overlay resources again!\n")); - BUG(); - } - saa7146_start_preview(ov_fh); + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; } return ret; |