From patchwork Wed Aug 24 18:41:31 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 1093882 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p7OIfiN7006644 for ; Wed, 24 Aug 2011 18:41:44 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753773Ab1HXSlm (ORCPT ); Wed, 24 Aug 2011 14:41:42 -0400 Received: from moutng.kundenserver.de ([212.227.17.10]:51231 "EHLO moutng.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753764Ab1HXSll (ORCPT ); Wed, 24 Aug 2011 14:41:41 -0400 Received: from axis700.grange (dslb-094-221-126-224.pools.arcor-ip.net [94.221.126.224]) by mrelayeu.kundenserver.de (node=mreu1) with ESMTP (Nemesis) id 0LiZ0S-1RWjbO18hA-00chxW; Wed, 24 Aug 2011 20:41:34 +0200 Received: from 6a.grange (6a.grange [192.168.1.11]) by axis700.grange (Postfix) with ESMTPS id C91A2189F9C; Wed, 24 Aug 2011 20:41:32 +0200 (CEST) Received: from lyakh by 6a.grange with local (Exim 4.72) (envelope-from ) id 1QwIOK-0002ih-G1; Wed, 24 Aug 2011 20:41:32 +0200 From: Guennadi Liakhovetski To: Linux Media Mailing List Cc: Hans Verkuil , Laurent Pinchart , Pawel Osciak , Sakari Ailus , Mauro Carvalho Chehab , Marek Szyprowski Subject: [PATCH 6/7 v5] V4L: sh-mobile-ceu-camera: prepare to support multi-size buffers Date: Wed, 24 Aug 2011 20:41:31 +0200 Message-Id: <1314211292-10414-7-git-send-email-g.liakhovetski@gmx.de> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1314211292-10414-1-git-send-email-g.liakhovetski@gmx.de> References: <1314211292-10414-1-git-send-email-g.liakhovetski@gmx.de> X-Provags-ID: V02:K0:1sTGa5C7Z2Pn7MFnXc01c0Ahlh/SpqHzK6oacwUwFoi FJTiZIKmJv0inTl5oGdgO0ZvM7dR0ZH9cyMfxBxAN6pyZCoDT7 WGrxRLX3TCeYu0RrqArDm02cDpcVJkcMoxPtobD+zkAhCkZqR4 JgV0aIyUprSYB/bqd/p6MkMg97dJgZmXBghOMDxsTDNA7YufUQ gVf/UcCnpFPid2Ewg65EaU9luAIGZxOzeRw0QUMaVrg06hJLSw 8AAnEESfhAdQLgog17dSu+Xc1bJbJz9g6DsdKhP5q+GMfU1BAh w8sgj941n+c9pvmhIsvJHz8B3+DgNgXbNTK+ESA2wa6+RAyiGs 2DUuVoLHnK12i7dO0Y/FoDhnVIuAKLe/rE2CN22oPMiWw5nY/t TK6leQKhtBzgQ== Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Wed, 24 Aug 2011 18:41:44 +0000 (UTC) Prepare the sh_mobile_ceu_camera friver to support the new VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s. The .queue_setup() vb2 operation must be able to handle buffer sizes, provided by the caller, and the .buf_prepare() operation must not use the currently configured frame format for its operation. Signed-off-by: Guennadi Liakhovetski Cc: Hans Verkuil Cc: Laurent Pinchart Cc: Marek Szyprowski Cc: Mauro Carvalho Chehab Cc: Pawel Osciak Cc: Sakari Ailus --- drivers/media/video/sh_mobile_ceu_camera.c | 121 ++++++++++++++++++---------- 1 files changed, 78 insertions(+), 43 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index db3a24d..08af456 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -90,7 +90,6 @@ struct sh_mobile_ceu_buffer { struct vb2_buffer vb; /* v4l buffer must be first */ struct list_head queue; - enum v4l2_mbus_pixelcode code; }; struct sh_mobile_ceu_dev { @@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev { unsigned int irq; void __iomem *base; - unsigned long video_limit; + size_t video_limit; + size_t buf_total; spinlock_t lock; /* Protects video buffer lists */ struct list_head capture; @@ -192,6 +192,12 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) /* * Videobuf operations */ + +/* + * .queue_setup() is called to check, whether the driver can accept the + * requested number of buffers and to fill in plane sizes + * for the current frame format if required + */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int *count, unsigned int *num_planes, @@ -200,25 +206,43 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + int bytes_per_line; + unsigned int height; + size_t size; + + if (fmt) { + const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, + fmt->fmt.pix.pixelformat); + bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, + xlate->host_fmt); + height = fmt->fmt.pix.height; + } else { + /* Called from VIDIOC_REQBUFS or in compatibility mode */ + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - + height = icd->user_height; + } if (bytes_per_line < 0) return bytes_per_line; + sizes[0] = bytes_per_line * height; + *num_planes = 1; - pcdev->sequence = 0; - sizes[0] = bytes_per_line * icd->user_height; alloc_ctxs[0] = pcdev->alloc_ctx; + if (!vq->num_buffers) + pcdev->sequence = 0; + if (!*count) *count = 2; - if (pcdev->video_limit) { - if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) - *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); - } + size = PAGE_ALIGN(sizes[0]) * *count; + + if (pcdev->video_limit && + size + pcdev->buf_total > pcdev->video_limit) + *count = (pcdev->video_limit - pcdev->buf_total) / + PAGE_ALIGN(sizes[0]); dev_dbg(icd->parent, "count=%d, size=%lu\n", *count, sizes[0]); @@ -331,23 +355,40 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) { + struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); + + /* Added list head initialization on alloc */ + WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); + + return 0; +} + +static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) +{ struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct sh_mobile_ceu_buffer *buf; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); + unsigned long size; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - unsigned long size; if (bytes_per_line < 0) - return bytes_per_line; + goto error; + + size = icd->user_height * bytes_per_line; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", + vb->v4l2_buf.index, vb2_plane_size(vb, 0), size); + goto error; + } - buf = to_ceu_vb(vb); + vb2_set_plane_payload(vb, 0, size); dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - /* Added list head initialization on alloc */ - WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); - #ifdef DEBUG /* * This can be useful if you want to see if we actually fill @@ -357,31 +398,6 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); #endif - BUG_ON(NULL == icd->current_fmt); - - size = icd->user_height * bytes_per_line; - - if (vb2_plane_size(vb, 0) < size) { - dev_err(icd->parent, "Buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -ENOBUFS; - } - - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); - - dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - spin_lock_irq(&pcdev->lock); list_add_tail(&buf->queue, &pcdev->capture); @@ -395,6 +411,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) sh_mobile_ceu_capture(pcdev); } spin_unlock_irq(&pcdev->lock); + + return; + +error: + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) @@ -419,11 +440,23 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) if (buf->queue.next) list_del_init(&buf->queue); + pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); + dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, + pcdev->buf_total); + spin_unlock_irq(&pcdev->lock); } static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) { + struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + + pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); + dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, + pcdev->buf_total); + /* This is for locking debugging only */ INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); return 0; @@ -525,6 +558,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) pm_runtime_get_sync(ici->v4l2_dev.dev); + pcdev->buf_total = 0; + ret = sh_mobile_ceu_soft_reset(pcdev); csi2_sd = find_csi2(pcdev); @@ -1674,7 +1709,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, image_mode = false; } - dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, + dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, pix->width, pix->height); dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);