media: camss: Make use of V4L2_CAP_IO_MC
authorAndrey Konovalov <andrey.konovalov@linaro.org>
Fri, 14 Aug 2020 20:54:01 +0000 (22:54 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Sat, 29 Aug 2020 06:17:40 +0000 (08:17 +0200)
Implement mbus_code filtering for format enumeration.

Without this patch libcamera errors out with:
"ERROR V4L2 v4l2_videodevice.cpp:982 /dev/video0[cap]: Media bus code
filtering not supported by the device"

Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/platform/qcom/camss/camss-video.c

index 0e2fcee..322532f 100644 (file)
@@ -529,17 +529,16 @@ static int video_querycap(struct file *file, void *fh,
        return 0;
 }
 
-static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+/*
+ *  Returns the index in the video->formats[] array of the element which
+ *  has the "ndx"th unique value of pixelformat field.
+ *  If not found (no more unique pixelformat's) returns -EINVAL.
+ */
+static int video_get_unique_pixelformat_by_index(struct camss_video *video,
+                                                int ndx)
 {
-       struct camss_video *video = video_drvdata(file);
        int i, j, k;
 
-       if (f->type != video->type)
-               return -EINVAL;
-
-       if (f->index >= video->nformats)
-               return -EINVAL;
-
        /* find index "i" of "k"th unique pixelformat in formats array */
        k = -1;
        for (i = 0; i < video->nformats; i++) {
@@ -552,11 +551,53 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
                if (j == i)
                        k++;
 
-               if (k == f->index)
-                       break;
+               if (k == ndx)
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+/*
+ *  Returns the index in the video->formats[] array of the element which
+ *  has code equal to mcode.
+ *  If not found returns -EINVAL.
+ */
+static int video_get_pixelformat_by_mbus_code(struct camss_video *video,
+                                             u32 mcode)
+{
+       int i;
+
+       for (i = 0; i < video->nformats; i++) {
+               if (video->formats[i].code == mcode)
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+       struct camss_video *video = video_drvdata(file);
+       int i;
+
+       if (f->type != video->type)
+               return -EINVAL;
+
+       if (f->index >= video->nformats)
+               return -EINVAL;
+
+       if (f->mbus_code) {
+               /* Each entry in formats[] table has unique mbus_code */
+               if (f->index > 0)
+                       return -EINVAL;
+
+               i = video_get_pixelformat_by_mbus_code(video, f->mbus_code);
+       } else {
+               i = video_get_unique_pixelformat_by_index(video, f->index);
        }
 
-       if (k < f->index)
+       if (i < 0)
                return -EINVAL;
 
        f->pixelformat = video->formats[i].pixelformat;
@@ -911,8 +952,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
        }
 
        vdev->fops = &msm_vid_fops;
-       vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING |
-                                                       V4L2_CAP_READWRITE;
+       vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING
+                         | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC;
        vdev->ioctl_ops = &msm_vid_ioctl_ops;
        vdev->release = msm_video_release;
        vdev->v4l2_dev = v4l2_dev;