X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Ftda9887.c;h=9768829bd2a26a515d06fe001f68128bda6d226f;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=aef701636aa869071745db52dbf98fe55ca6dbbc;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index aef701636..9768829bd 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -21,7 +21,7 @@ Note: OP2 of tda988x must be set to 1, else MT2032 is disabled! - KNC One TV-Station RDS (saa7134) */ - + /* Addresses to scan */ static unsigned short normal_i2c[] = { @@ -33,22 +33,30 @@ static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* insmod options */ -static int debug = 0; -static char *pal = "b"; -static char *secam = "l"; +static unsigned int debug = 0; MODULE_PARM(debug,"i"); -MODULE_PARM(pal,"s"); -MODULE_PARM(secam,"s"); MODULE_LICENSE("GPL"); /* ---------------------------------------------------------------------- */ +#define UNSET (-1U) +#define PREFIX "tda9885/6/7: " #define dprintk if (debug) printk struct tda9887 { - struct i2c_client client; - int radio,tvnorm; - int pinnacle_id; + struct i2c_client client; + v4l2_std_id std; + unsigned int radio; + unsigned int pinnacle_id; + unsigned int using_v4l2; +}; + +struct tvnorm { + v4l2_std_id std; + char *name; + unsigned char b; + unsigned char c; + unsigned char e; }; static struct i2c_driver driver; @@ -60,7 +68,7 @@ static struct i2c_client client_template; // TDA defines // -//// first reg +//// first reg (b) #define cVideoTrapBypassOFF 0x00 // bit b0 #define cVideoTrapBypassON 0x01 // bit b0 @@ -85,7 +93,7 @@ static struct i2c_client client_template; #define cOutputPort2Inactive 0x80 // bit b7 -//// second reg +//// second reg (c) #define cDeemphasisOFF 0x00 // bit c5 #define cDeemphasisON 0x20 // bit c5 @@ -96,7 +104,7 @@ static struct i2c_client client_template; #define cAudioGain6 0x80 // bit c7 -//// third reg +//// third reg (e) #define cAudioIF_4_5 0x00 // bit e0:1 #define cAudioIF_5_5 0x01 // bit e0:1 #define cAudioIF_6_0 0x02 // bit e0:1 @@ -122,126 +130,287 @@ static struct i2c_client client_template; #define cAgcOutON 0x80 // bit e7 #define cAgcOutOFF 0x00 // bit e7 -static int tda9887_miro(struct tda9887 *t) +/* ---------------------------------------------------------------------- */ + +static struct tvnorm tvnorms[] = { + { + .std = V4L2_STD_PAL_BG, + .name = "PAL-BG", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 ), + .e = ( cAudioIF_5_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_I, + .name = "PAL-I", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 ), + .e = ( cAudioIF_6_0 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_DK, + .name = "PAL-DK", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 ), + .e = ( cAudioIF_6_5 | + cVideoIF_38_00 ), + },{ + .std = V4L2_STD_PAL_M | V4L2_STD_PAL_N, + .name = "PAL-M/N", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis75 ), + .e = ( cAudioIF_4_5 | + cVideoIF_45_75 ), + },{ + .std = V4L2_STD_SECAM_L, + .name = "SECAM-L", + .b = ( cPositiveAmTV | + cQSS ), + .e = ( cAudioIF_6_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_SECAM_DK, + .name = "SECAM-DK", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 ), + .e = ( cAudioIF_6_5 | + cVideoIF_38_00 ), + },{ + .std = V4L2_STD_NTSC_M, + .name = "NTSC-M", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 ), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_45_75 ), + },{ + .std = V4L2_STD_NTSC_M_JP, + .name = "NTSC-JP", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 ), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_58_75 ), + } +}; + +static struct tvnorm radio = { + .name = "radio", + .b = ( cFmRadio | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 ), + .e = ( cAudioIF_5_5 | + cRadioIF_38_90 ), +}; + +/* ---------------------------------------------------------------------- */ + +static void dump_read_message(unsigned char *buf) { - int rc; - u8 bData[4] = { 0 }; - u8 bVideoIF = 0; - u8 bAudioIF = 0; - u8 bDeEmphasis = 0; - u8 bDeEmphVal = 0; - u8 bModulation = 0; - u8 bCarrierMode = 0; - u8 bOutPort1 = cOutputPort1Inactive; -#if 0 - u8 bOutPort2 = cOutputPort2Inactive & mbTADState; // store i2c tuner state -#else - u8 bOutPort2 = cOutputPort2Inactive; -#endif - u8 bVideoTrap = cVideoTrapBypassOFF; -#if 1 - u8 bTopAdjust = 0x0e /* -2dB */; -#else - u8 bTopAdjust = 0; -#endif + static char *afc[16] = { + "- 12.5 kHz", + "- 37.5 kHz", + "- 62.5 kHz", + "- 87.5 kHz", + "-112.5 kHz", + "-137.5 kHz", + "-162.5 kHz", + "-187.5 kHz [min]", + "+187.5 kHz [max]", + "+162.5 kHz", + "+137.5 kHz", + "+112.5 kHz", + "+ 87.5 kHz", + "+ 62.5 kHz", + "+ 37.5 kHz", + "+ 12.5 kHz", + }; + printk(PREFIX "read: 0x%2x\n", buf[0]); + printk(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); + printk(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); + printk(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); + printk(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); +} -#if 0 - if (mParams.fVideoTrap) - bVideoTrap = cVideoTrapBypassON; -#endif +static void dump_write_message(unsigned char *buf) +{ + static char *sound[4] = { + "AM/TV", + "FM/radio", + "FM/TV", + "FM/radio" + }; + static char *adjust[32] = { + "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", + "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", + "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", + "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" + }; + static char *deemph[4] = { + "no", "no", "75", "50" + }; + static char *carrier[4] = { + "4.5 MHz", + "5.5 MHz", + "6.0 MHz", + "6.5 MHz / AM" + }; + static char *vif[8] = { + "58.75 MHz", + "45.75 MHz", + "38.9 MHz", + "38.0 MHz", + "33.9 MHz", + "33.4 MHz", + "45.75 MHz + pin13", + "38.9 MHz + pin13", + }; + static char *rif[4] = { + "44 MHz", + "52 MHz", + "52 MHz", + "44 MHz", + }; + + printk(PREFIX "write: byte B 0x%02x\n",buf[1]); + printk(" B0 video mode : %s\n", + (buf[1] & 0x01) ? "video trap" : "sound trap"); + printk(" B1 auto mute fm : %s\n", + (buf[1] & 0x02) ? "yes" : "no"); + printk(" B2 carrier mode : %s\n", + (buf[1] & 0x04) ? "QSS" : "Intercarrier"); + printk(" B3-4 tv sound/radio : %s\n", + sound[(buf[1] & 0x18) >> 3]); + printk(" B5 force mute audio: %s\n", + (buf[1] & 0x20) ? "yes" : "no"); + printk(" B6 output port 1 : %s\n", + (buf[1] & 0x40) ? "high" : "low"); + printk(" B7 output port 2 : %s\n", + (buf[1] & 0x80) ? "high" : "low"); + + printk(PREFIX "write: byte C 0x%02x\n",buf[2]); + printk(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]); + printk(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]); + printk(" C7 audio gain : %s\n", + (buf[2] & 0x80) ? "-6" : "0"); + + printk(PREFIX "write: byte E 0x%02x\n",buf[3]); + printk(" E0-1 sound carrier : %s\n", + carrier[(buf[3] & 0x03)]); + printk(" E6 l pll ganting : %s\n", + (buf[3] & 0x40) ? "36" : "13"); + + if (buf[1] & 0x08) { + /* radio */ + printk(" E2-4 video if : %s\n", + rif[(buf[3] & 0x0c) >> 2]); + printk(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio") + : "fm radio carrier afc"); + } else { + /* video */ + printk(" E2-4 video if : %s\n", + vif[(buf[3] & 0x1c) >> 2]); + printk(" E5 tuner gain : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) ? "external" : "normal") + : ((buf[3] & 0x20) ? "minimum" : "normal")); + printk(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) + ? "pin3 port, pin22 vif agc out" + : "pin22 port, pin3 vif acg ext in") + : "pin3+pin22 port"); + } + printk("--\n"); +} + +/* ---------------------------------------------------------------------- */ + +static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) +{ + struct tvnorm *norm = NULL; + int i; if (t->radio) { - bVideoTrap = cVideoTrapBypassOFF; - bCarrierMode = cQSS; - bModulation = cFmRadio; - bOutPort1 = cOutputPort1Inactive; - bDeEmphasis = cDeemphasisON; - if (3 == t->pinnacle_id) { - /* ntsc */ - bDeEmphVal = cDeemphasis75; - bAudioIF = cAudioIF_4_5; - bVideoIF = cRadioIF_45_75; - } else { - /* pal */ - bAudioIF = cAudioIF_5_5; - bVideoIF = cRadioIF_38_90; - bDeEmphVal = cDeemphasis50; + norm = &radio; + } else { + for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { + if (tvnorms[i].std & t->std) { + norm = tvnorms+i; + break; + } } + } + if (NULL == norm) { + dprintk(PREFIX "Oops: no tvnorm entry found\n"); + return -1; + } + + dprintk(PREFIX "configure for: %s\n",norm->name); + buf[1] = norm->b; + buf[2] = norm->c; + buf[3] = norm->e; + return 0; +} + +static unsigned int port1 = 1; +static unsigned int port2 = 1; +static unsigned int qss = UNSET; +static unsigned int adjust = 0x10; +MODULE_PARM(port1,"i"); +MODULE_PARM(port2,"i"); +MODULE_PARM(qss,"i"); +MODULE_PARM(adjust,"i"); + +static int tda9887_set_insmod(struct tda9887 *t, char *buf) +{ + if (port1) + buf[1] |= cOutputPort1Inactive; + if (port2) + buf[1] |= cOutputPort2Inactive; + if (UNSET != qss) { + if (qss) + buf[1] |= cQSS; + else + buf[1] &= ~cQSS; + } + + if (adjust >= 0x00 && adjust < 0x20) + buf[2] |= adjust; + return 0; +} + +/* ---------------------------------------------------------------------- */ - } else if (t->tvnorm == VIDEO_MODE_PAL) { - bDeEmphasis = cDeemphasisON; - bDeEmphVal = cDeemphasis50; - bModulation = cNegativeFmTV; - bOutPort1 = cOutputPort1Inactive; +static int tda9887_set_pinnacle(struct tda9887 *t, char *buf) +{ + unsigned int bCarrierMode = UNSET; + + if (t->std & V4L2_STD_PAL) { if ((1 == t->pinnacle_id) || (7 == t->pinnacle_id)) { bCarrierMode = cIntercarrier; } else { - // stereo boards bCarrierMode = cQSS; } - switch (pal[0]) { - case 'b': - case 'g': - case 'h': - bVideoIF = cVideoIF_38_90; - bAudioIF = cAudioIF_5_5; - break; - case 'd': - bVideoIF = cVideoIF_38_00; - bAudioIF = cAudioIF_6_5; - break; - case 'i': - bVideoIF = cVideoIF_38_90; - bAudioIF = cAudioIF_6_0; - break; - case 'm': - case 'n': - bVideoIF = cVideoIF_45_75; - bAudioIF = cAudioIF_4_5; - bDeEmphVal = cDeemphasis75; - if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) { - bCarrierMode = cIntercarrier; - } else { - bCarrierMode = cQSS; - } - break; - } - - } else if (t->tvnorm == VIDEO_MODE_SECAM) { - bAudioIF = cAudioIF_6_5; - bDeEmphasis = cDeemphasisON; - bDeEmphVal = cDeemphasis50; - bModulation = cNegativeFmTV; - bCarrierMode = cQSS; - bOutPort1 = cOutputPort1Inactive; - switch (secam[0]) { - case 'd': - bVideoIF = cVideoIF_38_00; - break; - case 'k': - bVideoIF = cVideoIF_38_90; - break; - case 'l': - bVideoIF = cVideoIF_38_90; - bDeEmphasis = cDeemphasisOFF; - bDeEmphVal = cDeemphasis75; - bModulation = cPositiveAmTV; - break; - case 'L' /* L1 */: - bVideoIF = cVideoIF_33_90; - bDeEmphasis = cDeemphasisOFF; - bDeEmphVal = cDeemphasis75; - bModulation = cPositiveAmTV; - break; - } - - } else if (t->tvnorm == VIDEO_MODE_NTSC) { - bVideoIF = cVideoIF_45_75; - bAudioIF = cAudioIF_4_5; - bDeEmphasis = cDeemphasisON; - bDeEmphVal = cDeemphasis75; - bModulation = cNegativeFmTV; - bOutPort1 = cOutputPort1Inactive; + } + if (t->std & V4L2_STD_NTSC) { if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) { bCarrierMode = cIntercarrier; } else { @@ -249,99 +418,102 @@ static int tda9887_miro(struct tda9887 *t) } } - bData[1] = bVideoTrap | // B0: video trap bypass - cAutoMuteFmInactive | // B1: auto mute - bCarrierMode | // B2: InterCarrier for PAL else QSS - bModulation | // B3 - B4: positive AM TV for SECAM only - cForcedMuteAudioOFF | // B5: forced Audio Mute (off) - bOutPort1 | // B6: Out Port 1 - bOutPort2; // B7: Out Port 2 - bData[2] = bTopAdjust | // C0 - C4: Top Adjust 0 == -16dB 31 == 15dB - bDeEmphasis | // C5: De-emphasis on/off - bDeEmphVal | // C6: De-emphasis 50/75 microsec - cAudioGain0; // C7: normal audio gain - bData[3] = bAudioIF | // E0 - E1: Sound IF - bVideoIF | // E2 - E4: Video IF - cTunerGainNormal | // E5: Tuner gain (normal) - cGating_18 | // E6: Gating (18%) - cAgcOutOFF; // E7: VAGC (off) - - dprintk("tda9885/6/7: 0x%02x 0x%02x 0x%02x [pinnacle_id=%d]\n", - bData[1],bData[2],bData[3],t->pinnacle_id); - if (4 != (rc = i2c_master_send(&t->client,bData,4))) - printk("tda9885/6/7: i2c i/o error: rc == %d (should be 4)\n",rc); + if (bCarrierMode != UNSET) { + buf[1] &= ~0x04; + buf[1] |= bCarrierMode; + } return 0; } /* ---------------------------------------------------------------------- */ -#if 0 -/* just for reference: old knc-one saa7134 stuff */ -static unsigned char buf_pal_bg[] = { 0x00, 0x16, 0x70, 0x49 }; -static unsigned char buf_pal_i[] = { 0x00, 0x16, 0x70, 0x4a }; -static unsigned char buf_pal_dk[] = { 0x00, 0x16, 0x70, 0x4b }; -static unsigned char buf_pal_l[] = { 0x00, 0x06, 0x50, 0x4b }; -static unsigned char buf_fm_stereo[] = { 0x00, 0x0e, 0x0d, 0x77 }; -#endif - -static unsigned char buf_pal_bg[] = { 0x00, 0x96, 0x70, 0x49 }; -static unsigned char buf_pal_i[] = { 0x00, 0x96, 0x70, 0x4a }; -static unsigned char buf_pal_dk[] = { 0x00, 0x96, 0x70, 0x4b }; -static unsigned char buf_pal_l[] = { 0x00, 0x86, 0x50, 0x4b }; -static unsigned char buf_fm_stereo[] = { 0x00, 0x8e, 0x0d, 0x77 }; -static unsigned char buf_ntsc[] = { 0x00, 0x96, 0x70, 0x44 }; -static unsigned char buf_ntsc_jp[] = { 0x00, 0x96, 0x70, 0x40 }; +static char *pal = "-"; +MODULE_PARM(pal,"s"); +static char *secam = "-"; +MODULE_PARM(secam,"s"); -static int tda9887_configure(struct tda9887 *t) +static int tda9887_fixup_std(struct tda9887 *t) { - unsigned char *buf = NULL; - int rc; - - if (t->radio) { - dprintk("tda9885/6/7: FM Radio mode\n"); - buf = buf_fm_stereo; - - } else if (t->tvnorm == VIDEO_MODE_PAL) { - dprintk("tda9885/6/7: PAL-%c mode\n",pal[0]); + /* get more precise norm info from insmod option */ + if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { case 'b': + case 'B': case 'g': - buf = buf_pal_bg; + case 'G': + dprintk(PREFIX "insmod fixup: PAL => PAL-BG\n"); + t->std = V4L2_STD_PAL_BG; break; case 'i': - buf = buf_pal_i; + case 'I': + dprintk(PREFIX "insmod fixup: PAL => PAL-I\n"); + t->std = V4L2_STD_PAL_I; + break; + case 'd': + case 'D': + case 'k': + case 'K': + dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n"); + t->std = V4L2_STD_PAL_DK; break; + } + } + if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { + switch (secam[0]) { case 'd': + case 'D': case 'k': - buf = buf_pal_dk; + case 'K': + dprintk(PREFIX "insmod fixup: SECAM => SECAM-DK\n"); + t->std = V4L2_STD_SECAM_DK; break; case 'l': - buf = buf_pal_l; + case 'L': + dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n"); + t->std = V4L2_STD_SECAM_L; break; } + } + return 0; +} - } else if (t->tvnorm == VIDEO_MODE_NTSC) { - dprintk("tda9885/6/7: NTSC mode\n"); - buf = buf_ntsc; +static int tda9887_status(struct tda9887 *t) +{ + unsigned char buf[1]; + int rc; - } else if (t->tvnorm == VIDEO_MODE_SECAM) { - dprintk("tda9885/6/7: SECAM mode\n"); - buf = buf_pal_l; + memset(buf,0,sizeof(buf)); + if (1 != (rc = i2c_master_recv(&t->client,buf,1))) + printk(PREFIX "i2c i/o error: rc == %d (should be 1)\n",rc); + dump_read_message(buf); + return 0; +} - } else if (t->tvnorm == 6 /* BTTV hack */) { - dprintk("tda9885/6/7: NTSC-Japan mode\n"); - buf = buf_ntsc_jp; - } +static int tda9887_configure(struct tda9887 *t) +{ + unsigned char buf[4]; + int rc; - if (NULL == buf) { - printk("tda9885/6/7 unknown norm=%d\n",t->tvnorm); - return 0; + memset(buf,0,sizeof(buf)); + tda9887_set_tvnorm(t,buf); + if (UNSET != t->pinnacle_id) { + tda9887_set_pinnacle(t,buf); } + tda9887_set_insmod(t,buf); - dprintk("tda9885/6/7: 0x%02x 0x%02x 0x%02x\n", + dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", buf[1],buf[2],buf[3]); + if (debug > 1) + dump_write_message(buf); + if (4 != (rc = i2c_master_send(&t->client,buf,4))) - printk("tda9885/6/7: i2c i/o error: rc == %d (should be 4)\n",rc); + printk(PREFIX "i2c i/o error: rc == %d (should be 4)\n",rc); + + if (debug > 2) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + tda9887_status(t); + } return 0; } @@ -354,14 +526,14 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) client_template.adapter = adap; client_template.addr = addr; - printk("tda9887: chip found @ 0x%x\n", addr<<1); + printk(PREFIX "chip found @ 0x%x\n", addr<<1); if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL))) return -ENOMEM; memset(t,0,sizeof(*t)); - t->client = client_template; - t->pinnacle_id = -1; - t->tvnorm=VIDEO_MODE_PAL; + t->client = client_template; + t->std = 0;; + t->pinnacle_id = UNSET; i2c_set_clientdata(&t->client, t); i2c_attach_client(&t->client); @@ -370,8 +542,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) static int tda9887_probe(struct i2c_adapter *adap) { -#ifdef I2C_ADAP_CLASS_TV_ANALOG - if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) +#ifdef I2C_CLASS_TV_ANALOG + if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9887_attach); #else switch (adap->id) { @@ -394,6 +566,13 @@ static int tda9887_detach(struct i2c_client *client) return 0; } +#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \ + printk(PREFIX "switching to v4l2\n"); \ + t->using_v4l2 = 1; +#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \ + printk(PREFIX "ignore v4l1 call\n"); \ + return 0; } + static int tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -404,10 +583,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) /* --- configuration --- */ case AUDC_SET_RADIO: t->radio = 1; - if (-1 != t->pinnacle_id) - tda9887_miro(t); - else - tda9887_configure(t); + tda9887_configure(t); break; case AUDC_CONFIG_PINNACLE: @@ -415,7 +591,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) int *i = arg; t->pinnacle_id = *i; - tda9887_miro(t); + tda9887_configure(t); break; } /* --- v4l ioctls --- */ @@ -423,16 +599,52 @@ tda9887_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; - t->radio = 0; - t->tvnorm = vc->norm; - if (-1 != t->pinnacle_id) - tda9887_miro(t); - else - tda9887_configure(t); + CHECK_V4L2; + t->radio = 0; + if (vc->norm < ARRAY_SIZE(map)) + t->std = map[vc->norm]; + tda9887_fixup_std(t); + tda9887_configure(t); + break; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + + SWITCH_V4L2; + t->radio = 0; + t->std = *id; + tda9887_fixup_std(t); + tda9887_configure(t); break; } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + SWITCH_V4L2; + if (V4L2_TUNER_ANALOG_TV == f->type) { + if (t->radio == 0) + return 0; + t->radio = 0; + } + if (V4L2_TUNER_RADIO == f->type) { + if (t->radio == 1) + return 0; + t->radio = 1; + } + tda9887_configure(t); + } default: /* nothing */ break;