From patchwork Tue Mar 9 14:49:43 2010
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Pawel Osciak
X-Patchwork-Id: 84314
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o29EnrMe007458
for ;
Tue, 9 Mar 2010 14:49:53 GMT
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1754645Ab0CIOtv (ORCPT
);
Tue, 9 Mar 2010 09:49:51 -0500
Received: from mailout3.w1.samsung.com ([210.118.77.13]:23671 "EHLO
mailout3.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
with ESMTP id S1751813Ab0CIOtt (ORCPT
); Tue, 9 Mar 2010 09:49:49 -0500
MIME-version: 1.0
Content-transfer-encoding: 7BIT
Content-type: TEXT/PLAIN
Received: from eu_spt1 ([210.118.77.13]) by mailout3.w1.samsung.com
(Sun Java(tm) System Messaging Server 6.3-8.04 (built Jul 29 2009;
32bit))
with ESMTP id <0KZ000I4DRUYK750@mailout3.w1.samsung.com> for
linux-media@vger.kernel.org; Tue, 09 Mar 2010 14:49:47 +0000 (GMT)
Received: from linux.samsung.com ([106.116.38.10])
by spt1.w1.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built
Jul 14
2004)) with ESMTPA id <0KZ000AKKRUXB7@spt1.w1.samsung.com> for
linux-media@vger.kernel.org; Tue, 09 Mar 2010 14:49:46 +0000 (GMT)
Received: from localhost.localdomain (unknown [106.116.37.23])
by linux.samsung.com (Postfix) with ESMTP id BDFBF27004F; Tue,
09 Mar 2010 15:26:42 +0100 (CET)
Date: Tue, 09 Mar 2010 15:49:43 +0100
From: Pawel Osciak
Subject: [PATCH v2 3/3] v4l: vivi: add 2- and 3-planar YCbCr422
In-reply-to: <1268146183-2018-1-git-send-email-p.osciak@samsung.com>
To: linux-media@vger.kernel.org
Cc: p.osciak@samsung.com, m.szyprowski@samsung.com, kyungmin.park@samsung.com,
hverkuil@xs4all.nl
Message-id: <1268146183-2018-4-git-send-email-p.osciak@samsung.com>
X-Mailer: git-send-email 1.7.0
References: <1268146183-2018-1-git-send-email-p.osciak@samsung.com>
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.3 (demeter.kernel.org [140.211.167.41]);
Tue, 09 Mar 2010 14:49:54 +0000 (UTC)
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 37632a0..bc1ec0d 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -132,6 +132,9 @@ struct vivi_fmt {
char *name;
u32 fourcc; /* v4l2 format id */
int depth;
+ unsigned int num_planes;
+ unsigned int plane_w_shr;
+ unsigned int plane_h_shr;
};
static struct vivi_fmt formats[] = {
@@ -139,31 +142,53 @@ static struct vivi_fmt formats[] = {
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
+ .num_planes = 1,
},
{
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB555 (LE)",
.fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB555 (BE)",
.fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
.depth = 16,
+ .num_planes = 1,
+ },
+ {
+ .name = "YUV 4:2:2, 3-planar",
+ .fourcc = V4L2_PIX_FMT_YUV422PM,
+ .depth = 16,
+ .num_planes = 3,
+ .plane_w_shr = 1,
+ .plane_h_shr = 0,
+ },
+ {
+ .name = "YUV 4:2:2, 2-planar",
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .depth = 16,
+ .num_planes = 2,
+ .plane_w_shr = 1,
+ .plane_h_shr = 0,
},
};
@@ -361,6 +386,8 @@ static void precalculate_bars(struct vivi_fh *fh)
switch (fh->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUV422PM:
+ case V4L2_PIX_FMT_NV16M:
is_yuv = 1;
break;
case V4L2_PIX_FMT_RGB565:
@@ -410,6 +437,8 @@ static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
switch (fh->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YUV422PM:
+ case V4L2_PIX_FMT_NV16M:
switch (color) {
case 0:
case 2:
@@ -558,30 +587,58 @@ end:
static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
{
struct vivi_dev *dev = fh->dev;
- int h , pos = 0;
+ int i, x, h, curr_plane = 0, pos = 0;
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
- char *tmpbuf;
- void *vbuf = videobuf_to_vmalloc(&buf->vb);
+ char *tmpbuf, *p_tmpbuf;
+ char *vbuf[VIDEO_MAX_PLANES];
+
+ for (i = 0; i < fh->fmt->num_planes; ++i) {
+ vbuf[i] = videobuf_plane_to_vmalloc(&buf->vb, i);
+ if (!vbuf[i]) {
+ dprintk(dev, 1, "Failed acquiring vaddr for a plane\n");
+ return;
+ }
+ }
- if (!vbuf)
- return;
+ if (fh->fmt->num_planes > 1) {
+ tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ if (!tmpbuf)
+ return;
+
+ for (h = 0; h < hmax; h++) {
+ gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+ dev->timestr);
+ p_tmpbuf = tmpbuf;
+
+ for (x = 0; x < wmax; ++x) {
+ *(vbuf[0]++) = *p_tmpbuf++;
+ *(vbuf[curr_plane + 1]++) = *p_tmpbuf++;
+ if (V4L2_PIX_FMT_YUV422PM == fh->fmt->fourcc)
+ curr_plane = !curr_plane;
+ }
+ }
- tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
- if (!tmpbuf)
- return;
+ dev->mv_count++;
- for (h = 0; h < hmax; h++) {
- gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
- dev->timestr);
- memcpy(vbuf + pos, tmpbuf, wmax * 2);
- pos += wmax*2;
- }
+ kfree(tmpbuf);
+ } else {
+ tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ if (!tmpbuf)
+ return;
+
+ for (h = 0; h < hmax; h++) {
+ gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+ dev->timestr);
+ memcpy(vbuf[0] + pos, tmpbuf, wmax * 2);
+ pos += wmax*2;
+ }
- dev->mv_count++;
+ dev->mv_count++;
- kfree(tmpbuf);
+ kfree(tmpbuf);
+ }
/* Updates stream time */
@@ -708,8 +765,6 @@ static int vivi_start_thread(struct vivi_fh *fh)
dma_q->frame = 0;
dma_q->ini_jiffies = jiffies;
- dprintk(dev, 1, "%s\n", __func__);
-
dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
if (IS_ERR(dma_q->kthread)) {
@@ -719,7 +774,6 @@ static int vivi_start_thread(struct vivi_fh *fh)
/* Wakes thread */
wake_up_interruptible(&dma_q->wq);
- dprintk(dev, 1, "returning from %s\n", __func__);
return 0;
}
@@ -738,22 +792,66 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
/* ------------------------------------------------------------------
Videobuf operations
------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+static unsigned long get_plane_size(struct vivi_fh *fh, unsigned int plane)
{
- struct vivi_fh *fh = vq->priv_data;
- struct vivi_dev *dev = fh->dev;
+ unsigned long plane_size = 0;
+
+ if (plane >= fh->fmt->num_planes)
+ return 0;
+
+ if (1 == fh->fmt->num_planes) {
+ plane_size = fh->width * fh->height * 2;
+ } else {
+ if (0 == plane) {
+ plane_size = fh->width * fh->height;
+ } else {
+ plane_size = (fh->width >> 1) * fh->height;
+ if (2 == fh->fmt->num_planes)
+ plane_size *= 2;
+ }
+ }
+
+ return plane_size;
+}
+static int buffer_negotiate(struct videobuf_queue *vq, unsigned int *buf_count,
+ unsigned int *plane_count)
+{
+ struct vivi_fh *fh = vq->priv_data;
+ struct vivi_dev *dev = fh->dev;
+ unsigned int buf_size = 0;
+ unsigned int i;
+
+ *plane_count = fh->fmt->num_planes;
+
+ if (0 == *buf_count)
+ *buf_count = 32;
+
+ for (i = 0; i < fh->fmt->num_planes; ++i)
+ buf_size += get_plane_size(fh, i);
+
+ while (buf_size * *buf_count > vid_limit * 1024 * 1024)
+ (*buf_count)--;
+
+ dprintk(dev, 1, "%s, buffer count=%d, plane count=%d\n",
+ __func__, *buf_count, *plane_count);
- *size = fh->width*fh->height*2;
+ return 0;
+}
- if (0 == *count)
- *count = 32;
+static int buffer_setup_plane(struct videobuf_queue *vq, unsigned int plane,
+ unsigned int *plane_size)
+{
+ struct vivi_fh *fh = vq->priv_data;
+ struct vivi_dev *dev = fh->dev;
- while (*size * *count > vid_limit * 1024 * 1024)
- (*count)--;
+ if (plane >= fh->fmt->num_planes) {
+ dprintk(dev, 1, "%s, invalid plane=%d\n", __func__, plane);
+ return -EINVAL;
+ }
- dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
- *count, *size);
+ *plane_size = get_plane_size(fh, plane);
+ dprintk(dev, 1, "%s, plane=%d, size=%d\n",
+ __func__, plane, *plane_size);
return 0;
}
@@ -783,6 +881,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct vivi_dev *dev = fh->dev;
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
int rc;
+ unsigned int i;
dprintk(dev, 1, "%s, field=%d\n", __func__, field);
@@ -792,9 +891,17 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
fh->height < 32 || fh->height > norm_maxh())
return -EINVAL;
- buf->vb.size = fh->width*fh->height*2;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
+ for (i = 0; i < fh->fmt->num_planes; ++i) {
+ buf->vb.planes[i].size = get_plane_size(fh, i);
+
+ if (0 != buf->vb.planes[i].baddr
+ && buf->vb.planes[i].bsize < buf->vb.planes[i].size) {
+ dprintk(dev, 1, "%s, invalid plane %u size: (%d<%lu)\n",
+ __func__, i, buf->vb.planes[i].bsize,
+ buf->vb.planes[i].size);
+ return -EINVAL;
+ }
+ }
/* These properties only change when queue is idle, see s_fmt */
buf->fmt = fh->fmt;
@@ -846,7 +953,8 @@ static void buffer_release(struct videobuf_queue *vq,
}
static struct videobuf_queue_ops vivi_video_qops = {
- .buf_setup = buffer_setup,
+ .buf_negotiate = buffer_negotiate,
+ .buf_setup_plane = buffer_setup_plane,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
@@ -948,8 +1056,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct vivi_fh *fh = priv;
struct videobuf_queue *q = &fh->vb_vidq;
+ int ret;
- int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+ ret = vidioc_try_fmt_vid_cap(file, fh, f);
if (ret < 0)
return ret;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index bf3f33d..fbce9d7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -314,6 +314,8 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */
+#define V4L2_PIX_FMT_YUV422PM v4l2_fourcc('4', '2', '2', 'M') /* 16 YUV422 multiplane */
+
#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */
#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */
#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */
@@ -329,6 +331,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */
+#define V4L2_PIX_FMT_NV16M v4l2_fourcc('N', 'M', '1', '6') /* 16 Y/CbCr multiplane 4:2:2 */
#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */
/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */