Add 'struct media_pad pad' member and suitable glue code, so that
soc_camera/rcar_vin can become agnostic to whether an old or new-
style driver (wrt pad API use) can sit underneath

This version has been reworked to include appropriate constant and
datatype names for kernel v3.18
---
 drivers/media/platform/soc_camera/soc_camera.c     |  148 +++++++++++++++++++-
 drivers/media/platform/soc_camera/soc_scale_crop.c |   43 +++++-
 include/media/soc_camera.h                         |    1 +
 3 files changed, 182 insertions(+), 10 deletions(-)

diff --git a/drivers/media/platform/soc_camera/soc_camera.c 
b/drivers/media/platform/soc_camera/soc_camera.c
index f4be2a1..efc20bf 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -37,8 +37,11 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-of.h>
+#if 0
 #include <media/videobuf-core.h>
 #include <media/videobuf2-core.h>
+#endif
+#include <media/v4l2-mediabus.h>
 
 /* Default to VGA resolution */
 #define DEFAULT_WIDTH  640
@@ -453,6 +456,98 @@ static int soc_camera_expbuf(struct file *file, void *priv,
                return vb2_expbuf(&icd->vb2_vidq, p);
 }
 
+static int soc_camera_init_user_formats_pad(struct soc_camera_device *icd, int 
src_pad_idx)
+{
+       struct v4l2_subdev *sd= soc_camera_to_subdev(icd);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct v4l2_subdev_mbus_code_enum code;
+       int fmts= 0, raw_fmts, i, ret;
+
+       code.pad= src_pad_idx;
+       code.index= 0;
+
+       // subdev_has_op -> enum_mbus_code vs enum_mbus_fmt
+       if (v4l2_subdev_has_op(sd, pad, enum_mbus_code)) {
+               while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code))
+                       code.index++;
+       } else {
+               u32 pixcode;
+
+               while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, code.index, 
&pixcode))
+               {
+                       code.code= pixcode;
+                       code.index++;
+               }
+       }
+       raw_fmts= code.index;
+
+       if (!ici->ops->get_formats) {
+               /*
+                * Fallback mode - the host will have to serve all
+                * sensor-provided formats one-to-one to the user
+                */
+               fmts = raw_fmts;
+       }
+       else {
+               /*
+                * First pass - only count formats this host-sensor
+                * configuration can provide
+                */
+               for (i = 0; i < raw_fmts; i++) {
+                       int ret = ici->ops->get_formats(icd, i, NULL);
+                       if (ret < 0)
+                               return ret;
+                       fmts += ret;
+               }
+       }
+
+       if (!fmts)
+               return -ENXIO;
+
+       icd->user_formats =
+               vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+       if (!icd->user_formats)
+               return -ENOMEM;
+
+       dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts);
+
+       /* Second pass - actually fill data formats */
+       fmts = 0;
+       for (i = 0; i < raw_fmts; i++) {
+               if (!ici->ops->get_formats) {
+                       code.index= i;
+                       // subdev_has_op -> enum_mbus_code vs enum_mbus_fmt
+                       if (v4l2_subdev_has_op(sd, pad, enum_mbus_code)) {
+                               v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, 
&code);
+                       } else {
+                               u32 pixcode;
+
+                               v4l2_subdev_call(sd, video, enum_mbus_fmt, 
code.index, &pixcode);
+                               code.code= pixcode;
+                       }
+                       icd->user_formats[fmts].host_fmt =
+                               soc_mbus_get_fmtdesc(code.code);
+                       if (icd->user_formats[fmts].host_fmt)
+                               icd->user_formats[fmts++].code = code.code;
+               } else {
+                       ret = ici->ops->get_formats(icd, i,
+                                                   &icd->user_formats[fmts]);
+                       if (ret < 0)
+                               goto egfmt;
+                       fmts += ret;
+               }
+       }
+
+       icd->num_user_formats = fmts;
+       icd->current_fmt = &icd->user_formats[0];
+
+       return 0;
+
+egfmt:
+       vfree(icd->user_formats);
+       return ret;
+}
+
 /* Always entered with .host_lock held */
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
@@ -1289,6 +1384,7 @@ static int soc_camera_probe_finish(struct 
soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct v4l2_mbus_framefmt mf;
+       int src_pad_idx= -1;
        int ret;
 
        sd->grp_id = soc_camera_grp_id(icd);
@@ -1307,7 +1403,30 @@ static int soc_camera_probe_finish(struct 
soc_camera_device *icd)
        }
 
        /* At this point client .probe() should have run already */
-       ret = soc_camera_init_user_formats(icd);
+       // subdev_has_op -> enum_mbus_code vs enum_mbus_fmt
+       if (!v4l2_subdev_has_op(sd, pad, enum_mbus_code))
+               ret = soc_camera_init_user_formats(icd);
+       else {
+               ret = media_entity_init(&icd->vdev->entity, 1,
+                                       &icd->pad, 0);
+               if (!ret) {
+                       for (src_pad_idx= 0; src_pad_idx < sd->entity.num_pads; 
src_pad_idx++)
+                               if (sd->entity.pads[src_pad_idx].flags == 
MEDIA_PAD_FL_SOURCE)
+                                       break;
+
+                       if (src_pad_idx < sd->entity.num_pads) {
+                               ret = media_entity_create_link(
+                                       &icd->vdev->entity, 0,
+                                       &sd->entity, src_pad_idx,
+                                       MEDIA_LNK_FL_IMMUTABLE |
+                                       MEDIA_LNK_FL_ENABLED);
+                       }
+               }
+
+               if (!ret)
+                       ret = soc_camera_init_user_formats_pad(icd,
+                                                       src_pad_idx);
+       }
        if (ret < 0)
                goto eusrfmt;
 
@@ -1318,11 +1437,28 @@ static int soc_camera_probe_finish(struct 
soc_camera_device *icd)
                goto evidstart;
 
        /* Try to improve our guess of a reasonable window format */
-       if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
-               icd->user_width         = mf.width;
-               icd->user_height        = mf.height;
-               icd->colorspace         = mf.colorspace;
-               icd->field              = mf.field;
+       // subdev_has_op -> get_fmt vs g_mbus_fmt
+       if (v4l2_subdev_has_op(sd, pad, enum_mbus_code)
+               && v4l2_subdev_has_op(sd, pad, get_fmt)
+               && src_pad_idx != -1) {
+               struct v4l2_subdev_format sd_format;
+
+               sd_format.pad= src_pad_idx;
+               sd_format.which= V4L2_SUBDEV_FORMAT_ACTIVE;
+
+               if (!v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_format)) {
+                       icd->user_width         = sd_format.format.width;
+                       icd->user_height        = sd_format.format.height;
+                       icd->colorspace         = sd_format.format.colorspace;
+                       icd->field              = sd_format.format.field;
+               }
+       } else {
+               if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
+                       icd->user_width         = mf.width;
+                       icd->user_height        = mf.height;
+                       icd->colorspace         = mf.colorspace;
+                       icd->field              = mf.field;
+               }
        }
        soc_camera_remove_device(icd);
 
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c 
b/drivers/media/platform/soc_camera/soc_scale_crop.c
index 8e74fb7..8a1ca05 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -224,9 +224,27 @@ static int client_s_fmt(struct soc_camera_device *icd,
        bool host_1to1;
        int ret;
 
-       ret = v4l2_device_call_until_err(sd->v4l2_dev,
-                                        soc_camera_grp_id(icd), video,
-                                        s_mbus_fmt, mf);
+       // subdev_has_op -> set_fmt vs s_mbus_fmt
+       if (v4l2_subdev_has_op(sd, pad, set_fmt)) {
+               struct v4l2_subdev_format sd_format;
+               struct media_pad *remote_pad;
+
+               remote_pad= media_entity_remote_pad(
+                       &icd->vdev->entity.pads[0]);
+               sd_format.pad = remote_pad->index;
+               sd_format.which= V4L2_SUBDEV_FORMAT_ACTIVE;
+               sd_format.format= *mf;
+
+               ret = v4l2_device_call_until_err(sd->v4l2_dev,
+                       soc_camera_grp_id(icd), pad, set_fmt, NULL,
+                       &sd_format);
+
+               mf->width = sd_format.format.width;
+               mf->height = sd_format.format.height;
+       } else {
+               ret = v4l2_device_call_until_err(sd->v4l2_dev,
+                        soc_camera_grp_id(icd), video, s_mbus_fmt, mf);
+       }
        if (ret < 0)
                return ret;
 
@@ -264,9 +282,26 @@ static int client_s_fmt(struct soc_camera_device *icd,
                tmp_h = min(2 * tmp_h, max_height);
                mf->width = tmp_w;
                mf->height = tmp_h;
-               ret = v4l2_device_call_until_err(sd->v4l2_dev,
+               // subdev_has_op -> set_fmt vs s_mbus_fmt
+               if (v4l2_subdev_has_op(sd, pad, set_fmt)) {
+                       struct v4l2_subdev_format sd_format;
+                       struct media_pad *remote_pad;
+
+                       remote_pad= media_entity_remote_pad(
+                               &icd->vdev->entity.pads[0]);
+                       sd_format.pad = remote_pad->index;
+                       sd_format.which= V4L2_SUBDEV_FORMAT_ACTIVE;
+                       sd_format.format= *mf;
+
+                       ret = v4l2_device_call_until_err(sd->v4l2_dev,
+                                       soc_camera_grp_id(icd),
+                                       pad, set_fmt, NULL,
+                                       &sd_format);
+               } else {
+                       ret = v4l2_device_call_until_err(sd->v4l2_dev,
                                        soc_camera_grp_id(icd), video,
                                        s_mbus_fmt, mf);
+               }
                dev_geo(dev, "Camera scaled to %ux%u\n",
                        mf->width, mf->height);
                if (ret < 0) {
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 2f6261f..f0c5238 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -42,6 +42,7 @@ struct soc_camera_device {
        unsigned char devnum;           /* Device number per host */
        struct soc_camera_sense *sense; /* See comment in struct definition */
        struct video_device *vdev;
+       struct media_pad pad;
        struct v4l2_ctrl_handler ctrl_handler;
        const struct soc_camera_format_xlate *current_fmt;
        struct soc_camera_format_xlate *user_formats;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to