From patchwork Wed Aug 31 18:02:45 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 1117442 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 p7VI33Zh027866 for ; Wed, 31 Aug 2011 18:03:04 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756995Ab1HaSC7 (ORCPT ); Wed, 31 Aug 2011 14:02:59 -0400 Received: from moutng.kundenserver.de ([212.227.17.8]:64209 "EHLO moutng.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932188Ab1HaSC5 (ORCPT ); Wed, 31 Aug 2011 14:02:57 -0400 Received: from axis700.grange (dslb-094-221-100-032.pools.arcor-ip.net [94.221.100.32]) by mrelayeu.kundenserver.de (node=mrbap4) with ESMTP (Nemesis) id 0Lmc9z-1RXsgz3R4t-00ZzM8; Wed, 31 Aug 2011 20:02:51 +0200 Received: from 6a.grange (6a.grange [192.168.1.11]) by axis700.grange (Postfix) with ESMTPS id B799918B039; Wed, 31 Aug 2011 20:02:49 +0200 (CEST) Received: from lyakh by 6a.grange with local (Exim 4.72) (envelope-from ) id 1Qyp7h-0007Ea-At; Wed, 31 Aug 2011 20:02:49 +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/9 v6] V4L: sh-mobile-ceu-camera: prepare to support multi-size buffers Date: Wed, 31 Aug 2011 20:02:45 +0200 Message-Id: <1314813768-27752-7-git-send-email-g.liakhovetski@gmx.de> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1314813768-27752-1-git-send-email-g.liakhovetski@gmx.de> References: <1314813768-27752-1-git-send-email-g.liakhovetski@gmx.de> X-Provags-ID: V02:K0:CkKZqnk0plpqi8Cgm2pPW2CElO4IXd+i8pj+JHiuwRS aNuyxTnC4BC1xNpmd0kK3wpYEOHhcBDjcZOEQ1SY7FxvUurq+p N+xghtisvDFc+YT72cp5OezGN7z7lJxeMC8bljW01bO1ge0Mka 3QFflP+NYjJb1LjaHCdUF+hs1b2Wdl4eBKv3DriBtY6gk+itlH lbikSNl/ftKuu0yDKdH35yPK0zXyTkWu4KIWO2AH1v9iotvtOh TCUwq6gFDl5YQU6DdhSdAqX8u2BaHkD1EXBKLvm4VLV6Mk6oup SHpLyCBjdVnJcykuc7pxnMkOIVTM+Hze65XHPBw/qqp8ZngCFk xJpwU0zpmpZbYWg7iaBh0bm95eDN/TS5KBAq1dwg/WKUhwBNGI 2opENR7fy18wg== 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, 31 Aug 2011 18:03:04 +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 --- v6: Handle the case of VIDIOC_CREATE_BUFS, when vb2 creates fewer buffers, than requested by the user, correctly drivers/media/video/sh_mobile_ceu_camera.c | 122 ++++++++++++++++++---------- 1 files changed, 79 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..56bb82d 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,26 +206,45 @@ 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, - icd->current_fmt->host_fmt); + int bytes_per_line; + unsigned int height; + 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; - *num_planes = 1; + sizes[0] = bytes_per_line * height; - 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]); + /* If *num_planes != 0, we have already verified *count. */ + if (pcdev->video_limit && !*num_planes) { + size_t size = PAGE_ALIGN(sizes[0]) * *count; + + if (size + pcdev->buf_total > pcdev->video_limit) + *count = (pcdev->video_limit - pcdev->buf_total) / + PAGE_ALIGN(sizes[0]); } + *num_planes = 1; + dev_dbg(icd->parent, "count=%d, size=%lu\n", *count, sizes[0]); return 0; @@ -331,23 +356,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 +399,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 +412,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 +441,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 +559,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 +1710,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);