diff options
Diffstat (limited to 'drivers/media/common/saa7146/saa7146_fops.c')
-rw-r--r-- | drivers/media/common/saa7146/saa7146_fops.c | 373 |
1 files changed, 75 insertions, 298 deletions
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index e9a15de6126e..79214459387a 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -7,12 +7,11 @@ /****************************************************************************/ /* resource management functions, shamelessly stolen from saa7134 driver */ -int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) +int saa7146_res_get(struct saa7146_dev *dev, unsigned int bit) { - struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - if (fh->resources & bit) { + if (vv->resources & bit) { DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n", bit, vv->resources); /* have it already allocated */ @@ -27,42 +26,23 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) return 0; } /* it's free, grab it */ - fh->resources |= bit; vv->resources |= bit; DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources); return 1; } -void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) +void saa7146_res_free(struct saa7146_dev *dev, unsigned int bits) { - struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - BUG_ON((fh->resources & bits) != bits); + WARN_ON((vv->resources & bits) != bits); - fh->resources &= ~bits; vv->resources &= ~bits; DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources); } /********************************************************************************/ -/* common dma functions */ - -void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, - struct saa7146_buf *buf) -{ - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - DEB_EE("dev:%p, buf:%p\n", dev, buf); - - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - - -/********************************************************************************/ /* common buffer functions */ int saa7146_buffer_queue(struct saa7146_dev *dev, @@ -72,15 +52,15 @@ int saa7146_buffer_queue(struct saa7146_dev *dev, assert_spin_locked(&dev->slock); DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf); - BUG_ON(!q); + if (WARN_ON(!q)) + return -EIO; if (NULL == q->curr) { q->curr = buf; DEB_D("immediately activating buffer %p\n", buf); buf->activate(dev,buf,NULL); } else { - list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->list, &q->queue); DEB_D("adding buffer %p to queue. (active buffer present)\n", buf); } @@ -91,21 +71,31 @@ void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state) { + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_buf *buf = q->curr; + assert_spin_locked(&dev->slock); DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state); DEB_EE("q->curr:%p\n", q->curr); /* finish current buffer */ - if (NULL == q->curr) { + if (!buf) { DEB_D("aiii. no current buffer\n"); return; } - q->curr->vb.state = state; - q->curr->vb.ts = ktime_get_ns(); - wake_up(&q->curr->vb.done); - q->curr = NULL; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + if (vv->video_fmt.field == V4L2_FIELD_ALTERNATE) + buf->vb.field = vv->last_field; + else if (vv->video_fmt.field == V4L2_FIELD_ANY) + buf->vb.field = (vv->video_fmt.height > vv->standard->v_max_out / 2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + else + buf->vb.field = vv->video_fmt.field; + buf->vb.sequence = vv->seqnr++; + vb2_buffer_done(&buf->vb.vb2_buf, state); } void saa7146_buffer_next(struct saa7146_dev *dev, @@ -113,17 +103,18 @@ void saa7146_buffer_next(struct saa7146_dev *dev, { struct saa7146_buf *buf,*next = NULL; - BUG_ON(!q); + if (WARN_ON(!q)) + return; DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi); assert_spin_locked(&dev->slock); if (!list_empty(&q->queue)) { /* activate next one from queue */ - buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue); - list_del(&buf->vb.queue); + buf = list_entry(q->queue.next, struct saa7146_buf, list); + list_del(&buf->list); if (!list_empty(&q->queue)) - next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); + next = list_entry(q->queue.next, struct saa7146_buf, list); q->curr = buf; DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev, q->queue.next); @@ -171,7 +162,7 @@ void saa7146_buffer_timeout(struct timer_list *t) spin_lock_irqsave(&dev->slock,flags); if (q->curr) { DEB_D("timeout on %p\n", q->curr); - saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); + saa7146_buffer_finish(dev, q, VB2_BUF_STATE_ERROR); } /* we don't restart the transfer here like other drivers do. when @@ -180,256 +171,39 @@ void saa7146_buffer_timeout(struct timer_list *t) we mess up our capture logic. if a timeout occurs on another buffer, then something is seriously broken before, so no need to buffer the next capture IMHO... */ -/* - saa7146_buffer_next(dev,q); -*/ + + saa7146_buffer_next(dev, q, 0); + spin_unlock_irqrestore(&dev->slock,flags); } /********************************************************************************/ /* file operations */ -static int fops_open(struct file *file) +static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) { struct video_device *vdev = video_devdata(file); struct saa7146_dev *dev = video_drvdata(file); - struct saa7146_fh *fh = NULL; - int result = 0; - - DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev)); - - if (mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - - DEB_D("using: %p\n", dev); - - /* check if an extension is registered */ - if( NULL == dev->ext ) { - DEB_S("no extension registered for this device\n"); - result = -ENODEV; - goto out; - } - - /* allocate per open data */ - fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) { - DEB_S("cannot allocate memory for per open data\n"); - result = -ENOMEM; - goto out; - } - - v4l2_fh_init(&fh->fh, vdev); - - file->private_data = &fh->fh; - fh->dev = dev; - - if (vdev->vfl_type == VFL_TYPE_VBI) { - DEB_S("initializing vbi...\n"); - if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) - result = saa7146_vbi_uops.open(dev,file); - if (dev->ext_vv_data->vbi_fops.open) - dev->ext_vv_data->vbi_fops.open(file); - } else { - DEB_S("initializing video...\n"); - result = saa7146_video_uops.open(dev,file); - } - - if (0 != result) { - goto out; - } - - if( 0 == try_module_get(dev->ext->module)) { - result = -EINVAL; - goto out; - } - - result = 0; - v4l2_fh_add(&fh->fh); -out: - if (fh && result != 0) { - kfree(fh); - file->private_data = NULL; - } - mutex_unlock(vdev->lock); - return result; -} - -static int fops_release(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - - DEB_EE("file:%p\n", file); - - mutex_lock(vdev->lock); - - if (vdev->vfl_type == VFL_TYPE_VBI) { - if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) - saa7146_vbi_uops.release(dev,file); - if (dev->ext_vv_data->vbi_fops.release) - dev->ext_vv_data->vbi_fops.release(file); - } else { - saa7146_video_uops.release(dev,file); - } - - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - module_put(dev->ext->module); - file->private_data = NULL; - kfree(fh); - - mutex_unlock(vdev->lock); - - return 0; -} - -static int fops_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct video_device *vdev = video_devdata(file); - struct saa7146_fh *fh = file->private_data; - struct videobuf_queue *q; - int res; - - switch (vdev->vfl_type) { - case VFL_TYPE_VIDEO: { - DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n", - file, vma); - q = &fh->video_q; - break; - } - case VFL_TYPE_VBI: { - DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n", - file, vma); - if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) - return -ENODEV; - q = &fh->vbi_q; - break; - } - default: - BUG(); - } + int ret; + if (vdev->vfl_type != VFL_TYPE_VBI || !dev->ext_vv_data->vbi_fops.write) + return -EINVAL; if (mutex_lock_interruptible(vdev->lock)) return -ERESTARTSYS; - res = videobuf_mmap_mapper(q, vma); + ret = dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); mutex_unlock(vdev->lock); - return res; -} - -static __poll_t __fops_poll(struct file *file, struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - struct saa7146_fh *fh = file->private_data; - struct videobuf_buffer *buf = NULL; - struct videobuf_queue *q; - __poll_t res = v4l2_ctrl_poll(file, wait); - - DEB_EE("file:%p, poll:%p\n", file, wait); - - if (vdev->vfl_type == VFL_TYPE_VBI) { - if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) - return res | EPOLLOUT | EPOLLWRNORM; - if( 0 == fh->vbi_q.streaming ) - return res | videobuf_poll_stream(file, &fh->vbi_q, wait); - q = &fh->vbi_q; - } else { - DEB_D("using video queue\n"); - q = &fh->video_q; - } - - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - - if (!buf) { - DEB_D("buf == NULL!\n"); - return res | EPOLLERR; - } - - poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { - DEB_D("poll succeeded!\n"); - return res | EPOLLIN | EPOLLRDNORM; - } - - DEB_D("nothing to poll for, buf->state:%d\n", buf->state); - return res; -} - -static __poll_t fops_poll(struct file *file, struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - __poll_t res; - - mutex_lock(vdev->lock); - res = __fops_poll(file, wait); - mutex_unlock(vdev->lock); - return res; -} - -static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct video_device *vdev = video_devdata(file); - struct saa7146_fh *fh = file->private_data; - int ret; - - switch (vdev->vfl_type) { - case VFL_TYPE_VIDEO: -/* - DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", - file, data, (unsigned long)count); -*/ - return saa7146_video_uops.read(file,data,count,ppos); - case VFL_TYPE_VBI: -/* - DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", - file, data, (unsigned long)count); -*/ - if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) { - if (mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - ret = saa7146_vbi_uops.read(file, data, count, ppos); - mutex_unlock(vdev->lock); - return ret; - } - return -EINVAL; - default: - BUG(); - } -} - -static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) -{ - struct video_device *vdev = video_devdata(file); - struct saa7146_fh *fh = file->private_data; - int ret; - - switch (vdev->vfl_type) { - case VFL_TYPE_VIDEO: - return -EINVAL; - case VFL_TYPE_VBI: - if (fh->dev->ext_vv_data->vbi_fops.write) { - if (mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); - mutex_unlock(vdev->lock); - return ret; - } - return -EINVAL; - default: - BUG(); - } + return ret; } static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, - .open = fops_open, - .release = fops_release, - .read = fops_read, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, .write = fops_write, - .poll = fops_poll, - .mmap = fops_mmap, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; @@ -516,33 +290,15 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) configuration data) */ dev->ext_vv_data = ext_vv; - vv->d_clipping.cpu_addr = - dma_alloc_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM, - &vv->d_clipping.dma_handle, GFP_KERNEL); - if( NULL == vv->d_clipping.cpu_addr ) { - ERR("out of memory. aborting.\n"); - kfree(vv); - v4l2_ctrl_handler_free(hdl); - v4l2_device_unregister(&dev->v4l2_dev); - return -ENOMEM; - } - saa7146_video_uops.init(dev,vv); if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) saa7146_vbi_uops.init(dev,vv); - vv->ov_fb.fmt.width = vv->standard->h_max_out; - vv->ov_fb.fmt.height = vv->standard->v_max_out; - vv->ov_fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565; - vv->ov_fb.fmt.bytesperline = 2 * vv->ov_fb.fmt.width; - vv->ov_fb.fmt.sizeimage = vv->ov_fb.fmt.bytesperline * vv->ov_fb.fmt.height; - vv->ov_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB; - fmt = &vv->video_fmt; fmt->width = 384; fmt->height = 288; fmt->pixelformat = V4L2_PIX_FMT_BGR24; - fmt->field = V4L2_FIELD_ANY; + fmt->field = V4L2_FIELD_INTERLACED; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; fmt->bytesperline = 3 * fmt->width; fmt->sizeimage = fmt->bytesperline * fmt->height; @@ -561,8 +317,6 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) timer_setup(&vv->vbi_read_timeout, NULL, 0); - vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING; - vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY; dev->vv_data = vv; dev->vv_callback = &vv_callback; @@ -577,8 +331,6 @@ int saa7146_vv_release(struct saa7146_dev* dev) DEB_EE("dev:%p\n", dev); v4l2_device_unregister(&dev->v4l2_dev); - dma_free_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM, - vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); v4l2_ctrl_handler_free(&dev->ctrl_handler); kfree(vv); dev->vv_data = NULL; @@ -591,16 +343,20 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release); int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, char *name, int type) { + struct vb2_queue *q; int err; int i; DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type); vfd->fops = &video_fops; - if (type == VFL_TYPE_VIDEO) + if (type == VFL_TYPE_VIDEO) { vfd->ioctl_ops = &dev->ext_vv_data->vid_ops; - else + q = &dev->vv_data->video_dmaq.q; + } else { vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops; + q = &dev->vv_data->vbi_dmaq.q; + } vfd->release = video_device_release_empty; vfd->lock = &dev->v4l2_lock; vfd->v4l2_dev = &dev->v4l2_dev; @@ -608,15 +364,36 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, for (i = 0; i < dev->ext_vv_data->num_stds; i++) vfd->tvnorms |= dev->ext_vv_data->stds[i].id; strscpy(vfd->name, name, sizeof(vfd->name)); - vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; vfd->device_caps |= dev->ext_vv_data->capabilities; - if (type == VFL_TYPE_VIDEO) + if (type == VFL_TYPE_VIDEO) { vfd->device_caps &= ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); - else - vfd->device_caps &= - ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO); + } else if (vfd->device_caps & V4L2_CAP_SLICED_VBI_OUTPUT) { + vfd->vfl_dir = VFL_DIR_TX; + vfd->device_caps &= ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | V4L2_CAP_TUNER); + } else { + vfd->device_caps &= ~V4L2_CAP_VIDEO_CAPTURE; + } + + q->type = type == VFL_TYPE_VIDEO ? V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VBI_CAPTURE; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; + q->ops = type == VFL_TYPE_VIDEO ? &video_qops : &vbi_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->drv_priv = dev; + q->gfp_flags = __GFP_DMA32; + q->buf_struct_size = sizeof(struct saa7146_buf); + q->lock = &dev->v4l2_lock; + q->min_buffers_needed = 2; + q->dev = &dev->pci->dev; + err = vb2_queue_init(q); + if (err) + return err; + vfd->queue = q; + video_set_drvdata(vfd, dev); err = video_register_device(vfd, type, -1); |