From 7ec008222fcb4682fa2cfdbb62e657bf98950ec5 Mon Sep 17 00:00:00 2001
From: Naushir Patuck <naush@raspberrypi.com>
Date: Tue, 19 May 2020 15:56:47 +0100
Subject: [PATCH] staging: vc04_services: isp: Fixup g/s_selection
 implementation

Add V4L2_SEL_TGT_CROP_DEFAULT and V4L2_SEL_TGT_CROP_BOUND targets.
Disable the appropriate ioctls for the meta capture nodes - this now
passes v4l2-compliance tests.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 .../bcm2835-isp/bcm2835-v4l2-isp.c            | 84 ++++++++++++-------
 1 file changed, 55 insertions(+), 29 deletions(-)

--- a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c
+++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c
@@ -1006,15 +1006,32 @@ static int bcm2835_isp_node_s_selection(
 	if (!s->r.width || !s->r.height)
 		return -EINVAL;
 
-	/* Adjust the crop window if goes outside the frame dimensions. */
-	s->r.left = min((unsigned int)max(s->r.left, 0),
-			node->q_data.width - MIN_DIM);
-	s->r.top = min((unsigned int)max(s->r.top, 0),
-		       node->q_data.height - MIN_DIM);
-	s->r.width = max(min(s->r.width, node->q_data.width - s->r.left),
-			 MIN_DIM);
-	s->r.height = max(min(s->r.height, node->q_data.height - s->r.top),
-			  MIN_DIM);
+	/* We can only set crop on the input. */
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * Adjust the crop window if it goes outside of the frame
+		 * dimensions.
+		 */
+		s->r.left = min((unsigned int)max(s->r.left, 0),
+				node->q_data.width - MIN_DIM);
+		s->r.top = min((unsigned int)max(s->r.top, 0),
+			       node->q_data.height - MIN_DIM);
+		s->r.width = max(min(s->r.width,
+				     node->q_data.width - s->r.left), MIN_DIM);
+		s->r.height = max(min(s->r.height,
+				      node->q_data.height - s->r.top), MIN_DIM);
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		/* Default (i.e. no) crop window. */
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = node->q_data.width;
+		s->r.height = node->q_data.height;
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	crop.rect.x = s->r.left;
 	crop.rect.y = s->r.top;
@@ -1029,33 +1046,40 @@ static int bcm2835_isp_node_s_selection(
 static int bcm2835_isp_node_g_selection(struct file *file, void *fh,
 					struct v4l2_selection *s)
 {
+	struct mmal_parameter_crop crop;
 	struct bcm2835_isp_node *node = video_drvdata(file);
-	struct bcm2835_isp_dev *dev = node_get_dev(node);
 	struct vchiq_mmal_port *port = get_port_data(node);
-	struct mmal_parameter_crop crop;
+	struct bcm2835_isp_dev *dev = node_get_dev(node);
 	u32 crop_size = sizeof(crop);
 	int ret;
 
-	/* This return value is required for V4L2 compliance. */
-	if (node_is_stats(node))
-		return -ENOTTY;
-
 	/* We can only return out an input crop. */
-	if (s->target != V4L2_SEL_TGT_CROP)
-		return -EINVAL;
-
-	ret = vchiq_mmal_port_parameter_get(dev->mmal_instance, port,
-					    MMAL_PARAMETER_CROP,
-					    &crop, &crop_size);
-	if (!ret)
-		return -EINVAL;
-
-	s->r.left = crop.rect.x;
-	s->r.top = crop.rect.y;
-	s->r.width = crop.rect.width;
-	s->r.height = crop.rect.height;
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		ret = vchiq_mmal_port_parameter_get(dev->mmal_instance, port,
+						    MMAL_PARAMETER_CROP,
+						    &crop, &crop_size);
+		if (!ret) {
+			s->r.left = crop.rect.x;
+			s->r.top = crop.rect.y;
+			s->r.width = crop.rect.width;
+			s->r.height = crop.rect.height;
+		}
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		/* Default (i.e. no) crop window. */
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = node->q_data.width;
+		s->r.height = node->q_data.height;
+		ret = 0;
+		break;
+	default:
+		ret =  -EINVAL;
+	}
 
-	return 0;
+	return ret;
 }
 
 static int bcm3285_isp_subscribe_event(struct v4l2_fh *fh,
@@ -1218,6 +1242,8 @@ static int register_node(struct bcm2835_
 		node->vfl_dir = VFL_DIR_RX;
 		node->name = "stats";
 		v4l2_disable_ioctl(&node->vfd, VIDIOC_S_CTRL);
+		v4l2_disable_ioctl(&node->vfd, VIDIOC_S_SELECTION);
+		v4l2_disable_ioctl(&node->vfd, VIDIOC_G_SELECTION);
 		break;
 	}
 
