Fri May  9 23:27:51 CEST 2008
--- linux-2.6.25.1/drivers/media/video/cx25840/cx25840-core-d.c	2008-05-01 23:45:25.000000000 +0200
+++ linux-2.6.25.1/drivers/media/video/cx25840/cx25840-core.c	2008-05-07 22:25:56.000000000 +0200
@@ -704,6 +704,167 @@ static int get_v4lctrl(struct i2c_client
 
 /* ----------------------------------------------------------------------- */
 
+static int origin_v4lcrop(struct i2c_client *client, v4l2_std_id *cstd, int *hbdef, int *vbdef) 
+{
+	v4l2_std_id std = cx25840_get_v4lstd(client);
+	int hblank, vblank;
+
+	if(std & V4L2_STD_625_50) {
+		hblank=132;
+		vblank=36;
+	} else {
+		hblank=122;
+		if(std == V4L2_STD_PAL_M) {
+			vblank=20;
+		} else {
+			vblank=26;
+		}
+	}
+	if(cstd) *cstd=std;
+	if(hbdef) *hbdef=hblank;
+	if(vbdef) *vbdef=vblank;
+
+	return 0;
+}
+
+static int v4lcropcap(struct i2c_client *client, struct v4l2_cropcap *cap) 
+{
+	v4l2_std_id std;
+	int htotal, hbdef, vtotal, vbdef, vactive, doth, dotv;
+
+	if(cap->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	origin_v4lcrop(client, &std, &hbdef, &vbdef);
+	if(std & V4L2_STD_625_50) {
+	  htotal=864;
+	  vtotal=625;
+	  vactive=580;
+	  doth=59; 
+	  dotv=54;
+	} else {
+	  htotal=858;
+	  vtotal=525;
+	  vactive=487;
+	  doth=10; 
+	  dotv=11;
+	}
+
+	cap->bounds.left=3-hbdef;    /* hblank delay >=3 dot */
+	cap->bounds.width=htotal-4;  /* SAV EAV bt.656 */
+	cap->bounds.top=1-vbdef;     /* vblank delay >=1 halfline */
+	cap->bounds.height=vtotal-3; /* field sync + min_vblank = 2h+1h = 3h */
+
+	cap->defrect.left=0;
+	cap->defrect.width=720;
+	cap->defrect.top=0;
+	cap->defrect.height=(vactive >> 4) << 4;
+
+	cap->pixelaspect.numerator=dotv;
+	cap->pixelaspect.denominator=doth;
+
+	return 0;
+}
+
+/* 
+ * base    [7:0]=blank_cnt_low 
+ * base+1  [7:4]=active_cnt_low  [3:2]=ss  [1:0]=blank_cnt_high
+ * base+2  [7:6]=rr  [5:0]=active_cnt_high
+ */
+static int bsa_read(struct i2c_client *client, int base, int *pbl, int *psav, int *pact) 
+{
+	int save, blank, active;
+
+	blank = cx25840_read(client, base);
+	save = cx25840_read(client, base+1);
+	blank |= ((save & 3) << 8);
+	active = ((save & 0xf0) >> 4) 
+	  | ((cx25840_read(client, base+2) & 0x3f) << 4);
+
+	if(pbl) *pbl=blank;
+	if(psav) *psav=save;
+	if(pact) *pact=active;
+	return 0;
+}
+
+static int bsa_write(struct i2c_client *client, int base, int blank, int save, int active) 
+{
+	int snew;
+
+	cx25840_write(client, base, blank & 0xff);
+	snew = (save & 0x0c) | ((active & 0xf) << 4) | ((blank >> 8) & 3);
+	cx25840_write(client, base+1, snew);
+	cx25840_write(client, base+2, active >> 4);
+	return 0;
+}
+
+static int set_v4lcrop(struct i2c_client *client, struct v4l2_crop *crop) 
+{
+	v4l2_std_id std;
+	int is_50Hz;
+	int hbdef, hbnew, hanew, hsave, hblank, hactive;
+	int vbdef, vbnew, vbnew656, vanew, vsave, vblank, vblank656, vactive;
+
+	if(crop->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	origin_v4lcrop(client, &std, &hbdef, &vbdef);
+
+	hbnew=crop->c.left+hbdef;
+	hanew=crop->c.width;
+	if(hbnew<0 || hbnew>1023 || hanew<0 || hanew>1023) {
+		v4l_err(client, "invalid horizontal crop %d %d\n", crop->c.left, crop->c.width);
+		return -ERANGE;
+	}
+
+	is_50Hz=std & V4L2_STD_625_50;
+	vbnew=crop->c.top+vbdef;
+	vbnew656=vbnew+4;
+	vanew=crop->c.height+(is_50Hz ? 4 : 7);
+	if(vbnew<0 || vbnew>1023 || vanew<0 || vanew>1023) {
+		v4l_err(client, "invalid vertical crop %d %d\n", crop->c.top, crop->c.height);
+		return -ERANGE;
+	}
+
+	bsa_read(client, 0x470, &hblank, &hsave, &hactive);
+	bsa_write(client, 0x470, hbnew, hsave, hanew);
+	v4l_dbg(1, cx25840_debug, client, "hblank=%i->%i hactive=%i->%i\n", 
+		hblank, hbnew, hactive, hanew);
+
+	bsa_read(client, 0x474, &vblank, &vsave, &vactive);
+	vblank656 = cx25840_read(client, 0x477);
+	bsa_write(client, 0x474, vbnew, vsave, vanew);
+	cx25840_write(client, 0x477, vbnew656 & 0xff);  /* XXX at 256 */
+	v4l_dbg(1, cx25840_debug, client, "vblank=%i->%i vactive=%i->%i"
+		" vblank656=%i->%i\n", vblank,vbnew, vactive,vanew, 
+		vblank656,vbnew656);
+	return 0;
+}
+
+static int get_v4lcrop(struct i2c_client *client, struct v4l2_crop *crop) 
+{
+	v4l2_std_id std;
+	int hbdef, hblank, hactive;
+	int vbdef, vblank, vactive;
+
+	if(crop->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	origin_v4lcrop(client, &std, &hbdef, &vbdef);
+
+	bsa_read(client, 0x470, &hblank, NULL, &hactive);
+	crop->c.left = hblank-hbdef;
+	crop->c.width = hactive;
+
+	bsa_read(client, 0x474, &vblank, NULL, &vactive);
+	crop->c.top = vblank-vbdef;
+	crop->c.height = vactive - (std & V4L2_STD_625_50 ? 4 : 7);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
 static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 {
 	switch (fmt->type) {
@@ -1066,6 +1227,15 @@ static int cx25840_command(struct i2c_cl
 	case VIDIOC_S_CTRL:
 		return set_v4lctrl(client, (struct v4l2_control *)arg);
 
+	case VIDIOC_CROPCAP:
+		return v4lcropcap(client, (struct v4l2_cropcap *)arg);
+
+	case VIDIOC_G_CROP:
+		return get_v4lcrop(client, (struct v4l2_crop *)arg);
+
+	case VIDIOC_S_CROP:
+		return set_v4lcrop(client, (struct v4l2_crop *)arg);
+
 	case VIDIOC_QUERYCTRL:
 	{
 		struct v4l2_queryctrl *qc = arg;
--- linux-2.6.25.1/drivers/media/video/cx25840/cx25840-vbi-d.c	2008-05-01 23:45:25.000000000 +0200
+++ linux-2.6.25.1/drivers/media/video/cx25840/cx25840-vbi.c	2008-05-07 22:28:44.000000000 +0200
@@ -98,12 +98,12 @@ void cx25840_vbi_setup(struct i2c_client
 	}
 
 	if (std & V4L2_STD_625_50) {
-		hblank=0x084;
-		hactive=0x2d0;
-		burst=0x5d;
-		vblank=0x024;
-		vactive=0x244;
-		vblank656=0x28;
+		hblank=132;
+		hactive=720;
+		burst=93;
+		vblank=36;
+		vactive=580;
+		vblank656=40;
 		src_decimation=0x21f;
 
 		luma_lpf=2;
@@ -140,7 +140,6 @@ void cx25840_vbi_setup(struct i2c_client
 			vblank656=24;
 			burst=0x61;
 			comb=0x20;
-
 			sc=555452;
 		} else {
 			vblank=26;
@@ -179,9 +178,9 @@ void cx25840_vbi_setup(struct i2c_client
 						"%d.%06d MHz\n",
 						fsc/1000000,fsc%1000000);
 
-		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
-			"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
-			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i,"
+			" vblank %i, vactive %i, vblank656 %i, src_dec %i,"
+			" burst %i, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
 			" sc 0x%06x\n",
 			hblank, hactive, vblank, vactive, vblank656,
 			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
