The vim2m device is interesting to simulate a webcam. As most
sensors are arranged using bayer formats, the best is to support
to output data using those formats.

So, add support for them.

All 4 8-bit bayer formats tested with:

        $ qvidcap -p &
        $ v4l2-ctl --stream-mmap --stream-out-mmap --stream-to-host localhost 
--stream-lossless --stream-out-hor-speed 1 -v pixelformat=RGGB

Signed-off-by: Mauro Carvalho Chehab <mchehab+sams...@kernel.org>
---
 drivers/media/platform/vim2m.c | 97 ++++++++++++++++++++++++++++++++--
 1 file changed, 92 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index e31c14c7d37f..6240878def80 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -82,24 +82,47 @@ static struct platform_device vim2m_pdev = {
 struct vim2m_fmt {
        u32     fourcc;
        int     depth;
+       /* Types the format can be used for */
+       u32     types;
 };
 
 static struct vim2m_fmt formats[] = {
        {
                .fourcc = V4L2_PIX_FMT_RGB565,  /* rrrrrggg gggbbbbb */
                .depth  = 16,
+               .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
        }, {
                .fourcc = V4L2_PIX_FMT_RGB565X, /* gggbbbbb rrrrrggg */
                .depth  = 16,
+               .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
        }, {
                .fourcc = V4L2_PIX_FMT_RGB24,
                .depth  = 24,
+               .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
        }, {
                .fourcc = V4L2_PIX_FMT_BGR24,
                .depth  = 24,
+               .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
        }, {
                .fourcc = V4L2_PIX_FMT_YUYV,
                .depth  = 16,
+               .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SBGGR8,
+               .depth  = 8,
+               .types  = MEM2MEM_CAPTURE,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGBRG8,
+               .depth  = 8,
+               .types  = MEM2MEM_CAPTURE,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGRBG8,
+               .depth  = 8,
+               .types  = MEM2MEM_CAPTURE,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SRGGB8,
+               .depth  = 8,
+               .types  = MEM2MEM_CAPTURE,
        },
 };
 
@@ -208,7 +231,7 @@ static struct vim2m_q_data *get_q_data(struct vim2m_ctx 
*ctx,
        (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color)))
 
 static void copy_two_pixels(struct vim2m_fmt *in, struct vim2m_fmt *out,
-                           u8 **src, u8 **dst, bool reverse)
+                           u8 **src, u8 **dst, int y, bool reverse)
 {
        u8 _r[2], _g[2], _b[2], *r, *g, *b;
        int i, step;
@@ -379,7 +402,8 @@ static void copy_two_pixels(struct vim2m_fmt *in, struct 
vim2m_fmt *out,
                        *(*dst)++ = *r++;
                }
                return;
-       default: /* V4L2_PIX_FMT_YUYV */
+       case V4L2_PIX_FMT_YUYV:
+       default:
        {
                u8 y, y1, u, v;
 
@@ -399,6 +423,42 @@ static void copy_two_pixels(struct vim2m_fmt *in, struct 
vim2m_fmt *out,
                *(*dst)++ = v;
                return;
        }
+       case V4L2_PIX_FMT_SBGGR8:
+               if (!(y & 1)) {
+                       *(*dst)++ = *b;
+                       *(*dst)++ = *++g;
+               } else {
+                       *(*dst)++ = *g;
+                       *(*dst)++ = *++r;
+               }
+               return;
+       case V4L2_PIX_FMT_SGBRG8:
+               if (!(y & 1)) {
+                       *(*dst)++ = *g;
+                       *(*dst)++ = *++b;
+               } else {
+                       *(*dst)++ = *r;
+                       *(*dst)++ = *++g;
+               }
+               return;
+       case V4L2_PIX_FMT_SGRBG8:
+               if (!(y & 1)) {
+                       *(*dst)++ = *g;
+                       *(*dst)++ = *++r;
+               } else {
+                       *(*dst)++ = *b;
+                       *(*dst)++ = *++g;
+               }
+               return;
+       case V4L2_PIX_FMT_SRGGB8:
+               if (!(y & 1)) {
+                       *(*dst)++ = *r;
+                       *(*dst)++ = *++g;
+               } else {
+                       *(*dst)++ = *g;
+                       *(*dst)++ = *++b;
+               }
+               return;
        }
 }
 
@@ -449,7 +509,7 @@ static int device_process(struct vim2m_ctx *ctx,
                        p += bytesperline - (q_data_in->fmt->depth >> 3);
 
                for (x = 0; x < width >> 1; x++)
-                       copy_two_pixels(in, out, &p, &p_out,
+                       copy_two_pixels(in, out, &p, &p_out, y,
                                        ctx->mode & MEM2MEM_HFLIP);
        }
 
@@ -562,11 +622,25 @@ static int vidioc_querycap(struct file *file, void *priv,
 
 static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
 {
+       int i, num;
        struct vim2m_fmt *fmt;
 
-       if (f->index < NUM_FORMATS) {
+       num = 0;
+
+       for (i = 0; i < NUM_FORMATS; ++i) {
+               if (formats[i].types & type) {
+                       /* index-th format of type type found ? */
+                       if (num == f->index)
+                               break;
+                       /* Correct type but haven't reached our index yet,
+                        * just increment per-type index */
+                       ++num;
+               }
+       }
+
+       if (i < NUM_FORMATS) {
                /* Format found */
-               fmt = &formats[f->index];
+               fmt = &formats[i];
                f->pixelformat = fmt->fourcc;
                return 0;
        }
@@ -657,6 +731,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void 
*priv,
                f->fmt.pix.pixelformat = formats[0].fourcc;
                fmt = find_format(f);
        }
+       if (!(fmt->types & MEM2MEM_CAPTURE)) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "Fourcc format (0x%08x) invalid.\n",
+                        f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
        f->fmt.pix.colorspace = ctx->colorspace;
        f->fmt.pix.xfer_func = ctx->xfer_func;
        f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
@@ -669,12 +749,19 @@ static int vidioc_try_fmt_vid_out(struct file *file, void 
*priv,
                                  struct v4l2_format *f)
 {
        struct vim2m_fmt *fmt;
+       struct vim2m_ctx *ctx = file2ctx(file);
 
        fmt = find_format(f);
        if (!fmt) {
                f->fmt.pix.pixelformat = formats[0].fourcc;
                fmt = find_format(f);
        }
+       if (!(fmt->types & MEM2MEM_OUTPUT)) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "Fourcc format (0x%08x) invalid.\n",
+                        f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
        if (!f->fmt.pix.colorspace)
                f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
 
-- 
2.20.1

Reply via email to