[PATCH] v4l: 683: some v4l2 api calls implemented on msp3400.c
[safe/jmp/linux-2.6] / drivers / media / video / msp3400.c
index 6239254..6e2b077 100644 (file)
@@ -124,10 +124,14 @@ module_param(standard,         int, 0644);
 module_param(amsound,          int, 0644);
 module_param(dolby,            int, 0644);
 
+MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Simple, 2=Simpler");
 MODULE_PARM_DESC(once, "No continuous stereo monitoring");
 MODULE_PARM_DESC(debug, "Enable debug messages");
+MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
 MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
 MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
+MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
+
 
 MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
 MODULE_AUTHOR("Gerd Knorr");
@@ -378,6 +382,7 @@ static void msp3400c_setvolume(struct i2c_client *client,
 {
        int val = 0, bal = 0;
 
+muted=0;
        if (!muted) {
                /* 0x7f instead if 0x73 here has sound quality issues,
                 * probably due to overmodulation + clipping ... */
@@ -737,15 +742,13 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout)
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
                } else {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(msecs_to_jiffies(timeout));
+                       schedule_timeout_interruptible
+                                               (msecs_to_jiffies(timeout));
                }
        }
-       if (current->flags & PF_FREEZE) {
-               refrigerator ();
-       }
 
        remove_wait_queue(&msp->wq, &wait);
+       try_to_freeze();
        return msp->restart;
 }
 
@@ -987,6 +990,8 @@ static int msp34xx_modus(int norm)
 {
        switch (norm) {
        case VIDEO_MODE_PAL:
+               dprintk(KERN_DEBUG "msp34xx: video mode selected to PAL\n");
+
 #if 1
                /* experimental: not sure this works with all chip versions */
                return 0x7003;
@@ -995,12 +1000,16 @@ static int msp34xx_modus(int norm)
                return 0x1003;
 #endif
        case VIDEO_MODE_NTSC:  /* BTSC */
+               dprintk(KERN_DEBUG "msp34xx: video mode selected to NTSC\n");
                return 0x2003;
        case VIDEO_MODE_SECAM:
+               dprintk(KERN_DEBUG "msp34xx: video mode selected to SECAM\n");
                return 0x0003;
        case VIDEO_MODE_RADIO:
+               dprintk(KERN_DEBUG "msp34xx: video mode selected to Radio\n");
                return 0x0003;
        case VIDEO_MODE_AUTO:
+               dprintk(KERN_DEBUG "msp34xx: video mode selected to Auto\n");
                return 0x2003;
        default:
                return 0x0003;
@@ -1418,8 +1427,8 @@ static int msp_detach(struct i2c_client *client);
 static int msp_probe(struct i2c_adapter *adap);
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
-static int msp_suspend(struct device * dev, u32 state, u32 level);
-static int msp_resume(struct device * dev, u32 level);
+static int msp_suspend(struct device * dev, pm_message_t state);
+static int msp_resume(struct device * dev);
 
 static void msp_wake_thread(struct i2c_client *client);
 
@@ -1439,7 +1448,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-       I2C_DEVNAME("(unset)"),
+       .name      = "(unset)",
        .flags     = I2C_CLIENT_ALLOW_USE,
         .driver    = &driver,
 };
@@ -1454,7 +1463,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
         client_template.addr = addr;
 
         if (-1 == msp3400c_reset(&client_template)) {
-                dprintk("msp3400: no chip found\n");
+                dprintk("msp34xx: no chip found\n");
                 return -1;
         }
 
@@ -1480,7 +1489,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
        if (-1 == msp3400c_reset(c)) {
                kfree(msp);
                kfree(c);
-               dprintk("msp3400: no chip found\n");
+               dprintk("msp34xx: no chip found\n");
                return -1;
        }
 
@@ -1490,9 +1499,10 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
        if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
                kfree(msp);
                kfree(c);
-               printk("msp3400: error while reading chip version\n");
+               dprintk("msp34xx: error while reading chip version\n");
                return -1;
        }
+       printk(KERN_INFO "msp34xx: rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
 
        msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance);
 
@@ -1511,7 +1521,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
        }
 
        /* hello world :-) */
-       printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c));
+       printk(KERN_INFO "msp34xx: init: chip=%s", c->name);
        if (HAVE_NICAM(msp))
                printk(" +nicam");
        if (HAVE_SIMPLE(msp))
@@ -1760,6 +1770,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
                break;
        }
+
        case VIDIOCSCHAN:
        {
                struct video_channel *vc = arg;
@@ -1780,6 +1791,92 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        }
 
        /* --- v4l2 ioctls --- */
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *id = arg;
+
+               /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
+               if (*id & V4L2_STD_PAL) {
+                       msp->norm=VIDEO_MODE_PAL;
+               } else if (*id & V4L2_STD_SECAM) {
+                       msp->norm=VIDEO_MODE_SECAM;
+               } else {
+                       msp->norm=VIDEO_MODE_NTSC;
+               }
+
+               msp_wake_thread(client);
+               return 0;
+       }
+
+       case VIDIOC_G_AUDIO:
+       {
+               struct v4l2_audio *a = arg;
+
+               memset(a,0,sizeof(*a));
+
+               switch (a->index) {
+               case AUDIO_RADIO:
+                       strcpy(a->name,"Radio");
+                       break;
+               case AUDIO_EXTERN_1:
+                       strcpy(a->name,"Extern 1");
+                       break;
+               case AUDIO_EXTERN_2:
+                       strcpy(a->name,"Extern 2");
+                       break;
+               case AUDIO_TUNER:
+                       strcpy(a->name,"Television");
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               msp_any_detect_stereo(client);
+               if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
+                       a->capability=V4L2_AUDCAP_STEREO;
+               }
+
+               break;
+       }
+       case VIDIOC_S_AUDIO:
+       {
+               struct v4l2_audio *sarg = arg;
+
+               switch (sarg->index) {
+               case AUDIO_RADIO:
+                       /* Hauppauge uses IN2 for the radio */
+                       msp->mode   = MSP_MODE_FM_RADIO;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_EXTERN_1:
+                       /* IN1 is often used for external input ... */
+                       msp->mode   = MSP_MODE_EXTERN;
+                       scart       = SCART_IN1;
+                       break;
+               case AUDIO_EXTERN_2:
+                       /* ... sometimes it is IN2 through ;) */
+                       msp->mode   = MSP_MODE_EXTERN;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_TUNER:
+                       msp->mode   = -1;
+                       break;
+               }
+               if (scart) {
+                       msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       msp->audmode = V4L2_TUNER_MODE_STEREO;
+                       msp3400c_set_scart(client,scart,0);
+                       msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+               }
+               if (sarg->capability==V4L2_AUDCAP_STEREO) {
+                       msp->audmode = V4L2_TUNER_MODE_STEREO;
+               } else {
+                       msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
+               }
+               msp_any_set_audmode(client, msp->audmode);
+               msp_wake_thread(client);
+               break;
+       }
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = arg;
@@ -1819,7 +1916,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int msp_suspend(struct device * dev, u32 state, u32 level)
+static int msp_suspend(struct device * dev, pm_message_t state)
 {
        struct i2c_client *c = container_of(dev, struct i2c_client, dev);
 
@@ -1828,7 +1925,7 @@ static int msp_suspend(struct device * dev, u32 state, u32 level)
        return 0;
 }
 
-static int msp_resume(struct device * dev, u32 level)
+static int msp_resume(struct device * dev)
 {
        struct i2c_client *c = container_of(dev, struct i2c_client, dev);