X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Ftuner.c;h=bac17a3dc12e6abea3812261f850e9133139e4ca;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=ab7030447a34408b4bd12a6e78b6b72b6560b1e6;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c index ab7030447..bac17a3dc 100644 --- a/drivers/media/video/tuner.c +++ b/drivers/media/video/tuner.c @@ -26,15 +26,17 @@ I2C_CLIENT_INSMOD; static unsigned int debug = 0; static unsigned int type = UNSET; static unsigned int addr = 0; -static char *pal = "b"; static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; +static unsigned int tv_antenna = 1; +static unsigned int radio_antenna = 0; MODULE_PARM(debug,"i"); MODULE_PARM(type,"i"); MODULE_PARM(addr,"i"); MODULE_PARM(tv_range,"2i"); MODULE_PARM(radio_range,"2i"); -MODULE_PARM(pal,"s"); +MODULE_PARM(tv_antenna,"i"); +MODULE_PARM(radio_antenna,"i"); #define optimize_vco 1 @@ -48,10 +50,10 @@ static int this_adap; struct tuner { unsigned int type; /* chip type */ unsigned int freq; /* keep track of the current settings */ - unsigned int std; + v4l2_std_id std; + int using_v4l2; unsigned int radio; - unsigned int mode; /* current norm for multi-norm tuners */ unsigned int input; // only for MT2032 @@ -206,7 +208,7 @@ static struct tunertype tuners[] = { { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ - 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,732 }, // Corrected to NTSC=732 (was:940) + 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, @@ -227,7 +229,7 @@ static struct tunertype tuners[] = { 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, { "HITACHI V7-J180AT", HITACHI, NTSC, - 16*170.00, 16*450.00, 0x01,0x02,0x00,0x8e,940 }, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, { "Philips PAL_MK (FI1216 MK)", Philips, PAL, 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, @@ -239,6 +241,13 @@ static struct tunertype tuners[] = { 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, { "Microtune 4049 FM5",Microtune,PAL, 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, + { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, + 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, + { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, + 16*170.00, 16*450.00, 0x01,0x02,0x04,0x8e,732 }, + + { "Tenna TNF 8831 BGFF)", Philips, PAL, + 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, }; #define TUNERS ARRAY_SIZE(tuners) @@ -537,15 +546,16 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) int if2,from,to; // signal bandwidth and picture carrier - if (t->mode == VIDEO_MODE_NTSC) { - from=40750*1000; - to=46750*1000; - if2=45750*1000; + if (t->std & V4L2_STD_525_60) { + // NTSC + from = 40750*1000; + to = 46750*1000; + if2 = 45750*1000; } else { - // Pal - from=32900*1000; - to=39900*1000; - if2=38900*1000; + // PAL + from = 32900*1000; + to = 39900*1000; + if2 = 38900*1000; } mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, @@ -619,6 +629,17 @@ static int mt2032_init(struct i2c_client *c) return(1); } +static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) +{ + unsigned char buf[2]; + int ret; + + buf[0] = 6; + buf[1] = antenna ? 0x11 : 0x10; + ret=i2c_master_send(c,buf,2); + dprintk("mt2050: enabled antenna connector %d\n", antenna); +} + static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) { unsigned int if1=1218*1000*1000; @@ -683,13 +704,15 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); unsigned int if2; - if (t->mode == VIDEO_MODE_NTSC) { - if2=45750*1000; + if (t->std & V4L2_STD_525_60) { + // NTSC + if2 = 45750*1000; } else { - // Pal - if2=38900*1000; + // PAL + if2 = 38900*1000; } - mt2050_set_if_freq(c,freq*62500,if2); + mt2050_set_if_freq(c, freq*62500, if2); + mt2050_set_antenna(c, tv_antenna); } static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -698,6 +721,7 @@ static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) int if2 = t->radio_if2; mt2050_set_if_freq(c, freq*62500, if2); + mt2050_set_antenna(c, radio_antenna); } static int mt2050_init(struct i2c_client *c) @@ -731,8 +755,8 @@ static int microtune_init(struct i2c_client *c) unsigned char buf[21]; int company_code; - buf[0] = 0; - t->tv_freq = NULL; + memset(buf,0,sizeof(buf)); + t->tv_freq = NULL; t->radio_freq = NULL; name = "unknown"; @@ -751,6 +775,9 @@ static int microtune_init(struct i2c_client *c) company_code = buf[0x11] << 8 | buf[0x12]; printk("tuner: microtune: companycode=%04x part=%02x rev=%02x\n", company_code,buf[0x13],buf[0x14]); + +#if 0 + /* seems to cause more problems than it solves ... */ switch (company_code) { case 0x30bf: case 0x3cbf: @@ -764,6 +791,7 @@ static int microtune_init(struct i2c_client *c) printk("tuner: microtune: unknown companycode\n"); return 0; } +#endif if (buf[0x13] < ARRAY_SIZE(microtune_part) && NULL != microtune_part[buf[0x13]]) @@ -811,54 +839,40 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ config &= ~0x02; - if (t->mode == VIDEO_MODE_SECAM) + if (t->std & V4L2_STD_SECAM) config |= 0x02; break; case TUNER_TEMIC_4046FM5: config &= ~0x0f; - switch (pal[0]) { - case 'i': - case 'I': + + if (t->std & V4L2_STD_PAL_BG) { + config |= TEMIC_SET_PAL_BG; + + } else if (t->std & V4L2_STD_PAL_I) { config |= TEMIC_SET_PAL_I; - break; - case 'd': - case 'D': + + } else if (t->std & V4L2_STD_PAL_DK) { config |= TEMIC_SET_PAL_DK; - break; - case 'l': - case 'L': + + } else if (t->std & V4L2_STD_SECAM_L) { config |= TEMIC_SET_PAL_L; - break; - case 'b': - case 'B': - case 'g': - case 'G': - default: - config |= TEMIC_SET_PAL_BG; - break; + } break; case TUNER_PHILIPS_FQ1216ME: config &= ~0x0f; - switch (pal[0]) { - case 'i': - case 'I': + + if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { + config |= PHILIPS_SET_PAL_BGDK; + + } else if (t->std & V4L2_STD_PAL_I) { config |= PHILIPS_SET_PAL_I; - break; - case 'l': - case 'L': + + } else if (t->std & V4L2_STD_SECAM_L) { config |= PHILIPS_SET_PAL_L; - break; - case 'd': - case 'D': - case 'b': - case 'B': - case 'g': - case 'G': - config |= PHILIPS_SET_PAL_BGDK; - break; + } break; @@ -867,12 +881,9 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) /* 0x01 -> ATSC antenna input 2 */ /* 0x02 -> NTSC antenna input 1 */ /* 0x03 -> NTSC antenna input 2 */ - config &= ~0x03; -#ifdef VIDEO_MODE_ATSC - if (VIDEO_MODE_ATSC != t->mode) + if (t->std & V4L2_STD_ATSC) config |= 2; -#endif /* FIXME: input */ break; } @@ -930,6 +941,9 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) case TUNER_PHILIPS_FM1236_MK3: buffer[3] = 0x19; break; + case TUNER_LG_PAL_FM: + buffer[3] = 0xa5; + break; default: buffer[3] = 0xa4; break; @@ -990,6 +1004,22 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) t->radio_freq(c,freq); } +static void set_freq(struct i2c_client *c, unsigned long freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (t->radio) { + dprintk("tuner: radio freq set to %lu.%02lu\n", + freq/16,freq%16*100/16); + set_radio_freq(c,freq); + } else { + dprintk("tuner: tv freq set to %lu.%02lu\n", + freq/16,freq%16*100/16); + set_tv_freq(c, freq); + } + t->freq = freq; +} + static void set_type(struct i2c_client *c, unsigned int type, char *source) { struct tuner *t = i2c_get_clientdata(c); @@ -1019,6 +1049,38 @@ static void set_type(struct i2c_client *c, unsigned int type, char *source) } } +static char *pal = "-"; +MODULE_PARM(pal,"s"); + +static int tuner_fixup_std(struct tuner *t) +{ + if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { + /* get more precise norm info from insmod option */ + switch (pal[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + dprintk("insmod fixup: PAL => PAL-BG\n"); + t->std = V4L2_STD_PAL_BG; + break; + case 'i': + case 'I': + dprintk("insmod fixup: PAL => PAL-I\n"); + t->std = V4L2_STD_PAL_I; + break; + case 'd': + case 'D': + case 'k': + case 'K': + dprintk("insmod fixup: PAL => PAL-DK\n"); + t->std = V4L2_STD_PAL_DK; + break; + } + } + return 0; +} + /* ---------------------------------------------------------------------- */ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) @@ -1054,7 +1116,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) set_type(client, type, "insmod option"); printk("tuner: The type= insmod option will go away soon.\n"); printk("tuner: Please use the tuner= option provided by\n"); - printk("tuner: tv card core driver (bttv, saa7134, ...) instead.\n"); + printk("tuner: tv aard core driver (bttv, saa7134, ...) instead.\n"); } return 0; } @@ -1094,6 +1156,13 @@ static int tuner_detach(struct i2c_client *client) return 0; } +#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \ + printk("tuner: switching to v4l2\n"); \ + t->using_v4l2 = 1; +#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \ + printk("tuner: ignore v4l1 call\n"); \ + return 0; } + static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -1130,10 +1199,21 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) kernel pointer here... */ case VIDIOCSCHAN: { + static const v4l2_std_id map[] = { + [ VIDEO_MODE_PAL ] = V4L2_STD_PAL, + [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M, + [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM, + [ 4 /* bttv */ ] = V4L2_STD_PAL_M, + [ 5 /* bttv */ ] = V4L2_STD_PAL_N, + [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, + }; struct video_channel *vc = arg; + CHECK_V4L2; t->radio = 0; - t->mode = vc->norm; + if (vc->norm < ARRAY_SIZE(map)) + t->std = map[vc->norm]; + tuner_fixup_std(t); if (t->freq) set_tv_freq(client,t->freq); return 0; @@ -1142,22 +1222,15 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { unsigned long *v = arg; - if (t->radio) { - dprintk("tuner: radio freq set to %lu.%02lu\n", - (*v)/16,(*v)%16*100/16); - set_radio_freq(client,*v); - } else { - dprintk("tuner: tv freq set to %lu.%02lu\n", - (*v)/16,(*v)%16*100/16); - set_tv_freq(client,*v); - } - t->freq = *v; + CHECK_V4L2; + set_freq(client,*v); return 0; } case VIDIOCGTUNER: { struct video_tuner *vt = arg; + CHECK_V4L2; if (t->radio) vt->signal = tuner_signal(client); return 0; @@ -1165,10 +1238,52 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOCGAUDIO: { struct video_audio *va = arg; + + CHECK_V4L2; if (t->radio) va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO); return 0; } + + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + + SWITCH_V4L2; + t->radio = 0; + t->std = *id; + tuner_fixup_std(t); + if (t->freq) + set_freq(client,t->freq); + break; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + SWITCH_V4L2; + if (V4L2_TUNER_ANALOG_TV == f->type) { + t->radio = 0; + } + if (V4L2_TUNER_RADIO == f->type) { + if (!t->radio) { + set_tv_freq(client,400*16); + t->radio = 1; + } + } + t->freq = f->frequency; + set_freq(client,t->freq); + break; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *tuner = arg; + + SWITCH_V4L2; + if (t->radio) + tuner->signal = tuner_signal(client); + break; + } default: /* nothing */ break; @@ -1195,13 +1310,12 @@ static struct i2c_client client_template = .driver = &driver, }; -static int tuner_init_module(void) +static int __init tuner_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tuner_cleanup_module(void) +static void __exit tuner_cleanup_module(void) { i2c_del_driver(&driver); }