--- v4l-dvb-experimental-e9a7be188b2b/linux/drivers/media/tuners/xc3028-tuner.c	2007-06-08 21:46:14.000000000 +0200
+++ ../v4l-dvb-experimental-e9a7be188b2b/linux/drivers/media/tuners/xc3028-tuner.c	2007-07-28 15:27:29.000000000 +0200
@@ -100,9 +100,9 @@
 
 static int firmware_loader(struct v4l_dvb_tuner_ops *c, const struct firmware *fw,enum v4l2_tuner_type type);
 
-static struct _analogue_standards{
+static const struct _analogue_standards{
 	v4l2_std_id standard;
-	u8 filename[50];
+	const char *filename;
 } xc3028_standards[]={
 	{V4L2_STD_PAL_BG,"xc3028_BG_PAL_A2_A.i2c.fw"},
 	{V4L2_STD_PAL_I,"xc3028_I_PAL_NICAM.i2c.fw"},
@@ -141,11 +141,11 @@
 
  */
 
-static struct _digital_standards {
+static const struct _digital_standards {
 	unsigned int dvb:1;
 	unsigned int atsc:1;
 	int bandwidth;
-	char filename[50];
+	char *filename;
 } xc3028_dtv_standards[]={
 	{1, 0, BANDWIDTH_8_MHZ /* 8mhz  */, "xc3028_DTV8_2633.i2c.fw"     },
 	{1, 0, BANDWIDTH_7_MHZ /* 7mhz  */, "xc3028_DTV7_2633.i2c.fw"     },
@@ -155,13 +155,38 @@
 	{0, 1, BANDWIDTH_6_MHZ,             "xc3028_DTV6_ATSC_2620.i2c.fw"},
 };
 
+/* good old byte code stuff definition */
+struct bcode{
+	int len;
+	char *txt;
+};
+
+static struct bcode xc3028_analogue_freq[]={
+	{0x04,"\xa0\x00\x00\x00"},
+	{0x0c,"\x1e\x1f\x13\x87\x18\x02\x93\x91\x44\x86\x96\x8c"}, /* ??? */
+	{0x02,"\x00\x8c"},
+	{0x04,"\x80\x02\x00\x00"},
+	{}
+};
+
+static struct bcode xc3028_dvbt_freq[]={
+	{0x04,"\xa0\x00\x00\x00"},
+	{0x0c, // "\x1e\x1c\xf2\x4d\xe0\x00\x0b\x61\x66\x06\x69\x13"},
+	      "\x1e\x1a\x83\x25\xb4\x03\x6e\x01\x96\x86\xa8\x1c"},
+	{0x02,"\x00\x8c"},
+	{0x04,"\x80\x02\x00\x00"},
+	{}
+};
+
+
 static int xc3028_tuner_set_params(struct v4l_dvb_tuner_ops *c, struct dvb_int_frontend_parameters *params)
 {
 	struct xc3028_priv *priv=(struct xc3028_priv *)c->priv;
 	const struct firmware *fw = NULL;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0 };
+	static struct bcode *xc3028_setfreq;
 	unsigned char chanbuf[4];
-	unsigned long frequency=0;
+	unsigned long frequency=0, f_offset=0, f_scale = 1000;
 	unsigned long value;
 	int i;
 
@@ -171,9 +196,11 @@
 	case V4L2_INT_TUNER_ATSC_TV:
 	case V4L2_INT_TUNER_DVBT_TV:
 	case V4L2_INT_TUNER_DVBC_TV:
+		xc3028_setfreq=xc3028_dvbt_freq;
 		printk("DIGITAL TV REQUEST\n");
 		break;
 	case V4L2_INT_TUNER_ANALOG_TV:
+		xc3028_setfreq=xc3028_analogue_freq;
 		printk("ANALOG TV REQUEST\n");
 		break;
 	case V4L2_INT_TUNER_RADIO:
@@ -219,13 +246,13 @@
 		switch(params->u.ofdm.bandwidth){
 			case BANDWIDTH_AUTO:
 			case BANDWIDTH_8_MHZ:
-				frequency=(unsigned long long)params->frequency - priv->xc3028_offset_8mhz;
+				f_offset = priv->xc3028_offset_8mhz;
 				break;
 			case BANDWIDTH_7_MHZ:
-				frequency=(unsigned long long)params->frequency - priv->xc3028_offset_7mhz;
+				f_offset = priv->xc3028_offset_7mhz;
 				break;
 			case BANDWIDTH_6_MHZ:
-				frequency=(unsigned long long)params->frequency - priv->xc3028_offset_6mhz;
+				f_offset = priv->xc3028_offset_6mhz;
 				break;
 		}
 		break;
@@ -248,10 +275,10 @@
 				}
 			}
 		}
-		frequency=(unsigned long long)params->frequency*1000/16*1000;
+		f_scale = 16 * 1000;
 		break;
 	case V4L2_INT_TUNER_RADIO:
-		frequency=(unsigned long long)params->frequency*1000/16;
+		f_scale = 16;
 		break;
 	case V4L2_INT_TUNER_DVBC_TV:
 		printk("xc3028-tuner: dvb-c is currently not implemented\n");
@@ -260,18 +287,29 @@
 		printk("xc3028-tuner: requested mode not implemented!\n");
 	}
 
+	/* This prevents GCC from complaining about undefined __udivdi3
+	* gcc does not like mixed 64,32 bits divides, we'll use div_ll_X_l_rem
+	* instead.
+	*/
+	{
+		long unused;
+		frequency = params->frequency - f_offset;
+		frequency = div_ll_X_l_rem((u64)frequency * 1000, f_scale, &unused);
 
-	value=(frequency+(TUNING_GRANULARITY/2))/TUNING_GRANULARITY;
+		value=(frequency+(TUNING_GRANULARITY/2))/TUNING_GRANULARITY;
+
+		priv->frequency = div_ll_X_l_rem((u64)value * f_scale * TUNING_GRANULARITY , 1000, &unused) + f_offset;
+	}
 	chanbuf[0]=0;
 	chanbuf[1]=0;
 	chanbuf[2]=value>>8;
 	chanbuf[3]=value&0xff;
 
-	priv->frequency = params->frequency;
-
-	msg.buf = "\x80\x02\x00\x00";
-	msg.len = 4;
-	i2c_transfer(priv->i2c,&msg,1);
+	for(i=0;xc3028_setfreq[i].txt;i++){
+		msg.buf = xc3028_setfreq[i].txt;
+		msg.len = xc3028_setfreq[i].len;
+		i2c_transfer(priv->i2c,&msg,1);
+	}
 	msg.buf = chanbuf;
 	msg.len = 4;
 	i2c_transfer(priv->i2c,&msg,1);
@@ -567,7 +605,8 @@
 int xc3028_tuner_get_frequency(struct v4l_dvb_tuner_ops *dev, u32 *frequency)
 {
 	struct xc3028_priv *priv = dev->priv;
-	return priv->frequency;
+	*frequency = priv->frequency;
+	return 0;
 }
 
 int xc3028_tuner_get_bandwidth(struct v4l_dvb_tuner_ops *dev, u32 *status)
@@ -581,7 +620,7 @@
 		.name           = "Xceive XC3028",
 		.frequency_min  =  48000000,
 		.frequency_max  = 860000000,
-		.frequency_step =     50000,
+		.frequency_step = TUNING_GRANULARITY,
 	},
 
 	.release       = xc3028_release,
