drivers: camera: Fix v4l2 driver compliance
Bhanu Murthy V [Tue, 19 Jul 2016 01:00:42 +0000 (18:00 -0700)]
Fix s/g/query dv timings compliance, report not
supported if the sub device on CSI does not support
the timing fops.
Fix s/g crop fops for sub devices which does not
support cropping.
Fix subdev used in s/g param fops.

Bug 1675242
Bug 200214096

Change-Id: If262ca8038694ffb05273a99268b86984b1532c1
Signed-off-by: Bhanu Murthy V <bmurthyv@nvidia.com>
Reviewed-on: http://git-master/r/1183150
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>

drivers/media/platform/tegra/camera/channel.c

index 58993d7..e957363 100644 (file)
@@ -1048,6 +1048,9 @@ tegra_channel_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
        struct v4l2_subdev *sd = chan->subdev_on_csi;
 
+       if (!v4l2_subdev_has_op(sd, pad, get_edid))
+               return -ENOTTY;
+
        return v4l2_subdev_call(sd, pad, get_edid, edid);
 }
 
@@ -1058,6 +1061,9 @@ tegra_channel_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
        struct v4l2_subdev *sd = chan->subdev_on_csi;
 
+       if (!v4l2_subdev_has_op(sd, pad, set_edid))
+               return -ENOTTY;
+
        return v4l2_subdev_call(sd, pad, set_edid, edid);
 }
 
@@ -1070,6 +1076,9 @@ tegra_channel_s_dv_timings(struct file *file, void *fh,
        struct v4l2_bt_timings *bt = &timings->bt;
        int ret;
 
+       if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, s_dv_timings))
+               return -ENOTTY;
+
        ret = v4l2_device_call_until_err(chan->video.v4l2_dev,
                        chan->grp_id, video, s_dv_timings, timings);
 
@@ -1099,6 +1108,9 @@ tegra_channel_g_dv_timings(struct file *file, void *fh,
        struct v4l2_fh *vfh = file->private_data;
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
 
+       if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, g_dv_timings))
+               return -ENOTTY;
+
        return v4l2_device_call_until_err(chan->video.v4l2_dev,
                        chan->grp_id, video, g_dv_timings, timings);
 }
@@ -1110,6 +1122,9 @@ tegra_channel_query_dv_timings(struct file *file, void *fh,
        struct v4l2_fh *vfh = file->private_data;
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
 
+       if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, query_dv_timings))
+               return -ENOTTY;
+
        return v4l2_device_call_until_err(chan->video.v4l2_dev,
                        chan->grp_id, video, query_dv_timings, timings);
 }
@@ -1122,6 +1137,9 @@ tegra_channel_enum_dv_timings(struct file *file, void *fh,
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
        struct v4l2_subdev *sd = chan->subdev_on_csi;
 
+       if (!v4l2_subdev_has_op(sd, pad, enum_dv_timings))
+               return -ENOTTY;
+
        return v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
 }
 
@@ -1133,6 +1151,9 @@ tegra_channel_dv_timings_cap(struct file *file, void *fh,
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
        struct v4l2_subdev *sd = chan->subdev_on_csi;
 
+       if (!v4l2_subdev_has_op(sd, pad, dv_timings_cap))
+               return -ENOTTY;
+
        return v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
 }
 
@@ -1408,18 +1429,16 @@ static int tegra_channel_s_crop(struct file *file, void *fh,
 {
        struct v4l2_fh *vfh = file->private_data;
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
-       struct v4l2_subdev *subdev = NULL;
-       int num_sd = 0;
+       struct v4l2_subdev *subdev = chan->subdev_on_csi;
        int ret = 0;
 
-       while ((subdev = chan->subdev[num_sd++]) &&
-               (num_sd <= chan->num_subdevs)) {
-               ret = v4l2_subdev_call(subdev, video, s_crop, crop);
-               if (ret < 0 && ret != -ENOIOCTLCMD)
-                       return ret;
-       }
+       if (!v4l2_subdev_has_op(subdev, video, s_crop))
+               return -ENOTTY;
 
-       return 0;
+       ret = v4l2_device_call_until_err(chan->video.v4l2_dev,
+                       chan->grp_id, video, s_crop, crop);
+
+       return ret;
 }
 
 static int tegra_channel_g_crop(struct file *file, void *fh,
@@ -1427,18 +1446,16 @@ static int tegra_channel_g_crop(struct file *file, void *fh,
 {
        struct v4l2_fh *vfh = file->private_data;
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
-       struct v4l2_subdev *subdev = NULL;
-       int num_sd = 0;
+       struct v4l2_subdev *subdev = chan->subdev_on_csi;
        int ret = 0;
 
-       while ((subdev = chan->subdev[num_sd++]) &&
-               (num_sd <= chan->num_subdevs)) {
-               ret = v4l2_subdev_call(subdev, video, g_crop, crop);
-               if (ret < 0 && ret != -ENOIOCTLCMD)
-                       return ret;
-       }
+       if (!v4l2_subdev_has_op(subdev, video, g_crop))
+               return -ENOTTY;
 
-       return 0;
+       ret = v4l2_device_call_until_err(chan->video.v4l2_dev,
+                       chan->grp_id, video, g_crop, crop);
+
+       return ret;
 }
 
 static int tegra_channel_subscribe_event(struct v4l2_fh *fh,
@@ -1503,7 +1520,7 @@ static int tegra_channel_g_parm(struct file *file, void *fh,
 {
        struct v4l2_fh *vfh = file->private_data;
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
-       struct v4l2_subdev *subdev = chan->subdev[0];
+       struct v4l2_subdev *subdev = chan->subdev_on_csi;
        int ret = 0;
 
        ret = v4l2_subdev_call(subdev, video, g_parm, parm);
@@ -1518,7 +1535,7 @@ static int tegra_channel_s_parm(struct file *file, void *fh,
 {
        struct v4l2_fh *vfh = file->private_data;
        struct tegra_channel *chan = to_tegra_channel(vfh->vdev);
-       struct v4l2_subdev *subdev = chan->subdev[0];
+       struct v4l2_subdev *subdev = chan->subdev_on_csi;
        int ret = 0;
 
        ret = v4l2_subdev_call(subdev, video, s_parm, parm);