vserver 1.9.3
[linux-2.6.git] / drivers / media / video / tuner.c
index ab70304..bac17a3 100644 (file)
@@ -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=<n> insmod option will go away soon.\n");
                printk("tuner: Please use the tuner=<n> 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);
 }