VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / media / video / tuner.c
index ab70304..18e1118 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
@@ -537,15 +539,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 +622,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 +697,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 +714,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 +748,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 +768,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 +784,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 +832,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 +874,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;
        }
@@ -990,6 +994,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 +1039,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 +1106,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 +1146,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 +1189,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 +1212,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 +1228,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;