V4L/DVB (10711): zoran: fix TRY_FMT support

Actually try to turn the format into something usable rather than just
rejecting it if it isn't perfect.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 18834b1..774717b 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -835,7 +835,8 @@
 
 int
 zoran_check_jpg_settings (struct zoran              *zr,
-			  struct zoran_jpg_settings *settings)
+			  struct zoran_jpg_settings *settings,
+			  int try)
 {
 	int err = 0, err0 = 0;
 
@@ -900,35 +901,61 @@
 		/* We have to check the data the user has set */
 
 		if (settings->HorDcm != 1 && settings->HorDcm != 2 &&
-		    (zr->card.type == DC10_new || settings->HorDcm != 4))
+		    (zr->card.type == DC10_new || settings->HorDcm != 4)) {
+			settings->HorDcm = clamp(settings->HorDcm, 1, 2);
 			err0++;
-		if (settings->VerDcm != 1 && settings->VerDcm != 2)
+		}
+		if (settings->VerDcm != 1 && settings->VerDcm != 2) {
+			settings->VerDcm = clamp(settings->VerDcm, 1, 2);
 			err0++;
-		if (settings->TmpDcm != 1 && settings->TmpDcm != 2)
+		}
+		if (settings->TmpDcm != 1 && settings->TmpDcm != 2) {
+			settings->TmpDcm = clamp(settings->TmpDcm, 1, 2);
 			err0++;
+		}
 		if (settings->field_per_buff != 1 &&
-		    settings->field_per_buff != 2)
+		    settings->field_per_buff != 2) {
+			settings->field_per_buff = clamp(settings->field_per_buff, 1, 2);
 			err0++;
-		if (settings->img_x < 0)
+		}
+		if (settings->img_x < 0) {
+			settings->img_x = 0;
 			err0++;
-		if (settings->img_y < 0)
+		}
+		if (settings->img_y < 0) {
+			settings->img_y = 0;
 			err0++;
-		if (settings->img_width < 0)
+		}
+		if (settings->img_width < 0 || settings->img_width > BUZ_MAX_WIDTH) {
+			settings->img_width = clamp(settings->img_width, 0, (int)BUZ_MAX_WIDTH);
 			err0++;
-		if (settings->img_height < 0)
+		}
+		if (settings->img_height < 0 || settings->img_height > BUZ_MAX_HEIGHT / 2) {
+			settings->img_height = clamp(settings->img_height, 0, BUZ_MAX_HEIGHT / 2);
 			err0++;
-		if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH)
+		}
+		if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH) {
+			settings->img_x = BUZ_MAX_WIDTH - settings->img_width;
 			err0++;
-		if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2)
+		}
+		if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2) {
+			settings->img_y = BUZ_MAX_HEIGHT / 2 - settings->img_height;
 			err0++;
-		if (settings->HorDcm && settings->VerDcm) {
-			if (settings->img_width % (16 * settings->HorDcm) != 0)
-				err0++;
-			if (settings->img_height % (8 * settings->VerDcm) != 0)
-				err0++;
+		}
+		if (settings->img_width % (16 * settings->HorDcm) != 0) {
+			settings->img_width -= settings->img_width % (16 * settings->HorDcm);
+			if (settings->img_width == 0)
+				settings->img_width = 16 * settings->HorDcm;
+			err0++;
+		}
+		if (settings->img_height % (8 * settings->VerDcm) != 0) {
+			settings->img_height -= settings->img_height % (8 * settings->VerDcm);
+			if (settings->img_height == 0)
+				settings->img_height = 8 * settings->VerDcm;
+			err0++;
 		}
 
-		if (err0) {
+		if (!try && err0) {
 			dprintk(1,
 				KERN_ERR
 				"%s: check_jpg_settings() - error in params for decimation = 0\n",
@@ -1018,7 +1045,7 @@
 	       sizeof(zr->jpg_settings.jpg_comp.COM_data));
 	zr->jpg_settings.jpg_comp.jpeg_markers =
 	    JPEG_MARKER_DHT | JPEG_MARKER_DQT;
-	i = zoran_check_jpg_settings(zr, &zr->jpg_settings);
+	i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0);
 	if (i)
 		dprintk(1,
 			KERN_ERR
diff --git a/drivers/media/video/zoran/zoran_card.h b/drivers/media/video/zoran/zoran_card.h
index 4507bdc..4936fea 100644
--- a/drivers/media/video/zoran/zoran_card.h
+++ b/drivers/media/video/zoran/zoran_card.h
@@ -44,7 +44,8 @@
 extern struct video_device zoran_template;
 
 extern int zoran_check_jpg_settings(struct zoran *zr,
-				    struct zoran_jpg_settings *settings);
+				    struct zoran_jpg_settings *settings,
+				    int try);
 extern void zoran_open_init_params(struct zoran *zr);
 extern void zoran_vdev_release(struct video_device *vdev);
 
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 0cce652..cdfd3cc 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -1797,7 +1797,7 @@
 
 		/* Check the params first before overwriting our
 		 * nternal values */
-		if (zoran_check_jpg_settings(zr, &settings)) {
+		if (zoran_check_jpg_settings(zr, &settings, 0)) {
 			res = -EINVAL;
 			goto sparams_unlock_and_return;
 		}
@@ -2205,7 +2205,7 @@
 		settings.field_per_buff = 1;
 
 	/* check */
-	res = zoran_check_jpg_settings(zr, &settings);
+	res = zoran_check_jpg_settings(zr, &settings, 1);
 	if (res)
 		goto tryfmt_unlock_and_return;
 
@@ -2231,6 +2231,7 @@
 {
 	struct zoran_fh *fh = __fh;
 	struct zoran *zr = fh->zr;
+	int bpp;
 	int i;
 
 	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
@@ -2247,6 +2248,8 @@
 		return -EINVAL;
 	}
 
+	bpp = (zoran_formats[i].depth + 7) / 8;
+	fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3);
 	if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
 		fmt->fmt.pix.width = BUZ_MAX_WIDTH;
 	if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
@@ -2334,8 +2337,16 @@
 	else
 		settings.field_per_buff = 1;
 
+	if (settings.HorDcm > 1) {
+		settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+		settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+	} else {
+		settings.img_x = 0;
+		settings.img_width = BUZ_MAX_WIDTH;
+	}
+
 	/* check */
-	res = zoran_check_jpg_settings(zr, &settings);
+	res = zoran_check_jpg_settings(zr, &settings, 0);
 	if (res)
 		goto sfmtjpg_unlock_and_return;
 
@@ -3216,7 +3227,7 @@
 	settings.img_height = crop->c.height;
 
 	/* check validity */
-	res = zoran_check_jpg_settings(zr, &settings);
+	res = zoran_check_jpg_settings(zr, &settings, 0);
 	if (res)
 		goto scrop_unlock_and_return;
 
@@ -3278,7 +3289,7 @@
 		goto sjpegc_unlock_and_return;
 	}
 
-	res = zoran_check_jpg_settings(zr, &settings);
+	res = zoran_check_jpg_settings(zr, &settings, 0);
 	if (res)
 		goto sjpegc_unlock_and_return;
 	if (!fh->jpg_buffers.allocated)