--- 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,