From patchwork Thu Sep 9 09:19:47 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pawel Osciak X-Patchwork-Id: 4290 Return-path: Envelope-to: mchehab@pedra Delivery-date: Thu, 09 Sep 2010 09:55:24 -0300 Received: from mchehab by pedra with local (Exim 4.72) (envelope-from ) id 1Otgex-0004Yn-Qb for mchehab@pedra; Thu, 09 Sep 2010 09:55:24 -0300 Received: from bombadil.infradead.org [18.85.46.34] by pedra with IMAP (fetchmail-6.3.17) for (single-drop); Thu, 09 Sep 2010 09:55:23 -0300 (BRT) Received: from vger.kernel.org ([209.132.180.67]) by bombadil.infradead.org with esmtp (Exim 4.72 #1 (Red Hat Linux)) id 1OtdJ2-0001Rh-1G; Thu, 09 Sep 2010 09:20:32 +0000 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753905Ab0IIJU3 (ORCPT + 1 other); Thu, 9 Sep 2010 05:20:29 -0400 Received: from mailout1.w1.samsung.com ([210.118.77.11]:36758 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753511Ab0IIJUQ (ORCPT ); Thu, 9 Sep 2010 05:20:16 -0400 Received: from eu_spt2 (mailout1.w1.samsung.com [210.118.77.11]) by mailout1.w1.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built Jul 14 2004)) with ESMTP id <0L8H001UK39JVQ@mailout1.w1.samsung.com> for linux-media@vger.kernel.org; Thu, 09 Sep 2010 10:20:09 +0100 (BST) Received: from linux.samsung.com ([106.116.38.10]) by spt2.w1.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built Jul 14 2004)) with ESMTPA id <0L8H00KV639I83@spt2.w1.samsung.com> for linux-media@vger.kernel.org; Thu, 09 Sep 2010 10:20:07 +0100 (BST) Received: from mcdsrvbld02.digital.local (unknown [106.116.37.23]) by linux.samsung.com (Postfix) with ESMTP id 4D9EC27007B; Thu, 09 Sep 2010 11:16:45 +0200 (CEST) Date: Thu, 09 Sep 2010 11:19:47 +0200 From: Pawel Osciak Subject: [PATCH v1 6/7] v4l: vivi: port to videobuf2 In-reply-to: <1284023988-23351-1-git-send-email-p.osciak@samsung.com> To: linux-media@vger.kernel.org Cc: p.osciak@samsung.com, kyungmin.park@samsung.com, m.szyprowski@samsung.com, t.fujak@samsung.com Message-id: <1284023988-23351-7-git-send-email-p.osciak@samsung.com> MIME-version: 1.0 X-Mailer: git-send-email 1.7.1 Content-type: TEXT/PLAIN Content-transfer-encoding: 7BIT References: <1284023988-23351-1-git-send-email-p.osciak@samsung.com> Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Sender: Mauro Carvalho Chehab Make vivi use videobuf2 in place of videobuf. Signed-off-by: Pawel Osciak Signed-off-by: Kyungmin Park --- drivers/media/video/Kconfig | 2 +- drivers/media/video/vivi.c | 248 +++++++++++++++++++++---------------------- 2 files changed, 124 insertions(+), 126 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 5286b2f..c2ea549 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -558,7 +558,7 @@ config VIDEO_VIVI depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 depends on (FRAMEBUFFER_CONSOLE || STI_CONSOLE) && FONTS select FONT_8x16 - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index e17b6fe..b2dea81 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -7,6 +7,9 @@ * John Sokol * http://v4l.videotechnology.com/ * + * Conversion to videobuf2 by Pawel Osciak + * Copyright (c) 2010 Samsung Electronics + * * This program is free software; you can redistribute it and/or modify * it under the terms of the BSD Licence, GNU General Public License * as published by the Free Software Foundation; either version 2 of the @@ -26,7 +29,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) #include #endif -#include +#include #include #include #include @@ -42,7 +45,7 @@ #define MAX_HEIGHT 1200 #define VIVI_MAJOR_VERSION 0 -#define VIVI_MINOR_VERSION 7 +#define VIVI_MINOR_VERSION 8 #define VIVI_RELEASE 0 #define VIVI_VERSION \ KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) @@ -70,6 +73,9 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); /* Global font descriptor */ static const u8 *font8x16; +/* Videobuf2 allocator/memory handler context */ +static struct vb2_alloc_ctx *alloc_ctx; + #define dprintk(dev, level, fmt, arg...) \ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) @@ -141,7 +147,7 @@ struct sg_to_addr { /* buffer for one video frame */ struct vivi_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; + struct vb2_buffer vb; struct vivi_fmt *fmt; }; @@ -190,7 +196,9 @@ struct vivi_dev { /* video capture */ struct vivi_fmt *fmt; unsigned int width, height; - struct videobuf_queue vb_vidq; + struct vb2_queue vb_vidq; + enum v4l2_field field; + unsigned int field_count; unsigned long generating; u8 bars[9][3]; @@ -443,10 +451,10 @@ static void gen_text(struct vivi_dev *dev, char *basep, static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) { - int hmax = buf->vb.height; - int wmax = buf->vb.width; + int hmax = dev->width; + int wmax = dev->height; struct timeval ts; - void *vbuf = videobuf_to_vmalloc(&buf->vb); + void *vbuf = vb2_plane_vaddr(&buf->vb, 0); unsigned ms; char str[100]; int h, line = 1; @@ -483,11 +491,11 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) dev->mv_count += 2; - /* Advice that buffer was filled */ - buf->vb.field_count++; + buf->vb.v4l2_buf.field = dev->field; + dev->field_count++; + buf->vb.v4l2_buf.sequence = dev->field_count >> 1; do_gettimeofday(&ts); - buf->vb.ts = ts; - buf->vb.state = VIDEOBUF_DONE; + buf->vb.v4l2_buf.timestamp = ts; } static void vivi_thread_tick(struct vivi_dev *dev) @@ -504,23 +512,21 @@ static void vivi_thread_tick(struct vivi_dev *dev) goto unlock; } - buf = list_entry(dma_q->active.next, - struct vivi_buffer, vb.queue); - - /* Nobody is waiting on this buffer, return */ - if (!waitqueue_active(&buf->vb.done)) + /* If nobody is waiting for a buffer, return */ + if (!vb2_has_consumers(&dev->vb_vidq)) goto unlock; - list_del(&buf->vb.queue); + buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.drv_entry); + list_del(&buf->vb.drv_entry); - do_gettimeofday(&buf->vb.ts); + do_gettimeofday(&buf->vb.v4l2_buf.timestamp); /* Fill buffer */ vivi_fillbuff(dev, buf); dprintk(dev, 1, "filled buffer %p\n", buf); - wake_up(&buf->vb.done); - dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); unlock: spin_unlock_irqrestore(&dev->slock, flags); } @@ -619,8 +625,6 @@ static void vivi_stop_generating(struct file *file) kthread_stop(dma_q->kthread); dma_q->kthread = NULL; } - videobuf_stop(&dev->vb_vidq); - videobuf_mmap_free(&dev->vb_vidq); } static int vivi_is_generating(struct vivi_dev *dev) @@ -631,108 +635,119 @@ static int vivi_is_generating(struct vivi_dev *dev) /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) +static int queue_negotiate(struct vb2_queue *vq, unsigned int *num_buffers, + unsigned int *num_planes) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vq); + unsigned long size; + + size = dev->width * dev->height * 2; + + if (0 == *num_buffers) + *num_buffers = 32; + + while (size * *num_buffers > vid_limit * 1024 * 1024) + (*num_buffers)--; - *size = dev->width * dev->height * 2; + *num_planes = 1; + + dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, + *num_buffers, size); + + return 0; +} + +static int plane_setup(struct vb2_queue *vq, unsigned int plane_no, + unsigned long *plane_size) +{ + struct vivi_dev *dev = vb2_get_drv_priv(vq); - if (0 == *count) - *count = 32; + if (plane_no > 0) + return -EINVAL; - while (*size * *count > vid_limit * 1024 * 1024) - (*count)--; + *plane_size = dev->width * dev->height * 2; - dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, - *count, *size); + dprintk(dev, 1, "%s: plane: %d, size: %ld\n", + __func__, plane_no, *plane_size); return 0; } -static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) +static int buffer_init(struct vb2_buffer *vb) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + BUG_ON(NULL == dev->fmt); - dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state); + /* + * This callback is called once per buffer, after its allocation. + * + * Vivi does not allow changing format during streaming, but it is + * possible to do so when streaming is paused (i.e. in streamoff state). + * Buffers however are not freed when going into streamoff and so + * buffer size verification has to be done in buffer_prepare, on each + * qbuf. + * It would be best to move verification code here to buf_init and + * s_fmt though. + */ - videobuf_vmalloc_free(&buf->vb); - dprintk(dev, 1, "free_buffer: freed\n"); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + return 0; } -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) +static int buffer_prepare(struct vb2_buffer *vb) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - int rc; + unsigned long size; - dprintk(dev, 1, "%s, field=%d\n", __func__, field); + dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field); BUG_ON(NULL == dev->fmt); + /* + * Theses properties only change when queue is idle, see s_fmt. + * The below checks should not be performed here, on each + * buffer_prepare (i.e. on each qbuf). Most of the code in this function + * should thus be moved to buffer_init and s_fmt. + */ if (dev->width < 48 || dev->width > MAX_WIDTH || dev->height < 32 || dev->height > MAX_HEIGHT) return -EINVAL; - buf->vb.size = dev->width * dev->height * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + size = dev->width * dev->height * 2; + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb, 0, size); - /* These properties only change when queue is idle, see s_fmt */ - buf->fmt = dev->fmt; - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; + buf->fmt = dev->fmt; precalculate_bars(dev); precalculate_line(dev); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; return 0; - -fail: - free_buffer(vq, buf); - return rc; } -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_dmaqueue *vidq = &dev->vidq; dprintk(dev, 1, "%s\n", __func__); - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); + list_add_tail(&buf->vb.drv_entry, &vidq->active); } -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct vivi_dev *dev = vq->priv_data; - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops vivi_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, +static struct vb2_ops vivi_video_qops = { + .queue_negotiate = queue_negotiate, + .plane_setup = plane_setup, + .buf_init = buffer_init, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, }; /* ------------------------------------------------------------------ @@ -774,7 +789,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; - f->fmt.pix.field = dev->vb_vidq.field; + f->fmt.pix.field = dev->field; f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3; @@ -820,7 +835,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivi_dev *dev = video_drvdata(file); - struct videobuf_queue *q = &dev->vb_vidq; + struct vb2_queue *q = &dev->vb_vidq; int ret = vidioc_try_fmt_vid_cap(file, priv, f); if (ret < 0) @@ -837,7 +852,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->fmt = get_format(f); dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; - dev->vb_vidq.field = f->fmt.pix.field; + dev->field = f->fmt.pix.field; ret = 0; out: mutex_unlock(&q->vb_lock); @@ -849,53 +864,41 @@ static int vidioc_reqbufs(struct file *file, void *priv, { struct vivi_dev *dev = video_drvdata(file); - return videobuf_reqbufs(&dev->vb_vidq, p); + return vb2_reqbufs(&dev->vb_vidq, p); } static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct vivi_dev *dev = video_drvdata(file); - return videobuf_querybuf(&dev->vb_vidq, p); + return vb2_querybuf(&dev->vb_vidq, p); } static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct vivi_dev *dev = video_drvdata(file); - return videobuf_qbuf(&dev->vb_vidq, p); + return vb2_qbuf(&dev->vb_vidq, p); } static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct vivi_dev *dev = video_drvdata(file); - return videobuf_dqbuf(&dev->vb_vidq, p, - file->f_flags & O_NONBLOCK); -} - -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) -{ - struct vivi_dev *dev = video_drvdata(file); - - return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8); + return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK); } -#endif static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_dev *dev = video_drvdata(file); int ret; - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - ret = videobuf_streamon(&dev->vb_vidq); + ret = vb2_streamon(&dev->vb_vidq, i); if (ret) return ret; vivi_start_generating(file); - return 0; + return ret; } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) @@ -903,9 +906,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) struct vivi_dev *dev = video_drvdata(file); int ret; - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - ret = videobuf_streamoff(&dev->vb_vidq); + ret = vb2_streamoff(&dev->vb_vidq, i); if (!ret) vivi_stop_generating(file); return ret; @@ -1031,26 +1032,16 @@ static int vidioc_s_ctrl(struct file *file, void *priv, File operations for the device ------------------------------------------------------------------*/ -static ssize_t -vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct vivi_dev *dev = video_drvdata(file); - - vivi_start_generating(file); - return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_dev *dev = video_drvdata(file); - struct videobuf_queue *q = &dev->vb_vidq; + struct vb2_queue *q = &dev->vb_vidq; dprintk(dev, 1, "%s\n", __func__); vivi_start_generating(file); - return videobuf_poll_stream(file, q, wait); + return vb2_poll(q, file, wait); } static int vivi_close(struct file *file) @@ -1059,6 +1050,7 @@ static int vivi_close(struct file *file) struct vivi_dev *dev = video_drvdata(file); vivi_stop_generating(file); + vb2_queue_release(&dev->vb_vidq); dprintk(dev, 1, "close called (dev=%s)\n", video_device_node_name(vdev)); @@ -1072,7 +1064,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma) dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - ret = videobuf_mmap_mapper(&dev->vb_vidq, vma); + ret = vb2_mmap(&dev->vb_vidq, vma); dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, @@ -1084,7 +1076,6 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma) static const struct v4l2_file_operations vivi_fops = { .owner = THIS_MODULE, .release = vivi_close, - .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ .mmap = vivi_mmap, @@ -1145,6 +1136,8 @@ static int vivi_release(void) kfree(dev); } + vb2_vmalloc_cleanup(alloc_ctx); + return 0; } @@ -1173,10 +1166,8 @@ static int __init vivi_create_instance(int inst) dev->saturation = 127; dev->hue = 0; - videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops, - NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct vivi_buffer), dev); + vb2_queue_init(&dev->vb_vidq, &vivi_video_qops, alloc_ctx, + &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, dev); /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); @@ -1238,6 +1229,13 @@ static int __init vivi_init(void) } font8x16 = font->data; + /* Initialize vmalloc allocator */ + alloc_ctx = vb2_vmalloc_init(); + if (IS_ERR(alloc_ctx)) { + printk(KERN_ERR "vivi: allocator init failed\n"); + return PTR_ERR(alloc_ctx); + } + if (n_devs <= 0) n_devs = 1;