[PATCH] saa6752hs: resolutions handling

This patch handles the VIDIOC_S_FMT and VIDIOC_G_FMT ioctls for the
saa6752hs.

As only 4 preset video formats are supported (SIF, 1/2D1, 2/3D1, D1), we
compute to which the asked resolution is the nearest and apply it.

Signed-off-by: Frederic Cand <frederic.cand@anevia.com>
Acked-by: Gerd Knorr <kraxel@bytesex.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index cee1358..fe6abe3 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -32,9 +32,32 @@
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
+enum saa6752hs_videoformat {
+	SAA6752HS_VF_D1 = 0,    /* standard D1 video format: 720x576 */
+	SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
+	SAA6752HS_VF_1_2_D1 = 2,/* 1/2D1 video format: 352x576 */
+	SAA6752HS_VF_SIF = 3,   /* SIF video format: 352x288 */
+	SAA6752HS_VF_UNKNOWN,
+};
+
+static const struct v4l2_format v4l2_format_table[] =
+{
+	[SAA6752HS_VF_D1] = {
+		.fmt.pix.width = 720, .fmt.pix.height = 576 },
+	[SAA6752HS_VF_2_3_D1] = {
+		.fmt.pix.width = 480, .fmt.pix.height = 576 },
+	[SAA6752HS_VF_1_2_D1] = {
+		.fmt.pix.width = 352, .fmt.pix.height = 576 },
+	[SAA6752HS_VF_SIF] = {
+		.fmt.pix.width = 352, .fmt.pix.height = 288 },
+	[SAA6752HS_VF_UNKNOWN] = {
+		.fmt.pix.width = 0, .fmt.pix.height = 0},
+};
+
 struct saa6752hs_state {
 	struct i2c_client             client;
 	struct v4l2_mpeg_compression  params;
+	enum saa6752hs_videoformat    video_format;
 };
 
 enum saa6752hs_command {
@@ -256,6 +279,51 @@
 	return 0;
 }
 
+static void saa6752hs_set_subsampling(struct i2c_client* client,
+				      struct v4l2_format* f)
+{
+	struct saa6752hs_state *h = i2c_get_clientdata(client);
+	int dist_352, dist_480, dist_720;
+
+	/*
+	  FIXME: translate and round width/height into EMPRESS
+	  subsample type:
+
+	  type   |   PAL   |  NTSC
+	  ---------------------------
+	  SIF    | 352x288 | 352x240
+	  1/2 D1 | 352x576 | 352x480
+	  2/3 D1 | 480x576 | 480x480
+	  D1     | 720x576 | 720x480
+	*/
+
+	dist_352 = abs(f->fmt.pix.width - 352);
+	dist_480 = abs(f->fmt.pix.width - 480);
+	dist_720 = abs(f->fmt.pix.width - 720);
+	if (dist_720 < dist_480) {
+		f->fmt.pix.width = 720;
+		f->fmt.pix.height = 576;
+		h->video_format = SAA6752HS_VF_D1;
+	}
+	else if (dist_480 < dist_352) {
+		f->fmt.pix.width = 480;
+		f->fmt.pix.height = 576;
+		h->video_format = SAA6752HS_VF_2_3_D1;
+	}
+	else {
+		f->fmt.pix.width = 352;
+		if (abs(f->fmt.pix.height - 576) <
+		    abs(f->fmt.pix.height - 288)) {
+			f->fmt.pix.height = 576;
+			h->video_format = SAA6752HS_VF_1_2_D1;
+		}
+		else {
+			f->fmt.pix.height = 288;
+			h->video_format = SAA6752HS_VF_SIF;
+		}
+	}
+}
+
 
 static void saa6752hs_set_params(struct i2c_client* client,
 				 struct v4l2_mpeg_compression* params)
@@ -315,7 +383,7 @@
 
 	// Set video format - must be done first as it resets other settings
 	buf[0] = 0x41;
-	buf[1] = 0 /* MPEG_VIDEO_FORMAT_D1 */;
+	buf[1] = h->video_format;
 	i2c_master_send(client, buf, 2);
 
         // set bitrate
@@ -494,6 +562,25 @@
 	case VIDIOC_G_MPEGCOMP:
 		*params = h->params;
 		break;
+	case VIDIOC_G_FMT:
+	{
+           struct v4l2_format *f = arg;
+
+	   if (h->video_format == SAA6752HS_VF_UNKNOWN)
+		   h->video_format = SAA6752HS_VF_D1;
+	   f->fmt.pix.width =
+		   v4l2_format_table[h->video_format].fmt.pix.width;
+	   f->fmt.pix.height =
+		   v4l2_format_table[h->video_format].fmt.pix.height;
+	   break ;
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		saa6752hs_set_subsampling(client, f);
+		break;
+	}
 	default:
 		/* nothing */
 		break;